69 lines
4.3 KiB

# Bovine
Bovine is meant to be a modular FediVerse server that supports [ActivityPub]( During its history, as how to split the tasks between different modules has become clearer, and the split is not done yet. A lot of the changes are due to the realization that parts can be split away as an ActivityPub Client. Here an ActivityPub Client is an application that communicates with just a single ActivityPub Server.
There are a few more structural comments to make about ActivityPub. One job of a server should be to perform basic validation and sanitation for data it passes to clients (or receives for clients). Doing this for ActivityPub has some consequences:
- Objects are represented by json-ld with an id.
- If these objects are sanitized and validated by the server, this means that the object changes.
- Thus there are two representation: 1. outside (as seen in the Fediverse), 2. inside as passed to clients.
This is not ideal, due to an object with an id now representing two different things. It unfortunately seems unavoidable.
## Parts of bovine
When done, these parts should only depend on the parts above them. So bovine_process can be used with only bovine and bovine_store. Furthermore, bovine_store and bovine_process should just provide simple interfaces that can be swapped out.
- __[bovine](bovine)__ ([pypi](, [docs]( provides the basic ActivityPub communication with some form of authorization. Currently, HTTP Signatures and [Moo-Auth-1]( are supported.
- __[bovine_store](bovine_store)__ ([pypi](, [docs]( used to store json-ld by their id and provide a certain level of visibility and access control.
- Serves requests directly represented by objects
- Contains the actor storage code, and methods to manage actors
- Tested with both PostgreSQL and sqlite3 databases
- __[bovine_process](bovine_process)__ ([pypi]( contains the Activity processing described in [ActivityPub](
- Contains tests for the side effects of activities
- Supported: follow, accept, create, update, delete
- __[bovine_pubsub](bovine_pubsub)__ ([pypi]( allows events to be propagated to subscribers. Two variants exist
- Using `asyncio.Queue` in the case of a single worker
- Using Redis for multiple workers. Enabled through setting the environment variable `BOVINE_REDIS` to the URI of the redis server.
- __[bovine_herd](bovine_herd)__ ([pypi]( the FediVerse server implementation. This contains
- Webfinger, nodeinfo
- Requests to endpoints not directly represented by objects, i.e. POST inbox
- Glue code to make everything work together
- [](bovine_herd/
- __[bovine_tool](bovine_tool)__ ([pypi]( basic tools to administer actors in the bovine_store.
- __[tests](tests)__ contains a test suite that ensures that bovine_herd properly implements a FediVerse server
## Existing ActivityPub Clients
- [mechanical_bull]( automatically accepts follow requests. This was part of the evolution of my thinking how to separate out ActivityPub Clients.
- [longhorn]( is a blog. One can visit mine at [](
- [calf]( provides a simple terminal user interface for the inbox. This might get expanded into a full client in the future.
## Running tests
Using docker, one can run tests in various environments. For this first run
docker compose up -d
Then by running
docker compose run main ./
docker compose run main_sqlite ./
docker compose run main_11 ./
docker compose run main_sqlite_11 ./
one can run tests in various configurations. `main` runs tests using postgres and python 3.10, `main_11` runs tests using postgres and python 3.11, `main_sqlite` runs tests using sqlite3 and python 3.10.