分类
职业

再见,OpenResty Inc.

被前司(现在是前前司了)裁员之后,我受罗辑思维鼓动,想尝试知识付费,于是折腾了大半年。发现这样下去养不活自己和家庭之后,我又开始找工作,刚好看到春哥在微博上招人,因为事先对 OpenResty 有所耳闻,知道这是个很厉害的产品,春哥也是个很厉害的程序员,就去应聘。于是幸运的得到这个机会,加入了 OpenResty Inc.。

时光荏苒,一晃又是四年多,到了说再见的时间。

在 OpenResty 的工作整体来说是紧张而快乐的。春哥应该是很多程序员最向往的样子,至少对我来说是如此:

  1. 有成功的作品
  2. 有厉害的技术
  3. 有很高的业界声望
  4. 有良好的个人家庭生活

所以能为春哥工作对我来说是一件幸事,因为可以近距离观察这样一位成功的程序员,能从他身上学习,指导自己接下来的发展。我也的确从他那里学到很多东西。

不过相应的,在 OpenResty 工作也面临很大压力。一方面,OpenResty 是创业公司,我们要从零开始搭建很多产品,应对很多挑战;另一方面,春哥又会对产品的实施细节进行多方位多角度的监督和审视。所以,虽然过去几年都是远程工作,我面临的工作压力却一点也不小,工作时间也一点都不短。

这样紧张而快乐的生活在本月末画上了句号。接下来,我会为金山文档效力。希望接下来的新旅程能为我带来新的成长,希望我可以给新东家带来超出他们预期的价值吧。

聊聊远程

接下来聊聊远程。很多同学听说我放弃远程工作,转投一家集中办公的公司,表示不理解,所以今天借此机会聊两句。

远程工作爽么?爽,但也就那么回事。正像我在前面一篇博客中说的:没有工作会让你很爽。如果你工作的很爽,要么你有问题,要么工作有问题。

有人为财务自由划定了若干标准,比如菜场自由、超市自由、便利店自由、电子产品自由、车自由、房子自由等。这个做法其实很科学,因为很多事情本就不是非黑即白的,是否两头中间存在大量中间地带。

我也仿效 ta 来制定一些新的“自由”标准吧。远程工作可以带来很多平价自由,比如:

  • “穿衣自由”:我在过去四年里,85% 的时间只穿一条内裤
  • “食物自由”:韭菜盒子、臭豆腐、大蒜想吃就吃
  • “厕所自由”:几千块的卫立洗只有我一个人用
  • “空调自由”、“电影自由”、“青轴自由”、“听歌自由”等等等等

这些自由你说没价值吧,肯定不对;但是如果有人觉得应该抛弃其它要素来追求这些自由,那就完全跑偏了。因为很明显,还有很多更有价值、价格也更高的自由,比如“孩子上学自由”、“买电脑自由”、“买房自由”等。

所以,当一份工作,能够提供其它更有价值的加分项,只是缺少远程工作能带来的平价自由的话,我们当然应该好好考虑这个机会。尤其对于我这种年纪越来越大,机会越少越少,机会成本越来越高的中年男子来说,更是如此。

“远程工作工资会低么?”

多半会低。我们的工资是老板决定的,也是市场决定的,里面包含着地理位置溢价。比如,在北京,一个月至少要大几千块才能保证生活质量,那么一个靠谱的程序员就不可能接受万把块的工资;而比如我,假如在郑州老家的话,有房有车有老妈,一个月节省 1w 块的开销,收入一万就能抵两万。

所以同样技术水平、工作态度的两个人,一个在北京一个在郑州,两个人对工资的要求完全不同。集中办公时,他们俩不产生交集,无所谓;远程办公时,他们俩直接竞争,老板很可能更倾向于后者。

所以,远程工作的工资会明显低于一线,持平或略低于二线。除非候选人有他人没有的竞争优势。

“我没有在大城市工作过,想在老家找个远程工作,可以么?”

我不敢把话说死,说一定不行;但我必须说,这非常难。

对于程序员来说,自己的努力固然重要,公司带来的产品压力与用户压力同样重要。比如我的博客,一天几百访问,随便弄个月租$10 的小 VPS 就能跑起来。WordPress + 本地 MySQL,简单配置下缓存就好。如果你只搞过这个级别的服务,突然要你分库、读写分离、上缓存,你就没法搞。

