记一次清理root分区的经历

  • 2020-5-31

TL; DR

1
2
sudo journalctl --vacuum-size=7d # 仅保留最近7天的系统日志
sudo apt autoremove # 清理无用的软件包

详细经过

有一天晚上 ashwaniYDV 同学突然找到我,提醒我 gsoc.rocket.chat 挂了。我打开 URL 一看,网页内容不能正常加载了。于是,通过 ssh 连上一探究竟:

有了上次和 Sing 一起联调的经验,我估计这次又是硬盘空间不够,毕竟这 VPS 的 root 分区只有卑微 8G。上次 Sing 还特地给 home 分区重新挂载了一块 30G 的虚拟盘,这次问题应该就是 root 分区不够,先用 df -h 命令看下所有分区的可用空间:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Filesystem     1K-blocks    Used Available Use% Mounted on
udev 491520 0 491520 0% /dev
tmpfs 100732 804 99928 1% /run
/dev/xvda1 8065444 8049313 16131 99.8% /
tmpfs 503648 0 503648 0% /dev/shm
tmpfs 5120 0 5120 0% /run/lock
tmpfs 503648 0 503648 0% /sys/fs/cgroup
/dev/loop0 18688 18688 0 100% /snap/node/2369
/dev/loop4 18688 18688 0 100% /snap/node/2485
/dev/loop5 18432 18432 0 100% /snap/amazon-ssm-agent/1480
/dev/xvdf 31441920 714156 30727764 3% /home
tmpfs 100728 0 100728 0% /run/user/1000
/dev/loop3 18432 18432 0 100% /snap/amazon-ssm-agent/1566
/dev/loop1 96128 96128 0 100% /snap/core/8935
/dev/loop6 96256 96256 0 100% /snap/core/9066

显然,root 分区剩余空间只剩 0.2% 了,这占用率程序能正常工作才怪了。先用 du 看下具体的空间占用情况:

1
2
cd /
sudo du -ah --max-depth=1

发现 /usr/var 目录分别占用 2.1G 和 1.5G 。重复操作最终发现 /usr/src 目录下有一堆 linx-aws-headers-* 文件,占用大概1.5G;var/log 目录下的日志占用共 800M 左右;而其它一些占空间都是一些 libbin 啥的,这些肯定不能乱删,说不定一个不小心服务器就直接 shut down 了。 作为一个业余运维,多年来的经验告诉我,root 分区下的任何一个文件都不要直接用 rm 乱删,除非它是你创建的或你知道它是干什么的。

Google 一通,发现 linux-aws-headers-* 这些文件可以通过 apt 包管理器清理:

1
2
3
4
$ sudo apt autoremove
Reading package lists... Error!
E: Could not create temporary file for /var/cache/apt/pkgcache.bin - mkstemp (28: No space left on device)
E: The package lists or status file could not be parsed or opened.

呕吼完蛋,想清理 linux-aws-headers-* 但缺少空间执行这个操作。这就陷入死循环了。只能先清理其它文件了,还是拿日志开刀吧,我突然发现 journal.log 这个日志竟有 790M,把它删了,日志基本就不占空间了。借助 journalctl 自带日志清理的功能:

1
2
sudo journalctl --vacuum-time=2d # 仅保留最近两天的系统日志,多余的都自动删掉
sudo journalctl --vacuum-size=50M # 仅保留50M大小的系统日志,多余的都自动删掉

执行 journalctl --vacuum-size=10M 后,空间瞬间腾出了 700 多M出来,接着用 apt 清理多余的包:

1
2
sudo apt autoremove
sudo apt autoclean

linux-aws-headers-* 这些多余的包被如愿清理了,root 分区占用率一下子减到 62%,再用 pm2 重启一下进程 sudo pm2 restart 0,打开开头提到的网址,工作正常,收工!

JavaScript: push, pop, shift and unshift

  • 2020-5-14
20200518085839

JavaScript: typeof

  • 2020-5-14

As to typeof operator, we need to keep three 4 in ming:

  1. It returns a string ('undefined', 'object', 'boolean', 'number', 'bigint', 'string', 'symbol' and 'function')
  2. typeof null === 'object' (a never fixed bug, see here)
  3. typeof NaN === 'number' (even if NaN is "not a number", Use Number.isNaN to test NaN instead)
  4. typeof [] === 'object' (Use Array.isArray to test array instead)

How to get LAN IP address on MacOS

  • 2020-5-14

Different from using ifconfig to get this info on Linux. On Macos, we need to use arp -a to query this info.

apps-engine event handlers

  • 2020-4-21

Here we take creating a new livechat room closed event handler as an example.

Update AppMethod enum

The enum AppMethod maintains all the methods available to the app, thus we need to update this enum to the beginning.

  • Edit the file definition/metadata/AppMethod.ts, add EXECUTE_POST_LIVECHAT_ROOM_CLOSED = 'executePostLivechatRoomClosed' to the AppMethod enum.

Create IPostLivechatRoomClosed interface

