分类
flarum

解决 flarum 0.1.0-beta.12 升级 beta.13 时 `__PHP_Incomplete_Class` 问题

我在树莓派上部署了一个 flarum 实例,用来进行官网论坛的相关开发。前阵子升级 beta.13 之后,无法打开网页,报错:

Argument 1 passed to Flarum\Formatter\Event\Rendering::__construct() must be an instance of s9e\TextFormatter\Renderer, instance of __PHP_Incomplete_Class given

这个错误很奇怪,尝试调试了一下未果。我厂的论坛比较特殊,之前从邮件列表导入了很多帖子,这些帖子的 html 很不规范,所以我们魔改 /vendor/s9e/text-formatter/src/Renderers/PHP.php,去掉了 XML 校验。我怀疑跟这个有关。因为当时很忙,就没有深入。

这个周末稍微有点时间,就尝试深入了解一下,发现了这个帖子:https://discuss.flarum.org/d/19235-argument-1-passed-to-must-be-an-instance-of

在我的实例上尝试了一下,果然是这个问题。flarum 会在实例的 /storage/cache/ 下生成类的缓存文件,用来加速程序运行。但不知为何,在我的实例下,这个文件的权限既不是当前用户也不是 www-data,所以执行 php flarum cache:clear 的时候删不掉它,但是也不报错。而打开页面时,因为缓存文件有问题,就会报前面提到的错误。

使用 sudo 删掉后实例恢复正常。

分类
应用

应用创意:传承我的数字财产

我有很多数字财产,我相信大家也是如此。其中一些不怎么值钱,比如:

  1. 消费型会员账号,比如爱奇艺
  2. 各种云,比如套路云,大概3、4台服务器,托管着这个博客,以及别的一些朋友的东西
  3. 三五个域名

这些数字财产本身不太值钱,但是突然丢失会比较麻烦。比如域名,可能是帮朋友注册的,一次性付了十年二十年的租金,但是没有指向具体的服务器,如果因为某种原因我暂时无法操作账号,那么当朋友要用域名的时候,就无从下手了。

还有一些数字财产比较值钱,但又不像支付宝微信那样为大家所知,比如各种比特币、电子钱包之类的。很可能周围的人都不知道我有这个。

所以我觉得可以做个应用,叫做“传承我的数字财产”(本来想叫“我的数字遗产”,后来觉得这个名字好像不太吉利,所以改了一下),用来在特殊情况下把这些数字财产传递下去。

简单设计一下它的功能:

  1. 用户将自己的数字财产保存到应用里,比如“meathill,meathill is handsome”
  2. 这段字符会进行加密,确保运营方无法知道内容。这个加密是可逆的,因为将来需要让接收人看到明文。
  3. 用户可以把密码线索用另一种方式保存下来,比如“我小学的名字”
  4. 用户可以设置每个财产的接收人
  5. 用户需要每天打卡,打卡也需要使用密码,单独设置
  6. 如果用户没有打卡,则进入“传承倒计时”,一般是 30 天
  7. 倒计时完成后,系统自动将数字财产,和密码线索发送给指定的接收人
  8. 至此,流程完成

举个例子。有个朋友让我搭了一套网站,然后我就把“服务器、账号、密码”等保存到“传承我的数字遗产”app 里。然后有一天我突然被外星人抓走了,与此同时朋友谈妥了一个亿的融资,准备大力发展他的网站。一周后,他收到系统发送的短信,按照密码线索猜到密码,解密信息之后,就有了完整的服务器权限了。

分类
js

使用 webpack-mock-server 给组件库添加测试服务

再过一周,我就在我厂待满三年了。其实我的职业生涯还算比较顺利,除了第一次跳槽不太好,后面每个公司都选的不错,虽然远不能满足财务自由的梦想,但是几乎都能让我在技术上有所精进,在职业上也取得一定成长。

三年期间,我们做了不少产品,为了方便在不同产品之间复用代码,我把一些公共部分抽出来做成组件,独立开发和维护,并且通过 npm + GitHub Registry 管理依赖(这个部分,前面曾写过一篇文章《使用 GitHub Registry 托管私有 NPM 源》介绍)。

有一些组件,比如登录,独立出来开发没问题,但是测试比较难搞,为了它单独开发服务器有点太兴师动众。所幸我很快就找到 webpack-mock-server,它可以很方便的定义 API 接口,只要把它加到项目中,就能很容易的完成测试了。

使用方法

1. 安装

使用 npm 安装,并且添加配置文件。安装 typescript 是因为它默认会在项目根目录里找 webpack.mock.ts,我暂时不知道怎么不用 ts 写配置。

