damus-io / notedeck

A multiplatform nostr client
Other
47 stars 9 forks source link

Relays architecture #100

Open kernelkind opened 1 month ago

kernelkind commented 1 month ago

How will the relay architecture be implemented? Will each user account (public key) have a relay list associated with it? And the current deck will use the relay list associated with the current user account?

Related to #81

jb55 commented 1 month ago

@KernelKind wrote (from [#100]):

How will the relay architecture be implemented? Will each user account (public key) have a relay list associated with it? And the current deck will use the relay list associated with the current user account?

Related to [#81]

There should only ever be a single relay connection manager. When switching accounts, the relay pool simply maintains connections to all of the relays shared between these accounts.

I removed the RelayPool from the UserAccount because it doesn't make sense there. There should only ever been one connection pool, otherwise there would be multiple duplicate connections.

Keypairs have lots of associated data: mutelists, relay lists, deck lists, etc. It doesn't make sense to store those in UserAccount (aka Keypair). We can simply look those up in nostrdb when we need them, as we would want to make sure we are always in sync with whatever the latest version of those notes are.

We do this with profiles, which requires us to build a flatbuffer schema in nostrdb which can be a bit of work, but it simplifies notedeck code greatly when we do this. Profiles are the main example right now of something that parses json and stores it as flatbuffers in nostrdb.

It might make sense to add some more flexible machinery to nostrdb that allows you to parse arbitrary json data and store that as flatbuffers, but that would require some metaprogramming so it might be tricky. The alternative is messagepack which is a bit slower but more flexible for parsed data at runtime.

Another thing to mention from the refactor[1]: the relay generator also didn't really make sense. For example, in the outbox model, relays are selected dynamically from other user's relay lists. It is not as simple as selecting a single pool and then using that.

Outbox model relay selection is a function of the type of query you're doing. For example, if pulling a user's profile page, you likely just want to exclusively pull from that user's set of relays they write to. In the timeline case, we have to do this but as a union of all the pubkeys on your contact list, with some algorithm to choose a subset of all of those user's relays to query from. In threads, we follow relay hints, etc.

These are all ephemeral outbox connections. We can have some kind of LRU connection pool for outbox connections if we want to limit the number them.

[1] https://github.com/damus-io/notedeck/pull/80/commits/31b2b5c950591536263f3218bf4a11e8f6b59ec1 [#100] https://github.com/damus-io/notedeck/issues/100 [#81] https://github.com/damus-io/notedeck/issues/81

kernelkind commented 1 month ago

Ah I see, so we're just going to treat nostrdb as ground-truth for each account's set of relays. All relays belonging to all user accounts must be in RelayPool to maintain connection, but the relays in the RelayPool won't necessarily all be accessible to the current user's account, since nostrdb is the ground-truth?

jb55 commented 1 month ago

The relay pool just maintains connections to relays, different accounts just choose subsets of the relays to send to given the note fetching algorithm you're using:

Pool: Relays A,B,C,D Alice: Relay B,C Bob: Relay A,D,C

When switching between accounts you don't have to disconnect or reconnect, you just CLOSE and re-REQ to the corresponding relay subset, and query subsets based on user relay lists.

So yes relay lists are the ground truth. The relay pool is more just a connection manager. We add relays to this pool from user relay lists, and this pool is shared between accounts. When you switch accounts it may effect the active remote subscriptions and connections, but it's not like we will create a new pool or anything.