独立网络的下一步是什么?

我用英语写博客已经有一段时间了,但这是我第一次参与独立网络讨论。所以我觉得我应该先自我介绍一下。

我是Eltrac。我主要是网页开发者,但我喜欢编程的各种方面。我用Go、Clojure和Lua编程,并且一直在探索新技术。我通常每周写三次以上的博客,但我的大部分文章都是用中文写的。

我最近成为了Codeberg e.V.并且一直在做我自己的自由开源软件项目哭泣铃一阵子。这是新的网络提及接收器用克洛尤尔书写。

在这篇文章中,我将谈谈我为什么开发Weepinbell,如何设计它的架构,我对IndieWeb运动的看法,以及许多事情。

为什么是哭泣铃?

我写信给布伦南最近他特别好心提到了Weepinbell在他的博客上.在那封邮件中,我谈到了我为Weepinbell设定了一个新目标(即一个替代方案webmention.io)因为亚伦·帕雷茨基的重写webmention.io和克洛德一起。

稍后,在亚伦的回应到布伦南的新职位他提到Weepinbell是“对我重写的直接回应”。

我想澄清一下。我开始开发Weepinbell并不是因为Aaron的重写。我是在今年五月初开始学习Clojure的。我已经用中文写博客多年,当然我很喜欢IndieWeb的概念。

自然,我学习新语言的练习项目涉及IndieWeb技术。

我的动机是想亲自操作Webmention标准。我仔细阅读了W3C 规范文档然后开始把东西放进去括号.你现在还能在我的代码中找到那个文档的片段注释。

我基本上是按照规范写代码。这对我来说是一次有趣的经历。

 (if-let [error-msg (check-request source target allowlist)]
 ;; respond if request verification failed
 (bad-request {:status 400
 :message error-msg})
 ;; proceed if request is ok
 (do
 ;; The receiver SHOULD check that target is a valid
 ;; resource for which it can accept Webmentions.
 ;; This check SHOULD happen synchronously to reject
 ;; invalid Webmentions before more in-depth verification begins.
 ;;
 ;; Webmention verification SHOULD be handled asynchronously
 ;; to prevent DoS (Denial of Service) attacks.
 (put! wmc new-wm)
 ;; respond with 201 when Webmention passed checks and
 ;; was sent into queue, include a Location header
 (let [wm-id (digest (str source target))
 wm-url (str (:base-url config) "/api/mention/" wm-id)
 response {:status 201
 :message "Webmention is accepted and pending for verification."
 :url wm-url}]
 (created wm-url response))))))

以下摘录来自接收者。CLJ.

在最初的快速而粗暴实施时,我暂停了几个月的Weepinbell工作。而在那段时间里,我的博客一直在获得Web提及。一切都能正常运行,我很满意。

它基本上是一个个人工具。

然后webmention.io重写引起了我的注意。

为什么这让我不舒服?我根本不使用。webmention.io不再是。我看到一些朋友在寻找替代方案,而且......可选择的不多!有的网络提及由Horst Gutmann以及其他一些实现者。

我的朋友氯开发圆圈在Rust中。我相信还有更多。但坦白说,没有一个真正算作“替代webmention.io”.

别误会。我认为很多实例很适合它们的用途,比如可以自托管的小型服务。然而,对于非技术独立网络爱好者和那些根本没有服务器的人来说,它们可能相当困难。

它们需要一个公开实例。

可扩展性的重构

我决定继续开发Weepinbell,把它当作“下一个”webmention.io“至少我就是这么想的。

所以我仔细检查了我的代码。它们并不乱,分区良好(大多数情况下),也易于维护。我能轻松切换部分,因为我用过钩子函数和vtables。

架构足够灵活,而且Lisp 功率修改软件也变得非常简单。

接下来的部分会有一定的技术性内容。如果你不想继续阅读系统设计,可以直接跳到下一节。关键是:Weepinbell 要足够轻量,可以让人们自行托管;它也足够可扩展,能够支持大量流量。

活着的人说我是个围棋程序员。还有Clojure的core.async库非常像Go的协同编程风格,这意味着我在Go中构建可扩展应用的能力可以转化。

网络公开不是大数据。存储绝对不是瓶颈。事实上,直到几次提交前,哭泣贝尔会甚至不支持任何类型的数据库.它会把所有东西放进一个文件里,然后在需要时再加载回来。

然后它就......运行了好几个月。

当然,这既不性能也不安全。如果我想构建一个可靠的东西,我需要一个数据库。如果你看过我链接的那个提交,你可能会注意到业务逻辑是未受触碰.新增的只是一个新的存储实现、一个新的配置选项,以及主组件中的几行代码(core.clj).

我可能会在另一篇文章中详细讲解架构的灵活性。这是我非常自豪的事情。大意是使用新型数据库和ORM很简单,如果以后我决定重新做存储层,也会同样容易。

