Making an activitypub Server from scratch in Rust

In this blog post I sum up and review the experiences gained from last Stream. Check out the [VOD](https://youtu.be/RuvVvxwT1tY) If you like this content and would love to send me some treats you can Subscribe on my [GitHub Sponsor Page](https://github.com/sponsors/Toasterson) or checkout all the other pages via [Linktree](https://linktr.ee/toasterson) If you would like to have me as a coworker or consultant I am available for hire! #fedihire

So yesterday I went and dove into the crate activitypub_federation by the makers of the Lemmy link aggregator. Which makes you a kind of personal startpage of Articles and news. When people think about the Activity pub stdanrd some Vocabulary is used that I want to quickly Explain for those not so familair with it.

  • Object: This is a name for anything the Federation system interacts with and sends around. Examples: Notes (Mastodon, MicroBlogging); Articles (Blog Posts); Video File; Audio File etc. But also a Person (Account) has a representation
  • Activity: Something that is done to an Object like Following a Person, Creating a Article, Accepting a FollowRequest,
  • Actor: Somebody or a Bot that can perform actions. Mostly only a Person but in some scenarios may also be other Objects (Since the definitions are up to the network all these things can be extended)

Based on these defintions you have some protocols on what to send when and how but not what the Data is and how you handle it. You are completely free to handle this data sent around however you like. The Protocols have currently some limitations but as Extensions are supported a group of interested people can easily offer workarounds for limitations. One thing to note though is that even though people initially though that Batching is not supported, it infact is supported. Yes Batch transfer is wupported and used today See Issue 242 For details about the call that enabled it in 2017. With that said there is one last note about how we as a collective need to Organise ourselves so that Embrace -> Extend -> Extinguish becomes impossible.

How to prevent Embrace, Extend Extinguish

In his Post on the Forgefriends forum aschrijver summarized the key point brilliantly. Prevent producers to make custom extensions and make better collective extensions but only ever one per Type of Activity.

As an example: Imagine a Issue Tracker for Source code. Let’s take GitHub Issues and Focalboard and Trello as examples. Say we want to federate some simple Task between GitHub and Trello. We could make a Object like this:

{ "@context": [ "https://www.w3.org/ns/activitystreams", "https://forgefed.peers.community/ns" ], "type": "Ticket", "id": "https://example.dev/alice/myrepo/issues/42", "context": "https://example.dev/alice/myrepo", "attributedTo": "https://dev.community/bob", "summary": "Nothing works!", "content": "<p>Please fix. <i>Everything</i> is broken!</p>", "mediaType": "text/html", "source": { "content": "Please fix. *Everything* is broken!", "mediaType": "text/markdown; variant=CommonMark" }, "assignedTo": "https://example.dev/alice", "isResolved": false }

Notice the @context containing all the namespaces used in this Object. If we now want to Better represent other cases that could be used here like Status etc what happens when you base the formats on Application is:

{ "@context": [ "https://www.w3.org/ns/activitystreams", "https://forgefed.peers.community/ns", "https://mattermost.com/focalboard/2.0/ns" ], ... }

Notice that we have the Producer Mattermost now in the message. Now we have officially reached extend phase. Mattermost has extended the spec with their own. And will just get worse.

{ "@context": [ "https://www.w3.org/ns/activitystreams", "https://forgefed.peers.community/ns", "https://mattermost.com/focalboard/2.0/ns", "https://mattermost.com/extensions/jira/4.0/ns", "https://trello.com/remote/engineering/board" ], ... }

Now we get to extinguish. The one with the most Power will win. And since we are not taking any care to balance power here Money and workforce will be the factors that define Power.

But this can be changed with a couple rules:

  • The collective is right not the Individual: Same as with the Golden rule of Rust it needs a decision who should win in the case of an Argument. Here it must be the collective.
  • Blocklist all Corporate extensions: If any corporation uses own extensions, Blocklist them. It may end up with adoption issues but when Software developers are able to check which groups define the Standard, aka who is given power then we can prevent the cycle.
  • Be strict: Keep them out no matter what arguments they bring. A Governing board or group must have clear and strict rules which are simple to prevent the cycle. See IEEE or RFC’s as example. A simple rule is for example: It must have at least two implementations, be owned by a Baord representing all members (even small ones) and it must require consensus that the Protocol is ok to add extend. There is more to define and add so do not take these examples here.

A proper Object would not look like this:

{ "@context": [ "https://www.w3.org/ns/activitystreams", "https://w3id.org/fsdl/task-management/2.0", "https://w3id.org/fsdl/project-management/2.0", "https://w3id.org/fsdl/continuous-integration/1.0", "https://codeberg.org/CI/Woodpecker/notifications", ], ... }

The fun begins

With this said it will be interesting to build a own server and see how it fares. The Standard keeps me extremely free and only the library makes some OOP ish prerequisites but I will probably be ignoring them on my own or not. The nice thing is the protocoll on when to send which request where is implemented but the Data objects are completely left for me to handle. So I can brin in all the Rust knowledge I have to handle serialization the way I like it and performance and logging. We spent a lot of the time in the stream looking into the ecosystem and will further do so on other ocasions. It’s a fun project and I hope to get to interact with a lot of fun people while making this and the Package forge.

In terms of functionality I think Oxifed will focus in multi domain blogging (being able to setup your own domain on other servers) plus webauthn and forge will extend that with Tickets and other Software development related features as I need them.

Looking forward to a fun development time!

For those wanting to subscribe to the Code it is currently hosted here

– Toasty