6
1
mirror of https://git.mills.io/saltyim/saltyim.git synced 2024-06-26 00:38:22 +00:00
prologic-saltyim/service.go
xuu 38a6d71644 xuu/bot (#64)
Co-authored-by: Jon Lundy <jon@xuu.cc>
Co-authored-by: James Mills <prologic@shortcircuit.net.au>
Reviewed-on: https://git.mills.io/saltyim/saltyim/pulls/64
Co-authored-by: xuu <xuu@noreply@mills.io>
Co-committed-by: xuu <xuu@noreply@mills.io>
2022-03-26 14:43:05 +00:00

110 lines
2.4 KiB
Go

package saltyim
import (
"bytes"
"context"
"fmt"
"strings"
"sync"
"github.com/keys-pub/keys"
log "github.com/sirupsen/logrus"
"go.yarn.social/lextwt"
)
type Service struct {
*Client
mu sync.RWMutex
textFns map[string]MessageTextHandlerFunc
eventFns map[string]MessageEventHandlerFunc
}
type MessageTextHandlerFunc func(context.Context, *Service, *keys.EdX25519PublicKey, *lextwt.SaltyText) error
type MessageEventHandlerFunc func(context.Context, *Service, *keys.EdX25519PublicKey, *lextwt.SaltyEvent) error
func NewService(client *Client) (*Service, error) {
svc := &Service{
Client: client,
textFns: make(map[string]MessageTextHandlerFunc),
eventFns: make(map[string]MessageEventHandlerFunc),
}
svc.TextFunc("ping", func(ctx context.Context, svc *Service, key *keys.EdX25519PublicKey, msg *lextwt.SaltyText) error {
return svc.Send(msg.User.String(), "Pong!")
})
return svc, nil
}
func (svc *Service) String() string {
buf := &bytes.Buffer{}
fmt.Fprintln(buf, "Bot: ", svc.Client.me)
svc.mu.RLock()
defer svc.mu.RUnlock()
for k := range svc.textFns {
fmt.Fprintln(buf, " - TextCmd: ", k)
}
for k := range svc.eventFns {
fmt.Fprintln(buf, " - EventCmd: ", k)
}
return buf.String()
}
func (svc *Service) Run(ctx context.Context) {
log.Println("listining for bot: ", svc.Me().Endpoint())
msgch := svc.Read(ctx, "", "")
for {
select {
case <-ctx.Done():
return
case msg := <-msgch:
if err := svc.handle(ctx, msg); err != nil {
log.WithError(err).Println("failed to handle message")
}
}
}
}
func (svc *Service) handle(ctx context.Context, msg Message) error {
decoded, err := lextwt.ParseSalty(msg.Text)
if err != nil {
return err
}
switch m := decoded.(type) {
case *lextwt.SaltyText:
fields := strings.Fields(m.LiteralText())
svc.mu.RLock()
defer svc.mu.RUnlock()
if fn, ok := svc.textFns[strings.ToUpper(fields[0])]; ok {
err = fn(ctx, svc, msg.Key, m)
}
case *lextwt.SaltyEvent:
svc.mu.RLock()
defer svc.mu.RUnlock()
if fn, ok := svc.eventFns[strings.ToUpper(m.Command)]; ok {
err = fn(ctx, svc, msg.Key, m)
}
}
return err
}
func (svc *Service) TextFunc(name string, fn MessageTextHandlerFunc) {
svc.mu.Lock()
defer svc.mu.Unlock()
svc.textFns[strings.ToUpper(name)] = fn
}
func (svc *Service) EventFunc(name string, fn MessageEventHandlerFunc) {
svc.mu.Lock()
defer svc.mu.Unlock()
svc.eventFns[strings.ToUpper(name)] = fn
}