npm install -D webpack-mock-server typescript
const webpackMockServer = require("webpack-mock-server");
 
module.exports = {
  devServer: {
    before: webpackMockServer.use
  }
}

2. 配置接口

目前这个工具只会在根目录里找 webpack.mock.ts(或者说我用的还不太熟,只会这么做),好在写 express 配置并不复杂,也不需要 ts 语法:

import webpackMockServer from "webpack-mock-server";
 
// app is expressjs application
export default webpackMockServer.add((app, helper) => {
  // you can find more about expressjs here: https://expressjs.com/
  app.get("/testGet", (_req, res) => {
    res.json("JS get-object can be here. Random int:" + helper.getRandomInt());
  });
  app.post("/testPost", (_req, res) => {
    res.json("JS post-object can be here");
  });
});

3. 检查接口

接下来,正常启动 dev-server 即可:webpack-dev-server --config=build/webpack.dev.js,然后留心控制台,会多输出一个服务网址,比如:

WebpackMockServer. Started at http://localhost:8079/

这个服务一般是 dev-server 端口 -1,比如我的 dev-server 跑在 8080,那么它就在 8079。打开之后是如下所示的接口列表:

从中可以看到所有提供服务的接口,支持什么方法,点击还能查看返回结果,非常方便。

总结

使用这个工具,可以大大提升组件库的开发效率。目前我用的也不是很熟,文档中介绍的方法还没用完,也不清楚怎么不用 ts。先推荐给大家吧。

分类
linux

解决 WSL Ubuntu 20.04 下使用 apt 源安装 node.js 的问题

随着 Ubuntu 20.04 发布,各大平台都适配发布了对应版本的系统,Windows WSL 也不例外。如果你是新系统,直接在 Microsoft Store 里搜索并安装 Ubuntu 即可;如果你是老系统,已经装过以前的版本,那么需要先卸载再安装,如果直接安装 Ubuntu 20.04 会有多个不同版本的 Ubuntu 共存。

装完系统后,接着安装其它软件。我现在比较喜欢用包管理工具安装软件,因为容易更新,而我又是更新爱好者。所以按图索骥,找到 node.js 的二进制包安装指引,复制执行:curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash - ,结果报错:gpg: can't connect to the agent: IPC connect call failed

经过搜索,得知这是 WSL 版 Ubuntu 20.04 的问题,与 WSL1 有一些不兼容,在 WSL2 上就没这个问题了。解决方案是装一些工具:

sudo add-apt-repository ppa:rafaeldtinoco/lp1871129
sudo apt update
sudo apt install libc6=2.31-0ubuntu8+lp1871129~1 libc6-dev=2.31-0ubuntu8+lp1871129~1 libc-dev-bin=2.31-0ubuntu8+lp1871129~1 -y --allow-downgrades
sudo apt-mark hold libc6

然后问题就解决了。

这个 issue 里还记录了一些别的方案,包括上面方案的修正版,不过我用起来没问题,也就没继续往下看。感兴趣的同学可以研究一下。

分类
前端

零宽空格的问题与使用

今天有同学在群里提问:

“我的请求路径是这样的”
“路径上面自动多加东西了,好奇怪”

我的第一反应是“零宽空格”,然后该同学试着手动敲了一遍 url 地址,问题果然解决了。看起来,就是因为原来的 URL 里含有零宽空格,直接复制过来,虽然看起来没问题,但是在发起请求时,非标准字符被 encode 之后就出错了。

我们姑且不管为啥他的复制来源里会有零宽空格,聊一聊什么是“零宽空格”,以及“零宽空格”能干什么。

零宽空格定义

零宽空格是空格的一种空格,但是它的宽度为零,即不显示,所以看起来跟没有一样。我们可以在浏览器里启动开发者工具,然后切换到 Console 面板,输入以下代码:

> a = '\u200b'; // 即零宽空格
"" // 其实是有内容的,只是看不到
> a.length
1 // 长度为 1,说明有东西
> encodeURIComponent(a)
"%E2%80%8B" // encode 之后跟截图里一样,破案了

维基百科的解释:

零宽空格(zero-width space, ZWSP)是一种不可打印的Unicode字符,用于可能需要换行处。

它的用法:

在HTML页面中,零宽空格可以替代 <wbr>。但是在一些网页浏览器(例如 Internet Explorer的版本6或以下)不支持零宽空格的功能。

MDN 上没有零宽空格的定义,但是有 <wbr> 的内容。之前我也写过一篇文章:使用 <wbr> 解决长 URL 的换行问题,里面介绍了 HTML 换行算法,以及我选择 <wbr> 的思路,建议大家看一下。