前端也一样。我因为只考虑放客是开发者,所以只关心最新 PC/macOS Chrome 能不能看。但是真正的生产环境,哪家公司不得兼容最近三年所有系统和浏览器版本?到时候一堆兼容性和性能问题就折腾死人了。

没有大城市大公司的工作经验,往往就欠缺解决这些问题的技能和经验。于是跟那些大城市退回老家的人比起来,也就缺乏竞争力了。现在真正意义上的远程岗位并没有很多,大多数其实是接单和基础外包,所以我要说,很难。

总结

时光如流水,突如其来一个拐弯,我也步入下一个阶段。简单与前面告个别,希望下一个五年,能不负时光,继往开来。

分类
linux

Linux 命令行笔记

遍历目录查找内容

grep -rnw '/path/to/somewhere/' -e 'pattern'
  • -r 或 -R 表示遍历
  • -n 显示行号
  • -w 全文匹配
  • -l (小写 L) 只显示文件名
  • -e 匹配的表达式

参考:How do I find all files containing specific text on Linux? – Stack Overflow

分类
wsl

WSL2 使用 ssh-server 笔记

升级到 WSL2 之后,我面临几个问题:

  • webpack-dev-server 无法监控 /mnt/c/xxxx 这样的路径下的文件变化,使得 HMR 失效。只能借由 ~/path/to/project/ 启动开发环境。
  • 启动服务后,无法通过 127.0.0.1:port/ 访问,只能通过 localhost:port 访问。

今天想使用 ssh-server 连上去,结果失败,经查,原来 WSL2 的底层逻辑变了:

If this is WSL2 (which it appears to be) this is for all intents by-design. WSL2 has its own Real Linux™ network stack inside a VM, and a virtual Ethernet device. Contrast WSL1 which took the approach of attempting to present the Windows network stack inside Linux.

WSL2 就是这么设计的。它在虚拟机里有自己真实的 Linux 网络栈,以及虚拟的以太网设备。

WSL2: ifconfig not showing all network connections · Issue #4915 · microsoft/WSL (github.com)

所以要用不同的方式来做,记录在这篇笔记里。

方案一:使用 ssh-server

1. 在 Windows 里安装 ssh-server

  1. 设置 > 应用 > 应用和功能 > 可选功能 > 添加功能
  2. 搜索并安装 ssh-sever
  3. 启动 ssh-server,需使用管理员身份启动 powershell
# 启动 ssh 服务
Start-Service sshd

# 可选,设置 sshd 为开机自动启动
Set-Service -Name sshd -StartupType 'Automatic'

# 往防火墙里添加规则
if (!(Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -ErrorAction SilentlyContinue | Select-Object Name, Enabled)) {
    Write-Output "Firewall Rule 'OpenSSH-Server-In-TCP' does not exist, creating it..."
    New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
} else {
    Write-Output "Firewall rule 'OpenSSH-Server-In-TCP' has been created and exists."
}

2. ssh 连接

在另外一台机器上输入 ssh username@ip-or-host 即可完成连接。

不过需要注意的是,比如我的账户名为 Meathill Zhai,这个名称不能直接使用。我的邮箱是 realmeathill[at]hotmail.com,系统会自动截取一段,我在命令行里的初始位置是:C:\Users\realm,于是登录的时候只能用 ssh realm@ip,然后输入 realmeathill[at]hotmail.com 的密码,方能完成登录。

3. 改为连接 WSL2

默认情况下,使用 ssh 连入的命令行是 cmd.exe,可以通过以下命令修改为 Powershell:

New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force

如果把里面的 WindowsPowerShell\v1.0\powershell.exe 修改为 bash.exe,那么就会连入 WSL2 了。

4. 改回 powershell

直接连入WSL2 也不是不行,不过这样的话,一些涉及 Windows 系统的操作无法进行,exit 也是直接退出 ssh 连接。于是我觉得默认连入 powershell 比较好,想用 WSL 就手动 bash 进入 WSL 即可。

待解决问题

  • powershell ssh-server 不支持 authorized_keys 登录

参考文章

分类
chrome

Chrome Extension Manifest V3 升级笔记

关于 MV3 的知识,可以看这篇前文:

《Chrome 扩展大升级 Manifest V3:变化》

近期尝试把一个浏览器扩展升级到 MV3,然后发现了很多问题,写篇博客记录一下。

