···11+Copyright 2025 comet.sh
22+33+Permission is hereby granted, free of charge, to any person obtaining a copy of
44+this software and associated documentation files (the “Software”), to deal in
55+the Software without restriction, including without limitation the rights to
66+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
77+the Software, and to permit persons to whom the Software is furnished to do so,
88+subject to the following conditions:
99+1010+The above copyright notice and this permission notice shall be included in all
1111+copies or substantial portions of the Software.
1212+1313+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1414+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
1515+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
1616+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
1717+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1818+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+104-4
README.md
···11# Drinkup
2233-Drinkup is an ELixir library for listening to events from an ATProtocol
44-firehose.
33+An Elixir library for listening to events from an ATProtocol relay
44+(firehose/`com.atproto.sync.subscribeRepos`). Eventually aiming to support any
55+ATProtocol subscription.
5666-## Roadmap
77+## TODO
7889- Support for different subscriptions other than
99- `com.atproto.sync.subscribeRepo'
1010+ `com.atproto.sync.subscribeRepo'.
1111+- Validation (signatures, making sure to only track handle active accounts,
1212+ etc.) (see
1313+ [Firehose Validation Best Practices](https://atproto.com/specs/sync#firehose-validation-best-practices))
1414+- Look into backfilling? See if there's better ways to do it.
1515+- Built-in solutions for tracking resumption? (probably a pluggable solution to
1616+ allow for different things like Mnesia, Postgres, etc.)
1717+- Testing of multi-node/distribution.
1018- Tests
1119- Documentation
2020+2121+## Installation
2222+2323+Add `drinkup` to your `mix.exs`.
2424+2525+```elixir
2626+def deps do
2727+ [
2828+ {:drinkup, "~> 0.1"}
2929+ ]
3030+end
3131+```
3232+3333+Documentation can be found on HexDocs at https://hexdocs.pm/drinkup.
3434+3535+## Example Usage
3636+3737+First, create a module implementing the `Drinkup.Consumer` behaviour (only
3838+requires a `handle_event/1` function):
3939+4040+```elixir
4141+defmodule ExampleConsumer do
4242+ @behaviour Drinkup.Consumer
4343+4444+ def handle_event(%Drinkup.Event.Commit{} = event) do
4545+ IO.inspect(event, label: "Got commit event")
4646+ end
4747+4848+ def handle_event(_), do: :noop
4949+end
5050+```
5151+5252+Then add Drinkup and your consumer to your application's supervision tree:
5353+5454+```elixir
5555+defmodule MyApp.Application do
5656+ use Application
5757+5858+ def start(_type, _args) do
5959+ children = [{Drinkup, %{consumer: ExampleConsumer}}]
6060+ Supervisor.start_link(children, strategy: :one_for_one)
6161+ end
6262+end
6363+```
6464+6565+You should then be able to start your application and start seeing
6666+`Got commit event: ...` in the terminal.
6767+6868+### Record Consumer
6969+7070+One of the main reasons for listening to an ATProto relay is to synchronise a
7171+database with records. As a result, Drinkup provides a light extension around a
7272+basic consumer, the `RecordConsumer`, which only listens to commit events, and
7373+transforms them into a slightly nicer structure to work around, calling your
7474+`handle_create/1`, `handle_update/1`, and `handle_delete/1` functions for each
7575+record it comes across. It also allows for filtering of specific types of
7676+records either by full name or with a
7777+[Regex](https://hexdocs.pm/elixir/1.18.4/Regex.html) match.
7878+7979+```elixir
8080+defmodule ExampleRecordConsumer do
8181+ # Will respond to any events either `app.bsky.feed.post` records, or anything under `app.bsky.graph`.
8282+ use Drinkup.RecordConsumer, collections: [~r/app\.bsky\.graph\..+/, "app.bsky.feed.post"]
8383+ alias Drinkup.RecordConsumer.Record
8484+8585+ def handle_create(%Record{type: "app.bsky.feed.post"} = record) do
8686+ IO.inspect(record, label: "Bluesky post created")
8787+ end
8888+8989+ def handle_create(%Record{type: "app.bsky.graph" <> _} = record) do
9090+ IO.inspect(record, label: "Bluesky graph updated")
9191+ end
9292+9393+ def handle_update(record) do
9494+ # ...
9595+ end
9696+9797+ def handle_delete(record) do
9898+ # ...
9999+ end
100100+end
101101+```
102102+103103+## Special thanks
104104+105105+The process structure used in Drinkup is heavily inspired by the work done on
106106+[Nostrum](https://github.com/Kraigie/nostrum), an incredible Elixir library for
107107+Discord.
108108+109109+## License
110110+111111+This project is licensed under the [MIT License](./LICENSE)