用途一:在特定位置换行

比如一首古诗:

锄禾日当午,汗滴禾下土。谁知盘中餐,粒粒皆辛苦。

我们有时候会希望:

  1. 在宽度足够的时候,放一行
  2. 如果宽度不够,就在标点符号处换行

这个时候,我们可以先设置这段文字 word-break: keep-all,避免在汉字后断句换行;然后在每个标点后面加上零宽空格,这样,一行的时候就不会看到奇怪的空格,而宽度不够的时候,又能根据 white-space 属性正常换行。

用途二:特殊标记

我厂有一个产品,要输出大量日志,包含大量数字。为方便阅读,需要给数字添加千位分隔符;为了方便复制,又希望剪贴板上的是纯数字,不要千位分隔符;但是如果本来就是千位分隔符的,比如在别的软件里格式化的数字,就原样复制,不需要去掉千位分隔符。

这个时候就可以用到零宽空格。我先找出来足够长的数字,然后添加千位分隔符,然后在两头加上零宽空格。这样在用户眼里,看到的是千位分隔过的数字;等他们复制的时候,我就检查两端的零宽空格,如果有的话,就复原数字;如果没有的话,就原样返回。

其它零宽字符

除了零宽空格之外,还有很多零宽字符,可以用来在页面中加入特殊标记,或者实现一些控制功能。大家如果发现 url encode 之后的内容和之前肉眼看到的不符,那么多半是存在零宽字符,可以试着干掉它们,多半问题就能解决。

分类
linux

解决 Ubuntu 20.04 下无法打开蓝牙的问题

我的 Ubuntu 20.04 启动之后经常丢掉蓝牙。表现是设置里能看到蓝牙,状态是关闭,但是无法打开,每次点击开关过一会儿就恢复了,也没有报错。

因为要连接音箱,没有蓝牙很不方便,就搜索了一下,最后发现下面的解决方案。虽然没理解问题根源,但是解决了就好。

sudo rmmod btusb
sleep 1
sudo modprobe btusb

参考链接:

  1. Bluetooth firmware upload failing after ‘suspend’
  2. Bluetooth used to be enabled, now disabled and won’t enable. Ubuntu 16.04
分类
linux

重置 MariaDB root 密码

以我最常用的 Ubuntu 为例,记录如何重置 MariaDB root 密码。MariaDB 是 MySQL 原作者在 MySQL 闭源之后的再起之作,基本能完全兼容 MySQL。在我的 Ubuntu 上,它的大部分命名都沿用 MySQL。

1. 停掉 mysql 服务

$ service mysql stop

2. 以特殊方式启动 mysql

使用 --skip-grant-tables 可以跳过用户权限检查,让你没有密码也能连接。此时为了避免安全问题,可以加上 --skip-networking,防止有人此时通过网络连接你的数据库。在本地环境下差别不大。

$ sudo mysqld_safe --skip-grant-tables --skip-networking &

这一步可能会启动失败,导致下一步连接时报错:ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ’/var/run/mysqld/mysqld.sock’ (2),此时,可以这样修正:

$ sudo mkdir /var/run/mysqld
$ sudo chown mysql /var/run/mysqld

3. 连接数据库

$ mysql -u root

正常情况下就连上了。

4. 重置密码

mysql> FLUSH PRIVILEGES;
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'new_password';

5. 重启 mysql

按照参考文档里介绍的做法,需要

$ sudo kill `cat /var/run/mysqld/mysqld.pid`
# 或
$ sudo kill `/var/run/mariadb/mariadb.pid`

不过我实际操作的时候只要把(2)开启的进程关掉就好了。然后重启 mysql 服务:

$ service mysql restart

6. 完成

尝试一下连接,应该可以成功了:

$ mysql -uroot -p

7. Ghost 连接

虽然命令行连接成功,但是 ghost start 仍然报错,经查,是 Ghost 的数据库连接方式有点问题,修改 config.production.json,加入一行配置即可,大体如下:

{
  "client": "mysql",
  "connection": {
    ....
    "socketPath": "/var/run/mysqld/mysqld.sock",
  }
}
分类
招聘

突发招聘: Zine 诚聘 Web 前端开发工程师 全职远程

早上刷推,看到一家全职远程公司招聘 Web 前端开发工程师,叫 Zine,做编辑器产品。心想正好可以水一篇更新,就转载一下吧。

我跟这家公司并不熟,不过经常在 V2 上看到他们家的消息,应该还是可以的,有自己的产品,有五险一金。感兴趣、并且有定力的同学可以试一试。

投了再说:

hr@auramarker.com

