Akawa

ETY001的博客

最近在弄faucet 的重构工作,因为要全面使用新的依赖和模式,遇到了很多问题。

比如最近一周一直被 jest 无法在 ESM 模式下工作的问题卡住。

搜索引擎 + chatgpt 多方面的尝试都没有找到有效方案。

直到昨天看到 jest 官方文档里有专门的一页说这个,才搞定问题。

解决方案就是两步。

第一步是用空配置 {} 替换掉之前的 jest.config.jstransform,即关闭 transform

第二步增加环境变量 --experimental-vm-modules,以启用 node 的实验 API,因为 jest 使用的 node 的实验 API 实现的 ESM 支持,这也就意味着,可以卸载掉 babel-jest 插件了。

启用实验 API 这里, jest 官方文档只给了两个 CLI 下的使用例子,而我们的项目使用的是 package.json 中的 scripts 方式。

因此要想在 scripts 里启用,可以按照下面的格式:

1
2
3
"scripts": {
"jest": "NODE_OPTIONS=--experimental-vm-modules jest"
},

每次看完用完,因为别的项目又切换到非 js 语言,过段时间就又忘了,所以写下来总结一下,要不然每次都要现搜索。

使用 import 导入的时候是否加扩展名?

是的,在 ESM 模式下,使用 import 时需要包含文件的扩展名。

这是因为 ESM 模块解析严格遵循文件路径规范,不像 CommonJS 那样自动推断 .js、.json 或 .mjs 等扩展名。

假设有下面的文件结构

1
2
3
4
project/
├── app.js
└── utils/
└── helper.js

在 app.js 中,你需要这样导入 helper.js

1
import { myHelperFunction } from './utils/helper.js';

加 {} 和不加 {} 的区别

在 JavaScript 中,import 语句的语法有两种主要形式:具名导入和默认导入。

加 {} 和不加 {} 的区别在于你是导入模块中的一个具名导出还是默认导出。

1. 具名导入 (Named Import)

1
2
3
4
5
6
7
8
9
10
11
12
13
// utils.js
export const myFunction = () => {
console.log('This is myFunction');
};

export const anotherFunction = () => {
console.log('This is anotherFunction');
};

// main.js
import { myFunction } from './utils.js';

myFunction(); // 输出: This is myFunction

2. 默认导入 (Default Import)

1
2
3
4
5
6
7
8
9
10
11
// utils.js
const myFunction = () => {
console.log('This is myFunction');
};

export default myFunction;

// main.js
import myFunc from './utils.js';

myFunc(); // 输出: This is myFunction

这里对我来说,如果不看文档,纯靠我自己的经验
我一直以为不加 {} 的时候,是把整个文件导出的
也就是按照例子的代码,我的直观感觉应该是 myFunc.myFunction()

之前尝试过好几次,使用 xmodmap 来修改键位,但是都是以失败告终。

每次都是以为懂了,结果都是失败。

最近在一台 Chromebook 上装了 Archlinux,再次尝试调换键位。

想把 Search 键和 左Control 键对换位置。

下面是按键对应的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
--- xev 获取到两个按键的信息 ---
keycode 133 (keysym 0xffeb Super_L)
keycode 37 (keysym 0xffe3 Control_L)

--- xmodmap -pke | grep Control_L 和 grep Super_L 的信息---
keycode 37 = Control_L NoSymbol Control_L
keycode 133 = Super_L Super_L Super_L Super_L Caps_Lock Super_L Caps_Lock
keycode 206 = NoSymbol Super_L NoSymbol Super_L

--- xmodmap -pm 的信息 ---
shift Shift_L (0x32), Shift_R (0x3e)
lock Caps_Lock (0x42)
control Control_L (0x25), Control_R (0x69)
mod1 Alt_L (0x40), Alt_L (0xcc), Meta_L (0xcd)
mod2 Num_Lock (0x4d)
mod3 ISO_Level5_Shift (0xcb)
mod4 Super_L (0x85), Super_R (0x86), Super_L (0xce), Hyper_L (0xcf)
mod5 ISO_Level3_Shift (0x5c)

尝试创建了一份 .Xmodmap 配置如下:

1
2
3
4
5
6
remove control = Control_L
remove mod4 = Super_L
add mod4 = Control_L
add control = Super_L
keycode 37 = Super_L
keycode 133 = Control_L

结果失败了。

不过经过不懈搜索,发现了一个替代方案 – keyd.