;; all I need to make sure is that the new storage implementation
;; returns a valid storage vtable, like this:
(defn use-store [db-file]
 (let [ds (make-datasource db-file)]
 (create-tables ds)
 {:append (partial insert-webmention ds)
 :update (partial update-webmention ds)
 :delete (partial delete-webmention ds)
 :get (partial get-webmention ds)
 :get-by-domain (partial get-webmentions-by-domain ds)}))

除了新的SQLite实现外,我还添加了一个仓库工人它以异步方式处理I/O。因此,当处理新的Webment时,处理器不必等待数据库事务(或附加文件;它不关心文件底层发生了什么)结束。

它只需委派给仓库工人并且继续处理下一个网络讨论。

该处理器通过将操作对象放入频道.这和我之前用的接收器类似。当新的 webmention 请求被发送到网页服务器,接收者进行一些基本检查(例如:do)source以及target看起来像真实的URL?

)然后将请求放入网络提及队列.A处理器我会去拿,确保source真的提到过target解析微格式,将数据封装为有效记录,并交接给仓库工人.

从通道读取是线程安全.而且由于I/O内部由以下方式处理仓库工人,也可以是线程安全的,无需互斥锁.这样我们可以添加任意数量的处理器,同时处理网页提及。

整体架构如下:

那是水平缩放.对于自助主机,只需设置pipeline-concurrency到1,且只有一个处理器处理网页提及,使用合理的内存和CPU。

对于大型团队或想托管公共实例的人,只需在配置中更改一个数字即可。

所有这些都被汇总成一个.jar.

微格式的噩梦

在我转向非技术话题之前,有一件事我必须说投诉使用微格式标记很简单。解析它其实并不容易。

这里有一个示例摘录microformats.io.


 Mitchell Baker
 (Mozilla Foundation)

它就是普通的 HTML 和标准化的类名,比如h-card以及p-name.给你的 HTML 添加几个类很容易。不过,用 HTML 解析结构数据仍然很难只是还有几节课。

幸好已经有一些解析器了......右?

生产准备的解析器适用于:Go、Node、PHP、Python、Ruby。

右。。。我用的是Clojure......

Clojure 可以用 Java 代码,因为它运行在 Java 之上。我发现MF2J, 一个“正在开发中的 Microformats2 Java 解析器”。它自......十年前以来就没有更新过。

有一个Clojure 实现.它已经归档,最后一次更新是在11年前。

我应该自己实现一个新语言吗?还是接着他们停下的地方?我该如何确保自己不会因此感到疲惫而放弃它?毕竟,Clojure 是个小众语言,IndieWeb 也算是小众。

我无法想象还有另一个 Clojurist 会开发依赖微格式的东西。至少,我不认识这样的人。

我曾短暂考虑过运行一个微服务,包裹Go解析器,Weepinbell可以用RESTful API或gRPC与该服务通信。但它感觉很繁重,所有内容都放不进一个地方.jar.

那么Clojure怎么运行用非JVM语言编写的程序?还有什么能运行在JVM上?Scala、Groovy......等等,WebAssembly能用吗?

是的!WebAssembly运行在JVM上。有一个本地的 JVM WebAssembly 运行时叫做菊苣.

我花了一个下午学习灭绝主义还有手枪。然后我写了一个小小的围棋包装纸,是威尔·诺里斯的解析器库.

package main

import (
	"bytes"

	"github.com/extism/go-pdk"
	"willnorris.com/go/microformats"
)

//go:wasmexport parse
func parse() int32 {
	input := pdk.Input()
	r := bytes.NewReader(input)
	data := microformats.Parse(r, nil)

	pdk.OutputJSON(data)
	return 0
}

然后我把它编译成.wasm使用提尼戈编译器,捆绑在.wasm里面.jar,并用菊苣调出了Clojure的Extism插件。瞧!这里有MF2CLJ,是从现有微格式解析器的Go封装编译而成的ClojureWebAssembly封装器。

顺便说一句,我做了一个小标志,纯粹是为了好玩。

A combination of Clojure logo and the microformats logo

你用它就像普通的Clojure图书馆一样。而且速度出乎意料地快。

