Files
dislate/internals/discord/bot/events/messages.go
2024-08-28 10:04:55 -03:00

294 lines
7.6 KiB
Go

package events
import (
e "errors"
"log/slog"
"slices"
"dislate/internals/discord/bot/errors"
"dislate/internals/discord/bot/gconf"
"dislate/internals/guilddb"
"dislate/internals/translator"
"dislate/internals/translator/lang"
dgo "github.com/bwmarrin/discordgo"
)
type MessageCreate struct {
db gconf.DB
translator translator.Translator
}
func NewMessageCreate(db gconf.DB, t translator.Translator) MessageCreate {
return MessageCreate{db, t}
}
func (h MessageCreate) Serve(s *dgo.Session, ev *dgo.MessageCreate) {
if ev.Message.Author.Bot {
return
}
log := gconf.GetLogger(ev.GuildID, s, h.db)
ch, err := h.db.Channel(ev.GuildID, ev.ChannelID)
if e.Is(err, guilddb.ErrNotFound) {
log.Debug("Channel is not in database, ignoring.",
slog.String("guild", ev.GuildID),
slog.String("channel", ev.ChannelID),
)
return
} else if err != nil {
errors.NewErrDatabase(
slog.String("guild", ev.GuildID),
slog.String("channel", ev.ChannelID),
slog.String("err", err.Error()),
).LogReply(log, s, ev.Message)
return
}
gc, err := h.db.ChannelGroup(ch.GuildID, ch.ID)
if e.Is(err, guilddb.ErrNotFound) {
log.Debug("Channel is not in a group, ignoring.",
slog.String("guild", ev.GuildID),
slog.String("channel", ev.ChannelID),
)
return
} else if err != nil {
errors.NewErrDatabase(
slog.String("guild", ev.GuildID),
slog.String("channel", ev.ChannelID),
slog.String("err", err.Error()),
).LogReply(log, s, ev.Message)
return
}
_, err = getMessage(h.db, ev.Message, ch.Language)
if err != nil {
errors.NewErrDatabase(
slog.String("guild", ev.Message.GuildID),
slog.String("channel", ev.Message.ChannelID),
slog.String("message", ev.Message.ID),
slog.String("err", err.Error()),
).LogReply(log, s, ev.Message)
return
}
for _, c := range gc {
if c.ID == ch.ID && c.GuildID == ch.GuildID {
continue
}
go func(c guilddb.Channel) {
uw, err := getUserWebhook(s, c.ID, ev.Message.Author)
if err != nil {
errors.NewErrUserWebhook(
slog.String("guild", ev.Message.GuildID),
slog.String("channel", ev.Message.ChannelID),
slog.Any("user", ev.Message.Author),
).LogReply(log, s, ev.Message)
}
t, err := h.translator.Translate(ch.Language, c.Language, ev.Message.Content)
if err != nil {
errors.New("Error while trying to translate message",
slog.String("guild", ev.Message.GuildID),
slog.String("channel", ev.Message.ChannelID),
slog.String("message", ev.Message.ID),
slog.String("content", ev.Message.Content),
slog.String("err", err.Error()),
).LogReply(log, s, ev.Message)
}
tdm, err := s.WebhookExecute(uw.ID, uw.Token, true, &dgo.WebhookParams{
AvatarURL: ev.Message.Author.AvatarURL(""),
Username: ev.Message.Author.GlobalName,
Content: t,
})
if err != nil {
errors.NewErrUserWebhook(
slog.String("guild", ev.Message.GuildID),
slog.String("channel", ev.Message.ChannelID),
slog.String("message", ev.Message.ID),
slog.String("content", ev.Message.Content),
slog.String("err", err.Error()),
).LogReply(log, s, ev.Message)
}
if tdm.GuildID == "" {
tdm.GuildID = ev.Message.GuildID
}
_, err = getTranslatedMessage(h.db, tdm, ev.Message, c.Language)
if err != nil {
errors.NewErrDatabase(
slog.String("guild", ev.Message.GuildID),
slog.String("channel", ev.Message.ChannelID),
slog.String("message", ev.Message.ID),
slog.String("err", err.Error()),
).LogReply(log, s, ev.Message)
}
}(c)
}
}
type MessageEdit struct {
db gconf.DB
translator translator.Translator
}
func NewMessageEdit(db gconf.DB, t translator.Translator) MessageEdit {
return MessageEdit{db, t}
}
func (h MessageEdit) Serve(s *dgo.Session, ev *dgo.MessageUpdate) {
if ev.Message.Author.Bot {
return
}
log := gconf.GetLogger(ev.Message.GuildID, s, h.db)
msg, err := getMessage(h.db, ev.Message, lang.EN)
if e.Is(err, guilddb.ErrNotFound) {
log.Debug("Message is not in database, ignoring.",
slog.String("guild", ev.Message.GuildID),
slog.String("channel", ev.Message.ChannelID),
)
return
} else if err != nil {
errors.NewErrDatabase(
slog.String("guild", ev.Message.GuildID),
slog.String("channel", ev.Message.ChannelID),
slog.String("err", err.Error()),
).LogReply(log, s, ev.Message)
return
}
tmsgs, err := h.db.MessagesWithOrigin(msg.GuildID, msg.ChannelID, msg.ID)
if e.Is(err, guilddb.ErrNotFound) {
log.Debug("No translated message found, ignoring.",
slog.String("guild", ev.GuildID),
slog.String("channel", ev.ChannelID),
)
return
} else if err != nil {
errors.NewErrDatabase(
slog.String("guild", ev.GuildID),
slog.String("channel", ev.ChannelID),
slog.String("err", err.Error()),
).LogReply(log, s, ev.Message)
return
}
for _, m := range tmsgs {
if m.ID == msg.ID && m.GuildID == msg.GuildID {
continue
}
go func(m guilddb.Message) {
uw, err := getUserWebhook(s, m.ChannelID, ev.Message.Author)
if err != nil {
errors.NewErrUserWebhook(
slog.String("guild", ev.Message.GuildID),
slog.String("channel", ev.Message.ChannelID),
slog.Any("user", ev.Message.Author),
slog.String("err", err.Error()),
).LogReply(log, s, ev.Message)
return
}
t, err := h.translator.Translate(msg.Language, m.Language, ev.Message.Content)
if err != nil {
errors.New("Error while trying to translate message",
slog.String("guild", ev.Message.GuildID),
slog.String("channel", ev.Message.ChannelID),
slog.String("message", ev.Message.ID),
slog.String("content", ev.Message.Content),
slog.String("err", err.Error()),
).LogReply(log, s, ev.Message)
return
}
_, err = s.WebhookMessageEdit(uw.ID, uw.Token, m.ID, &dgo.WebhookEdit{
Content: &t,
})
if err != nil {
errors.NewErrUserWebhook(
slog.String("guild", ev.Message.GuildID),
slog.String("channel", ev.Message.ChannelID),
slog.String("message", ev.Message.ID),
slog.String("content", ev.Message.Content),
slog.String("err", err.Error()),
).LogReply(log, s, ev.Message)
return
}
}(m)
}
}
func getUserWebhook(s *dgo.Session, channelID string, user *dgo.User) (*dgo.Webhook, error) {
whName := "DISLATE_USER_WEBHOOK_" + user.ID
ws, err := s.ChannelWebhooks(channelID)
if err != nil {
return &dgo.Webhook{}, err
}
wi := slices.IndexFunc(ws, func(w *dgo.Webhook) bool {
return w.Name == whName
})
if wi > -1 {
return ws[wi], nil
}
w, err := s.WebhookCreate(channelID, whName, user.AvatarURL(""))
if err != nil {
return &dgo.Webhook{}, err
}
return w, nil
}
func getMessage(db gconf.DB, m *dgo.Message, lang lang.Language) (guilddb.Message, error) {
msg, err := db.Message(m.GuildID, m.ChannelID, m.ID)
if e.Is(err, guilddb.ErrNotFound) {
if err := db.MessageInsert(guilddb.NewMessage(m.GuildID, m.ChannelID, m.ID, lang)); err != nil {
return guilddb.Message{}, err
}
msg, err = db.Message(m.GuildID, m.ChannelID, m.ID)
if err != nil {
return guilddb.Message{}, err
}
}
return msg, nil
}
func getTranslatedMessage(
db gconf.DB,
m, original *dgo.Message,
lang lang.Language,
) (guilddb.Message, error) {
msg, err := db.Message(m.GuildID, m.ChannelID, m.ID)
if e.Is(err, guilddb.ErrNotFound) {
if err := db.MessageInsert(guilddb.NewTranslatedMessage(
m.GuildID,
m.ChannelID,
m.ID,
lang,
original.ChannelID,
original.ID,
)); err != nil {
return guilddb.Message{}, err
}
msg, err = db.Message(m.GuildID, m.ChannelID, m.ID)
if err != nil {
return guilddb.Message{}, err
}
} else if err != nil {
return guilddb.Message{}, err
}
return msg, nil
}