与文档不符

  • 很多号称返回 Promise 实例的方法实际上不会返回结果,或者在没有 callback 的时候会报错

文档未说明

  • service worker 里无法使用 chrome.i18n.getMessage 或者 chrome.i18n.getUILanguage。于是目前右键菜单都无法 i18n 了。
  • chrome.contextMenus.create 无法向 browser_action 添加菜单项

未实现 Promise 或者有 bug

  • chrome.storage.local.get(keys) Promise 结果固定返回 undefined,不可用,需用回 callback
  • chrome.permissions.request 未 Promise 化,无返回值
  • 必须传入 callback,不然报错
    • chrome.permissions.contains
    • chrome.contextMenus.remove

文档写了,但我没看见(>_<!)

  • 在 service worker 里使用 chrome.contextMenus.create 时,必须传入 id,且不能使用 onclick 函数。只能侦听 chrome.contextMenus.onClicked.addListener,然后做进一步判断。

MV2 存在的功能,但无法迁移至 MV3

(有些可能是暂时的)

因:不允许使用 remote JS

MV3 不支持使用外部 JS,所以 Google Analytics 和 Facebook 分享按钮之类的 SDK 都无法使用。也即是说,现在扩展不能使用 GA,也不能嵌入 Facebook Like,也不能使用其它需要引用外部 SDK 才能实现的功能。

因:Service worker 取代 background page/JS

无法获取系统 light/dark mode

Service worker 没有 window 对象,也就没有那些 window 对象上才有的方法,比如 matchMedia()。所以我们就无法在 service worker 里检查系统的 dark mode,实现动态修改 icon 的功能。

无法使用 Image 解析图像

Service worker 也没有 Image 对象,只能使用 createImageBitmap 获取 ImageBitmap,无法转换成 ImageData,也就无法使用一些依赖 ImageData 的仓库,比如没法解析二维码。(可以通过手动解析二进制的方式绕过)

因为 createImageBitmap 无法解析 SVG blob,所以原则上,所有 SVG 的操作均无法执行。

只能通过 chrome.tabs.create() 的方式传出内容

自然,alert()prompt() 都无法使用,也无法手动弹出 popup。所以如果我们想从 service worker 里向外传出内容,只有两个选择:

  1. 使用通知 notification API
  2. 直接打开页面

而 notification API 需要权限,所以可能只好选后者。

分类
招聘

代友招聘:广州番禺广告公司招 PHP 工程师

做 ocpx 和 rta 方面的。dsp 平台 adx 方便的接口对接。

(上面这一行我完全看不懂……)

岗位职责:

  1. 负责公司产品后端系统维护,新功能开发,广告投放API对接;
  2. 参与需求讨论,对产品原型、功能逻辑设计等提出可靠建议;
  3. 使用yii2框架实现产品的标准化。

岗位要求:

  1. 计算机相关专业大专或本科学历,有2年以上PHP开发经验,有大型网站或者数据系统开发经验者优先;
  2. 熟悉前端语言:HTML5/CSS3,JavaScript,Ajax,jQuery等;
  3. 熟悉 MVC 框架,熟悉主流 PHP 框架 yii2,有独立开发项目经验者优先;
  4. 精通 MySQL,熟悉 Linux、Apache/nginx、Redis 的管理和维护。
  5. 有开发小程序后端、广告 Marketing API 项目经验者优先;
  6. 熟悉版本控制器 git/svn 的使用;
  7. 有优秀的沟通与表达能力,突出的学习能力,较强的动手能力与逻辑分析能力;
  8. 具备良好的团队合作精神,高度的责任感,善于沟通,为人踏实,抗压能力强,拥有严谨的工作态度,能虚心学习。
  9. 具备良好的代码编程习惯,熟悉面向对象编程,及较强的文档编写能力。

工作地点在番禺,朋友的公司,很靠谱。感兴趣的同学直接联系我吧。

分类
招聘

OpenResty Inc. 诚聘中高级前端工程师

OpenResty Inc. 是一家根植于开源 DNA 的技术型公司,我们致力于机器编程。我们有世界一流的技术实力,研发全新的技术,解决工业级别的挑战,服务全球众多企业级客户。

目前我们有四大产品,本次招聘的对象主要负责其中的 OpenResty Showman。所用到的技术栈包括 Vue 全家桶,现代化前端工具链,CodeMirror,浏览器扩展等。

