ScuttleBot

feat: use IRCv3 account-tag, server-time, and msgid in bridge and relay (#119, #122) Bridge: add MsgID field to Message, populate from msgid tag. Relay: read account-tag for sender attribution, use server-time for accurate timestamps, populate MsgID from msgid tag. Both already had account-tag/server-time partially — this completes it.

lmata 2026-04-05 03:52 trunk
Commit 09875dcc70ba7d9d154a8241ce36536e8e5ffc019b4581a1e62fe7e445df978a
--- internal/bots/bridge/bridge.go
+++ internal/bots/bridge/bridge.go
@@ -34,10 +34,11 @@
3434
type Message struct {
3535
At time.Time `json:"at"`
3636
Channel string `json:"channel"`
3737
Nick string `json:"nick"`
3838
Text string `json:"text"`
39
+ MsgID string `json:"msgid,omitempty"`
3940
Meta *Meta `json:"meta,omitempty"`
4041
}
4142
4243
// ringBuf is a fixed-capacity circular buffer of Messages.
4344
type ringBuf struct {
@@ -219,15 +220,20 @@
219220
nick := e.Source.Name
220221
if acct, ok := e.Tags.Get("account"); ok && acct != "" {
221222
nick = acct
222223
}
223224
225
+ var msgID string
226
+ if id, ok := e.Tags.Get("msgid"); ok {
227
+ msgID = id
228
+ }
224229
b.dispatch(Message{
225230
At: e.Timestamp,
226231
Channel: channel,
227232
Nick: nick,
228233
Text: e.Last(),
234
+ MsgID: msgID,
229235
})
230236
})
231237
232238
b.client = c
233239
234240
--- internal/bots/bridge/bridge.go
+++ internal/bots/bridge/bridge.go
@@ -34,10 +34,11 @@
34 type Message struct {
35 At time.Time `json:"at"`
36 Channel string `json:"channel"`
37 Nick string `json:"nick"`
38 Text string `json:"text"`
 
39 Meta *Meta `json:"meta,omitempty"`
40 }
41
42 // ringBuf is a fixed-capacity circular buffer of Messages.
43 type ringBuf struct {
@@ -219,15 +220,20 @@
219 nick := e.Source.Name
220 if acct, ok := e.Tags.Get("account"); ok && acct != "" {
221 nick = acct
222 }
223
 
 
 
 
224 b.dispatch(Message{
225 At: e.Timestamp,
226 Channel: channel,
227 Nick: nick,
228 Text: e.Last(),
 
229 })
230 })
231
232 b.client = c
233
234
--- internal/bots/bridge/bridge.go
+++ internal/bots/bridge/bridge.go
@@ -34,10 +34,11 @@
34 type Message struct {
35 At time.Time `json:"at"`
36 Channel string `json:"channel"`
37 Nick string `json:"nick"`
38 Text string `json:"text"`
39 MsgID string `json:"msgid,omitempty"`
40 Meta *Meta `json:"meta,omitempty"`
41 }
42
43 // ringBuf is a fixed-capacity circular buffer of Messages.
44 type ringBuf struct {
@@ -219,15 +220,20 @@
220 nick := e.Source.Name
221 if acct, ok := e.Tags.Get("account"); ok && acct != "" {
222 nick = acct
223 }
224
225 var msgID string
226 if id, ok := e.Tags.Get("msgid"); ok {
227 msgID = id
228 }
229 b.dispatch(Message{
230 At: e.Timestamp,
231 Channel: channel,
232 Nick: nick,
233 Text: e.Last(),
234 MsgID: msgID,
235 })
236 })
237
238 b.client = c
239
240
--- pkg/sessionrelay/irc.go
+++ pkg/sessionrelay/irc.go
@@ -134,19 +134,33 @@
134134
}
135135
target := normalizeChannel(e.Params[0])
136136
if !c.hasChannel(target) {
137137
return
138138
}
139
+ // Prefer account-tag (IRCv3) over source nick.
139140
sender := e.Source.Name
141
+ if acct, ok := e.Tags.Get("account"); ok && acct != "" {
142
+ sender = acct
143
+ }
140144
text := strings.TrimSpace(e.Last())
145
+ // Fallback: parse legacy [nick] prefix from bridge bot.
141146
if sender == "bridge" && strings.HasPrefix(text, "[") {
142147
if end := strings.Index(text, "] "); end != -1 {
143148
sender = text[1:end]
144149
text = strings.TrimSpace(text[end+2:])
145150
}
146151
}
147
- c.appendMessage(Message{At: time.Now(), Channel: target, Nick: sender, Text: text})
152
+ // Use server-time when available; fall back to local clock.
153
+ at := e.Timestamp
154
+ if at.IsZero() {
155
+ at = time.Now()
156
+ }
157
+ var msgID string
158
+ if id, ok := e.Tags.Get("msgid"); ok {
159
+ msgID = id
160
+ }
161
+ c.appendMessage(Message{At: at, Channel: target, Nick: sender, Text: text, MsgID: msgID})
148162
})
149163
150164
c.mu.Lock()
151165
c.client = client
152166
c.mu.Unlock()
153167
--- pkg/sessionrelay/irc.go
+++ pkg/sessionrelay/irc.go
@@ -134,19 +134,33 @@
134 }
135 target := normalizeChannel(e.Params[0])
136 if !c.hasChannel(target) {
137 return
138 }
 
