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()) 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 }