mirror of https://github.com/veonik/squircy3
7 changed files with 240 additions and 0 deletions
@ -0,0 +1,132 @@
|
||||
package discord |
||||
|
||||
import ( |
||||
"sync" |
||||
|
||||
"code.dopame.me/veonik/squircy3/event" |
||||
"github.com/bwmarrin/discordgo" |
||||
"github.com/pkg/errors" |
||||
"github.com/sirupsen/logrus" |
||||
) |
||||
|
||||
var ErrNotConnected = errors.New("not connected") |
||||
|
||||
type Config struct { |
||||
Token string `toml:"token"` |
||||
ActivityName string `toml:"activity"` |
||||
OwnerID string `toml:"owner"` |
||||
|
||||
enabled bool |
||||
} |
||||
|
||||
type Manager struct { |
||||
conf Config |
||||
|
||||
ev *event.Dispatcher |
||||
session *discordgo.Session |
||||
|
||||
channels map[string]*discordgo.Channel |
||||
|
||||
mu sync.Mutex |
||||
} |
||||
|
||||
func NewManager(ev *event.Dispatcher) *Manager { |
||||
return &Manager{ev: ev, channels: make(map[string]*discordgo.Channel)} |
||||
} |
||||
|
||||
func (m *Manager) Configure(c Config) error { |
||||
c.enabled = len(c.Token) > 0 |
||||
m.mu.Lock() |
||||
defer m.mu.Unlock() |
||||
m.conf = c |
||||
return nil |
||||
} |
||||
|
||||
func (m *Manager) Connect() error { |
||||
m.mu.Lock() |
||||
defer m.mu.Unlock() |
||||
if m.session != nil { |
||||
return errors.New("already connected") |
||||
} |
||||
if !m.conf.enabled { |
||||
return errors.New("not enabled") |
||||
} |
||||
s, err := discordgo.New("Bot " + m.conf.Token) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
m.session = s |
||||
m.session.AddHandler(m.onMessageCreate) |
||||
m.session.Identify.Intents = discordgo.IntentsGuildMessages | discordgo.IntentGuildMessageTyping | discordgo.IntentsDirectMessages |
||||
m.session.Identify.Presence.Game = discordgo.Activity{Name: m.conf.ActivityName} |
||||
return m.session.Open() |
||||
} |
||||
|
||||
func (m *Manager) Disconnect() error { |
||||
m.mu.Lock() |
||||
defer m.mu.Unlock() |
||||
if m.session == nil { |
||||
return ErrNotConnected |
||||
} |
||||
s := m.session |
||||
m.session = nil |
||||
return s.Close() |
||||
} |
||||
|
||||
func userToMap(user *discordgo.User) map[string]interface{} { |
||||
return map[string]interface{}{ |
||||
"ID": user.ID, |
||||
"Username": user.Username, |
||||
} |
||||
} |
||||
|
||||
func (m *Manager) onMessageCreate(s *discordgo.Session, e *discordgo.MessageCreate) { |
||||
ch, err := m.getChannel(e.ChannelID) |
||||
isDM := false |
||||
if err != nil { |
||||
logrus.Warnf("%s: failed to get channel for %s: %s", PluginName, e.ChannelID, err) |
||||
} else { |
||||
isDM = ch.Type == discordgo.ChannelTypeDM |
||||
} |
||||
m.ev.Emit("discord.MESSAGE", map[string]interface{}{ |
||||
"ID": e.ID, |
||||
"Content": e.Content, |
||||
"ChannelID": e.ChannelID, |
||||
"GuildID": e.GuildID, |
||||
"Author": userToMap(e.Author), |
||||
"FromSelf": e.Author.ID == s.State.User.ID, |
||||
"IsDM": isDM, |
||||
}) |
||||
} |
||||
|
||||
func (m *Manager) MessageChannel(channelID, message string) error { |
||||
_, err := m.session.ChannelMessageSend(channelID, message) |
||||
return err |
||||
} |
||||
|
||||
func (m *Manager) MessageChannelTTS(channelID, message string) error { |
||||
_, err := m.session.ChannelMessageSendTTS(channelID, message) |
||||
return err |
||||
} |
||||
|
||||
func (m *Manager) CurrentUsername() (string, error) { |
||||
return m.session.State.User.Username, nil |
||||
} |
||||
|
||||
func (m *Manager) OwnerID() string { |
||||
return m.conf.OwnerID |
||||
} |
||||
|
||||
func (m *Manager) getChannel(id string) (*discordgo.Channel, error) { |
||||
m.mu.Lock() |
||||
defer m.mu.Unlock() |
||||
if ch, ok := m.channels[id]; ok { |
||||
return ch, nil |
||||
} |
||||
ch, err := m.session.Channel(id) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
m.channels[id] = ch |
||||
return ch, nil |
||||
} |
@ -0,0 +1,74 @@
|
||||
package discord |
||||
|
||||
import ( |
||||
"code.dopame.me/veonik/squircy3/config" |
||||
"code.dopame.me/veonik/squircy3/event" |
||||
"code.dopame.me/veonik/squircy3/plugin" |
||||
"github.com/dop251/goja" |
||||
"github.com/pkg/errors" |
||||
"github.com/sirupsen/logrus" |
||||
) |
||||
|
||||
const PluginName = "discord" |
||||
|
||||
func Initialize(m *plugin.Manager) (plugin.Plugin, error) { |
||||
ev, err := event.FromPlugins(m) |
||||
if err != nil { |
||||
return nil, errors.Wrapf(err, "%s: required dependency missing (event)", PluginName) |
||||
} |
||||
return &discordPlugin{NewManager(ev)}, nil |
||||
} |
||||
|
||||
type discordPlugin struct { |
||||
manager *Manager |
||||
} |
||||
|
||||
func (p *discordPlugin) Configure(c config.Config) error { |
||||
if gcv, ok := c.Self().(*Config); ok { |
||||
return p.manager.Configure(*gcv) |
||||
} |
||||
cf := Config{} |
||||
cf.Token, _ = c.String("token") |
||||
cf.OwnerID, _ = c.String("owner") |
||||
cf.ActivityName, _ = c.String("activity") |
||||
return p.manager.Configure(cf) |
||||
} |
||||
|
||||
func (p *discordPlugin) Options() []config.SetupOption { |
||||
return []config.SetupOption{config.WithInitValue(&Config{})} |
||||
} |
||||
|
||||
func (p *discordPlugin) Name() string { |
||||
return PluginName |
||||
} |
||||
|
||||
// must logs the given error as a warning
|
||||
func must(what string, err error) { |
||||
if err != nil { |
||||
logrus.Warnf("%s: error %s: %s", PluginName, what, err) |
||||
} |
||||
} |
||||
|
||||
func (p *discordPlugin) HandleRuntimeInit(gr *goja.Runtime) { |
||||
v := gr.NewObject() |
||||
must("setting connect", v.Set("connect", p.manager.Connect)) |
||||
must("setting messageChannel", v.Set("messageChannel", p.manager.MessageChannel)) |
||||
must("setting messageChannelTTS", v.Set("messageChannelTTS", p.manager.MessageChannelTTS)) |
||||
must("setting getCurrentUsername", v.Set("getCurrentUsername", p.manager.CurrentUsername)) |
||||
must("setting getOwnerID", v.Set("getOwnerID", p.manager.OwnerID)) |
||||
if err := gr.Set("discord", v); err != nil { |
||||
logrus.Warnf("%s: error initializing runtime: %s", PluginName, err) |
||||
} |
||||
} |
||||
|
||||
func (p *discordPlugin) HandleShutdown() { |
||||
if p.manager == nil { |
||||
logrus.Warnf("%s: shutting down uninitialized plugin", PluginName) |
||||
return |
||||
} |
||||
if err := p.manager.Disconnect(); err != nil { |
||||
if err != ErrNotConnected { |
||||
logrus.Warnf("%s: failed to disconnect before shutting down: %s", PluginName, err) |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,14 @@
|
||||
package main |
||||
|
||||
import ( |
||||
"code.dopame.me/veonik/squircy3/plugin" |
||||
"code.dopame.me/veonik/squircy3/plugins/discord" |
||||
) |
||||
|
||||
func main() { |
||||
plugin.Main(discord.PluginName) |
||||
} |
||||
|
||||
func Initialize(m *plugin.Manager) (plugin.Plugin, error) { |
||||
return discord.Initialize(m) |
||||
} |
Loading…
Reference in new issue