Changeset 535 in code for trunk


Ignore:
Timestamp:
May 25, 2021, 2:42:51 PM (4 years ago)
Author:
contact
Message:

Introduce the soju.im/bouncer-networks-notify capability

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/doc/ext/bouncer-networks.md

    r533 r535  
    4343`BOUNCER` command.
    4444
     45The `bouncer-networks` capability MUST be negociated. This allows the server and
     46client to behave differently when the client is aware of the bouncer networks.
     47
     48The `bouncer-networks-notify` capability MAY be negociated. This allows the
     49client to signal that it is capable of receiving and correctly processing
     50bouncer network notifications.
     51
    4552### `RPL_ISUPPORT` token
    4653
     
    128135### Network notifications
    129136
    130 When a network attributes are updated, the bouncer MUST broadcast a
    131 `BOUNCER NETWORK` message to all connected clients with the updated attributes:
     137If the client has negociated the `bouncer-networks-notify` capability, the
     138server MUST send an initial batch of `BOUNCER NETWORK` messages with the current
     139list of network, and MUST send notification messages whenever a network is
     140added, updated or removed.
     141
     142If the client has not negociated the `bouncer-networks-notify` capability, the
     143server MUST NOT send implicit `BOUNCER NETWORK` messages.
     144
     145When network attributes are updated, the bouncer MUST broadcast a
     146`BOUNCER NETWORK` message with the updated attributes to all connected clients
     147with the `bouncer-networks-notify` capability enabled:
    132148
    133149    BOUNCER NETWORK <netid> <attributes>
    134150
     151The notification SHOULD NOT contain attributes that haven't been updated.
     152
    135153When a network is removed, the bouncer MUST broadcast a `BOUNCER NETWORK`
    136 message to all connected clients:
     154message with the special argument `*` to all connected clients with the
     155`bouncer-networks-notify` capability enabled:
    137156
    138157    BOUNCER NETWORK <netid> *
     
    232251    C: NICK emersion
    233252    C: USER emersion 0 0 :Simon
    234     S: CAP * LS :sasl=PLAIN bouncer-networks
     253    S: CAP * LS :sasl=PLAIN bouncer-networks bouncer-networks-notify
    235254    C: CAP REQ :sasl bouncer-networks
    236255    [SASL authentication]
     
    249268
    250269    C: BOUNCER ADDNETWORK name=OFTC;host=irc.oftc.net
    251     S: BOUNCER NETWORK 44 status=connecting
     270    S: BOUNCER NETWORK 44 name=OFTC;host=irc.oftc.net;status=connecting
    252271    S: BOUNCER ADDNETWORK 44
    253272    S: BOUNCER NETWORK 44 status=connected
  • trunk/downstream.go

    r534 r535  
    5858}}
    5959
    60 func parseBouncerNetID(s string) (int64, error) {
     60func parseBouncerNetID(subcommand, s string) (int64, error) {
    6161        id, err := strconv.ParseInt(s, 10, 64)
    6262        if err != nil {
    6363                return 0, ircError{&irc.Message{
    6464                        Command: "FAIL",
    65                         Params:  []string{"BOUNCER", "INVALID_NETID", s, "Invalid network ID"},
     65                        Params:  []string{"BOUNCER", "INVALID_NETID", subcommand, s, "Invalid network ID"},
    6666                }}
    6767        }
    6868        return id, nil
     69}
     70
     71func getNetworkAttrs(network *network) irc.Tags {
     72        state := "disconnected"
     73        if uc := network.conn; uc != nil {
     74                state = "connected"
     75        }
     76
     77        attrs := irc.Tags{
     78                "name":     irc.TagValue(network.GetName()),
     79                "state":    irc.TagValue(state),
     80                "nickname": irc.TagValue(network.Nick),
     81        }
     82
     83        if network.Username != "" {
     84                attrs["username"] = irc.TagValue(network.Username)
     85        }
     86        if network.Realname != "" {
     87                attrs["realname"] = irc.TagValue(network.Realname)
     88        }
     89
     90        if u, err := network.URL(); err == nil {
     91                hasHostPort := true
     92                switch u.Scheme {
     93                case "ircs":
     94                        attrs["tls"] = irc.TagValue("1")
     95                case "irc+insecure":
     96                        attrs["tls"] = irc.TagValue("0")
     97                default:
     98                        hasHostPort = false
     99                }
     100                if host, port, err := net.SplitHostPort(u.Host); err == nil && hasHostPort {
     101                        attrs["host"] = irc.TagValue(host)
     102                        attrs["port"] = irc.TagValue(port)
     103                } else if hasHostPort {
     104                        attrs["host"] = irc.TagValue(u.Host)
     105                }
     106        }
     107
     108        return attrs
    69109}
    70110
     
    76116// capabilities.
    77117var permanentDownstreamCaps = map[string]string{
    78         "batch":                    "",
    79         "soju.im/bouncer-networks": "",
    80         "cap-notify":               "",
    81         "echo-message":             "",
    82         "invite-notify":            "",
    83         "message-tags":             "",
    84         "sasl":                     "PLAIN",
    85         "server-time":              "",
     118        "batch":         "",
     119        "cap-notify":    "",
     120        "echo-message":  "",
     121        "invite-notify": "",
     122        "message-tags":  "",
     123        "sasl":          "PLAIN",
     124        "server-time":   "",
     125
     126        "soju.im/bouncer-networks":        "",
     127        "soju.im/bouncer-networks-notify": "",
    86128}
    87129
     
    599641                        }
    600642
    601                         id, err := parseBouncerNetID(idStr)
     643                        id, err := parseBouncerNetID(subcommand, idStr)
    602644                        if err != nil {
    603645                                return err
     
    10221064        dc.updateNick()
    10231065        dc.updateSupportedCaps()
     1066
     1067        if dc.caps["soju.im/bouncer-networks-notify"] {
     1068                dc.SendMessage(&irc.Message{
     1069                        Prefix:  dc.srv.prefix(),
     1070                        Command: "BATCH",
     1071                        Params:  []string{"+networks", "bouncer-networks"},
     1072                })
     1073                dc.user.forEachNetwork(func(network *network) {
     1074                        idStr := fmt.Sprintf("%v", network.ID)
     1075                        attrs := getNetworkAttrs(network)
     1076                        dc.SendMessage(&irc.Message{
     1077                                Tags:    irc.Tags{"batch": irc.TagValue("networks")},
     1078                                Prefix:  dc.srv.prefix(),
     1079                                Command: "BOUNCER",
     1080                                Params:  []string{"NETWORK", idStr, attrs.String()},
     1081                        })
     1082                })
     1083                dc.SendMessage(&irc.Message{
     1084                        Prefix:  dc.srv.prefix(),
     1085                        Command: "BATCH",
     1086                        Params:  []string{"-networks"},
     1087                })
     1088        }
    10241089
    10251090        dc.forEachUpstream(func(uc *upstreamConn) {
     
    19862051                        })
    19872052                        dc.user.forEachNetwork(func(network *network) {
    1988                                 id := fmt.Sprintf("%v", network.ID)
    1989 
    1990                                 state := "disconnected"
    1991                                 if uc := network.conn; uc != nil {
    1992                                         state = "connected"
    1993                                 }
    1994 
    1995                                 attrs := irc.Tags{
    1996                                         "name":     irc.TagValue(network.GetName()),
    1997                                         "state":    irc.TagValue(state),
    1998                                         "nickname": irc.TagValue(network.Nick),
    1999                                 }
    2000 
    2001                                 if network.Username != "" {
    2002                                         attrs["username"] = irc.TagValue(network.Username)
    2003                                 }
    2004                                 if network.Realname != "" {
    2005                                         attrs["realname"] = irc.TagValue(network.Realname)
    2006                                 }
    2007 
    2008                                 if u, err := network.URL(); err == nil {
    2009                                         hasHostPort := true
    2010                                         switch u.Scheme {
    2011                                         case "ircs":
    2012                                                 attrs["tls"] = irc.TagValue("1")
    2013                                         case "irc+insecure":
    2014                                                 attrs["tls"] = irc.TagValue("0")
    2015                                         default:
    2016                                                 hasHostPort = false
    2017                                         }
    2018                                         if host, port, err := net.SplitHostPort(u.Host); err == nil && hasHostPort {
    2019                                                 attrs["host"] = irc.TagValue(host)
    2020                                                 attrs["port"] = irc.TagValue(port)
    2021                                         } else if hasHostPort {
    2022                                                 attrs["host"] = irc.TagValue(u.Host)
    2023                                         }
    2024                                 }
    2025 
     2053                                idStr := fmt.Sprintf("%v", network.ID)
     2054                                attrs := getNetworkAttrs(network)
    20262055                                dc.SendMessage(&irc.Message{
    20272056                                        Tags:    irc.Tags{"batch": irc.TagValue("networks")},
    20282057                                        Prefix:  dc.srv.prefix(),
    20292058                                        Command: "BOUNCER",
    2030                                         Params:  []string{"NETWORK", id, attrs.String()},
     2059                                        Params:  []string{"NETWORK", idStr, attrs.String()},
    20312060                                })
    20322061                        })
     
    20962125                                return err
    20972126                        }
    2098                         id, err := parseBouncerNetID(idStr)
     2127                        id, err := parseBouncerNetID(subcommand, idStr)
    20992128                        if err != nil {
    21002129                                return err
     
    21062135                                return ircError{&irc.Message{
    21072136                                        Command: "FAIL",
    2108                                         Params:  []string{"BOUNCER", "INVALID_NETID", idStr, "Invalid network ID"},
     2137                                        Params:  []string{"BOUNCER", "INVALID_NETID", subcommand, idStr, "Invalid network ID"},
    21092138                                }}
    21102139                        }
     
    21492178                                return err
    21502179                        }
    2151                         id, err := parseBouncerNetID(idStr)
     2180                        id, err := parseBouncerNetID(subcommand, idStr)
    21522181                        if err != nil {
    21532182                                return err
     
    21582187                                return ircError{&irc.Message{
    21592188                                        Command: "FAIL",
    2160                                         Params:  []string{"BOUNCER", "INVALID_NETID", idStr, "Invalid network ID"},
     2189                                        Params:  []string{"BOUNCER", "INVALID_NETID", subcommand, idStr, "Invalid network ID"},
    21612190                                }}
    21622191                        }
  • trunk/user.go

    r532 r535  
    519519                                dc.updateSupportedCaps()
    520520
    521                                 if dc.caps["soju.im/bouncer-networks"] {
     521                                if dc.caps["soju.im/bouncer-networks-notify"] {
    522522                                        dc.SendMessage(&irc.Message{
    523523                                                Prefix:  dc.srv.prefix(),
     
    658658                dc.updateSupportedCaps()
    659659
    660                 if dc.caps["soju.im/bouncer-networks"] {
     660                if dc.caps["soju.im/bouncer-networks-notify"] {
    661661                        dc.SendMessage(&irc.Message{
    662662                                Prefix:  dc.srv.prefix(),
     
    726726        u.addNetwork(network)
    727727
    728         // TODO: broadcast network status
    729728        idStr := fmt.Sprintf("%v", network.ID)
     729        attrs := getNetworkAttrs(network)
    730730        u.forEachDownstream(func(dc *downstreamConn) {
    731                 if dc.caps["soju.im/bouncer-networks"] {
     731                if dc.caps["soju.im/bouncer-networks-notify"] {
    732732                        dc.SendMessage(&irc.Message{
    733733                                Prefix:  dc.srv.prefix(),
    734734                                Command: "BOUNCER",
    735                                 Params:  []string{"NETWORK", idStr, "network=" + network.GetName()},
     735                                Params:  []string{"NETWORK", idStr, attrs.String()},
    736736                        })
    737737                }
     
    791791        u.addNetwork(updatedNetwork)
    792792
    793         // TODO: broadcast BOUNCER NETWORK notifications
     793        // TODO: only broadcast attributes that have changed
     794        idStr := fmt.Sprintf("%v", updatedNetwork.ID)
     795        attrs := getNetworkAttrs(updatedNetwork)
     796        u.forEachDownstream(func(dc *downstreamConn) {
     797                if dc.caps["soju.im/bouncer-networks-notify"] {
     798                        dc.SendMessage(&irc.Message{
     799                                Prefix:  dc.srv.prefix(),
     800                                Command: "BOUNCER",
     801                                Params:  []string{"NETWORK", idStr, attrs.String()},
     802                        })
     803                }
     804        })
    794805
    795806        return updatedNetwork, nil
     
    810821        idStr := fmt.Sprintf("%v", network.ID)
    811822        u.forEachDownstream(func(dc *downstreamConn) {
    812                 if dc.caps["soju.im/bouncer-networks"] {
     823                if dc.caps["soju.im/bouncer-networks-notify"] {
    813824                        dc.SendMessage(&irc.Message{
    814825                                Prefix:  dc.srv.prefix(),
Note: See TracChangeset for help on using the changeset viewer.