(require '[mf2clj.core :as mf2clj])
(mf2clj/parse html-string)

更令人惊讶的是,还捆绑了一捆.wasm二进制和WebAssembly运行时在.jar没有我想象的那么重。那个.jar体积只增加了2MB。我真的在用Java吗?

然而,噩梦还未结束。起初,我满足于未完成的部分mf2j库并用了一段时间。那时,我调用了 JSON 输出”地狱的数据结构”.我依然如此——一切都是阵法!

一切都深藏在某种深处properties或children!没有什么是确定性的!每个网站的格式都不同!

{
 "items": [{
 "type": ["h-card"],
 "properties": {
 "url": ["http://blog.lizardwrangler.com/"],
 "name": ["Mitchell Baker"],
 "org": [{
 "value": "Mozilla Foundation",
 "type": ["h-card"],
 "properties": {
 "name": ["Mozilla Foundation"],
 "url": ["http://mozilla.org/"]
 }
 }]
 }
 }],
 "rels": {},
 "rel-urls": {}
}

最后,我不得不写一个更小的解析器来解析原始解析器的输出。我称这个功能为微格式缩减.我记得webmention.io有类似的东西。

"microformats": {
 "author": {
 "name": "Mitchell Baker",
 "url": "http://blog.lizardwrangler.com/",
 "photo": "https://blog.lizardwrangler.com/photo.png"
 },
 "type": "mention",
 "published": "2026-07-25T00:00:00-07:00",
 "content": {
 "html": "..."
 "text": "..."
 }
}

如果某样东西不存在,它就会存在null.格式尚未最终确定,我会做一些调整。这个功能可以通过以下方式关闭?microformats=raw在查询网页提及时,

另外,我觉得我在Weepinbell里发现的bug中,超过一半都和微格式相关功能有关。也许我们应该切换到Open Graph和JSON-LD,朋友们?

总之,我很高兴它终于能起作用了。

放慢脚步

到现在为止,我几乎完成了所有关于v1.0.0发布:一个完善的数据库,水平可扩展性,最新的微格式解析器。至于托管公共实例,那需要认证用户并创建一个管理网页提及的仪表盘。

那将是另一个独立项目。

我计划开发一个服务,放在Weepinbell前面,负责登录等事务。我在项目中提到了这个想法PHILOSOPHY.md.

我想保持 weepinbell 的核心简约。那些想自己做系统管理员的人不必担心身份验证。他们甚至不需要前端。他们只需要自托管一个.jar用API查询网页提问,用RSS接收通知,用webhook自动化操作。

这些都是内置功能。

A平台比如webmention.io需要更多。如果我想让Weepinbell“同时适合个人和大群体”,我就得把东西分开。而且,这样一切都变得模块化且可更换,是个不错的架构选择。

我写信给Brennan,是想让更多Clojure开发者加入团队。嗯,结果不太好。为了新平台,将命名为林加贝尔我想用更主流的技术栈,可能是Go,这样大家更容易参与进来。

目前,我仍在开发weepinbell的测试套件。目前测试覆盖率超过83%,但仍有一些边缘情况尚未通过测试覆盖。我不得不手动测试很多路径。

而且新的SQLite实现需要时间稳定。

我认为我们不需要也不应该在开发可靠软件时急于行动,无论有没有大型语言模型。

独立,以及现在的分权

针对布伦南最近的提问,“我们现在该怎么办?”我认为是时候更加去中心化了。

去中心化从来不是要摆脱企业网络(那就是独立性)。而是不依赖单点无论目的是什么,涉及谁。

我同意Brennan的看法,不要把IndieWeb和小写indie web混为一谈。这个IndieWeb 训练营这是一个不错的社区,也是了解独立网络的绝佳入门。

但我认为我们应该建立更多独立网络社区,而不仅仅是IndieWeb阵营。

omg.lol是一个例子。这是一个有趣的网络社区尼特尼克.他们提供了基础设施,比如简单的个人资料页、Fediverse 实例和邮件转发。Brennan 也在建设folk.zone,也承载了webmention.io.

这两者可能不是IndieWeb阵营的完全替代选择,但它们可以成为。而且人们可以选择更多。

技术人员如果愿意,可以自行托管基础设施。对于非技术人员来说,应该有更多替代IndieWeb阵营的选择。有能力的人可以托管公共服务,建立一个小型社区。

毕竟,社区是将独立网络凝聚在一起的关键。我们可以也应该建立更多社区(这可能更像是多中心中心,而非去中心化)。我们可以拥有LispyWeb对于Lisp程序员来说,ArtsyWeb对于艺术家,以及独立独立文学俱乐部!

献给爱书人。这些只是我随便想出来的一些名字。

也许即将到来的林加贝尔也许会成为下一个温馨的小社区。谁知道呢?感谢所有愿意读完这篇文章的人,我希望我们都能做到找到我们的人.


  1. Clojure 中的 vtable 基本上是一个哈希图,其值是函数。这是 Bob 叔叔的书中提到的一种技术,功能设计.
  2. 其实我才刚起步。别把我当成任何领域的专家。XD
  3. Clojure 运行在 JVM 上,所以它会像 Java 一样编译成 JVM 字节码。
  4. 意思是“听起来了”。
  5. 这个指称是一个名为“的女游戏”多基多基文学社”.:3
添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论