EAimTY 的博客
肥宅
首页
关于
主题
LeetCode 笔记

我从今年六月开始学 Rust,到现在差不多有半年了。写 hummingbird 这个项目的想法我在八月就已经有了:写一个用 git 仓库作为数据库的内容管理系统,给 git repo 中 markdown 格式的文章套 HTML 模板,然后 serve。
这样能结合传统 CMS 和 GitHub Pages 的优点——能用对于 CMS 本身只读的 git 仓库保证数据的安全性,也能像传统的 CMS 一样提供动态内容,比如搜索文章内容,甚至支持在一次搜索中使用多个 filter 来缩小范围,还不必像(免费版) GitHub Pages 一样只能建在公开仓库上。GitHub 的仓库文件编辑器还可以直接视为管理后台。
当然这种实现也会导致一些限制,例如不能原生支持评论,能实现的功能比较少,数据库更新不能太频繁,比起 GitHub Pages 需要一台服务器来跑服务端...
hummingbird 比 WordPress 大概会快十倍吧,大概(

总之我觉得这个项目应该有适合的使用场景,所以就开始动手了。经过断断续续 4 个月的开发,终于把雏形写出来了。

写 hummingbird 的过程基本上就是我入门 Rust 的过程。每过一段时间,回头看之前写的代码就会觉得写得稀烂,想重构。这个项目的数据库实现我重写过不下五次,然而现在还是觉得写得很差。这也算是学习的过程吧。

不论从代码上看,还是从软件工程角度看 hummingbird,都有些问题——某些功能实现地很幼稚,抽象也到处漏,但我总算是写完了一个比较复杂的项目,比起之前总是纸上谈兵还是有进步的。

说说大体的实现思路吧:

整个项目主要分成 3 个部分:配置、数据库和服务器 / 路由。

配置部分很简单,就是读一个 TOML 格式的配置文件然后解析数据,没什么好说的。

数据库部分大概又能分 3 个部分吧:内存里的数据库存储部分,集成的 git 客户端,还有模板系统。
存储的实现比较原始,就是在解析过 git 仓库之后把其中的所有内容存进二叉堆排序,然后转成 Vec。另外还有些关于内容作者之类的映射。
git 部分是用 libgit2 实现的,用了 git2-rs 这个 Rust 的 bindings。这里算是写项目前期坑最多的地方,libgit2 暴露的 API 层级比较低,不像平时直接用 git 命令一样方便,而且当时还不太熟悉 Rust,实现反向遍历 commits 拿到文章作者、创建时间和更改时间花了很大力气。另外,git2-rs 的仓库抽象是 !Send!Sync 的,所以刚开始写数据库时我只能做一个 RepoGuard 包住 git 仓库把它留在主线程用 Channel 通信,把剩下的部分 spawn 成 tasks 出去,从 git 仓库取数据的过程又臭又长。后面我发现 libgit2 的文档中只提到不能 parallel 地使用仓库,所以才会 !Send!Sync。hummingbird 只有在被手动触发数据更新的时候才会操作 git 仓库,而且操作会上排他锁,所以直接把仓库标成 Sync 作为数据库成员走状态共享肯定没问题。
模板系统中的 markdown 解析用了 pulldown-cmark,HTML 模板应用是自己手写的,因为 tera 这类的模板实现实在是太重了。说实话我不是很满意现在的实现,有一大堆 clone。之后我想写一个完全 Evaluate-on-Write 的、带 Cacher 的 StringBuilder。

服务器 / 路由部分我也改过很多次。最早是用 axum 写的,但后来发现 axum 的很多功能我完全用不到,比如 middleware 之类的,而且 axum 有大约四百个依赖,太重了。所以我换到了 hyper,不过就要自己解决路由的问题了。开始时我想用一张大的字典当路由表,在更新数据库的时候就把所有所有数据解析好,但是发现存储效率不是很高,改成存过程也比较难实现。最后我的解决方案是用一张字典存文章、页面和的其它的静态路径,其它有参数的路径用字典树匹配和捕获。我写了一个泛型的字典树实现,但是 bench 后发现效率比 matchit 低至少一倍, 我还是太年轻 ,所以就用了 matchit。

hummingbird 有什么适用的具体使用场景吗?我觉得可能用来 serve 长篇的文档、说明比较好(类似于 LLVM IR 这种),用来做一个简单的博客也不错,只是需要外挂评论系统。

最近架了个 Mindustry 游戏服务器和朋友一起玩 PvP(然而没玩几天就弃坑跑去 MC 了 ),感觉不错,只是每次输命令和上传地图的时候都要 ssh/sftp 到服务器上有点不方便,所以就写了个 Telegram 机器人用来输命令和上传地图:

teledustry - Manage your Mindustry server through Telegram bot

我不会写 Java,所以没把这个 bot 写成 mod 的形式,而是直接把游戏服务器进程创建为子进程,然后读写子进程的 stdio。
这个 bot 用起来很简单,只要用

$ teledustry -t API_TOKEN -u YOUR_TELEGRAM_USERNAME SERVER_FILE.jar

就可以启动 Mindustry 服务器和 bot,然后去找 bot 聊天就能执行命令和上传地图了(记得用 /output 命令让 bot 把输出发到当前聊天里)。

Pangu 是一个有名的用来在全角字符与半角字符间添加空格的库,支持多种语言,其中 Node.js 版 pangu.js 可以作为命令行前端来使用。
但是由于是 Node.js,想要用 pangu 就需要装很多依赖,类 Unix 系统有包管理还好说,在 Windows 平台下装 node 只为了用 Pangu 实在是有点麻烦。

为了解决这个问题,我写了一个 Pangu 的命令行前端 Xuanwu,基于 pangu-rs,非常简单,只有六十行代码😂,还没有任何依赖。

需要用 Pangu 的时候,可以直接到 Release 里下载编译好的可执行文件(暂时没有 macos 的,darwin 交叉编译有点麻烦),比装 node + pangu.js 方便得多。

至于为什么叫 Xuanwu 这个名字,传说玄武大帝是盘古的儿子,这个工具基于 Pangu,那自然就要叫 Xuanwu 了😂

最近一段时间在学 Rust,想写一些简单的小工具来巩固一下对语言基本特性的认识。之前用其它语言写过 Telegram bot,所以我想通过用 Rust 写 Telegram bot 来更深刻地了解 Rust 的独特之处。

Rust 相比于其它流行的语言网络上的资源比较少,中文内容更是寥寥无几。虽然我的 Rust 连入门都谈不上,代码里可能会有不少不合理的地方,但是还是想把过程记录一下,供他人参考,希望可以为 Rust 社区做一些微不足道的贡献,也算是抛砖引玉吧。

成品 bot 在 EAimTY/eaimty_bot。这是个用来练手的小项目,不止有 OCR 功能,还有一些其它的杂七杂八的功能,其中 OCR 部分在 这里

仅仅写这样一个简单的 OCR bot 并不能了解到太多 Rust 优秀的地方,毕竟写的只是像脚本一样的线性处理过程。但总归是写了点东西,对之后更深入的学习还是有点帮助的。

又是整整一年过去,是时候该总结一下之前的一年了。

过去的一年我干了什么?无非只是吃饭、睡觉、摸鱼、应付考试而已。有时候心血来潮会学习或写一些新东西,可惜都是三天打鱼两天晒网,没有向哪个方向深入就停下了。深知自己没什么技术,可是却一直提不起干劲。

由于大流行,去年有近 9 个月的时间都是在家中度过的,经常熬夜,靠外卖度日,下半年回到学校后也是经常摸鱼。过了这样一年“懒散”的生活,再加上作息与饮食的不规律,我感觉自己变“老”了。这里的“老”指的并不是年龄的增长,而是指精神状态变差。我能实在地感觉到自己的思维貌似变慢了,敏锐不再,而且对思考新问题的兴趣也变低了。我之前经常嘲讽蔑视那些因循保守,不愿意接触新事物的“笼中人”。然而现在我觉得自己也在慢慢地成为他们其中的一员。

不知这种情况是由何导致的,但是看来今年必须要处理一下了。从高中后半段开始,我就感觉自己的精神状态一天比一天差,持续到现在,睡眠质量也不断下降,而且由于身体原因,我一直以来都很少运动。在高中前半段时我还很瘦,然而现在已经变成中等偏胖的体型了。这可能是甲减和睾酮低的症状?所以我准备从适量运动开始改善精神状态。当然,这些都是推测,但运动总归是利大于弊的。饮食和睡眠也要更规律一些,不能像之前一样经常熬夜到两三点或者一天只吃一顿饭。
还有就是尽量多做一些“正经事”。很多时候我就算觉得无聊,无事可做,也不愿意学或写点新东西。之后尽量督促自己多做更有意义的事吧。

本来准备 1 月初就写出这篇文章,但是由于期末考试与放寒假之后的习惯性懒散,现在才静下心来总结。发文励己,今年加油吧。