半吊子全栈开发者的日常

类比 systemd 的 macOS launchd 使用笔记

现在各大 Linux 发行版很多都变成 systemd 的形状了,连 Synology DSM 7 都开始用 systemd 了,可以说是 Learn once, operate anywhere。不过有时候还是要在 Mac 机器上部署一些服务,需要用到 launchd/launchctl。

本文以一个熟悉 systemd/systemctl 工具的运维视角,整理了常用的 launchd 相关命令备忘。(说实话我每次都会忘记怎么用,然后得去翻手册……而且网上有时候还会教你用 load/unload 子命令,这些其实都已经标记为过时了,有新的命令替代它们)

> READ MORE...

禁止 Synology/QNAP NAS 通过 ssh 密码登录

使用成品 NAS,在相对省心的同时,也意味着更低的自由度。很多自定义操作都是在和这些定制化 OS 斗智斗勇。

本文介绍了在 QNAP 威联通 NAS(以及 Synology 群晖 NAS)上关闭 ssh 密码登录,仅允许密钥登录的方法。Synology 相对还好,对 OpenSSH 的魔改不多,和普通 Linux 一样修改 /etc/ssh/sshd_config 就好了。

但是 QNAP 这个 B,每次启动 sshd 服务都会重新生成配置,直接修改上述配置文件是没法持久化保存的。

> READ MORE...

修复 Synology NAS 升级后 M.2 存储池兼容性问题

我的主力 NAS 是 Synology 群晖 DS920+,陪了我也快 4 年了。DS920+ 出厂默认是不支持将 M.2 NVMe SSD 作为存储池的,只能作为缓存使用。后来出的 DS923+ 倒是支持创建 M.2 存储池了,但是只能用它自家的兼容性列表中的盘,也不知道套的哪家 OEM,贵得要死,买是不可能买的这辈子不可能买的。

好在有大神写了脚本 Synology_HDD_db,可以直接修改这个「兼容性列表」所在的数据库,把你在用的硬盘型号加进去。系统一读这个数据库发现型号在里面,就可以正常使用了。不过缺点是每次系统更新后,都需要重新执行一遍脚本。

今天看到关于 飞牛 fnOS 0day 漏洞 的帖子,寻思着也给 DS920+ 更新一下系统,毕竟一直都稳定运行着,也没有特意去升级。虽然我没用飞牛,也没有把服务暴露到公网,不过各家 NAS 系统的 CVE 其实都挺多的,以防万一嘛。

结果升级完系统 NAS 就开始疯狂嘀嘀嘀叫,才想起来还有硬盘兼容性这一茬……太久远了,顺手记录一下,免得下次再忘了。

> READ MORE...

极空间与 QNAP NAS 实现共享 NUT UPS

我有三台 NAS,Synology 群晖、QNAP 威联通和 ZSpace 极空间,前者放在出租屋里作为主力,后两台放在老家作为备份。

因为极空间是 arm64 版本双盘位的,功耗不高,所以和 QNAP 共用一台 UPS 就好了。之前折腾了一下,让极空间作为 Master 通过 USB 连接 UPS,然后 QNAP 作为 Slave 通过 NUT (Network UPS Tools) 局域网连接。

不过因为涉及到系统文件改动,每次极空间系统升级后都需要重新操作一遍,每次我都会忘记要怎么捣鼓……所以写篇博客记录下。

话说 2025 年居然一篇博客都没写,工作太忙了呀,而且总是犯懒。以前上学的时候写博客,不怎么理解那些断更的博主,现在可以体会到那种感觉了……草稿倒是堆了很多,希望明年可以发出来吧!

> READ MORE...

重构博客友链页面 & 友链朋友圈开源

先来看看效果:友情链接 - PRIN BLOG

自我感觉还是不错的,友链的博客们有什么更新都可以实时展示在页面上,一目了然。作为博主,不用打开 RSS 阅读器就可以查看新文章;作为访客,也可以快速找到更多自己感兴趣的内容,比起原来全是链接的页面,看起来也让人更有点击欲望了。

从临时起意到开发完成总共两个晚上,最速传说就是我!(误)

