Skip to content

Commit 78c28b0

Browse files
committed
message: make username part of the sender
This allows us to eliminate a user's display name from contexts where we don't want to provide it, particularly learning.
1 parent 0cf77ac commit 78c28b0

File tree

11 files changed

+37
-34
lines changed

11 files changed

+37
-34
lines changed

brain/learn_test.go

-2
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ func TestRecall(t *testing.T) {
109109
ID: "1",
110110
To: "#bocchi",
111111
Sender: userhash.Hash{1},
112-
Name: "bocchi",
113112
Text: "bocchi the rock!",
114113
Timestamp: 1,
115114
},
@@ -122,7 +121,6 @@ func TestRecall(t *testing.T) {
122121
ID: "1",
123122
To: "#bocchi",
124123
Sender: userhash.Hash{1},
125-
Name: "bocchi",
126124
Text: "bocchi the rock!",
127125
Timestamp: 1,
128126
},

channel/channel.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ type Channel struct {
3737
// History is a list of recent messages seen in the channel.
3838
// Note that messages which are forgotten due to moderation are not removed
3939
// from this list in general.
40-
History History[*message.Received[string]]
40+
History History[*message.Received[message.User]]
4141
// Memery is the meme detector for the channel.
4242
Memery *MemeDetector
4343
// Emotes is the distribution of emotes.

command/command.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ type Invocation struct {
3333
// Message is the message which triggered the invocation with the platform
3434
// user ID as the type argument.
3535
// It is always non-nil, but not all fields are guaranteed to be populated.
36-
Message *message.Received[string]
36+
Message *message.Received[message.User]
3737
// Args is the parsed arguments to the command.
3838
Args map[string]string
3939
}

command/marriage.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ import (
1515
"github.com/zephyrtronium/robot/message"
1616
)
1717

18-
func score(log *slog.Logger, h *channel.History[*message.Received[string]], user string) (x float64, c, f, l, n int) {
18+
func score(log *slog.Logger, h *channel.History[*message.Received[message.User]], user string) (x float64, c, f, l, n int) {
1919
mine := make(map[string]map[string]struct{})
2020
for m := range h.All() {
21-
who, text := m.Sender, m.Text
21+
who, text := m.Sender.ID, m.Text
2222
n++
2323
// Count the number of distinct other users who said each of your messages
2424
// after you said it.
@@ -77,12 +77,12 @@ var affections = pick.New([]pick.Case[string]{
7777
// Affection describes the caller's affection MMR.
7878
// No arguments.
7979
func Affection(ctx context.Context, robo *Robot, call *Invocation) {
80-
x, c, f, l, n := score(robo.Log, &call.Channel.History, call.Message.Sender)
80+
x, c, f, l, n := score(robo.Log, &call.Channel.History, call.Message.Sender.ID)
8181
// Anything we do will require an emote.
8282
e := call.Channel.Emotes.Pick(rand.Uint32())
8383
if x == 0 {
8484
// Check for the broadcaster. They get special treatment.
85-
if strings.EqualFold(call.Message.Name, strings.TrimPrefix(call.Channel.Name, "#")) {
85+
if strings.EqualFold(call.Message.Sender.Name, strings.TrimPrefix(call.Channel.Name, "#")) {
8686
if _, ok := call.Channel.Extra.LoadOrStore(broadcasterAffectionKey{}, struct{}{}); ok {
8787
call.Channel.Message(ctx, message.Format("", "Don't make me repeat myself, it's embarrassing! %s", e).AsReply(call.Message.ID))
8888
return
@@ -111,14 +111,14 @@ type partner struct {
111111
// Marry proposes to the robo.
112112
// - partnership: Type of partnership requested, e.g. "wife", "waifu", "daddy". Optional.
113113
func Marry(ctx context.Context, robo *Robot, call *Invocation) {
114-
x, _, _, _, _ := score(robo.Log, &call.Channel.History, call.Message.Sender)
114+
x, _, _, _, _ := score(robo.Log, &call.Channel.History, call.Message.Sender.ID)
115115
e := call.Channel.Emotes.Pick(rand.Uint32())
116-
broadcaster := strings.EqualFold(call.Message.Name, strings.TrimPrefix(call.Channel.Name, "#")) && x == 0
116+
broadcaster := strings.EqualFold(call.Message.Sender.Name, strings.TrimPrefix(call.Channel.Name, "#")) && x == 0
117117
if x < 10 && !broadcaster {
118118
call.Channel.Message(ctx, message.Format("", "no %s", e).AsReply(call.Message.ID))
119119
return
120120
}
121-
me := &partner{who: call.Message.Sender, until: call.Message.Time().Add(time.Hour)}
121+
me := &partner{who: call.Message.Sender.ID, until: call.Message.Time().Add(time.Hour)}
122122
for {
123123
l, ok := call.Channel.Extra.LoadOrStore(partnerKey{}, me)
124124
if !ok {

command/privacy.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
)
1010

1111
func Private(ctx context.Context, robo *Robot, call *Invocation) {
12-
err := robo.Privacy.Add(ctx, call.Message.Sender)
12+
err := robo.Privacy.Add(ctx, call.Message.Sender.ID)
1313
if err != nil {
1414
robo.Log.ErrorContext(ctx, "privacy add failed", slog.Any("err", err), slog.String("channel", call.Channel.Name))
1515
call.Channel.Message(ctx, message.Format("", "Something went wrong while trying to add you to the privacy list. Try again. Sorry!").AsReply(call.Message.ID))
@@ -20,7 +20,7 @@ func Private(ctx context.Context, robo *Robot, call *Invocation) {
2020
}
2121

2222
func Unprivate(ctx context.Context, robo *Robot, call *Invocation) {
23-
err := robo.Privacy.Remove(ctx, call.Message.Sender)
23+
err := robo.Privacy.Remove(ctx, call.Message.Sender.ID)
2424
if err != nil {
2525
robo.Log.ErrorContext(ctx, "privacy remove failed", slog.Any("err", err), slog.String("channel", call.Channel.Name))
2626
call.Channel.Message(ctx, message.Format("", "Something went wrong while trying to add you to the privacy list. Try again. Sorry!").AsReply(call.Message.ID))

command/talk.go

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ func speakCmd(ctx context.Context, robo *Robot, call *Invocation, effect string)
1818
if ngPrompt.MatchString(call.Args["prompt"]) {
1919
robo.Log.WarnContext(ctx, "nasty prompt",
2020
slog.String("in", call.Channel.Name),
21-
slog.String("from", call.Message.Name),
2221
slog.String("prompt", call.Args["prompt"]),
2322
)
2423
e := call.Channel.Emotes.Pick(rand.Uint32())

message/irc.go

+3-4
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,15 @@ import (
77
)
88

99
// FromTMI adapts a TMI IRC message.
10-
func FromTMI(m *tmi.Message) *Received[string] {
10+
func FromTMI(m *tmi.Message) *Received[User] {
1111
id, _ := m.Tag("id")
1212
sender, _ := m.Tag("user-id")
1313
ts, _ := m.Tag("tmi-sent-ts")
1414
u, _ := strconv.ParseInt(ts, 10, 64)
15-
r := Received[string]{
15+
r := Received[User]{
1616
ID: id,
1717
To: m.To(),
18-
Sender: sender,
19-
Name: m.DisplayName(),
18+
Sender: User{ID: sender, Name: m.DisplayName()},
2019
Text: m.Trailing,
2120
Timestamp: u,
2221
IsModerator: moderator(m),

message/irc_test.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import (
66
"testing"
77
"time"
88

9-
"github.com/zephyrtronium/robot/message"
109
"gitlab.com/zephyrtronium/tmi"
10+
11+
"github.com/zephyrtronium/robot/message"
1112
)
1213

1314
func TestFromIRC(t *testing.T) {
@@ -74,10 +75,10 @@ func TestFromIRC(t *testing.T) {
7475
if got := msg.To; got != c.to {
7576
t.Errorf("wrong to: want %q, got %q", c.to, got)
7677
}
77-
if got := msg.Sender; got != c.sender {
78+
if got := msg.Sender.ID; got != c.sender {
7879
t.Errorf("wrong sender: want %q, got %q", c.sender, got)
7980
}
80-
if got := msg.Name; got != c.disp {
81+
if got := msg.Sender.Name; got != c.disp {
8182
t.Errorf("wrong display name: want %q, got %q", c.disp, got)
8283
}
8384
if got := msg.Text; got != c.text {

message/message.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ type Received[U comparable] struct {
1717
// Whether it remains constant for a given sender depends on the semantics
1818
// of the type argument.
1919
Sender U
20-
// Name is the display name of the message sender.
21-
Name string
2220
// Text is the text of the message.
2321
Text string
2422
// Timestamp is the timestamp of the message as milliseconds since the
@@ -37,6 +35,15 @@ func (m *Received[U]) Time() time.Time {
3735
return time.UnixMilli(m.Timestamp)
3836
}
3937

38+
// User is a user's ID and display name.
39+
type User struct {
40+
// ID is a user's ID.
41+
// It must remain constant for a given user even across name changes.
42+
ID string
43+
// Name is a user's display name.
44+
Name string
45+
}
46+
4047
// Sent is a message to be sent to a service.
4148
type Sent struct {
4249
// Reply is a message to reply to. If empty, the message is not interpreted

privmsg.go

+9-10
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func (robo *Robot) tmiMessage(ctx context.Context, send chan<- *tmi.Message, msg
3333
log := slog.With(slog.String("trace", m.ID), slog.String("in", ch.Name))
3434
log.InfoContext(ctx, "privmsg", slog.Duration("bias", time.Since(m.Time())))
3535
defer log.InfoContext(ctx, "end")
36-
if ch.Ignore[m.Sender] {
36+
if ch.Ignore[m.Sender.ID] {
3737
log.InfoContext(ctx, "message from ignored user")
3838
return
3939
}
@@ -42,7 +42,7 @@ func (robo *Robot) tmiMessage(ctx context.Context, send chan<- *tmi.Message, msg
4242
return
4343
}
4444
if cmd, ok := parseCommand(robo.tmi.name, m.Text); ok {
45-
robo.command(ctx, log, ch, m, m.Sender, cmd)
45+
robo.command(ctx, log, ch, m, cmd)
4646
return
4747
}
4848
ch.History.Add(m.Time(), m)
@@ -56,7 +56,7 @@ func (robo *Robot) tmiMessage(ctx context.Context, send chan<- *tmi.Message, msg
5656
m.Text = t
5757
}
5858
robo.learn(ctx, log, ch, robo.hashes(), m)
59-
switch err := ch.Memery.Check(m.Time(), m.Sender, m.Text); err {
59+
switch err := ch.Memery.Check(m.Time(), m.Sender.ID, m.Text); err {
6060
case channel.ErrNotCopypasta: // do nothing
6161
case nil:
6262
// Meme detected. Copypasta.
@@ -142,20 +142,20 @@ func (robo *Robot) tmiMessage(ctx context.Context, send chan<- *tmi.Message, msg
142142
robo.sendTMI(ctx, send, out)
143143
}
144144

145-
func (robo *Robot) command(ctx context.Context, log *slog.Logger, ch *channel.Channel, m *message.Received[string], from, cmd string) {
145+
func (robo *Robot) command(ctx context.Context, log *slog.Logger, ch *channel.Channel, m *message.Received[message.User], cmd string) {
146146
robo.Metrics.TMICommandCount.Observe(1)
147147
var c *twitchCommand
148148
var args map[string]string
149149
level := "any"
150150
switch {
151-
case from == robo.tmi.owner:
151+
case m.Sender.ID == robo.tmi.owner:
152152
c, args = findTwitch(twitchOwner, cmd)
153153
if c != nil {
154154
level = "owner"
155155
break
156156
}
157157
fallthrough
158-
case ch.Mod[from], m.IsModerator:
158+
case ch.Mod[m.Sender.ID], m.IsModerator:
159159
c, args = findTwitch(twitchMod, cmd)
160160
if c != nil {
161161
level = "mod"
@@ -192,12 +192,12 @@ func (robo *Robot) command(ctx context.Context, log *slog.Logger, ch *channel.Ch
192192
}
193193

194194
// learn learns a given message's text if it passes ch's filters.
195-
func (robo *Robot) learn(ctx context.Context, log *slog.Logger, ch *channel.Channel, hasher userhash.Hasher, msg *message.Received[string]) {
195+
func (robo *Robot) learn(ctx context.Context, log *slog.Logger, ch *channel.Channel, hasher userhash.Hasher, msg *message.Received[message.User]) {
196196
if !ch.Enabled.Load() {
197197
log.DebugContext(ctx, "not learning in disabled channel")
198198
return
199199
}
200-
switch err := robo.privacy.Check(ctx, msg.Sender); err {
200+
switch err := robo.privacy.Check(ctx, msg.Sender.ID); err {
201201
case nil: // do nothing
202202
case privacy.ErrPrivate:
203203
log.DebugContext(ctx, "private sender")
@@ -214,12 +214,11 @@ func (robo *Robot) learn(ctx context.Context, log *slog.Logger, ch *channel.Chan
214214
log.DebugContext(ctx, "no learn tag")
215215
return
216216
}
217-
user := hasher.Hash(msg.Sender, msg.To, msg.Time())
217+
user := hasher.Hash(msg.Sender.ID, msg.To, msg.Time())
218218
m := brain.Message{
219219
ID: msg.ID,
220220
To: msg.To,
221221
Sender: user,
222-
Name: msg.Name,
223222
Text: msg.Text,
224223
Timestamp: msg.Timestamp,
225224
IsModerator: msg.IsModerator,

tmi.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ func (robo *Robot) clearchat(ctx context.Context, msg *tmi.Message) {
138138
default:
139139
// Delete from user.
140140
for m := range ch.History.All() {
141-
if m.Sender != t {
141+
if m.Sender.ID != t {
142142
continue
143143
}
144144
slog.DebugContext(ctx, "forget from user", slog.String("channel", msg.To()), slog.String("id", m.ID))

0 commit comments

Comments
 (0)