commit 0ba374b
delthas
·
2022-08-10 11:06:54 +0000 UTC
parent 9fe1d36
Add support for soju.im/bouncer-networks-notify This enables dynamic discovery of new and deleted networks. Fixes: https://todo.sr.ht/~taiite/senpai/71
5 files changed,
+89,
-19
M
app.go
+51,
-7
1@@ -8,6 +8,7 @@ import (
2 "os"
3 "os/exec"
4 "strings"
5+ "sync"
6 "time"
7 "unicode"
8
9@@ -84,7 +85,7 @@ type boundKey struct {
10
11 type App struct {
12 win *ui.UI
13- sessions map[string]*irc.Session
14+ sessions map[string]*irc.Session // map of network IDs to their current session
15 pasting bool
16 events chan event
17
18@@ -99,12 +100,18 @@ type App struct {
19
20 monitor map[string]map[string]struct{} // set of targets we want to monitor per netID, best-effort. netID->target->{}
21
22+ networkLock sync.RWMutex // locks networks
23+ networks map[string]struct{} // set of network IDs we want to connect to; to be locked with networkLock
24+
25 lastMessageTime time.Time
26 lastCloseTime time.Time
27 }
28
29 func NewApp(cfg Config) (app *App, err error) {
30 app = &App{
31+ networks: map[string]struct{}{
32+ "": {}, // add the master network by default
33+ },
34 sessions: map[string]*irc.Session{},
35 events: make(chan event, eventChanSize),
36 cfg: cfg,
37@@ -262,6 +269,16 @@ func (app *App) handleEvent(ev event) bool {
38 return true
39 }
40
41+func (app *App) wantsNetwork(netID string) bool {
42+ if app.win.ShouldExit() {
43+ return false
44+ }
45+ app.networkLock.RLock()
46+ _, ok := app.networks[netID]
47+ app.networkLock.RUnlock()
48+ return ok
49+}
50+
51 // ircLoop maintains a connection to the IRC server by connecting and then
52 // forwarding IRC events to app.events repeatedly.
53 func (app *App) ircLoop(netID string) {
54@@ -279,8 +296,11 @@ func (app *App) ircLoop(netID string) {
55 NetID: netID,
56 Auth: auth,
57 }
58- for !app.win.ShouldExit() {
59+ for app.wantsNetwork(netID) {
60 conn := app.connect(netID)
61+ if conn == nil {
62+ break
63+ }
64 in, out := irc.ChanInOut(conn)
65 if app.cfg.Debug {
66 out = app.debugOutputMessages(netID, out)
67@@ -320,7 +340,7 @@ func (app *App) ircLoop(netID string) {
68 HeadColor: tcell.ColorRed,
69 Body: ui.PlainString("Connection lost"),
70 })
71- if app.win.ShouldExit() {
72+ if !app.wantsNetwork(netID) {
73 break
74 }
75 time.Sleep(10 * time.Second)
76@@ -328,7 +348,7 @@ func (app *App) ircLoop(netID string) {
77 }
78
79 func (app *App) connect(netID string) net.Conn {
80- for {
81+ for app.wantsNetwork(netID) {
82 app.queueStatusLine(netID, ui.Line{
83 Head: "--",
84 Body: ui.PlainSprintf("Connecting to %s...", app.cfg.Addr),
85@@ -344,6 +364,7 @@ func (app *App) connect(netID string) net.Conn {
86 })
87 time.Sleep(1 * time.Minute)
88 }
89+ return nil
90 }
91
92 func (app *App) tryConnect() (conn net.Conn, err error) {
93@@ -663,6 +684,12 @@ func (app *App) handleIRCEvent(netID string, ev interface{}) {
94 if s, ok := app.sessions[netID]; ok {
95 s.Close()
96 }
97+ if !app.wantsNetwork(netID) {
98+ delete(app.sessions, netID)
99+ delete(app.monitor, netID)
100+ s.Close()
101+ return
102+ }
103 app.sessions[netID] = s
104 if _, ok := app.monitor[netID]; !ok {
105 app.monitor[netID] = make(map[string]struct{})
106@@ -921,9 +948,26 @@ func (app *App) handleIRCEvent(netID string, ev interface{}) {
107 case irc.ReadEvent:
108 app.win.SetRead(netID, ev.Target, ev.Timestamp)
109 case irc.BouncerNetworkEvent:
110- _, added := app.win.AddBuffer(ev.ID, ev.Name, "")
111- if added {
112- go app.ircLoop(ev.ID)
113+ if !ev.Delete {
114+ _, added := app.win.AddBuffer(ev.ID, ev.Name, "")
115+ if added {
116+ app.networkLock.Lock()
117+ app.networks[ev.ID] = struct{}{}
118+ app.networkLock.Unlock()
119+ go app.ircLoop(ev.ID)
120+ }
121+ } else {
122+ app.networkLock.Lock()
123+ delete(app.networks, ev.ID)
124+ app.networkLock.Unlock()
125+ // if a session was already opened, close it now.
126+ // otherwise, we'll close it when it sends a new session event.
127+ if s, ok := app.sessions[ev.ID]; ok {
128+ s.Close()
129+ delete(app.sessions, ev.ID)
130+ delete(app.monitor, ev.ID)
131+ }
132+ app.win.RemoveNetworkBuffers(ev.ID)
133 }
134 case irc.ErrorEvent:
135 if isBlackListed(msg.Command) {
+3,
-2
1@@ -104,6 +104,7 @@ type SearchEvent struct {
2 }
3
4 type BouncerNetworkEvent struct {
5- ID string
6- Name string
7+ ID string
8+ Name string
9+ Delete bool
10 }
+16,
-10
1@@ -62,11 +62,12 @@ var SupportedCapabilities = map[string]struct{}{
2 "sasl": {},
3 "setname": {},
4
5- "draft/chathistory": {},
6- "draft/event-playback": {},
7- "draft/read-marker": {},
8- "soju.im/bouncer-networks": {},
9- "soju.im/search": {},
10+ "draft/chathistory": {},
11+ "draft/event-playback": {},
12+ "draft/read-marker": {},
13+ "soju.im/bouncer-networks-notify": {},
14+ "soju.im/bouncer-networks": {},
15+ "soju.im/search": {},
16 }
17
18 // Values taken by the "@+typing=" client tag. TypingUnspec means the value or
19@@ -1336,11 +1337,16 @@ func (s *Session) handleMessageRegistered(msg Message, playback bool) (Event, er
20 break
21 }
22 id := msg.Params[1]
23- attrs := parseTags(msg.Params[2])
24- return BouncerNetworkEvent{
25- ID: id,
26- Name: attrs["name"],
27- }, nil
28+ event := BouncerNetworkEvent{
29+ ID: id,
30+ }
31+ if msg.Params[2] != "*" {
32+ attrs := parseTags(msg.Params[2])
33+ event.Name = attrs["name"]
34+ } else {
35+ event.Delete = true
36+ }
37+ return event, nil
38 case "PING":
39 var payload string
40 if err := msg.ParseParams(&payload); err != nil {
+14,
-0
1@@ -342,6 +342,20 @@ func (bs *BufferList) Remove(netID, title string) bool {
2 return true
3 }
4
5+func (bs *BufferList) RemoveNetwork(netID string) {
6+ for idx := 0; idx < len(bs.list); idx++ {
7+ b := &bs.list[idx]
8+ if b.netID != netID {
9+ continue
10+ }
11+ bs.list = append(bs.list[:idx], bs.list[idx+1:]...)
12+ if len(bs.list) <= bs.current {
13+ bs.current--
14+ }
15+ idx--
16+ }
17+}
18+
19 func (bs *BufferList) mergeLine(former *Line, addition Line) (keepLine bool) {
20 bs.doMergeLine(former, addition)
21 if former.Body.string == "" {
M
ui/ui.go
+5,
-0
1@@ -260,6 +260,11 @@ func (ui *UI) RemoveBuffer(netID, title string) {
2 ui.memberOffset = 0
3 }
4
5+func (ui *UI) RemoveNetworkBuffers(netID string) {
6+ ui.bs.RemoveNetwork(netID)
7+ ui.memberOffset = 0
8+}
9+
10 func (ui *UI) AddLine(netID, buffer string, notify NotifyType, line Line) {
11 ui.bs.AddLine(netID, buffer, notify, line)
12 }