Changeset 284 in code for trunk


Ignore:
Timestamp:
May 1, 2020, 1:18:14 PM (5 years ago)
Author:
contact
Message:

Add support for detached channels

Channels can now be detached by leaving them with the reason "detach",
and re-attached by joining them again. Upon detaching the channel is
no longer forwarded to downstream connections. Upon re-attaching the
history buffer is sent.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/db.go

    r267 r284  
    4444
    4545type Channel struct {
    46         ID   int64
    47         Name string
    48         Key  string
     46        ID       int64
     47        Name     string
     48        Key      string
     49        Detached bool
    4950}
    5051
     
    7778        name VARCHAR(255) NOT NULL,
    7879        key VARCHAR(255),
     80        detached INTEGER NOT NULL DEFAULT 0,
    7981        FOREIGN KEY(network) REFERENCES Network(id),
    8082        UNIQUE(network, name)
     
    8587        "", // migration #0 is reserved for schema initialization
    8688        "ALTER TABLE Network ADD COLUMN connect_commands VARCHAR(1023)",
     89        "ALTER TABLE Channel ADD COLUMN detached INTEGER NOT NULL DEFAULT 0",
    8790}
    8891
     
    347350        defer db.lock.RUnlock()
    348351
    349         rows, err := db.db.Query("SELECT id, name, key FROM Channel WHERE network = ?", networkID)
     352        rows, err := db.db.Query(`SELECT id, name, key, detached
     353                FROM Channel
     354                WHERE network = ?`, networkID)
    350355        if err != nil {
    351356                return nil, err
     
    357362                var ch Channel
    358363                var key *string
    359                 if err := rows.Scan(&ch.ID, &ch.Name, &key); err != nil {
     364                if err := rows.Scan(&ch.ID, &ch.Name, &key, &ch.Detached); err != nil {
    360365                        return nil, err
    361366                }
     
    379384        if ch.ID != 0 {
    380385                _, err = db.db.Exec(`UPDATE Channel
    381                         SET network = ?, name = ?, key = ?
    382                         WHERE id = ?`, networkID, ch.Name, key, ch.ID)
     386                        SET network = ?, name = ?, key = ?, detached = ?
     387                        WHERE id = ?`,
     388                        networkID, ch.Name, key, ch.Detached, ch.ID)
    383389        } else {
    384390                var res sql.Result
    385                 res, err = db.db.Exec(`INSERT INTO Channel(network, name, key)
    386                         VALUES (?, ?, ?)`, networkID, ch.Name, key)
     391                res, err = db.db.Exec(`INSERT INTO Channel(network, name, key, detached)
     392                        VALUES (?, ?, ?, ?)`,
     393                        networkID, ch.Name, key, ch.Detached)
    387394                if err != nil {
    388395                        return err
  • trunk/doc/soju.1.scd

    r270 r284  
    2424the next connection. When registering or authenticating with NickServ, the
    2525credentials will be saved and automatically used on the next connection if the
    26 server supports SASL.
     26server supports SASL. When parting a channel with the reason "detach", the
     27channel will be detached instead of being left.
    2728
    2829When all clients are disconnected from the bouncer, the user is automatically
  • trunk/downstream.go

    r279 r284  
    768768        dc.forEachUpstream(func(uc *upstreamConn) {
    769769                for _, ch := range uc.channels {
    770                         if ch.complete {
    771                                 dc.SendMessage(&irc.Message{
    772                                         Prefix:  dc.prefix(),
    773                                         Command: "JOIN",
    774                                         Params:  []string{dc.marshalEntity(ch.conn.network, ch.Name)},
    775                                 })
    776 
    777                                 forwardChannel(dc, ch)
    778                         }
     770                        if !ch.complete {
     771                                continue
     772                        }
     773                        if record, ok := uc.network.channels[ch.Name]; ok && record.Detached {
     774                                continue
     775                        }
     776
     777                        dc.SendMessage(&irc.Message{
     778                                Prefix:  dc.prefix(),
     779                                Command: "JOIN",
     780                                Params:  []string{dc.marshalEntity(ch.conn.network, ch.Name)},
     781                        })
     782
     783                        forwardChannel(dc, ch)
    779784                }
    780785        })
     
    794799func (dc *downstreamConn) sendNetworkHistory(net *network) {
    795800        for target, history := range net.history {
     801                if ch, ok := net.channels[target]; ok && ch.Detached {
     802                        continue
     803                }
     804
    796805                seq, ok := history.offlineClients[dc.clientName]
    797806                if !ok {
     
    946955                        })
    947956
    948                         ch := &Channel{Name: upstreamName, Key: key}
     957                        ch := &Channel{Name: upstreamName, Key: key, Detached: false}
    949958                        if err := uc.network.createUpdateChannel(ch); err != nil {
    950959                                dc.logger.Printf("failed to create or update channel %q: %v", upstreamName, err)
     
    968977                        }
    969978
    970                         params := []string{upstreamName}
    971                         if reason != "" {
    972                                 params = append(params, reason)
    973                         }
    974                         uc.SendMessage(&irc.Message{
    975                                 Command: "PART",
    976                                 Params:  params,
    977                         })
    978 
    979                         if err := uc.network.deleteChannel(upstreamName); err != nil {
    980                                 dc.logger.Printf("failed to delete channel %q: %v", upstreamName, err)
     979                        if strings.EqualFold(reason, "detach") {
     980                                ch := &Channel{Name: upstreamName, Detached: true}
     981                                if err := uc.network.createUpdateChannel(ch); err != nil {
     982                                        dc.logger.Printf("failed to detach channel %q: %v", upstreamName, err)
     983                                }
     984                        } else {
     985                                params := []string{upstreamName}
     986                                if reason != "" {
     987                                        params = append(params, reason)
     988                                }
     989                                uc.SendMessage(&irc.Message{
     990                                        Command: "PART",
     991                                        Params:  params,
     992                                })
     993
     994                                if err := uc.network.deleteChannel(upstreamName); err != nil {
     995                                        dc.logger.Printf("failed to delete channel %q: %v", upstreamName, err)
     996                                }
    981997                        }
    982998                }
  • trunk/upstream.go

    r282 r284  
    14061406// appendHistory appends a message to the history. entity can be empty.
    14071407func (uc *upstreamConn) appendHistory(entity string, msg *irc.Message) {
     1408        detached := false
     1409        if ch, ok := uc.network.channels[entity]; ok {
     1410                detached = ch.Detached
     1411        }
     1412
    14081413        // If no client is offline, no need to append the message to the buffer
    1409         if len(uc.network.offlineClients) == 0 {
     1414        if len(uc.network.offlineClients) == 0 && !detached {
    14101415                return
    14111416        }
     
    14211426                for clientName, _ := range uc.network.offlineClients {
    14221427                        history.offlineClients[clientName] = 0
     1428                }
     1429
     1430                if detached {
     1431                        // If the channel is detached, online clients act as offline
     1432                        // clients too
     1433                        uc.forEachDownstream(func(dc *downstreamConn) {
     1434                                history.offlineClients[dc.clientName] = 0
     1435                        })
    14231436                }
    14241437        }
     
    14391452        uc.appendHistory(target, msg)
    14401453
     1454        // Don't forward messages if it's a detached channel
     1455        if ch, ok := uc.network.channels[target]; ok && ch.Detached {
     1456                return
     1457        }
     1458
    14411459        uc.forEachDownstream(func(dc *downstreamConn) {
    14421460                if dc != origin || dc.caps["echo-message"] {
  • trunk/user.go

    r283 r284  
    151151                return err
    152152        }
     153        prev := net.channels[ch.Name]
    153154        net.channels[ch.Name] = ch
     155
     156        if prev != nil && prev.Detached != ch.Detached {
     157                history := net.history[ch.Name]
     158                if ch.Detached {
     159                        net.user.srv.Logger.Printf("network %q: detaching channel %q", net.GetName(), ch.Name)
     160                        net.forEachDownstream(func(dc *downstreamConn) {
     161                                net.offlineClients[dc.clientName] = struct{}{}
     162                                if history != nil {
     163                                        history.offlineClients[dc.clientName] = history.ring.Cur()
     164                                }
     165
     166                                dc.SendMessage(&irc.Message{
     167                                        Prefix:  dc.prefix(),
     168                                        Command: "PART",
     169                                        Params:  []string{dc.marshalEntity(net, ch.Name), "Detach"},
     170                                })
     171                        })
     172                } else {
     173                        net.user.srv.Logger.Printf("network %q: attaching channel %q", net.GetName(), ch.Name)
     174
     175                        var uch *upstreamChannel
     176                        if net.conn != nil {
     177                                uch = net.conn.channels[ch.Name]
     178                        }
     179
     180                        net.forEachDownstream(func(dc *downstreamConn) {
     181                                dc.SendMessage(&irc.Message{
     182                                        Prefix:  dc.prefix(),
     183                                        Command: "JOIN",
     184                                        Params:  []string{dc.marshalEntity(net, ch.Name)},
     185                                })
     186
     187                                if uch != nil {
     188                                        forwardChannel(dc, uch)
     189                                }
     190
     191                                if history != nil {
     192                                        dc.sendNetworkHistory(net)
     193                                }
     194                        })
     195                }
     196        }
     197
    154198        return nil
    155199}
     
    343387
    344388                                net.offlineClients[dc.clientName] = struct{}{}
    345                                 for _, history := range net.history {
     389                                for target, history := range net.history {
     390                                        if ch, ok := net.channels[target]; ok && ch.Detached {
     391                                                continue
     392                                        }
    346393                                        history.offlineClients[dc.clientName] = history.ring.Cur()
    347394                                }
Note: See TracChangeset for help on using the changeset viewer.