岗位要求

  1. 精通 HTML/CSS/JavaScript
  2. 熟练掌握 Vue,了解其生态、发展状态,具备很好的开发和调试能力
  3. 熟悉 Web 规范,具备较强的工程能力,能够妥善规划和实施前端项目开发
  4. 熟悉 Node.js,了解前端工具链的发展,具备工具链开发能力
  5. 对设计模式等软件工程知识有较深理解
  6. 理解浏览器工作原理,具备较强的分析和调优能力
  7. 具备良好的代码习惯,能够坚持最佳实践
  8. 具备良好的自我管理能力,能独立完成工作

加分项

  1. 有实现过自己的小语言,写过语言编译器,或 CodeMirror Mode
  2. 熟悉浏览器插件机制和 API,写过自己的浏览器插件
  3. 有较强的主动学习能力
  4. 英语能力佳

工作地点不限,国家不限。我们不纠结于学历和专业,只看能力和经验。远程工作模式,自由度高。我们在深圳也有办公室。

分类
nodejs

捕获 promisify `child_process.exec` 的错误

这个东西文档里没写清楚,所以写篇博客记一下。

在 Node.js 里,我们可以使用 child_process 下的命令分裂出一个进程,执行其他的命令。这些命令包括 execexecFilespawn

我比较常使用 execspawn。前者用起来比较方便,只要传入完整的命令和参数,很接近日常命令行体验;后者传参要麻烦一些,不过可以实时获取输出,包括 stdoutstderr,比较方便给用户及时反馈。

下面贴一下文档里的例子,spawn 的使用将来有机会再说。

const { exec } = require('child_process');
exec('cat *.js missing_file | wc -l', (error, stdout, stderr) => {
  if (error) {
    console.error(`exec error: ${error}`);
    return;
  }
  console.log(`stdout: ${stdout}`);
  console.error(`stderr: ${stderr}`);
});

Node.js 8 之后,我们可以用 util.promisify() 命令将 exec 转换为 Promise 风格的方法,即不再需要 callback 函数,而是返回 Promise 实例,方便我们链式调用或者使用 Async function。

此时,它的样子是这样的:

const util = require('util');
const exec = util.promisify(require('child_process').exec);

async function lsExample() {
  const { stdout, stderr } = await exec('ls');
  console.log('stdout:', stdout);
  console.error('stderr:', stderr);
}
lsExample();

官方文档没解释清楚错误处理,经过我的尝试,是这样的:

  1. 命令发生错误,或者被意外中断都会引发错误
  2. 如果不出错,就会正确返回 stdoutstderr
  3. 否则,错误实例里会包含 stdoutstderrcode
  4. 1~127 是各种错误编码,128+ 则是 signal + 127 的结果,通常来说是受控于我们的操作。比如使用 FFmpeg 录屏的时候,结束录制就要 Ctrl+C,此时就会得到值为 128 的 code。所以此时很可能不是真的失败。
const util = require('util');
const exec = util.promisify(require('child_process').exec);

(async () => {
  let code, stdout, stderr;
  try {
    ({stdout, stderr} = await exec('ls'));
  } catch (e) {
    ({code, stdout, stderr} = e);
  }

  if (code && code > 127) {
    // 确实失败了
  }
  console.log('stdout:', stdout);
  console.log('stderr:', stderr);
})();
分类
应用

应用创意:家用媒体中心

(这个灵感部分来源于群里的同学)

前阵子群里有同学问,能否用 electron 搭建服务器,提供局域网内的文件共享。

我突然想到,可以做一个这样的简单家用媒体中心:

  1. 封装成 Electron 应用,分发部署会容易很多
  2. 集成 Ghost,作为 CMS,提供 API 和网页服务
  3. 启动后,选择本地视频文件,就自动提取关键信息,然后从豆瓣上抓取影片内容,并生成影片详情页
  4. 然后局域网内电脑就可以访问这个服务,然后点播视频
  5. 也可以集成一些下载工具,直接下载磁力、BT等开放格式

产品功用

从功能来说,虽然弱于同类产品,比如 NAS 服务器。但是对于我这样的用户来说,平时下片和看片不多,偶尔可能需要在家里不同设备上看片,如果有个低成本的贡献工具,会比来回拷简单很多。

教程价值

