Skip to content

Commit

Permalink
fix: handle deleted messages
Browse files Browse the repository at this point in the history
  • Loading branch information
graytonio committed Feb 1, 2025
1 parent fb569eb commit 7d03994
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 14 deletions.
4 changes: 3 additions & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ services:
env_file:
- .env
environment:
MYSQL_DB_DSN: discordgit:password@tcp(db:3306)/discordgit?charset=utf8mb4&parseTime=True&loc=UTC
LOG_LEVEL: DEBUG
UPDATE_TASK_CRON: "* * * * *"
MYSQL_DB_DSN: discordgit:password@tcp(db:3306)/discordgit?charset=utf8mb4&parseTime=True&loc=UTC\
ports:
- 2112:2112
depends_on:
Expand Down
28 changes: 25 additions & 3 deletions internal/manager/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func CreateNewLinkedMessage(log *logrus.Entry, s DiscordSessionInterface, dbConn
MessageID: msgIDs[0],
MessageChain: msgIDs,
LinkedPage: datatypes.URL(*contentURL),
NextUpdate: time.Now().Add(updateRateSetting.DurationValue),
NextUpdate: time.Now().Add(updateRateSetting.DurationValue),
}).Error
if err != nil {
log.WithError(err).Error("cloud not save message data in db")
Expand Down Expand Up @@ -102,7 +102,7 @@ func UpdateMessage(log *logrus.Entry, s DiscordSessionInterface, dbConn *gorm.DB
log.WithError(err).Error("could not build embed objects")
return err
}

msgIds := make([]string, len(embeds))
for i, e := range embeds {
var msg *discordgo.Message
Expand All @@ -113,6 +113,13 @@ func UpdateMessage(log *logrus.Entry, s DiscordSessionInterface, dbConn *gorm.DB
}

if err != nil {
if restErr, ok := err.(*discordgo.RESTError); ok {
err = handleRESTErrors(log, s, dbConn, &linkedMessage, restErr)
if err == nil {
return nil
}
}

log.WithError(err).Error("could not update message chain")
return err
}
Expand Down Expand Up @@ -150,6 +157,21 @@ func UpdateMessage(log *logrus.Entry, s DiscordSessionInterface, dbConn *gorm.DB
return nil
}

func handleRESTErrors(log *logrus.Entry, s DiscordSessionInterface, dbConn *gorm.DB, linkedMessage *db.LinkedMessage, err *discordgo.RESTError) error {
log.Debug("handling rest error")
switch err.Message.Code {
case discordgo.ErrCodeUnknownMessage:
log.Debug("deleting stale message")
return dbConn.Delete(linkedMessage).Error
case discordgo.ErrCodePerformedOperationOnArchivedThread:
// TODO(roadmap) Figure out what to do about archived threads
default:
log.WithError(err).Warn("unknown rest error")
return err
}
return nil
}

// Fetch content of url as string
func fetchPage(log *logrus.Entry, link *url.URL) (string, error) {
res, err := http.Get(link.String())
Expand All @@ -168,7 +190,7 @@ func fetchPage(log *logrus.Entry, link *url.URL) (string, error) {
return string(body), nil
}

var pageBreakFinder = regexp.MustCompile(`(?m)^-{3,}$`) // TODO Remove need for regex
var pageBreakFinder = regexp.MustCompile(`(?m)^-{3,}$`) // TODO(maint) Remove need for regex

// Break raw page content into embed blocks to send or update
func buildEmbedContents(content string, link *url.URL, pageBreakSetting bool) ([]*discordgo.MessageEmbed, error) {
Expand Down
21 changes: 18 additions & 3 deletions internal/scheduler/scheduler.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package scheduler

import (
"fmt"
"time"

"github.com/go-co-op/gocron/v2"
"github.com/google/uuid"
"github.com/graytonio/discord-git-sync/internal/db"
"github.com/graytonio/discord-git-sync/internal/manager"
"github.com/graytonio/discord-git-sync/internal/metrics"
"github.com/graytonio/discord-git-sync/internal/utils"
"github.com/prometheus/client_golang/prometheus"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
)
Expand All @@ -16,7 +21,7 @@ import (

func InitJobScheduler(db *gorm.DB, s manager.DiscordSessionInterface) (gocron.Scheduler, error) {
var err error
// locker, err := gormlock.NewGormLocker(db, os.Getenv("WORKER_ID")) // TODO Update dependency after bump
// locker, err := gormlock.NewGormLocker(db, os.Getenv("WORKER_ID")) // TODO(roadmap) Update dependency after bump
// if err != nil {
// return err
// }
Expand All @@ -27,8 +32,10 @@ func InitJobScheduler(db *gorm.DB, s manager.DiscordSessionInterface) (gocron.Sc
}

scheduler.NewJob(
gocron.CronJob("*/5 * * * *", false), // TODO Configurable
gocron.CronJob(utils.GetEnv("UPDATE_TASK_CRON", "*/5 * * * *"), false),
gocron.NewTask(fetchAndDispatchMessageUpdates, db, scheduler, s),
gocron.WithName("message-batch-collection"),
gocron.WithSingletonMode(gocron.LimitModeReschedule),
)

scheduler.Start()
Expand All @@ -52,10 +59,18 @@ func fetchAndDispatchMessageUpdates(dbConn *gorm.DB, scheduler gocron.Scheduler,
})

log.Debug("auto updating linked message")

scheduler.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartImmediately()),
gocron.NewTask(manager.UpdateMessage, log, s, dbConn, m.GuildID, m.ChannelID, m.MessageID),
gocron.WithName(fmt.Sprintf("message-update-%s", m.MessageID)),
gocron.WithEventListeners(
gocron.AfterJobRuns(func(jobID uuid.UUID, jobName string) {
metrics.CommandsServed.With(prometheus.Labels{"command": "auto-update"}).Inc()
}),
gocron.AfterJobRunsWithError(func(jobID uuid.UUID, jobName string, err error) {
metrics.CommandsFailed.With(prometheus.Labels{"command": "auto-update"}).Inc()
}),
),
)
}
}
10 changes: 10 additions & 0 deletions internal/utils/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package utils

import "os"

func GetEnv(key, fallback string) string {
if value, ok := os.LookupEnv(key); ok {
return value
}
return fallback
}
10 changes: 8 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,23 @@ import (
"github.com/graytonio/discord-git-sync/internal/db"
"github.com/graytonio/discord-git-sync/internal/metrics"
"github.com/graytonio/discord-git-sync/internal/scheduler"
"github.com/graytonio/discord-git-sync/internal/utils"
"github.com/sirupsen/logrus"
)

func main() {
logLevel, err := logrus.ParseLevel(utils.GetEnv("LOG_LEVEL", "INFO"))
if err != nil {
logrus.WithField("LOG_LEVEL", utils.GetEnv("LOG_LEVEL", "INFO")).Warn("invalid log level defaulting to info")
logLevel = logrus.InfoLevel
}
logrus.SetLevel(logLevel)

dbConn, err := db.InitDB(os.Getenv("MYSQL_DB_DSN"))
if err != nil {
logrus.WithError(err).Fatal("could not connect to db")
}



s, err := bot.InitBot(os.Getenv("DISCORD_BOT_TOKEN"), dbConn, os.Getenv("TEST_GUILD_ID"))
if err != nil {
logrus.WithError(err).Fatal("could not start bot")
Expand Down
14 changes: 9 additions & 5 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@

A discord bot able to create and live update webpage embeds in channels.

TODO Add example screenshot
TODO(docs) Add Discord invite link

Roadmap:
TODO(docs) Add Website Link

- [ ] Add automatic update timers
- [ ] Support messages longer than 6000 characters
- [ ] Support message links for update command
TODO(docs) Add example screenshot

Features:

- Link existing text into discord without needing to copy and paste
- Keep live updated messages in channel without needing to maintain them
- Collaborate on announcement messages or documentation

0 comments on commit 7d03994

Please sign in to comment.