> READ MORE...

真的不可以在 React 组件内部嵌套定义子组件吗?

最近在 Code Review 时,看到有同事写了这样的代码:

function TodoList() {
  const [list, setList] = useState([]);

  const TodoItem = useCallback((props) => {
    return <li>{props.text}</li>;
  }, []);

  return <ul>{list.map((item, index) => <TodoItem key={index} text={item} />)}</ul>;
}

有经验的 React 开发者肯定一下子就看出问题了:在组件内部嵌套定义组件,会导致子组件每次都重新挂载。因为每次渲染时,创建的函数组件其实都是不同的对象。

但是他又有包了 useCallback 让引用保持一致,好像又没什么问题……?

这波骚操作让我突然有点拿不准了,所以今天咱们一起来验证一下,用 useMemo 或者 useCallback 包裹嵌套定义的子组件,对 React 渲染会有什么影响。以及如果有影响,应该如何用更合适的方法重构。

> READ MORE...

使用 TikZ 在 Hexo 博客中愉快地画图

一转眼就到 2024 年了!大家新年快乐!

前段时间在写文章时,需要一些配图,于是就使用了 TikZ 来绘制。TikZ 是一个强大的 宏包,可以使用代码的形式绘制出各种各样精美的矢量图。

xf(x)f(x)=xf(x)=sinxf(x)=120exA0B0ABC0D0CDf0ag0h0bfhk0cdkg

如果你的阅读器看不到上面的 SVG 格式图片,可以点这里查看 PNG 格式。 example-tikz-graph

上面的图对应的 TikZ 代码可以在这里找到。然而画是画爽了,想把它贴到博客里时却犯了难——目前竟然没有什么好办法可以直接在博客里使用 TikZ!

> READ MORE...

详解 PixiJS Filter 中的参数与坐标系

除草啦除草啦,再不更新博客就要变成热带雨林啦!🌿

最近在给一个 PixiJS 程序编写 WebGL Shader,被各种参数和坐标系搞得晕头转向。痛定思痛,整理了一下 PixiJS Filter 系统中的各种概念,以供后续参阅。

在 WebGL 中,我们可以通过编写顶点着色器 (Vertex Shader) 和片元着色器 (Fragment Shader) 来实现各种各样的渲染效果。而在 PixiJS 中,渲染引擎为我们屏蔽了绝大多数的底层实现,通常情况下用户是不需要自己调用 WebGL API 的。如果有编写自定义着色器代码的需求,一般是使用 Filter 来实现。

> READ MORE...

逆向拼多多上的「关灯神器」,实现蓝牙遥控开关灯

依稀记得以前在某个友链博主那边看到过一篇文章,讲的是因为他们寝室所有人都懒得下床关灯,所以就用树莓派和舵机做了个远程遥控关灯的小玩意儿,当时我就感叹,果然懒才是第一生产力。

自从今年初开始出来租房住,突然就感觉睡前关灯变得好麻烦好麻烦。我的房间里是有好几盏灯的,床头的开关只能控制其中的两盏,剩下的开关在另一个地方,另外还有一个总开关位于进门的门厅处。于是我就陷入了两难之境:

  • 不用总开关:每天睡前把灯一一关掉,第二天回家又得一一开回来;
  • 直接用总开关:开关离床太远,关完灯要摸黑上床,早上起来又得先过去开灯。

不爽,太不爽了!现在都讲究智能家居,我这他喵的是智障家居啊……

> READ MORE...

在 M1 Mac 上运行 macOS 虚拟机

Apple M1 芯片问世一年有余,时至今日,在 M1 Mac 上运行 Windows、Linux 虚拟机的方法都已经比较成熟了。然而 macOS 本身的虚拟化却并非如此:直到 Monterey 发布,于 M1 Mac 上运行 macOS 虚拟机才成为可能。

最近有几个小实验需要在 macOS 虚拟机上跑,本来以为去 Parallels Desktop 上开一个就完事了,搜了一下才发现,其实事情没那么简单……实际配置过程中也是踩了几个坑,所以顺带记录一下。

> READ MORE...