···1+Copyright 2025 comet.sh
2+3+Permission is hereby granted, free of charge, to any person obtaining a copy of
4+this software and associated documentation files (the “Software”), to deal in
5+the Software without restriction, including without limitation the rights to
6+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7+the Software, and to permit persons to whom the Software is furnished to do so,
8+subject to the following conditions:
9+10+The above copyright notice and this permission notice shall be included in all
11+copies or substantial portions of the Software.
12+13+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+104-4
README.md
···1# Drinkup
23-Drinkup is an ELixir library for listening to events from an ATProtocol
4-firehose.
056-## Roadmap
78- Support for different subscriptions other than
9- `com.atproto.sync.subscribeRepo'
000000010- Tests
11- Documentation
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
···1# Drinkup
23+An Elixir library for listening to events from an ATProtocol relay
4+(firehose/`com.atproto.sync.subscribeRepos`). Eventually aiming to support any
5+ATProtocol subscription.
67+## TODO
89- Support for different subscriptions other than
10+ `com.atproto.sync.subscribeRepo'.
11+- Validation (signatures, making sure to only track handle active accounts,
12+ etc.) (see
13+ [Firehose Validation Best Practices](https://atproto.com/specs/sync#firehose-validation-best-practices))
14+- Look into backfilling? See if there's better ways to do it.
15+- Built-in solutions for tracking resumption? (probably a pluggable solution to
16+ allow for different things like Mnesia, Postgres, etc.)
17+- Testing of multi-node/distribution.
18- Tests
19- Documentation
20+21+## Installation
22+23+Add `drinkup` to your `mix.exs`.
24+25+```elixir
26+def deps do
27+ [
28+ {:drinkup, "~> 0.1"}
29+ ]
30+end
31+```
32+33+Documentation can be found on HexDocs at https://hexdocs.pm/drinkup.
34+35+## Example Usage
36+37+First, create a module implementing the `Drinkup.Consumer` behaviour (only
38+requires a `handle_event/1` function):
39+40+```elixir
41+defmodule ExampleConsumer do
42+ @behaviour Drinkup.Consumer
43+44+ def handle_event(%Drinkup.Event.Commit{} = event) do
45+ IO.inspect(event, label: "Got commit event")
46+ end
47+48+ def handle_event(_), do: :noop
49+end
50+```
51+52+Then add Drinkup and your consumer to your application's supervision tree:
53+54+```elixir
55+defmodule MyApp.Application do
56+ use Application
57+58+ def start(_type, _args) do
59+ children = [{Drinkup, %{consumer: ExampleConsumer}}]
60+ Supervisor.start_link(children, strategy: :one_for_one)
61+ end
62+end
63+```
64+65+You should then be able to start your application and start seeing
66+`Got commit event: ...` in the terminal.
67+68+### Record Consumer
69+70+One of the main reasons for listening to an ATProto relay is to synchronise a
71+database with records. As a result, Drinkup provides a light extension around a
72+basic consumer, the `RecordConsumer`, which only listens to commit events, and
73+transforms them into a slightly nicer structure to work around, calling your
74+`handle_create/1`, `handle_update/1`, and `handle_delete/1` functions for each
75+record it comes across. It also allows for filtering of specific types of
76+records either by full name or with a
77+[Regex](https://hexdocs.pm/elixir/1.18.4/Regex.html) match.
78+79+```elixir
80+defmodule ExampleRecordConsumer do
81+ # Will respond to any events either `app.bsky.feed.post` records, or anything under `app.bsky.graph`.
82+ use Drinkup.RecordConsumer, collections: [~r/app\.bsky\.graph\..+/, "app.bsky.feed.post"]
83+ alias Drinkup.RecordConsumer.Record
84+85+ def handle_create(%Record{type: "app.bsky.feed.post"} = record) do
86+ IO.inspect(record, label: "Bluesky post created")
87+ end
88+89+ def handle_create(%Record{type: "app.bsky.graph" <> _} = record) do
90+ IO.inspect(record, label: "Bluesky graph updated")
91+ end
92+93+ def handle_update(record) do
94+ # ...
95+ end
96+97+ def handle_delete(record) do
98+ # ...
99+ end
100+end
101+```
102+103+## Special thanks
104+105+The process structure used in Drinkup is heavily inspired by the work done on
106+[Nostrum](https://github.com/Kraigie/nostrum), an incredible Elixir library for
107+Discord.
108+109+## License
110+111+This project is licensed under the [MIT License](./LICENSE)