139 sender := e.Source.Name
 
 
 
140 text := strings.TrimSpace(e.Last())
 
141 if sender == "bridge" && strings.HasPrefix(text, "[") {
142 if end := strings.Index(text, "] "); end != -1 {
143 sender = text[1:end]
144 text = strings.TrimSpace(text[end+2:])
145 }
146 }
147 c.appendMessage(Message{At: time.Now(), Channel: target, Nick: sender, Text: text})
 
 
 
 
 
 
 
 
 
148 })
149
150 c.mu.Lock()
151 c.client = client
152 c.mu.Unlock()
153
--- pkg/sessionrelay/irc.go
+++ pkg/sessionrelay/irc.go
@@ -134,19 +134,33 @@
134 }
135 target := normalizeChannel(e.Params[0])
136 if !c.hasChannel(target) {
137 return
138 }
139 // Prefer account-tag (IRCv3) over source nick.
140 sender := e.Source.Name
141 if acct, ok := e.Tags.Get("account"); ok && acct != "" {
142 sender = acct
143 }
144 text := strings.TrimSpace(e.Last())
145 // Fallback: parse legacy [nick] prefix from bridge bot.
146 if sender == "bridge" && strings.HasPrefix(text, "[") {
147 if end := strings.Index(text, "] "); end != -1 {
148 sender = text[1:end]
149 text = strings.TrimSpace(text[end+2:])
150 }
151 }
152 // Use server-time when available; fall back to local clock.
153 at := e.Timestamp
154 if at.IsZero() {
155 at = time.Now()
156 }
157 var msgID string
158 if id, ok := e.Tags.Get("msgid"); ok {
159 msgID = id
160 }
161 c.appendMessage(Message{At: at, Channel: target, Nick: sender, Text: text, MsgID: msgID})
162 })
163
164 c.mu.Lock()
165 c.client = client
166 c.mu.Unlock()
167
--- pkg/sessionrelay/sessionrelay.go
+++ pkg/sessionrelay/sessionrelay.go
@@ -42,10 +42,11 @@
4242
type Message struct {
4343
At time.Time
4444
Channel string
4545
Nick string
4646
Text string
47
+ MsgID string
4748
}
4849
4950
type Connector interface {
5051
Connect(ctx context.Context) error
5152
Post(ctx context.Context, text string) error
5253
--- pkg/sessionrelay/sessionrelay.go
+++ pkg/sessionrelay/sessionrelay.go
@@ -42,10 +42,11 @@
42 type Message struct {
43 At time.Time
44 Channel string
45 Nick string
46 Text string
 
47 }
48
49 type Connector interface {
50 Connect(ctx context.Context) error
51 Post(ctx context.Context, text string) error
52
--- pkg/sessionrelay/sessionrelay.go
+++ pkg/sessionrelay/sessionrelay.go
@@ -42,10 +42,11 @@
42 type Message struct {
43 At time.Time
44 Channel string
45 Nick string
46 Text string
47 MsgID string
48 }
49
50 type Connector interface {
51 Connect(ctx context.Context) error
52 Post(ctx context.Context, text string) error
53

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button