这个项目就是为了解决各种键盘问题的,非常感谢这个项目。

同时还找到了一份 针对 Chromebook 的 keyd 配置

通过下面的命令来获取一下按键的名字

1
sudo keyd monitor

根据得到的键位信息,在上面的那份配置的基础上,增加下面的内容

1
2
3
4
5
[main]
....

leftmeta = leftcontrol
leftcontrol = leftmeta

重新载入一下

1
sudo keyd reload

搞定!

咱就说,Linux 下很多东西(iptables啊,X11啊)的配置也不知道为啥搞的很反人类,明明是可以搞的这么简单的啊!

最近我的 BTS 见证人总是收到丢块报警,排查了原因,大概率是因为 API 和 出块都使用同一个程序的原因。

从 Abit 那里了解到,API 请求和出块并没有做线程优先级,所以在有大量 API 请求进入或者长耗时操作的时候,都会对出块造成影响。

对于底层的 C++ 改起来太麻烦,主要我也不会改,所以思路变换一下,那么就在入口位置进行拦截。

最初尝试使用 nginx 的 limit_conn 来限流,但是没有效果。

主要原因是 Websocket 握手建立连接后,就不会再触发规则了,而所有的请求都以 Websocket 的消息形式与后端交互了。

于是换成了 openresty,通过 lua 来建立一个 Websocket 的消息转发机制,符合条件的放行,不符合的拦截。

最终代码越写越复杂,成型的规则就是在 IP 黑名单中的,且 method 也在黑名单里,那么就限流。

具体的代码实现在这里:https://github.com/ety001/openresty/blob/master/scripts/lua/bts/limit_req.lua,可以作为参考。

SPS的机制概述

  • 用户提交提案,提案只要有投票就算是激活了。
  • 提案的钱来自 steem.dao 账号,理论上每小时结算一次,按照投票数排序提案,顺次发钱,发完为止(因为每小时发放数额有限)。

资金来源

steem.dao 账号的资金来源于每次出块时 10% 的 steem,按照喂价中位数转化为 SBD 后存入,同时更新 dgp.sps_interval_ledger(相关逻辑在 database::process_funds() 中)。

dgp.sps_interval_ledger 会在每小时结算的时候清零(相关逻辑在 sps_processor::record_funding() 中)。

资金发放

公式一:

1
每天发放资金量 = steem.dao中的 SBD 数量 / 100 + 每日通胀

公式二:

1
当前小时发放资金 = (当前块时间戳 - 上次发放时间戳)/(24*3600) * 每天发放资金量

发放资金的时候,会按照投票数,从多到少排序所有激活的提案。

然后遍历排序好的提案,每个提案从公式二计算出的资金里发钱,直到公式二计算的资金发完为止(该逻辑在 sps_processor::transfer_payments() )。

备注1: 当前块时间戳,在区块浏览器的某个块的 timestamp 字段。
备注2: 上次发放时间戳,可以从 dgp.last_budget_time 获得。
备注3: SPS 中的通胀在当前的 HF23 版本还没有设计好,所有涉及到通胀的地方都是 0。
备注4: 公式一和公式二在 sps_processor::calculate_maintenance_budget() 中。
备注5: https://steemdb.io/block/79880772 在这个页面的 Virtual Ops 下可以看到当时那个小时的结算情况。

当前状态

目前排名第一的提案,每小时提取 24w SBD 到 steem.dao 账号,而系统每小时发放的资金大约在 1600 SBD,所以第一名的提案把钱都花完了,相当于变相停止了 SPS 系统。

但是目前排名第一的提案截止到 2029年12月31日,在其后面的还有一个截止 2030年3月1日的。这就意味着,最后这个提案可以从 2030年1月1日 到 2030年3月1日,每小时获得 1000 SBD。

在 Archlinux 下通过 snapcraft 安装了 Tradingview。但是登陆是通过浏览器网页登陆后,跳转回程序完成登陆。

而 Chrome 浏览器调用 xdg-open 打开 tradingview:// 格式的 URI 时,提示找不到程序,无法打开。

解决方法就是在 ~/.config/mimeapps.list 中,在 [Default Applications] 块里加入下面一行

1
x-scheme-handler/tradingview=tradingview_tradingview.desktop

保存退出后,可以执行下面的命令,查看是否添加成功

1
xdg-mime query default x-scheme-handler/tradingview

之后,再次登陆即可成功跳转到 Tradingview 程序。

