delthas: 1 bouncer-networks: Add a read-only error attribute 3 files changed, 43 insertions(+), 6 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~emersion/public-inbox/patches/30960/mbox | git am -3Learn more about email & git
This is useful for clients to display additional info about why a network is disconnected. With this change, we also stop sending network disconnect/connect NOTICEs to clients which support bouncer-networks-notify, because they now have access to all the information that would be sent in that message. --- doc/ext/bouncer-networks.md | 4 ++++ downstream.go | 4 ++++ user.go | 41 +++++++++++++++++++++++++++++++------ 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/doc/ext/bouncer-networks.md b/doc/ext/bouncer-networks.md index cefb72d..1f55a80 100644 --- a/doc/ext/bouncer-networks.md +++ b/doc/ext/bouncer-networks.md @@ -242,6 +242,10 @@ Bouncers MUST recognise the following network attributes: * `realname`: the realname to use during registration. * `pass`: the server password (PASS) to use during registration. +Bouncers MAY recognise the following network attributes: +* `error` (read-only): a human-readable short text describing an error with the current network. + This is typically used when the bouncer state is `disconnected` to describe the reason why the bouncer is disconnected. + TODO: more attributes ### Examples diff --git a/downstream.go b/downstream.go index bef6adf..01b1812 100644 --- a/downstream.go +++ b/downstream.go @@ -142,6 +142,10 @@ func getNetworkAttrs(network *network) irc.Tags { attrs["realname"] = irc.TagValue(realname) } + if network.lastError != nil { + attrs["error"] = irc.TagValue(network.lastError.Error()) + } + fillNetworkAddrAttrs(attrs, &network.Network) return attrs diff --git a/user.go b/user.go index 29bbe85..eced60e 100644 --- a/user.go +++ b/user.go @@ -562,7 +562,7 @@ func (u *user) run() { uc.forEachDownstream(func(dc *downstreamConn) { dc.updateSupportedCaps() - if !dc.caps.IsEnabled("soju.im/bouncer-networks") { + if !dc.caps.IsEnabled("soju.im/bouncer-networks-notify") { sendServiceNOTICE(dc, fmt.Sprintf("connected to %s", uc.network.GetName())) } @@ -576,7 +576,10 @@ func (u *user) run() { dc.SendMessage(&irc.Message{ Prefix: dc.srv.prefix(), Command: "BOUNCER", - Params: []string{"NETWORK", netIDStr, "state=connected"}, + Params: []string{"NETWORK", netIDStr, irc.Tags{ + "state": "connected", + "error": "", + }.String()}, }) } }) @@ -595,17 +598,43 @@ func (u *user) run() { if !stopped && (net.lastError == nil || net.lastError.Error() != e.err.Error()) { net.forEachDownstream(func(dc *downstreamConn) { - sendServiceNOTICE(dc, fmt.Sprintf("failed connecting/registering to %s: %v", net.GetName(), e.err)) + if !dc.caps.IsEnabled("soju.im/bouncer-networks-notify") { + sendServiceNOTICE(dc, fmt.Sprintf("failed connecting/registering to %s: %v", net.GetName(), e.err)) + } }) } net.lastError = e.err + u.forEachDownstream(func(dc *downstreamConn) { + if dc.caps.IsEnabled("soju.im/bouncer-networks-notify") { + dc.SendMessage(&irc.Message{ + Prefix: dc.srv.prefix(), + Command: "BOUNCER", + Params: []string{"NETWORK", fmt.Sprintf("%v", net.ID), irc.Tags{ + "error": irc.TagValue(net.lastError.Error()), + }.String()}, + }) + } + }) case eventUpstreamError: uc := e.uc uc.forEachDownstream(func(dc *downstreamConn) { - sendServiceNOTICE(dc, fmt.Sprintf("disconnected from %s: %v", uc.network.GetName(), e.err)) + if !dc.caps.IsEnabled("soju.im/bouncer-networks-notify") { + sendServiceNOTICE(dc, fmt.Sprintf("disconnected from %s: %v", uc.network.GetName(), e.err)) + } }) uc.network.lastError = e.err + u.forEachDownstream(func(dc *downstreamConn) { + if dc.caps.IsEnabled("soju.im/bouncer-networks-notify") { + dc.SendMessage(&irc.Message{ + Prefix: dc.srv.prefix(), + Command: "BOUNCER", + Params: []string{"NETWORK", fmt.Sprintf("%v", uc.network.ID), irc.Tags{ + "error": irc.TagValue(uc.network.lastError.Error()), + }.String()}, + }) + } + }) case eventUpstreamMessage: msg, uc := e.msg, e.uc if uc.isClosed() { @@ -651,7 +680,7 @@ func (u *user) run() { u.downstreamConns = append(u.downstreamConns, dc) dc.forEachNetwork(func(network *network) { - if network.lastError != nil { + if network.lastError != nil && dc.caps.IsEnabled("soju.im/bouncer-networks") { sendServiceNOTICE(dc, fmt.Sprintf("disconnected from %s: %v", network.GetName(), network.lastError)) } }) @@ -774,7 +803,7 @@ func (u *user) handleUpstreamDisconnected(uc *upstreamConn) { if uc.network.lastError == nil { uc.forEachDownstream(func(dc *downstreamConn) { - if !dc.caps.IsEnabled("soju.im/bouncer-networks") { + if !dc.caps.IsEnabled("soju.im/bouncer-networks-notify") { sendServiceNOTICE(dc, fmt.Sprintf("disconnected from %s", uc.network.GetName())) } }) base-commit: d8ca6d22224893fb6286495033c72e7d7be3f9af -- 2.30.0
Hm, after some more discussion on IRC, unfortunately this approach won't cut it. bouncer-networks-notify is typically just enabled on a single connection (one where BOUNCER BIND isn't used). I've opened [1] to track this issue. I've merged the first version of the patch. Thanks! [1]: https://todo.sr.ht/~emersion/soju/195