Skip to content

cometsh/drinkup

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Drinkup

An Elixir library for listening to events from an ATProtocol relay (firehose/com.atproto.sync.subscribeRepos). Eventually aiming to support any ATProtocol subscription.

TODO

  • Support for different subscriptions other than `com.atproto.sync.subscribeRepo'.
  • Validation (signatures, making sure to only track handle active accounts, etc.) (see Firehose Validation Best Practices)
  • Look into backfilling? See if there's better ways to do it.
  • Built-in solutions for tracking resumption? (probably a pluggable solution to allow for different things like Mnesia, Postgres, etc.)
  • Testing of multi-node/distribution.
  • Tests
  • Documentation

Installation

Add drinkup to your mix.exs.

def deps do
  [
    {:drinkup, "~> 0.1"}
  ]
end

Documentation can be found on HexDocs at https://hexdocs.pm/drinkup.

Example Usage

First, create a module implementing the Drinkup.Consumer behaviour (only requires a handle_event/1 function):

defmodule ExampleConsumer do
  @behaviour Drinkup.Consumer

  def handle_event(%Drinkup.Event.Commit{} = event) do
    IO.inspect(event, label: "Got commit event")
  end

  def handle_event(_), do: :noop
end

Then add Drinkup and your consumer to your application's supervision tree:

defmodule MyApp.Application do
  use Application

  def start(_type, _args) do
    children = [{Drinkup, %{consumer: ExampleConsumer}}]
    Supervisor.start_link(children, strategy: :one_for_one)
  end
end

You should then be able to start your application and start seeing Got commit event: ... in the terminal.

Record Consumer

One of the main reasons for listening to an ATProto relay is to synchronise a database with records. As a result, Drinkup provides a light extension around a basic consumer, the RecordConsumer, which only listens to commit events, and transforms them into a slightly nicer structure to work around, calling your handle_create/1, handle_update/1, and handle_delete/1 functions for each record it comes across. It also allows for filtering of specific types of records either by full name or with a Regex match.

defmodule ExampleRecordConsumer do
  # Will respond to any events either `app.bsky.feed.post` records, or anything under `app.bsky.graph`.
  use Drinkup.RecordConsumer, collections: [~r/app\.bsky\.graph\..+/, "app.bsky.feed.post"]
  alias Drinkup.RecordConsumer.Record

  def handle_create(%Record{type: "app.bsky.feed.post"} = record) do
    IO.inspect(record, label: "Bluesky post created")
  end

  def handle_create(%Record{type: "app.bsky.graph" <> _} = record) do
    IO.inspect(record, label: "Bluesky graph updated")
  end

  def handle_update(record) do
    # ...
  end

  def handle_delete(record) do
    # ...
  end
end

Special thanks

The process structure used in Drinkup is heavily inspired by the work done on Nostrum, an incredible Elixir library for Discord.

License

This project is licensed under the MIT License