The main purpose of this document is to establish the API for version 1.0 of the library.
The structure of the models will be different than what it is today.
- The
activitypubmodule will be renamed tovocaband contain the vanilla types described in the Activity vocabulary specification. - The
processingmodule will become the newactivitypubmodule, and it will contain the state machine for processing client to server and server to server activities.- It will include subpackages for convenience functionality to interop with the wider Go ecosystem: HTTP handlers
- The
authmodule moves as a subpackage here. Now that the osin server has been removed, maybe we can rename it.
- The
clientmodule stays as is. Perhaps we move the oauth2 and http-signatures round trippers to the authorization module.- Another option is to move it as a subpackage of
processing.
- Another option is to move it as a subpackage of
General module rules
When applicable, each package needs to have a single main data type that operates on, this is not entirely idiomatic with the Go language suggestion of keeping everything related in the same package.
processing: the same struct will be both a validator and a processor.client: will hold thehttp.Clientwrapper. It can retain the subpackages for the OAuth2 and HTTP-Signatures transports.auth: will hold the OAuth2 and HTTP-Signatures verifiers.
This makes it that there is a single <package-name>.New(...InitFn) initializer and a single type for the initializer functions arguments.
The initializer can return unexported data types.
The vocabulary
Generating code should start from a Go struct with annotations.
The steps should be something like this:
Structure
We need to validate the struct’s compatibility with the Vanilla AP objects:
- the properties must match the position and type of one of the
Object,Actor,IntransitiveActivity,Activity,Link, etc. - the struct must validate against the JSON-LD contexts that the developer chooses for them.
Helper functions
Generate helper functions:
- Initializer function:
New<Type>- Perhaps builders - with generics - would provide a better UX?
- Generate function type
With<Type>Fnthat’s used as parameters forOn<StructName> - Generate functions:
On<StructName>, andTo<StructName>- Perhaps change
To<StructName>to return*StructName, boolinstead of error
- Perhaps change
- Generate
MarshalJSON/UnmarshalJSON,GobEncode/GobDecode - Add type switch cases to the
IsObject,IsActor,IsActivity,IsIntransitiveActivity,IsLink - Add type switch cases to the
ToObject,ToActor,ToActivity,ToIntransitiveActivity,ToLink - Add type switch cases to the
IsNilfunction.
Types
Accumulate types for generated objects and add their types to the slices for:
ActorTypes: struct has Inbox/Outbox propertiesActivityTypes: struct has Actor/Object propertiesIntransitiveActivityTypes: struct has Actor property but no Object propertyLinkTypes: no ID property, but has a Href property.CollectionTypes: struct hasItems/OrderedItemsandTotalItems(perhapsNext?).ObjectTypes: what’s left? - This is the default when there’s nothing else annotated.
Accumulate types into the interfaces that can be used by generic code (Actors, Objects, etc).
The state machine
The ActivityPub state machine needs to operate the following:
- Validate received Activity.
- Determine which properties need to be dereferenced.
- Dereference properties and save them in local storage.
- Validate dereferenced objects.
- Persist flattened activity to storage.
- Operate Activity side-effects.
- Aggregate recipients.
- Dereference recipients.(?)
- Disseminate to local recipients.
- Disseminate to remote recipients.
Data types
We need some interfaces that unifies behaviour between client to server and server to server logic.
We should establish if the current authorized actor needs to be part of the API, or we can leave it as an implementation detail.
The implementations for the Processor and Validator would be scoped per each section of the specification:
- one for client to server for activities received in outboxes
- one for server to server for activities received in inboxes
// dereferencer is a helper interface that gets used
// by the [Validator] to enrich an activity with additional information.
type dereferencer interface {
// Maybe Load instead to keep it similar to readStore?
// (but without the filters?)
Fetch(iri vocab.IRI) (vocab.Item, error)
}
// disseminator is a helper interface that gets used
// by the [Processor] to submit activities to recipients.
type disseminator interface {
ToCollection(colIRI vocab.IRI, it vocab.Item) error
}
// readStore is a helper interface that gets used
// by the [Processor] or [Validator] to retrieve
// objects and activities from *local* storage.
type readStore interface {
Load(iri vocab.IRI, ff ...filters.Check) (vocab.Item, error)
}
// readStore is a helper interface that gets used
// by the [Processor] to save objects and collections to *local* storage.
type writeStore interface {
// Save saves the incoming ActivityStreams Object, and returns it together with any properties
// populated by the method's side effects. (eg, Published property can point to the current time, etc.).
Save(vocab.Item) (vocab.Item, error)
// Delete deletes completely from storage the ActivityStreams Object, this is usually
// a side effect of an Undo activity.
Delete(vocab.Item) error
// AddTo adds "it" element to the "col" collection.
AddTo(vocab.IRI, ...vocab.Item) error
// RemoveFrom removes "it" item from "col" collection
RemoveFrom(vocab.IRI, ...vocab.Item) error
}
// store is a helper interface that gets used
// by the [Processor] or [Validator] to retrieve and/or store
// objects and activities from *local* storage.
type store interface {
readStore
writeStore
}
type Validator interface {
// ValidateActivity validates an activity.
// It dereferences all properties that need to be dereferenced and validates it.
// The "it" parameter gets enriched with the dereferenced properties.
Validate(ctx context.Context, it vocab.Item) error
}
type Processor interface {
// Process processes the incoming activity
// The "it" parameter gets enriched with whichever additional information operating
// the activity adds.
// Eg. In the case of a Create activity operated in an outbox collection, its Object
// would receive an ID, or the Published property gets added if they're missing.
Process(ctx context.Context, it vocab.Item) error
}