Creating a new IPostLivechatRoomClosed interface so that apps can choose whether to implement this interface according their actual needs.

  • Create a new file IPostLivechatRoomClosed.ts under the directory definition/livechat

  • Define the interface IPostLivechatRoomClosed in this file, the content is something like below:

    IPostLivechatRoomClosed.ts
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import { IHttp, IPersistence, IRead } from '../accessors';
    import { AppMethod } from '../metadata';
    import { ILivechatRoom } from './ILivechatRoom';

    /**
    * Handler called after a livechat room is closed.
    */
    export interface IPostLivechatRoomClosed {
    /**
    * Method called *after* a livechat room is closed.
    *
    * @param livechatRoom The livechat room which is closed.
    * @param read An accessor to the environment
    * @param http An accessor to the outside world
    * @param persistence An accessor to the App's persistence
    */
    [AppMethod.EXECUTE_POST_LIVECHAT_ROOM_CLOSED](data: ILivechatRoom, read: IRead, http: IHttp, persistence: IPersistence): Promise<void>;
    }

  • Export the new interface in the definition/livechat/index.ts file.

Update AppInterface enum

We maintain all interfaces that apps can implement via a enum AppInterface in the file AppImplements.ts under the directory server/compiler. Notice that currently all items of AppInterface are exactly events' keys that we used them on the RocketChat side. In short, AppInterface maintains all the event handlers that apps can choose to implement.

  • Add the new interface we created above IPostLivechatRoomClosed = IPostLivechatRoomClosed to this enum.

Update AppListenerManager

Another essential step that we need to finish is to execute the new AppMethod executePostLivechatRoomClosed and the contextual data to it while receiving corresponding events. We do this work in the class AppListenerManager of the file AppListenerManager.ts in the directory server/managers.

  • Update the method executeListener's signature (params' data type and return value's data type) if needed

  • Add a new case branch to the method executeListener

    1
    2
    3
    4
    ...
    case AppInterface.IPostLivechatRoomClosed:
    return this.executePostLivechatRoomClosed(data as ILivechatRoom);
    ...

  • Define a new event handler method executePostLivechatRoomClosed

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    private async executePostLivechatRoomClosed(data: ILivechatRoom): Promise<void> {
    const cfLivechatRoom = Utilities.deepCloneAndFreeze(data);

    for (const appId of this.listeners.get(AppInterface.ILivechatRoomClosedHandler)) {
    const app = this.manager.getOneById(appId);

    if (!app.hasMethod(AppMethod.EXECUTE_LIVECHAT_ROOM_CLOSED_HANDLER)) {
    continue;
    }

    await app.call(AppMethod.EXECUTE_LIVECHAT_ROOM_CLOSED_HANDLER,
    cfLivechatRoom,
    this.am.getReader(appId),
    this.am.getHttp(appId),
    this.am.getPersistence(appId),
    );
    }
    }

    executePostLivechatRoomClosed is a manager method that is responsible for distributing the contextual data to each event handler app.call(AppMethod.EXECUTE_POST_LIVECHAT_ROOM_CLOSED, data) of apps who implemented the interface. As for the method app.call, it's a common wrapper. We need to logging, doing some checks before executing the real events handlers that apps implemented.

Vim Advanced - Day 8

  1. q: Show command history; q/ Show history for searches

How to remap complex shortcuts using Karabiner Elements

We can use Karabiner Complex Modification online editor to finish such work.

Links

  1. Karabiner-Elements complex_modifications rules

How to disable Mac's radius corner of the window

Tested on Catalina 10.15.3 | Last Updated: Wed Apr 8 22:32:32 CST 2020

  1. Disable SIP (There are lots tutorial online to teach you how to do it, will not expand the details here)

  2. Install ThemeEngine (Note: only this build supports catalina 10.15)

  3. Make system volume writable: sudo mount / -uw

  4. Backup original theme resources: rsync -rI /System/Library/CoreServices/SystemAppearance.bundle/Contents/Resources/ .

  5. Create a new folder for editing the theme file: mkdir edited && cd edited

  6. Copy a theme file here and edit it (SystemApperance.car for the light theme and DarkAquaAppearance.car for the dark theme). Take SystemAppearance.car as an example:

    1
    2
    cp ../SystemAppearance.car .
    open . # Open this folder with finder

  7. Double click the file SystemAppearance.car to edit it with ThemeEngine that we installed before

  8. Edit WindowFrame_WindowShapeEdges

    • Replace masks to squares
    • Replace base images to pure transparent images
  9. Save all changes, replace the modified SystemAppearance.car back to the system path.

    1
    sudo cp SystemAppearance.car /System/Library/CoreServices/SystemAppearance.bundle/Contents/Resources/

  10. Reboot

Links

  1. ThemeEngine - GitHub
  2. macOS Mojave disable all 4 rounded window corners either with defaults, or software, or programatically
  3. square-macos-windows - GitHub

How we manage icons in Rocket.Chat?

  • 2020-3-6
  1. Add a new SVG icon file into app/ui-master/public/icons folder
  2. Run the automation script node ../generateSprite.js to generate icons.svg from those SVG files in the above folder. (the SVG's filename is exactly the icons' identifier)
  3. In the meteor.startup callback function, using Asset.getText to download icons.svg file as plain text to the client first, and then with the help of injectIntoBody function to insert the entire content as raw text into the body.

Note: the generated icons.svg the file contains multiple icons, where we use the tag symbol as a delimiter.

Remove default ABC input method on Mac

  • 2020-3-5

TL;DR

1
code ~/Library/Preferences/com.apple.HIToolbox.plist

Delete the dict that represents the ABC method and it will take effect after rebooting the system.