从钩子(hook)说起

按 wikipedia 的说法:

hooking 指通过拦截软件模块间的函数调用、消息传递、事件传递来修改或扩展操作系统、应用程序或其他软件组件的行为的各种技术。处理被拦截的函数调用、事件、消息的代码,被称为钩子(hook)。

hooking 有多种用途,如调试、扩展功能。例如在键盘或鼠标事件到达应用程序之前拦截这些事件;拦截应用程序或其他模块的操作系统调用以监督行为、修改功能。也广泛用于 benchmarking 程序,如度量 3D 游戏的帧率…游戏外挂是另一类例子。

有两种方法实现 hooking,物理修改和运行时修改

物理修改

在应用程序执行之前,物理修改可执行程序,这典型通过找到函数调用入口点,修改入口点使之在函数被执行前先执行其他的代码。

运行时修改

操作系统与软件可提供方法,在运行时插入事件钩子…Linux 允许类似的钩子通过 NetFilter 以处理网络事件。

也可拦截进程的库函数调用,在函数调用开始处注入代码。这可通过修改内存中的进程的中断向量表或输入表(import table)实现。

从这条描述可以看出,钩子当然也是黑客感兴趣的东西。

webhook

对 webhook 的兴趣最初来自 Github 和 IFTTT,两者都支持 webhook:

通过 webhook,用户可以根据自己的需求灵活当前使用的系统(Github/IFTTT),而不需要对已有系统做修改。这是一种叫做事件驱动的编程模型。

这种可扩展性令我很感兴趣。

尤其是读了 minsky 的《心智社会》之后,对于可组合的事物更是充满兴趣,相信智能会从中生长出来。

在概念上,可以将 webhook 视为可组合的材料。

webhook 所勾连的行为,往往是未知的,多数时候不发生在系统部署的当下,而是发生在未来,所发生事件并不知道它将引起什么行为。如此一来,充满了灵活性,而这种灵活性,大大地提高了可能性空间。智能和复杂行为便都有可能从中生长出来。

技术视角

从技术视角看,webhook 平淡无奇: 系统 A 请求系统 B 的一个 URI。

它的威力在于它背后的想法: 混搭(Mashup)。前头提及的可组合性与此有关。

但这里值得注意的是,系统 A 请求系统 B 的一个 URI,这个 URI 由用户自定义,而且请求 URI 触发的行为,也是用户自定义的,这里包含了极大的灵活性。 我们将这个 URI 称为 callback, 充满事件驱动的味道。

回调(callback)

Webhooks 是用户定义的HTTP回调。它们通常是由某些事件触发的,例如将代码推送到存储库或将评论发布到博客。当该事件发生时,源站点向为 Webhook 配置的 URL 发出 HTTP 请求。用户可以将它们配置为导致一个站点上的事件调用另一个站点上的行为。

这些回调可以由不一定与原始网站或应用程序有关联的第三方用户和开发人员维护,修改和管理。

我的兴趣点

CodeLab Adapter致力于连接, 关注可扩展性, webhook 在此能派上许多用场。

这是我近期重新把视线放在 webhook 上的原因,一番搜罗下,对几个项目很感兴趣

webhook

webhook 是轻量级响应 webhook 请求(incoming webhook server)的服务器,用于运行 shell 命令.

可配置工具,它使你可以轻松地在服务器上创建 HTTP endpoints(hook),用于执行已配置的命令。还可以将数据从 HTTP 请求(例如 header,payload 或查询变量)传递到 shell 命令。webhook 还允许你指定触发 hook 必须满足的规则。

webhook 专注在以下事情:

  1. 接收请求,
  2. 解析 header,payload 和查询变量,
  3. 检查是否满足 hook 的指定规则,
  4. 最后,通过命令行参数或环境变量将指定的参数传递给指定的命令。

其余事情都交给你。确实是个轻量又灵活的小工具,小而美。

使用

在树莓派中可以直接安装它: sudo apt-get install webhook

开始一个简单的例子: hooks.json

1
2
3
4
5
6
7
[
  {
    "id": "test-webhook",
    "execute-command": "/tmp/test.sh",
    "command-working-directory": "/tmp"
  }
]

/tmp/test.sh内容为:

1
2
#!/bin/bash
echo "hello webhook"

赋予脚本运行权限: chmod +x test.sh

启用 webhook: webhook -hooks hooks.json -verbose

访问http://rpi4.codelab.club:9000/hooks/test-webhook

请求参数

参考 XiaoMi Vacuum + Amazon Button = Dash Cleaning

Python script

我们当然也可以使用 python 脚本替代test.sh

/tmp/test.py

1
2
3
#!/usr/bin/env python3

print("hello webhook python")

赋予脚本运行权限: chmod +x test.py

hooks.json 相应调整为

1
2
3
4
5
6
7
[
  {
    "id": "test-webhook",
    "execute-command": "/tmp/test.py",
    "command-working-directory": "/tmp"
  }
]

webhook 思路是完全通用的,我们可以自行实现它,我之后准备在 CodeLab Adapter 中视线一个 webhook extension。

websocketd

严格来说,websocketd 与 webhook 关系不大,但我却认为它是很好的工具,用来构建 web hook(字面意思)。对于一些流式行为,websocket 是理想选择,所以我将 websocketd 视为流版本的 webhook。

关于 websocketd 更多内容,我之前做过笔记:websocketd:一个小而美的管道工具

Quick and dirty mock service with Starlette

这篇文章阐述了如何利用异步机制构建webhook服务。

参考