Changeset 435 in code


Ignore:
Timestamp:
Dec 14, 2020, 7:54:02 PM (4 years ago)
Author:
delthas
Message:

Add customizable auto-detaching, auto-reattaching, relaying.

This uses the fields added previously to the Channel struct to implement
the actual detaching/reattaching/relaying logic.

The FilterDefault values of the messages filters are currently
hardcoded.

The values of the message filters are not currently user-settable.

This introduces a new user event, eventChannelDetach, which stores an
upstreamConn (which might become invalid at the time of processing), and
a channel name, used for auto-detaching. Every time the channel detach
timer is refreshed (by receveing a message, etc.), a new timer is
created on the upstreamChannel, which will dispatch this event after the
duration (and discards the previous timer, if any).

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/downstream.go

    r431 r435  
    11581158                        })
    11591159
    1160                         ch := &Channel{Name: upstreamName, Key: key, Detached: false}
    1161                         if current, ok := uc.network.channels[ch.Name]; ok && key == "" {
     1160                        var ch *Channel
     1161                        var ok bool
     1162                        if ch, ok = uc.network.channels[upstreamName]; ok {
    11621163                                // Don't clear the channel key if there's one set
    11631164                                // TODO: add a way to unset the channel key
    1164                                 ch.Key = current.Key
    1165                         }
    1166                         if err := uc.network.createUpdateChannel(ch); err != nil {
     1165                                if key != "" {
     1166                                        ch.Key = key
     1167                                }
     1168                                uc.network.attach(ch)
     1169                        } else {
     1170                                ch = &Channel{
     1171                                        Name: upstreamName,
     1172                                        Key:  key,
     1173                                }
     1174                                uc.network.channels[upstreamName] = ch
     1175                        }
     1176                        if err := dc.srv.db.StoreChannel(uc.network.ID, ch); err != nil {
    11671177                                dc.logger.Printf("failed to create or update channel %q: %v", upstreamName, err)
    11681178                        }
     
    11861196
    11871197                        if strings.EqualFold(reason, "detach") {
    1188                                 ch := &Channel{Name: upstreamName, Detached: true}
    1189                                 if err := uc.network.createUpdateChannel(ch); err != nil {
    1190                                         dc.logger.Printf("failed to detach channel %q: %v", upstreamName, err)
     1198                                var ch *Channel
     1199                                var ok bool
     1200                                if ch, ok = uc.network.channels[upstreamName]; ok {
     1201                                        uc.network.detach(ch)
     1202                                } else {
     1203                                        ch = &Channel{
     1204                                                Name:     name,
     1205                                                Detached: true,
     1206                                        }
     1207                                        uc.network.channels[upstreamName] = ch
     1208                                }
     1209                                if err := dc.srv.db.StoreChannel(uc.network.ID, ch); err != nil {
     1210                                        dc.logger.Printf("failed to create or update channel %q: %v", upstreamName, err)
    11911211                                }
    11921212                        } else {
     
    16141634                        }
    16151635                        uc.produce(upstreamName, echoMsg, dc)
     1636
     1637                        uc.updateChannelAutoDetach(upstreamName)
    16161638                }
    16171639        case "NOTICE":
     
    16371659                                Params:  []string{upstreamName, unmarshaledText},
    16381660                        })
     1661
     1662                        uc.updateChannelAutoDetach(upstreamName)
    16391663                }
    16401664        case "TAGMSG":
     
    16591683                                Params:  []string{upstreamName},
    16601684                        })
     1685
     1686                        uc.updateChannelAutoDetach(upstreamName)
    16611687                }
    16621688        case "INVITE":
  • trunk/upstream.go

    r428 r435  
    5151        Members      map[string]*memberships
    5252        complete     bool
     53        detachTimer  *time.Timer
     54}
     55
     56func (uc *upstreamChannel) updateAutoDetach(dur time.Duration) {
     57        if uc.detachTimer != nil {
     58                uc.detachTimer.Stop()
     59                uc.detachTimer = nil
     60        }
     61
     62        if dur == 0 {
     63                return
     64        }
     65
     66        uc.detachTimer = time.AfterFunc(dur, func() {
     67                uc.conn.network.user.events <- eventChannelDetach{
     68                        uc:   uc.conn,
     69                        name: uc.Name,
     70                }
     71        })
    5372}
    5473
     
    404423                                target = msg.Prefix.Name
    405424                        }
     425
     426                        if ch, ok := uc.network.channels[target]; ok {
     427                                if ch.Detached {
     428                                        uc.handleDetachedMessage(msg.Prefix.Name, text, ch)
     429                                }
     430
     431                                highlight := msg.Prefix.Name != uc.nick && isHighlight(text, uc.nick)
     432                                if ch.DetachOn == FilterMessage || ch.DetachOn == FilterDefault || (ch.DetachOn == FilterHighlight && highlight) {
     433                                        uc.updateChannelAutoDetach(target)
     434                                }
     435                        }
     436
    406437                        uc.produce(target, msg, nil)
    407 
    408                         highlight := msg.Prefix.Name != uc.nick && isHighlight(text, uc.nick)
    409                         if ch, ok := uc.network.channels[target]; ok && ch.Detached && highlight {
    410                                 uc.forEachDownstream(func(dc *downstreamConn) {
    411                                         sendServiceNOTICE(dc, fmt.Sprintf("highlight in %v: <%v> %v", dc.marshalEntity(uc.network, ch.Name), msg.Prefix.Name, text))
    412                                 })
    413                         }
    414438                }
    415439        case "CAP":
     
    737761                                        Members: make(map[string]*memberships),
    738762                                }
     763                                uc.updateChannelAutoDetach(ch)
    739764
    740765                                uc.SendMessage(&irc.Message{
     
    767792                        if msg.Prefix.Name == uc.nick {
    768793                                uc.logger.Printf("parted channel %q", ch)
    769                                 delete(uc.channels, ch)
     794                                if uch, ok := uc.channels[ch]; ok {
     795                                        delete(uc.channels, ch)
     796                                        uch.updateAutoDetach(0)
     797                                }
    770798                        } else {
    771799                                ch, err := uc.getChannel(ch)
     
    14091437}
    14101438
     1439func (uc *upstreamConn) handleDetachedMessage(sender string, text string, ch *Channel) {
     1440        highlight := sender != uc.nick && isHighlight(text, uc.nick)
     1441        if ch.RelayDetached == FilterMessage || ((ch.RelayDetached == FilterHighlight || ch.RelayDetached == FilterDefault) && highlight) {
     1442                uc.forEachDownstream(func(dc *downstreamConn) {
     1443                        if highlight {
     1444                                sendServiceNOTICE(dc, fmt.Sprintf("highlight in %v: <%v> %v", dc.marshalEntity(uc.network, ch.Name), sender, text))
     1445                        } else {
     1446                                sendServiceNOTICE(dc, fmt.Sprintf("message in %v: <%v> %v", dc.marshalEntity(uc.network, ch.Name), sender, text))
     1447                        }
     1448                })
     1449        }
     1450        if ch.ReattachOn == FilterMessage || (ch.ReattachOn == FilterHighlight && highlight) {
     1451                uc.network.attach(ch)
     1452                if err := uc.srv.db.StoreChannel(uc.network.ID, ch); err != nil {
     1453                        uc.logger.Printf("failed to update channel %q: %v", ch.Name, err)
     1454                }
     1455        }
     1456}
     1457
    14111458func (uc *upstreamConn) handleSupportedCaps(capsStr string) {
    14121459        caps := strings.Fields(capsStr)
     
    17021749        uc.away = away
    17031750}
     1751
     1752func (uc *upstreamConn) updateChannelAutoDetach(name string) {
     1753        if uch, ok := uc.channels[name]; ok {
     1754                if ch, ok := uc.network.channels[name]; ok && !ch.Detached {
     1755                        uch.updateAutoDetach(ch.DetachAfter)
     1756                }
     1757        }
     1758}
  • trunk/user.go

    r423 r435  
    4747type eventDownstreamDisconnected struct {
    4848        dc *downstreamConn
     49}
     50
     51type eventChannelDetach struct {
     52        uc   *upstreamConn
     53        name string
    4954}
    5055
     
    177182}
    178183
    179 func (net *network) createUpdateChannel(ch *Channel) error {
    180         if current, ok := net.channels[ch.Name]; ok {
    181                 ch.ID = current.ID // update channel if it already exists
    182         }
    183         if err := net.user.srv.db.StoreChannel(net.ID, ch); err != nil {
    184                 return err
    185         }
    186         prev := net.channels[ch.Name]
    187         net.channels[ch.Name] = ch
    188 
    189         if prev != nil && prev.Detached != ch.Detached {
    190                 history := net.history[ch.Name]
    191                 if ch.Detached {
    192                         net.user.srv.Logger.Printf("network %q: detaching channel %q", net.GetName(), ch.Name)
    193                         net.forEachDownstream(func(dc *downstreamConn) {
    194                                 net.offlineClients[dc.clientName] = struct{}{}
    195 
    196                                 dc.SendMessage(&irc.Message{
    197                                         Prefix:  dc.prefix(),
    198                                         Command: "PART",
    199                                         Params:  []string{dc.marshalEntity(net, ch.Name), "Detach"},
    200                                 })
    201                         })
    202                 } else {
    203                         net.user.srv.Logger.Printf("network %q: attaching channel %q", net.GetName(), ch.Name)
    204 
    205                         var uch *upstreamChannel
    206                         if net.conn != nil {
    207                                 uch = net.conn.channels[ch.Name]
    208                         }
    209 
    210                         net.forEachDownstream(func(dc *downstreamConn) {
    211                                 dc.SendMessage(&irc.Message{
    212                                         Prefix:  dc.prefix(),
    213                                         Command: "JOIN",
    214                                         Params:  []string{dc.marshalEntity(net, ch.Name)},
    215                                 })
    216 
    217                                 if uch != nil {
    218                                         forwardChannel(dc, uch)
    219                                 }
    220 
    221                                 if history != nil {
    222                                         dc.sendNetworkHistory(net)
    223                                 }
    224                         })
    225                 }
    226         }
    227 
    228         return nil
     184func (net *network) detach(ch *Channel) {
     185        if ch.Detached {
     186                return
     187        }
     188        ch.Detached = true
     189        net.user.srv.Logger.Printf("network %q: detaching channel %q", net.GetName(), ch.Name)
     190
     191        if net.conn != nil {
     192                if uch, ok := net.conn.channels[ch.Name]; ok {
     193                        uch.updateAutoDetach(0)
     194                }
     195        }
     196
     197        net.forEachDownstream(func(dc *downstreamConn) {
     198                net.offlineClients[dc.clientName] = struct{}{}
     199
     200                dc.SendMessage(&irc.Message{
     201                        Prefix:  dc.prefix(),
     202                        Command: "PART",
     203                        Params:  []string{dc.marshalEntity(net, ch.Name), "Detach"},
     204                })
     205        })
     206}
     207
     208func (net *network) attach(ch *Channel) {
     209        if !ch.Detached {
     210                return
     211        }
     212        ch.Detached = false
     213        net.user.srv.Logger.Printf("network %q: attaching channel %q", net.GetName(), ch.Name)
     214
     215        var uch *upstreamChannel
     216        if net.conn != nil {
     217                uch = net.conn.channels[ch.Name]
     218
     219                net.conn.updateChannelAutoDetach(ch.Name)
     220        }
     221
     222        net.forEachDownstream(func(dc *downstreamConn) {
     223                dc.SendMessage(&irc.Message{
     224                        Prefix:  dc.prefix(),
     225                        Command: "JOIN",
     226                        Params:  []string{dc.marshalEntity(net, ch.Name)},
     227                })
     228
     229                if uch != nil {
     230                        forwardChannel(dc, uch)
     231                }
     232
     233                if net.history[ch.Name] != nil {
     234                        dc.sendNetworkHistory(net)
     235                }
     236        })
    229237}
    230238
     
    234242                return fmt.Errorf("unknown channel %q", name)
    235243        }
     244        if net.conn != nil {
     245                if uch, ok := net.conn.channels[ch.Name]; ok {
     246                        uch.updateAutoDetach(0)
     247                }
     248        }
     249
    236250        if err := net.user.srv.db.DeleteChannel(ch.ID); err != nil {
    237251                return err
     
    399413                                uc.logger.Printf("failed to handle message %q: %v", msg, err)
    400414                        }
     415                case eventChannelDetach:
     416                        uc, name := e.uc, e.name
     417                        c, ok := uc.network.channels[name]
     418                        if !ok || c.Detached {
     419                                continue
     420                        }
     421                        uc.network.detach(c)
     422                        if err := uc.srv.db.StoreChannel(uc.network.ID, c); err != nil {
     423                                u.srv.Logger.Printf("failed to store updated detached channel %q: %v", c.Name, err)
     424                        }
    401425                case eventDownstreamConnected:
    402426                        dc := e.dc
     
    476500        uc.endPendingLISTs(true)
    477501
     502        for _, uch := range uc.channels {
     503                uch.updateAutoDetach(0)
     504        }
     505
    478506        uc.forEachDownstream(func(dc *downstreamConn) {
    479507                dc.updateSupportedCaps()
Note: See TracChangeset for help on using the changeset viewer.