Skip to content

Commit

Permalink
channel: add message send closure
Browse files Browse the repository at this point in the history
Fixes #36.
  • Loading branch information
zephyrtronium committed Feb 15, 2024
1 parent 2cf336f commit ec7f63f
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 13 deletions.
6 changes: 4 additions & 2 deletions channel/channel.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package channel

import (
"context"
"regexp"

"golang.org/x/time/rate"

"gitlab.com/zephyrtronium/pick"
"golang.org/x/time/rate"
)

type Channel struct {
// Name is the name of the channel.
Name string
// Message sends a message to the channel with an optional reply message ID.
Message func(ctx context.Context, reply, text string)
// Learn and Send are the channel tags.
Learn, Send string
// Block is a regex that matches messages which should not be used for
Expand Down
20 changes: 15 additions & 5 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/BurntSushi/toml"
"gitlab.com/zephyrtronium/pick"
"gitlab.com/zephyrtronium/sq"
"gitlab.com/zephyrtronium/tmi"
"golang.org/x/crypto/hkdf"
"golang.org/x/crypto/sha3"
"golang.org/x/oauth2"
Expand All @@ -22,6 +23,7 @@ import (
"github.com/zephyrtronium/robot/auth"
"github.com/zephyrtronium/robot/brain/sqlbrain"
"github.com/zephyrtronium/robot/channel"
"github.com/zephyrtronium/robot/message"
"github.com/zephyrtronium/robot/privacy"
)

Expand Down Expand Up @@ -76,7 +78,9 @@ func (robo *Robot) SetSources(ctx context.Context, brain, priv *sq.DB) error {
// It must be called after SetSecrets.
func (robo *Robot) SetTMI(ctx context.Context, cfg ClientCfg) error {
cfg.endpoint = twitch.Endpoint
tmi, err := loadClient(ctx, cfg, *robo.secrets.twitch, "chat:read", "chat:edit")
send := make(chan *tmi.Message, 1)
recv := make(chan *tmi.Message, 8) // 8 is enough for on-connect msgs
tmi, err := loadClient(ctx, cfg, send, recv, *robo.secrets.twitch, "chat:read", "chat:edit")
if err != nil {
return fmt.Errorf("couldn't load TMI client: %w", err)
}
Expand Down Expand Up @@ -113,7 +117,7 @@ func (robo *Robot) SetTwitchChannels(ctx context.Context, global Global, channel
}
}
for _, p := range ch.Channels {
v := channel.Channel{
v := &channel.Channel{
Name: p,
Learn: ch.Learn,
Send: ch.Send,
Expand All @@ -125,7 +129,11 @@ func (robo *Robot) SetTwitchChannels(ctx context.Context, global Global, channel
Memery: channel.NewMemeDetector(ch.Copypasta.Need, fseconds(ch.Copypasta.Within)),
Emotes: emotes,
}
robo.channels[p] = &v
v.Message = func(ctx context.Context, reply, text string) {
msg := message.Format(reply, v.Name, "%s", text)
robo.sendTMI(ctx, robo.tmi.send, msg)
}
robo.channels[p] = v
}
}
return nil
Expand Down Expand Up @@ -171,7 +179,7 @@ func fseconds(s float64) time.Duration {
}

// loadClient loads client configuration from unmarshaled TOML.
func loadClient(ctx context.Context, t ClientCfg, key [auth.KeySize]byte, scopes ...string) (*client, error) {
func loadClient[Send, Receive any](ctx context.Context, t ClientCfg, send chan Send, recv chan Receive, key [auth.KeySize]byte, scopes ...string) (*client[Send, Receive], error) {
secret, err := os.ReadFile(t.SecretFile)
if err != nil {
return nil, fmt.Errorf("couldn't read client secret: %w", err)
Expand All @@ -197,7 +205,9 @@ func loadClient(ctx context.Context, t ClientCfg, key [auth.KeySize]byte, scopes
if err != nil {
return nil, fmt.Errorf("couldn't create token: %w", err)
}
return &client{
return &client[Send, Receive]{
send: send,
recv: recv,
me: t.User,
owner: t.Owner,
rate: rate.NewLimiter(rate.Every(fseconds(t.Rate.Every)), t.Rate.Num),
Expand Down
15 changes: 9 additions & 6 deletions robot.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,16 @@ type Robot struct {
ownerContact string
// tmi contains the bot's Twitch OAuth2 settings. It may be nil if there is
// no Twitch configuration.
tmi *client
tmi *client[*tmi.Message, *tmi.Message]
}

// client is the settings for OAuth2 and related elements.
type client struct {
// The type parameter is the type of messages sent TO the service.
type client[Send, Receive any] struct {
// send is the channel on which messages are sent.
send chan Send
// recv is the channel on which received messages are communicated.
recv chan Receive
// me is the bot's username. The interpretation of this is domain-specific.
me string
// owner is the user ID of the owner. The interpretation of this is
Expand Down Expand Up @@ -90,11 +95,9 @@ func (robo *Robot) twitch(ctx context.Context, group *errgroup.Group) error {
Capabilities: []string{"twitch.tv/commands", "twitch.tv/tags"},
Timeout: 300 * time.Second,
}
send := make(chan *tmi.Message, 1)
recv := make(chan *tmi.Message, 8) // 8 is enough for on-connect msgs
// TODO(zeph): could run several instances of loop
go robo.tmiLoop(ctx, send, recv)
tmi.Connect(ctx, cfg, tmi.Log(log.Default(), false), send, recv)
go robo.tmiLoop(ctx, robo.tmi.send, robo.tmi.recv)
tmi.Connect(ctx, cfg, tmi.Log(log.Default(), false), robo.tmi.send, robo.tmi.recv)
return ctx.Err()
}

Expand Down

0 comments on commit ec7f63f

Please sign in to comment.