farseer - another kind of Farcaster hub
farseer is a lightweight re-implementation of a Farcaster hub that does not require syncing to operate & is extendable through plugins. In short, you can bring your own DB, logic & infrastructure and harvest data from the protocol while fostering decentralization! If you like this project, consider giving a star to the repository: it's a real help for motivation! Looking for PRs, issues & feedback, so feel free to write something and send it to me!
See the todos to see what's left to do :)
How to get started?
General architecture
There are four components to farseer: a config file (config.toml
), plugins, the identity file & the hub itself. Here's a quick rundown of how it works:
.
├── compiled_handlers <== where you'll put your compiled plugins
│ └── postgresql.so
├── config.toml <== configure the behaviour of the hubs & the plugin
├── docker-compose.yml <== infrastructure example
├── Dockerfile <== automatization of the process
├── hub_identity <== SECRET private key of the hub (needs to be generated for docker-compose)
├── relay <== what you'll run (binary)
Easy mode (Docker)
Compiling the plugins for Docker
- Generate a
hub_identity
using the latest utility found in the release section or run the code in the identity
folder. Don't forget to put in the root of the repository!
- Run this command to start the containers!
docker-compose up -d
This will start the hub with the default behavior & plug-ins.
The DIY way
- Get the source from somewhere:
git clone https://github.com/noctisatrae/farseer.git
- Compile with Go 1.22+ and produce a binary in the same directory where
config.toml
is:
go build -v -o app ./relay
- Compile your plugins/custom handlers using the plugin mode of
go build
(here we'll compile the example postgresql
plugin):
go build -buildmode=plugin -o ./compiled_handlers/postgresql.so postgresql/postgresql.go
There's a lot going here but essentially, we tell Go to build a plugin from the postgresql.go file output it in the compiled_handlers
folder that will be read by the hub to exectute the custom logic.
- Now, you'll start the hub by running:
./app
- For fine-tuning the behavior of the hub, see the configuration section
Configuration
[hub]
# How can other peers reach your hub!
PublicHubIp = "92.158.95.48"
GossipPort = 2282
# Who will be your first contacts?
# Quick rundown of the libp2p multiaddr format:
# /typeOfAddr/addr/protocol/port/p2p/publicIdentity
BootstrapPeers = [
# Those are the peers used by the farcaster dev team, nemes.farcaster.xyz is the public one & the others will certainly not make the connection with you!
# As of the 25th of July 2024, nemes.farcaster.xyz is not working
# "/dns/lamia.farcaster.xyz/tcp/2283/p2p/12D3KooWJECuSHn5edaorpufE9ceAoqR5zcAuD4ThoyDzVaz77GV",
# "/dns/nemes.farcaster.xyz/tcp/2283/p2p/12D3KooWMQrf6unpGJfLBmTGy3eKTo4cGcXktWRbgMnfbZLXqBbn",
# "/dns/hoyt.farcaster.xyz/tcp/2283/p2p/12D3KooWRnSZUxjVJjbSHhVKpXtvibMarSfLSKDBeMpfVaNm1Joo",
]
# Super handy when things go wrong!
Debug = false
# Not sure of the usefulness of this, it's something I have yet to experiment with
BufferSize = 128
ContactInterval = 30
# The interesting part!
# To define the behavior of a plugin in `compiled_handlers`, you write:
# [handlers.(pluginName)]
[handlers.postgresql]
# This is common to all plugins: do you want to enable it?
Enabled = true
# Below, the options are specific:
# The options below are determined to by the developer of the plugin. They manage how the arguments are parsed and used!
DbAddress = "postgres://postgres:example@db:5432/postgres"
# refer to the enum l.60 in message.proto for the integer of msg types | here we only want to save the casts & deletions
# delete a filter to not use it!
MessageTypesAllowed = [1, 2]
# who are you tracking?
FidsAllowed = [10626]
Plugins
Handler API
At some point, you'll want to make your own plug-ins. To get started, you should look at handlers/handlers.go
! A plugin exports a Handler struct
defining its own function to handle the message; here's an excerpt from the struct
:
type Handler struct {
Name string
// Used to make a connection to the DB. Go to handlers/handlers.go to see a method to pass down variables to the functions.
InitHandler InitBehaviour
// Those functions will handle incoming messages! It's up to you to define those you need.
CastAddHandler HandlerBehaviour
CastRemoveHandler HandlerBehaviour
FrameActionHandler HandlerBehaviour
ReactionAddHandler HandlerBehaviour
ReactionRemoveHandler HandlerBehaviour
LinkAddHandler HandlerBehaviour
LinkRemoveHandler HandlerBehaviour
VerificationAddHandler HandlerBehaviour
VerificationRemoveHandler HandlerBehaviour
}
var PluginHandler = handler.Handler{
// .... amazing stuff here
}
// Then you compile & put it in compiled_handlers!
It's up to you to define & verify the paramaters that will be used in config.toml
.
Compiling plugins for Docker
You can edit the project's Dockerfile to add your plugin build command!
FROM golang:1.22
WORKDIR /usr/src/app
# pre-copy/cache go.mod for pre-downloading dependencies and only redownloading them in subsequent builds if they change
COPY go.mod go.sum ./
RUN go mod download && go mod verify
# 1. Make sure your plugin is included into the image
COPY . .
+ RUN go build -buildmode=plugin -o ./compiled_handlers/[plugin name].so [your source code for the plugin]
# 2. Example for the postgresql plugin
RUN go build -buildmode=plugin -o ./compiled_handlers/postgresql.so postgresql/postgresql.go
# Then, build the hub itself
RUN go build -v -o /usr/local/bin/app ./relay
CMD ["app"]