最近需要在服务器上安装桌面。于是总结一下。

1
2
3
apt update && apt-get upgrade -y && \
apt install -y xubuntu-desktop && \
apt install -y xrdp

在用户家目录输出 xfce4 的 session

1
echo "xfce4-session" | tee .xsession

重启 xrdp

1
systemctl restart xrdp

Android 12及以上用户在使用Termux时,有时会显示 [Process completed (signal 9) - press Enter],这是因为Android 12的 PhantomProcesskiller 限制了应用的子进程,最大允许应用有32个子进程。

解决方案就是通过 adb 命令来修改底层的配置,命令如下:

1
2
adb shell device_config set_sync_disabled_for_tests persistent 
adb shell device_config put activity_manager max_phantom_processes 65536

这两条命令执行完,即修改最大子进程数为 65536。

补充:

可以直接在 termux 中安装 adb 工具,使用开发者工具里的无线调试来连接,并执行上面的两条指令。

1
2
3
4
5
pkg install android-tools

adb pair ip:port

adb connect ip:port

补充:

鸿蒙系统的话,执行下面的命令

1
2
adb shell /system/bin/device_config set_sync_disabled_for_tests persistent 
adb shell /system/bin/device_config put activity_manager max_phantom_processes 65536

1.安装 termux

https://github.com/termux/termux-app 下载并安装

2.打开 termux 执行下面的命令

1
2
3
4
5
$ pkg update
$ pkg upgrade
$ pkg install x11-repo proot-distro pulseaudio vim
$ pkg install termux-x11-nightly virglrenderer-android
$ proot-distro install archlinux

上面的命令是更新 termux 的包管理,安装 x11 相关工具,安装 proot,安装声音相关内容,安装 3D 相关内容,安装 archlinux。

3.进入 archlinux

1
$ proot-distro login archlinux --user root --shared-tmp

以 root 用户身份进入 archlinux,并且跟 termux 共享 /tmp

4.更换 archlinux 源(/etc/pacman.d/mirrorlist)

1
Server = https://mirrors.tuna.tsinghua.edu.cn/archlinuxarm/$arch/$repo

5.更新安装archlinux相关内容

1
2
3
# pacman -Syu
# pacman -S vim firefox networkmanager xorg xorg-server pulseaudio noto-fonts-cjk git openssh fakeroot base-devel
# pacman -S xfce4 xfce4-goodies lightdm tigervnc

6.配置密码和普通用户

1
2
3
4
# passwd
# pacman -S sudo
# useradd -m -g users -G wheel,audio,video,storage -s /bin/bash ety001
# passwd ety001

7.配置 sudo

1
2
3
# vim /etc/sudoers

ety001 ALL=(ALL:ALL) NOPASSWD: ALL

8.安装 yay

1
2
# su ety001
$ git clone https://aur.archlinux.org/yay.git && cd yay && makepkg -si

9.设置时区

1
# ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

10.配置语言

修改 /etc/locale.genzh_CN.开头的注释符,并执行 locale-gen

配置默认语言

1
# echo "LANG=zh_CN.UTF-8" >> /etc/locale.conf

11.配置 vncserver

1
$ vncserver -localhost

如果是第一次启动 vncserver,会提示配置 vnc 的密码。

1
$ vncserver -kill :1

停止服务,然后访问 ~/.vnc/xstartup,注释掉所有内容后,添加下面的内容

1
startxfce4 &

这样启动 vncserver 后,会执行启动 xfce4 桌面的命令。

这里需要注意的是,在启动 vncserver 前,还需要设置下面的环境变量

1
export DISPLAY=:1

12.启动桌面

回到 termux,创建 start.sh 脚本

1
2
3
4
5
6
7
pulseaudio --start --load="module-native-protocol-tcp auth-ip-acl=127.0.0.1 auth-anonymous=1" --exit-idle-time=-1

pacmd load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1 auth-anonymous=1

virgl_test_server_android &

proot-distro login archlinux --user ety001 --shared-tmp -- bash -c "export DISPLAY=:1 PULSE_SERVER=tcp:127.0.0.1; dbus-launch --exit-with-session vncserver :1"

以后,只需要打开 termux 后,执行 start.sh 脚本即可启动 archlinux 容器和桌面。

只需要用 vnc 软件连接 127.0.0.1:5901 即可。

另外,还需要在 xfce4 的配置面板中,关闭屏保和锁屏功能。

0%