Some WebPushSubscription entries aren't tried to a network, in
which case the "network" column is NULL. But then all users share
the same row. Oops.
Fortunately network-less subscriptions aren't used for anything
yet, they're just stored. So the impact should be minimal.
This fixes a serious bug where we stop executing forEachDownstream on
the first downstream that does not match the network. Instead we want to
simply continue; it's a basic filter.
Currently, if we fail connecting to a new networking during welcome, we
send no error message to the client, and the connection remains open in
an undefined state.
Given the input:
NICK nick
USER user/invalid.xyz s e r
PASS pass
soju will fail to connect, add a message to its own logs, but will
return no message to the downstream.
This fixes the issue by forwarding the error message if it is an IRC
error message (which it is for connecting to new networks).
We should probably also close the connection after the message is
written, because it leaves the connection in an undefined state. This is
TODO for now because we'd have to wait for the error message to be
written out first, which is non-trivial.
When fetching messages via draft/chathistory from a conversation
with another user, soju would send the following:
:sender PRIVMSG sender :hey
instead of
:sender PRIVMSG recipient :hey
because the file-system message store format doesn't contain the
original PRIVMSG target.
Fix this by doing some guesswork.
READ lets downstream clients share information between each other about
what messages have been read by other downstreams.
Each target/entity has an optional corresponding read receipt, which is
stored as a timestamp.
- When a downstream sends:
READ #chan timestamp=2020-01-01T01:23:45.000Z
the read receipt for that target is set to that date
- soju sends READ to downstreams:
- on JOIN, if the client uses the soju.im/read capability
- when the read receipt timestamp is set by any downstream
The read receipt date is clamped by the previous receipt date and the
current time.
Right now there is no consistent ordering in the network list:
no ORDER BY in the DB, and network updates move entries to the end.
Let's always sort by network ID so that users don't see the entries
move around.
I've contemplated sorting by Network.GetName() instead, but:
- Clients have now way to figure out dynamic order changes, e.g.
when renaming a network.
- Some clients might use ISUPPORT NETWORK when a user hasn't
explicitly named a network, but soju won't use that for ordering,
leading to non-alphabetic ordering in the client.
Let's leave it to clients to sort the networks by display name if
they want to.
If a client queues a high number of commands and then disconnects,
remove all of the pending commands. This avoids unnecessarily
sending commands whose results won't be used.
The first reconnection attempt waits for 1min, the second the 2min,
and so on up to 10min. There's a 1min jitter so that multiple failed
connections don't try to reconnect at the exact same time.
Closes: https://todo.sr.ht/~emersion/soju/161
Once the downstream connection has logged in with their bouncer
credentials, allow them to issue more SASL auths which will be
redirected to the upstream network. This allows downstream clients
to provide UIs to login to transparently login to upstream networks.
Add support for MONITOR in single-upstream mode.
Each downstream has its own set of monitored targets. These sets
are merged together to compute the MONITOR commands to send to
upstream.
Each upstream has a set of monitored targets accepted by the server
alongside with their status (online/offline). This is used to
directly send replies to downstreams adding a target another
downstream has already added, and send MONITOR S[TATUS] replies.
Co-authored-by: delthas <delthas@dille.cc>
This has the following upsides:
- We can now routes WHO replies to the correct client, without
broadcasting them to everybody.
- We are less likely to hit server rate limits when multiple downstreams
are issuing WHO commands at the same time.
The message stores don't need to access the internal network
struct, they just need network metadata such as ID and name.
This can ease moving message stores into a separate package in the
future.
This is a mecanical change, which just lifts up the context.TODO()
calls from inside the DB implementations to the callers.
Future work involves properly wiring up the contexts when it makes
sense.