关于投简历的建议:

  1. 开篇写一段100~150字的自我描述,让招聘方对你有一个概括的了解。同时你会更像一个人,而不是某个数字。
  2. 针对对方的 JD 强调自己的优势,比如类似的技术背景、产品开发经验、或者深度用户
  3. 对职业经历的描述要体现自己的价值,哪怕只是参与者,不要写“负责完成领导交付的任务”

完整的 JD 在这里:

【全职远程】 Zine 诚聘 Web 前端开发工程师

V2上的帖子:

「全职远程」 Zine 诚聘 Web 前端 开发者

分类
github

GitHub 开放自定义 Profile 功能

GitHub 有一个个人简介(Profile)页面,比如我,我的用户名是 meathill,我的个人简介就是 https://github.com/meathill。这个页面和 GitHub Pages 有所不同,后者是完全自定义的,想放啥都可以;Profile 页面只体现我们在 GitHub 上的状态。

不过很多同学并不满足 GitHub Pages,还想定义这个页面;现在 GitHub 闲钱也比较多,可以改进这些痒点;于是乎,自定义 profile 就诞生了。

使用方法:

  1. 创建一个与用户名相同的仓库,比如我,就是 meathill 仓库
  2. 创建时,你就能看到小提示了:(因为我已经创建过仓库,所以有错误提示,正常没有)
  3. 如提示所写,你只需要编辑这个仓库里的 README 文件,就会自动更新页面上的内容
  4. 更新后的效果如下:

感觉还不错,近期找工作的同学赶紧用起来吧,是个不错的加分项。

分类
linux

Ubuntu 20.04 科学上网

闲言少叙,直奔主题。

0. 服务器

首先,你得先准备个服务器。本文不讨论如何制备科学上网服务器。

如果你想买现成的,可以考虑这个

1. 客户端

接下来,下载客户端。

我用的是 shadowsocks-qt5,先在 https://github.com/shadowsocks/shadowsocks-qt5/releases 这个页面下载打包好的 AppImage 文件。

右键点击文件,在“权限”选项卡里勾选“允许文件作为程序执行”,然后双击运行,配置服务器信息。配置完成,点击“连接”,顺利的话,就会显示连接成功。

在命令行里输入 gnome-session-properties,会启动如下图所示的“启动应用程序首选项”,把刚才下载的 AppImage 路径添加进来,这样每次启动 ss 客户端都会自动启动了。

启动应用程序首选项

2. 生成 pac

安装genpac

pip install genpac

Ubuntu 20.04 默认 python版本是 3,所以可以使用 pip3 替代上面的 pip。

使用在线的 gfwlist

genpac --pac-proxy "SOCKS5 127.0.0.1:1080" --gfwlist-proxy="SOCKS5 127.0.0.1:1080" --gfwlist-url=https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt --output="autoproxy.pac"

使用离线的 gfwlist

如果你的机器没有完成配置,暂时无法访问到 gfwlist,也可以先想办法下载到这个文件,然后离线生成。

genpac --pac-proxy "SOCKS5 127.0.0.1:1080" --gfwlist-proxy="SOCKS5 127.0.0.1:1080" --gfwlist-local=你的路径/gfwlist.txt --output="autoproxy.pac"

3. 配置服务器

Ubuntu 安装时就集成了 Apache2,并且默认也会启动它,所以直接把刚才生成的 pac 文件放在 /var/www/html/ 目录下,就能通过 http://localhost/autoproxy.pac 访问到。

不过我不喜欢用 apache,一般都会用 nginx 或者 openresty 取代之。好在默认情况下,nginx 的 web 服务目录也是 /var/www/html,所以只要卸载 apache 然后重新安装 nginx 即可。另外因为这个服务只为使用 pac 文件,所以可以不用换源。

sudo apt remove apache2
sudo apt update
# 安装 openresty 需要的系统依赖
sudo apt-get -y install --no-install-recommends wget gnupg ca-certificates
# 添加 key
wget -O - https://openresty.org/package/pubkey.gpg | sudo apt-key add -
# 添加 openresty 官方源
echo "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main" \
    | sudo tee /etc/apt/sources.list.d/openresty.list
# 在更新一次,然后安装
sudo apt update
sudo apt install openresty
sudo service openresty start

然后访问 http://localhost/autoproxy.pac,如果能打开,就说明配置成功。

4. 启动全局配置

如果,打开“设置”,找到“网络”,打开“网络代理”,选择“自动”,然后填入上面说的 pac 地址即可。

5. 在其它应用里完成配置

比如,打开 Firefox,在“首选项”里找到“网络设置”,然后选择“使用系统代理设置”即可。