GoActivityPub library¶
The GoActivityPub library contains the building blocks for adding ActivityPub functionality to both client and server applications for the Go programming language. It is a robust, “batteries included” product with a high level of interoperability with the rest of the Go ecosystem.
The focus is on high spec compliance, minimal external dependencies, and minimal computing requirements.
The library is divided into functionally independent modules connected through interfaces.
The high level view on the project offers the following distinct pieces:
- Activity Vocabulary data types for Go.
- The ActivityPub state machine which deals with processing different activities, handling their side effects and disseminating them and their objects to recipients and collections.
- Custom storage mechanisms specifically created for ActivityPub objects and supporting a standardised API.
- A custom HTTP client with an extended API for interacting with ActivityPub servers for both fetching data and submitting activities.
- Authorization mechanisms for this client that support both server to server and client to server algorithms.
Below you can find short descriptions of the individual modules.
The module layout¶
Processing¶
Defines most of the logic for handling the ActivityPub interactions for both Client to Server and Server to Server dissemination in the form of a state machine making decisions based on the Activity and Object types pairs.
This state machine is wrapped in standard HTTP Handlers that are compatible with the rest of the Go ecosystem.
It also contains additional handlers used to output individual objects and collections after retrieving them from storage.
Finally, it defines the interfaces that the storage backends need to implement to be able to work with the rest of the GoActivityPub modules.
Storage modules¶
We provide multiple implementations of storage backends which are compatible with the processing module.
The interfaces that they need to implement are defined in the processing module.
Currently we support:
- storage-fs: direct filesystem storage, every activity and object corresponds to a file on disk under a folder structure that closely mimics the layout found when querying the fedbox server. It is generally meant to be used for development environments.
- storage-sqlite: a simple object storage on top of a single SQLite database.
- storage-boltdb: BoltDB is a performant key value store.
- storage-badger: another, more modern key value store. This backend suffers from performance issues at the moment.
Client¶
Represents a module that can be used as a base for a client that interacts with ActivityPub servers. It can be used with both client to server and server to server authorization mechanisms.
Auth¶
Defines the logic for verifying and generating HTTPSig and OAuth2 compatible authorization headers, for both Client to Server and Server to Server authorization.
Cache¶
A module to help with creating an in-memory cache for ActivityPub objects. It stores objects under the key of their ID.
It is used in various places where caching the objects makes sense, like the slower storage modules, or just as a memoisation mechanism.
Currently the module has no explicit method for cache invalidation or limiting the amount of space it uses, so please handle with care.
ActivityPub¶
Is the module that contains the default Activity Vocabulary data types as described by the ActivityStreams vocabulary, with additions made for presenting public keys for actors which are required by the server to server HTTP Signatures authorization mechanism.
The types in this module require the JSON-LD module for marshaling and
unmarshaling to be compatible with other ActivityPub services, the standard
library json module does not deal with the dynamic nature of the linked data
properties in a correct fashion, see design decisions for details.
JSON-LD¶
A module to help with the JSON-LD marshaling and unmarshaling of the ActivityPub
vocabulary objects. It provides the functionality to deal with the peculiarities
of having dynamic values for the objects’ properties, and also adds a small
convenience over dealing with the @context property that JSON-LD requires.
This module needs to be reimplemented or switched to something better.
Errors¶
Has wrappers for dealing with specific errors inside our library, mostly focused around dealing with HTTP errors.
Design decisions¶
The main problem of implementing the ActivityPub specification in the Go programming language stems from the very dynamic nature of JSON-LD, which is used as its data format, and the limited (in this respect) features of the Go type system.
This apparent incompatibility stems from the fact that an object property in the ActivityPub specification can have any of the following values:
- an IRI which can be dereferenced to an ActivityPub object
- a full ActivityPub object
- an array of ActivityPub objects
- an array of IRIs to ActivityPub objects.
Because the Go type system can’t express this union explicitly, we rely on
implementing these four meta-types independently and giving them unifying behavoiur
through the interface: ObjectOrLink.
Basically if any type implements this interface[1], it can be used with the
GoActivityPub modules.
To keep in line with Go’s interface guidelines, we have tried to keep the methods this interface exposed to a minimum, and this led to a very limited guaranteed API for the module.
To circumvent the fact that most of the library deals with instances of this interface, we had to create the convenience functions that allow a developer to assert them to actual useful ActivityPub structs.
They are the functions starting with OnXXX and ToXXX in the module and give
the possibility of treating any struct that impelments ObjectOrIRI as an XXX
ActivityPub object, where XXX can be an Activity, an Actor, Object,
Link samd.
This is incidentally the mechanism through which we allow extending the default
AP vocabulary by other modules. Other developers can create their own type
YYY, implement the interface and add their OnYYY functionality[2].
The first caveat about this type of logic is that it relies heavily (at least
currently) on the fact that the memory layout for each type needs to be
identical for the properties which are common. The properties need to have the
same order and the same type. Basically the existing ToXXX functions
work as a cast does in plain C. It takes the pointer the interface holds, and
converts it to the desired type (using the unsafe package) relying on the fact
that the common properties of the Objects are at the same offsets from the
pointer[3].
[1] The interface matches the ActivityStreams separation between Object compatible structs and Link compatible structs.
[2] This also requires overriding the default typer function, which is used to
return the correct type based on the YYY.Type property.
[3] This behaviour is risky and it can probably change without warning if the Go dev team changes the language’s memory model at a later date. I hope I’ll find a cleaner way to implemnt this in the future, but for now it serves its purpose.
Dependency graph¶
github.com/go-ap/jsonld: - no dependencies
- github.com/go-ap/activitypub
- github.com/go-ap/client
- github.com/go-ap/errors
- github.com/go-ap/filters
- github.com/go-ap/activitypub
- github.com/go-ap/client
- github.com/go-ap/errors
- github.com/go-ap/filters
- github.com/go-ap/activitypub
- github.com/go-ap/cache
- github.com/go-ap/errors
- github.com/go-ap/filters
- github.com/go-ap/jsonld
github.com/go-ap/storage-sqlite
- github.com/go-ap/activitypub
- github.com/go-ap/cache
- github.com/go-ap/errors
- github.com/go-ap/filters
- github.com/go-ap/jsonld
github.com/go-ap/storage-boltdb
- github.com/go-ap/activitypub
- github.com/go-ap/errors
- github.com/go-ap/filters
- github.com/go-ap/jsonld
github.com/go-ap/storage-badger: currently in a failing state
- github.com/go-ap/activitypub
- github.com/go-ap/errors
- github.com/go-ap/filters
- github.com/go-ap/jsonld
- github.com/go-ap/activitypub
- github.com/go-ap/cache
- github.com/go-ap/errors
- github.com/go-ap/filters
- github.com/go-ap/storage-fs
- github.com/go-ap/storage-sqlite
- github.com/go-ap/storage-boltdb
- github.com/go-ap/storage-badger
Pitfalls¶
I compiled a list of pitfalls when using the modules.