Changeset 292 in code for trunk


Ignore:
Timestamp:
May 11, 2020, 10:25:49 AM (5 years ago)
Author:
delthas
Message:

Add support for multiple user channel memberships

User channel memberships are actually a set of memberships, not a single
value. This introduces memberships, a type representing a set of
memberships, stored as an array of memberships ordered by descending
rank.

This also adds multi-prefix to the permanent downstream and upstream
capabilities, so that we try to get all possible channel memberships.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/bridge.go

    r260 r292  
    3939        downstreamName := dc.marshalEntity(ch.conn.network, ch.Name)
    4040
    41         for nick, membership := range ch.Members {
    42                 s := membership.String() + dc.marshalEntity(ch.conn.network, nick)
     41        for nick, memberships := range ch.Members {
     42                s := memberships.Format(dc) + dc.marshalEntity(ch.conn.network, nick)
    4343
    4444                dc.SendMessage(&irc.Message{
  • trunk/downstream.go

    r291 r292  
    6060        "sasl":         "PLAIN",
    6161        "server-time":  "",
     62}
     63
     64// needAllDownstreamCaps is the list of downstream capabilities that
     65// require support from all upstreams to be enabled
     66var needAllDownstreamCaps = map[string]string{
     67        "away-notify":  "",
     68        "multi-prefix": "",
    6269}
    6370
     
    597604
    598605func (dc *downstreamConn) updateSupportedCaps() {
    599         awayNotifySupported := true
     606        supportedCaps := make(map[string]bool)
     607        for cap := range needAllDownstreamCaps {
     608                supportedCaps[cap] = true
     609        }
    600610        dc.forEachUpstream(func(uc *upstreamConn) {
    601                 awayNotifySupported = awayNotifySupported && uc.caps["away-notify"]
     611                for cap, supported := range supportedCaps {
     612                        supportedCaps[cap] = supported && uc.caps[cap]
     613                }
    602614        })
    603615
    604         if awayNotifySupported {
    605                 dc.setSupportedCap("away-notify", "")
    606         } else {
    607                 dc.unsetSupportedCap("away-notify")
     616        for cap, supported := range supportedCaps {
     617                if supported {
     618                        dc.setSupportedCap(cap, needAllDownstreamCaps[cap])
     619                } else {
     620                        dc.unsetSupportedCap(cap)
     621                }
    608622        }
    609623}
  • trunk/irc.go

    r193 r292  
    177177}
    178178
    179 func (m *membership) String() string {
    180         if m == nil {
    181                 return ""
    182         }
    183         return string(m.Prefix)
     179// memberships always sorted by descending membership rank
     180type memberships []membership
     181
     182func (m *memberships) Add(availableMemberships []membership, newMembership membership) {
     183        l := *m
     184        i := 0
     185        for _, availableMembership := range availableMemberships {
     186                if i >= len(l) {
     187                        break
     188                }
     189                if l[i] == availableMembership {
     190                        if availableMembership == newMembership {
     191                                // we already have this membership
     192                                return
     193                        }
     194                        i++
     195                        continue
     196                }
     197                if availableMembership == newMembership {
     198                        break
     199                }
     200        }
     201        // insert newMembership at i
     202        l = append(l, membership{})
     203        copy(l[i+1:], l[i:])
     204        l[i] = newMembership
     205        *m = l
     206}
     207
     208func (m *memberships) Remove(oldMembership membership) {
     209        l := *m
     210        for i, currentMembership := range l {
     211                if currentMembership == oldMembership {
     212                        *m = append(l[:i], l[i+1:]...)
     213                        return
     214                }
     215        }
     216}
     217
     218func (m memberships) Format(dc *downstreamConn) string {
     219        if !dc.caps["multi-prefix"] {
     220                if len(m) == 0 {
     221                        return ""
     222                }
     223                return string(m[0].Prefix)
     224        }
     225        prefixes := make([]byte, len(m))
     226        for i, membership := range m {
     227                prefixes[i] = membership.Prefix
     228        }
     229        return string(prefixes)
    184230}
    185231
  • trunk/upstream.go

    r288 r292  
    2525        "labeled-response": true,
    2626        "message-tags":     true,
     27        "multi-prefix":     true,
    2728        "server-time":      true,
    2829}
     
    3738        modes        channelModes
    3839        creationTime string
    39         Members      map[string]*membership
     40        Members      map[string]*memberships
    4041        complete     bool
    4142}
     
    230231}
    231232
    232 func (uc *upstreamConn) parseMembershipPrefix(s string) (membership *membership, nick string) {
     233func (uc *upstreamConn) parseMembershipPrefix(s string) (ms *memberships, nick string) {
     234        memberships := make(memberships, 0, 4)
     235        i := 0
    233236        for _, m := range uc.availableMemberships {
    234                 if m.Prefix == s[0] {
    235                         return &m, s[1:]
    236                 }
    237         }
    238         return nil, s
     237                if i >= len(s) {
     238                        break
     239                }
     240                if s[i] == m.Prefix {
     241                        memberships = append(memberships, m)
     242                        i++
     243                }
     244        }
     245        return &memberships, s[i:]
    239246}
    240247
     
    645652
    646653                for _, ch := range uc.channels {
    647                         if membership, ok := ch.Members[msg.Prefix.Name]; ok {
     654                        if memberships, ok := ch.Members[msg.Prefix.Name]; ok {
    648655                                delete(ch.Members, msg.Prefix.Name)
    649                                 ch.Members[newNick] = membership
     656                                ch.Members[newNick] = memberships
    650657                                uc.appendLog(ch.Name, msg)
    651658                                uc.appendHistory(ch.Name, msg)
     
    674681                                        Name:    ch,
    675682                                        conn:    uc,
    676                                         Members: make(map[string]*membership),
     683                                        Members: make(map[string]*memberships),
    677684                                }
    678685
     
    940947                                members := splitSpace(members)
    941948                                for i, member := range members {
    942                                         membership, nick := uc.parseMembershipPrefix(member)
    943                                         members[i] = membership.String() + dc.marshalEntity(uc.network, nick)
     949                                        memberships, nick := uc.parseMembershipPrefix(member)
     950                                        members[i] = memberships.Format(dc) + dc.marshalEntity(uc.network, nick)
    944951                                }
    945952                                memberStr := strings.Join(members, " ")
     
    961968
    962969                for _, s := range splitSpace(members) {
    963                         membership, nick := uc.parseMembershipPrefix(s)
    964                         ch.Members[nick] = membership
     970                        memberships, nick := uc.parseMembershipPrefix(s)
     971                        ch.Members[nick] = memberships
    965972                }
    966973        case irc.RPL_ENDOFNAMES:
     
    11131120                                prefix, channel := uc.parseMembershipPrefix(channel)
    11141121                                channel = dc.marshalEntity(uc.network, channel)
    1115                                 channelList[i] = prefix.String() + channel
     1122                                channelList[i] = prefix.Format(dc) + channel
    11161123                        }
    11171124                        channels := strings.Join(channelList, " ")
Note: See TracChangeset for help on using the changeset viewer.