从教程价值来考虑,这个项目倒是可圈可点。

  1. Electron 跨平台、易部署,其实一直都很受人关注
  2. Ghost 可以提供完整的 RESTful API,甚至好用的界面
  3. 于是我们可以很容易的把注意力集中在:
    1. 使用 RESTful API 的 SPA 开发,Vue3 全家桶可用
    2. 从豆瓣等网站抓取内容,简单的爬虫开发
    3. 集成第三方库,开发下载工具

简单来说,就是技术选型潜力大,开发量可控,开发难度不大,覆盖面广,且最终产品有一定市场价值。似乎是个很好的教程题材。

分类
招聘

OpenResty 再次开启招聘!

以下内容来源于老板春哥,关键词:一流的技术实力研发全新的技术远程工作模式

OpenResty Inc. 公司诚邀有追求的工程师加入我们的研发团队。

我们的技术栈是 Nginx, OpenResty, Lua, C/C++, Perl, Python 等等。从高性能网关系统和 CDN 系统,小语言编译器的开发,再到内核开发和动态追踪,以及数据库分析和调优,还有视频生成和处理,可按能力和兴趣选择。我们有世界一流的技术实力,研发全新的技术,解决工业级别的挑战,服务全球众多企业级客户。

工作地点不限,国家不限。我们不纠结于学历和专业,只看能力和经验。远程工作模式,自由度高。我们在深圳也有办公室。

有兴趣的朋友欢迎发送简历至 talents@openresty.com

详情请戳:网页链接


另外老板说,前端也可以聊,欢迎投简历。

分类
应用

应用创意:视频剪辑工具 Not-Final-Cut

0. 目标视频类型

我日常要处理的视频类型和工作流程是:

  1. 教学视频、分享视频、讲解视频
  2. 我会录制一个长视频,说清楚前因后果,然后以此视频为主,进行剪辑,大部分时候往下剪,很少往上加
  3. 我也很少分镜、混入多素材等
  4. 我希望通过 STT,得到人声对应的文本。然后以文本为基础进行剪辑,自动删掉不要的内容。也以文本为基础,添加图层、剪辑、音乐等

1. 产品需求

做视频 Up 主一段时间之后,越发感觉缺少一个趁手的视频剪辑工具。结合我的日常录制流程,我需要的剪辑工具应该具备以下功能:

  1. 自动剪掉没有人声的部分。我不说话的片段基本都不需要保留
  2. STT,输出语音对应的文本
  3. 可以根据文本进行剪辑,比如我不想要保留“嗯啊哦这个那个”这种无意义的虚词,都可以剪掉。
  4. 可以使用新文本替代现有文本,作为字幕,自动对齐时间。
  5. 可以方便地插入 slide,用来显示需要强调的内容。时间用文字来标记。
  6. 可以方便地切分视频,类似插入分页符
  7. 可以方便地插入章节标题
  8. 可以方便地插入暂停、插入图片、插入其它视频等,都用文字作为标记。
  9. 可以加片头、片尾、背景音乐等。

2. 产品形态

至于产品形态,我觉得可以分三种:

2.1 命令行工具

  1. 安装:npm i @meathill/nfc
  2. 启动:nfc a.mp4
  3. 打开浏览器,编辑并保存、导出

需要用户能够自行配置 node.js 环境、自行配置 ffmpeg、自行配置云服务 key。可以开放给其它录制教学视频的开发者使用,以便收集需求、bug,说不定还有人给我发 PR。

2.2 Electron 打包

像普通软件一样使用。可以卖给普通用户,不过考虑到大家的付费意愿,不一定能收回云服务的成本。也会有大量盗版问题。

还有个办法是要求用户注册,付少量的费用,只 cover 阿里云的费用。因为转码过程在本地,不消耗我的资源。

2.3 网站

用户上传视频到网站,在线编辑,导出。成本控制会容易一些,不过运营网站挺麻烦,而且视频剪辑需要的资源不是一星半点。

3. 项目启动

项目早就启动了,不过搁置很久了,以后继续吧。

感兴趣的同学可以关注:https://github.com/meathill/not-final-cut

4. 项目进展

  1. 选定视频开始编辑
  2. 剪辑文字
  3. 剪掉没有人声的片段
  4. 导出视频
  5. 修改字幕
  6. 添加章节封面
  7. 打包发布
  8. electron 版本
  9. 网站版本