ActivityPub 协议是一个去中心化的社交网络协议,其基于 ActivityStreams 2.0 数据格式。
2017年5月9日,W3C 的社交 Web 工作组(Social Web Working Group)发布了 ActivityPub 的候选推荐标准(Candidate Recommendation),向公众征集参考实现。这是一个社交网络交互协议,采用 ActivityStreams 2.0数据格式,提供了一个客户端到服务器的 API,来帮助 Web 应用程序创建、更新、删除社交网络内容,以及在一组联邦服务器之间的 API(federated server to server API),来在多个不同社交服务之间传递状态、通知及对内容的订阅。
2017年5月23日,W3C 的社交 Web 工作组(Social Web Working Group)发布活动流(Activity Streams 2.0 )与活动词汇表(Activity Vocabulary)正式推荐标准。Activity Streams 2.0(简称AS2)提供了一种数据模型以及词汇表,表现一般在线社交对象,活动,及其二者之间的关系。AS2 预计将成为在不同的(或分散的)社交 Web 应用程序之间分享社交数据的事实标准,并且建立在常用的 ActivityStreams 1.0 的基础上。活动流 2.0 词汇表(AS2 Vocabulary)提供了一套核心术语(term),可扩展使用JSON-LD,并且社交 Web 孵化器社区组(Social Web Incubator Community Group)可使这些扩展变得稳定。AS2 可用于任何协议,不过社交 Web 工作组还是特别为了基于 AS2 的客户端与服务器以及服务器与服务器之间的交互,正致力于开发 ActivityPub 规范。
在 ActivityPub 协议里,一个用户在服务器上的角色为“参与者(actor)”。用户在不同的服务器上的角色为不同的“参与者”。每一名“参与者”有:
一个收件箱:用于接收消息
一个发件箱:用于发送消息
例如,我在实例 A 上注册成为 251@example.com,而在另外一个实例 B 上注册成为 251@mastodon.art,虽然都是我一个人注册的,但因为在不同的实例上注册,故为不同的参与者。我分别在实例 A 与实例 B 都有一个收件箱和发件箱。而这收件箱和发件箱其实就是在 ActivityPub 参与者的 ActivityStreams 里的一个 URL。
{"@context": "https://www.w3.org/ns/activitystreams",
"type": "Person",
"id": "https://example.com/251/",
"name": "Kiryuu Sakuya",
"preferredUsername": "misaka00251",
"summary": "FAQ is love",
"inbox": "https://example.com/251/inbox/",
"outbox": "https://example.com/251/outbox/",
"followers": "https://example.com/251/followers/",
"following": "https://example.com/251/following/",
"liked": "https://example.com/251/liked/"}
正如前文说过,ActivityPub 基于 ActivityStreams 数据格式。而后者基本上概括了所有社交网络需要的活动,例如上面例子里的“粉丝”、“正在关注”、“喜欢的内容”。就算没有概括,它使用一种基于 JSON 的格式 JSON-LD。其目的既是为了可读,又方便机器处理,甚至如果你要加东西进去也很简单。
假设我现在要和 nong 哥互相隔空喊话,ActivityPub 如何帮我们做到这个?W3C 规范里有一张图:
简单来说就是:
我们在前文说过了,我在实例 A 上作为参与者,有一个收件箱和发件箱。那么,我首先要发送一个 ActivityStreams 对象(object):
{"@context": "https://www.w3.org/ns/activitystreams",
"type": "Note",
"to": ["https://example.org/anong/"],
"attributedTo": "https://example.com/251/",
"content": "nong 哥,柯文哲說要競選了,妳怎麼看"}
能看得出来,这个对象(object)是要给 nong 哥的。接着,我把这个内容(object)发送(POST)到我的发件箱。
因为这是并不是一个活动(non-activity,其 type 为 note)对象(object),实例 A 意识到这是一个新被创建的对象(object),并创建一个活动(activity,其 type 为 create):
W3C 规定 ActivityStreams 有八大核心 type,以及用于社交网络而延伸的三组 type,总共四组。
虽然 create 是活动内容里面的,但 note 不属于,这么理解即可。
{"@context": "https://www.w3.org/ns/activitystreams",
"type": "Create",
"id": "https://example.com/251/posts/9f905da5-ce8e-4b9e-a76a-8ef4b1dacc98",
"to": ["https://example.org/anong/"],
"actor": "https://example.com/251/",
"object": {"type": "Note",
"id": "https://example.com/251/posts/9f905da5-ce8e-4b9e-a76a-8ef4b1dacc98",
"attributedTo": "https://example.com/251/",
"to": ["https://example.org/anong/"],
"content": "nong 哥,柯文哲說要競選了,妳怎麼看"}}
然后,实例 A 就通过 ActivityStreams 查看 nong 哥 的”参与者”(actor object),找到他的收件箱,然后发送(POST)创建的这个对象(object)给他。技术上来说,这分了两个步骤,一个是客户端到服务器的通讯,一个是服务器与服务器之间的通讯(组成联盟)。这个例子里我们都用了,所以我们可以把整个过程抽象的理解成是我的发件箱 –> nong 哥的发件箱。过了一会,我想看他收到了什么新消息,于是他的客户端开始获取(GET)操作,除了其他人发的沙雕图片和视频以外,还有这样一条消息:
{"@context": "https://www.w3.org/ns/activitystreams",
"type": "Create",
"id": "https://example.org/anong/p/114514",
"to": ["https://example.com/251/"],
"actor": "https://example.org/anong/",
"object": {"type": "Note",
"id": "https://example.org/anong/p/114513",
"attributedTo": "https://chatty.example/ben/",
"to": ["https://example.com/251/"],
"inReplyTo": "https://example.com/251/posts/9f905da5-ce8e-4b9e-a76a-8ef4b1dacc98",
"content": "幹 還敢釣R
"}}
我收到消息之后,喜欢了这个 post:
{"@context": "https://www.w3.org/ns/activitystreams",
"type": "Like",
"id": "https://example.com/251/posts/e6dc43cb-f95e-4a26-8e41-ea9a5e77d0f8",
"to": ["https://example.org/anong/"],
"actor": "https://example.com/251/",
"object": "https://example.org/anong/p/114514"}
当然,我把这个对象(object)发送(POST)到我了的发件箱。因为这是一个活动(activity, 其 type 为 Like),实例 A 就不需要重新包装,可以直接发送出去。Like 是属于 Activity Types 里面的。最后,我给我的粉丝们发送了一条公共消息。因为是公共消息,所以不仅粉丝们可以收到,任何人原则上也可以看到。
{"@context": "https://www.w3.org/ns/activitystreams",
"type": "Create",
"id": "https://example.com/251/posts/30c68a4e-f3a8-483a-ae39-2618fcfc31fb",
"to": ["https://example.com/251/followers/",
"https://www.w3.org/ns/activitystreams#Public"],
"actor": "https://social.example/alyssa/",
"object": {"type": "Note",
"id": "https://example.com/251/posts/30c68a4e-f3a8-483a-ae39-2618fcfc31fb",
"attributedTo": "https://example.com/251/",
"to": ["https://example.com/251/followers/",
"https://www.w3.org/ns/activitystreams#Public"],
"content": "還是被發現了,哭哭"}}
以上就是一个很简单的例子了。我们通常说,某人(Somebody)对某个对象(object)做了什么(something);在 ActivityPub 里则是说是某个参与者(actor)在对一个对象(object)执行一个活动(activity)。
参考资料