独立网络的下一步是什么?
我用英语写博客已经有一段时间了,但这是我第一次参与独立网络讨论。所以我觉得我应该先自我介绍一下。
我是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封装器。
顺便说一句,我做了一个小标志,纯粹是为了好玩。
你用它就像普通的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对于艺术家,以及独立独立文学俱乐部!
献给爱书人。这些只是我随便想出来的一些名字。
也许即将到来的林加贝尔也许会成为下一个温馨的小社区。谁知道呢?感谢所有愿意读完这篇文章的人,我希望我们都能做到找到我们的人.
- Clojure 中的 vtable 基本上是一个哈希图,其值是函数。这是 Bob 叔叔的书中提到的一种技术,功能设计.
- 其实我才刚起步。别把我当成任何领域的专家。XD
- Clojure 运行在 JVM 上,所以它会像 Java 一样编译成 JVM 字节码。
- 意思是“听起来了”。
- 这个指称是一个名为“的女游戏”多基多基文学社”.:3