From 53e6eecb3ff80670cd0ec87033c0e54e37c7a996 Mon Sep 17 00:00:00 2001 From: Zsolt Tasnadi Date: Tue, 20 Jan 2026 20:58:18 +0100 Subject: [PATCH] multiple discord senders --- env-example | 3 +++ lib/config.go | 31 +++++++++++++++------------- lib/fetcher.gitea.go | 13 ++++++------ lib/fetcher.go | 18 +++++++--------- lib/fetcher.redmine.go | 13 ++++++------ lib/fetcher.wikijs.go | 13 ++++++------ lib/message.go | 13 ++++++++++++ lib/runner.go | 47 ++++++++++++++++++++++++++++-------------- lib/sender.discord.go | 18 +++++++--------- 9 files changed, 100 insertions(+), 69 deletions(-) create mode 100644 lib/message.go diff --git a/env-example b/env-example index 3e2ee34..e2ac377 100644 --- a/env-example +++ b/env-example @@ -1,16 +1,19 @@ WIKI_BASE_URL= WIKI_TOKEN= WIKI_CONTENT_LIMIT=10 +WIKI_DISCORD_WEBHOOK= REDMINE_BASE_URL= REDMINE_KEY= REDMINE_CONTENT_LIMIT=10 +REDMINE_DISCORD_WEBHOOK= GITEA_TOKEN= GITEA_BASE_URL= GITEA_REPOS=org/repo1,org/repo2 GITEA_CONTENT_LIMIT=10 +GITEA_DISCORD_WEBHOOK= DISCORD_WEBHOOK= diff --git a/lib/config.go b/lib/config.go index 01c0a59..6496e87 100644 --- a/lib/config.go +++ b/lib/config.go @@ -10,19 +10,22 @@ import ( ) type Config struct { - WikiBaseURL string - WikiToken string - WikiContentLimit int - RedmineBaseURL string - RedmineKey string - RedmineContentLimit int - GiteaToken string - GiteaBaseURL string - GiteaRepos []string - GiteaContentLimit int - DiscordWebhook string - DiscordFake bool - Interval time.Duration + WikiBaseURL string + WikiToken string + WikiContentLimit int + WikiDiscordWebhook string + RedmineBaseURL string + RedmineKey string + RedmineContentLimit int + RedmineDiscordWebhook string + GiteaToken string + GiteaBaseURL string + GiteaRepos []string + GiteaContentLimit int + GiteaDiscordWebhook string + DiscordWebhook string + DiscordFake bool + Interval time.Duration } func envToInteger(key string, defaultValue int) int { @@ -40,6 +43,6 @@ func envToInteger(key string, defaultValue int) int { func loadEnv() { if err := godotenv.Load(); err != nil { - log.Println("Warning: .env file not found, using environment variables") + log.Println("[BOOT] .env file not found") } } diff --git a/lib/fetcher.gitea.go b/lib/fetcher.gitea.go index ef1f01a..7fc5e0c 100644 --- a/lib/fetcher.gitea.go +++ b/lib/fetcher.gitea.go @@ -24,8 +24,8 @@ func (f *GiteaFetcher) Name() string { return "Gitea" } -func (f *GiteaFetcher) Fetch() []Entry { - var entries []Entry +func (f *GiteaFetcher) Fetch() []Message { + var messages []Message for _, repo := range f.Repos { repo = strings.TrimSpace(repo) @@ -54,18 +54,19 @@ func (f *GiteaFetcher) Fetch() []Entry { for _, content := range response { cacheKey := "gitea_commit_" + url.QueryEscape(f.BaseURL+repo+"_"+content.Sha) - entry := f.TryCreateEntry( + message := f.TryCreateMessage( + "gitea", cacheKey, content.Sha, fmt.Sprintf("📝 [%s] - (%s) %s", f.Name(), repo, content.Commit.Message), content.HTMLURL, ) - if entry != nil { - entries = append(entries, *entry) + if message != nil { + messages = append(messages, *message) } } } - return entries + return messages } diff --git a/lib/fetcher.go b/lib/fetcher.go index 0d1f23a..1f8f2cb 100644 --- a/lib/fetcher.go +++ b/lib/fetcher.go @@ -7,16 +7,10 @@ import ( "net/http" ) -// Entry represents a single fetched item. -type Entry struct { - Title string - URL string -} - // Fetcher is the interface for a fetcher. type Fetcher interface { Name() string - Fetch() []Entry + Fetch() []Message } // BaseFetcher contains common fields for all fetchers. @@ -27,10 +21,14 @@ type BaseFetcher struct { ContentLimit int } -// TryCreateEntry checks the cache and creates an Entry if the value has changed. -func (b *BaseFetcher) TryCreateEntry(cacheKey, cacheValue, title, url string) *Entry { +// TryCreateMessage checks the cache and creates a Message if the value has changed. +func (b *BaseFetcher) TryCreateMessage(channel, cacheKey, cacheValue, title, url string) *Message { if b.Cache.TryUpdate(cacheKey, cacheValue) { - return &Entry{Title: title, URL: url} + return &Message{ + Channel: channel, + Title: title, + URL: url, + } } return nil } diff --git a/lib/fetcher.redmine.go b/lib/fetcher.redmine.go index b5c521f..c4bbc76 100644 --- a/lib/fetcher.redmine.go +++ b/lib/fetcher.redmine.go @@ -21,8 +21,8 @@ func (f *RedmineFetcher) Name() string { return "Redmine" } -func (f *RedmineFetcher) Fetch() []Entry { - var entries []Entry +func (f *RedmineFetcher) Fetch() []Message { + var messages []Message path := fmt.Sprintf("/issues.json?limit=%d&sort=updated_on:desc", f.ContentLimit) req := FetcherRequest{ BaseURL: f.BaseURL, @@ -43,16 +43,17 @@ func (f *RedmineFetcher) Fetch() []Entry { } for _, content := range response.Issues { - entry := f.TryCreateEntry( + message := f.TryCreateMessage( + "redmine", fmt.Sprintf("redmine_%d", content.ID), content.UpdatedOn, fmt.Sprintf("🎫 [%s] - #%d %s", f.Name(), content.ID, content.Subject), fmt.Sprintf("%s/issues/%d", f.BaseURL, content.ID), ) - if entry != nil { - entries = append(entries, *entry) + if message != nil { + messages = append(messages, *message) } } - return entries + return messages } diff --git a/lib/fetcher.wikijs.go b/lib/fetcher.wikijs.go index 7b8c927..2dcc97a 100644 --- a/lib/fetcher.wikijs.go +++ b/lib/fetcher.wikijs.go @@ -25,8 +25,8 @@ func (f *WikiFetcher) Name() string { return "WikiJS" } -func (f *WikiFetcher) Fetch() []Entry { - var entries []Entry +func (f *WikiFetcher) Fetch() []Message { + var messages []Message query := fmt.Sprintf(`{"query":"{ pages { list(orderBy: UPDATED, orderByDirection: DESC, limit: %d){ path, updatedAt, title }}}"}`, f.ContentLimit) req := FetcherRequest{ @@ -50,17 +50,18 @@ func (f *WikiFetcher) Fetch() []Entry { } for _, content := range response.Data.Pages.List { - entry := f.TryCreateEntry( + message := f.TryCreateMessage( + "wiki", "wiki_"+content.Path, content.UpdatedAt, fmt.Sprintf("📖 [%s] - %s", f.Name(), content.Title), fmt.Sprintf("%s/%s", f.BaseURL, content.Path), ) - if entry != nil { - entries = append(entries, *entry) + if message != nil { + messages = append(messages, *message) } } - return entries + return messages } diff --git a/lib/message.go b/lib/message.go new file mode 100644 index 0000000..71360dd --- /dev/null +++ b/lib/message.go @@ -0,0 +1,13 @@ +package lib + +import "fmt" + +type Message struct { + Channel string + Title string + URL string +} + +func (m Message) ToDiscord() string { + return fmt.Sprintf("[%s](%s)", m.Title, m.URL) +} diff --git a/lib/runner.go b/lib/runner.go index f0538d1..5c91c74 100644 --- a/lib/runner.go +++ b/lib/runner.go @@ -1,7 +1,6 @@ package lib import ( - "fmt" "log" "os" "strings" @@ -62,34 +61,50 @@ func getCache() Cache { return cache } -func getDiscordSender(config Config) DiscordSender { - return DiscordSender{ - Webhook: config.DiscordWebhook, - Fake: config.DiscordFake, - } -} - -func getMessages(fetchers []Fetcher) []string { - messages := []string{} +func getMessages(fetchers []Fetcher) []Message { + messages := []Message{} for _, fetcher := range fetchers { - entries := fetcher.Fetch() - for _, entry := range entries { - messages = append(messages, fmt.Sprintf("[%s](%s)", entry.Title, entry.URL)) + fetchedMessages := fetcher.Fetch() + for _, message := range fetchedMessages { + messages = append(messages, message) } } return messages } +func sendMessageToDiscord(sender DiscordSender, message Message) { + log.Printf("[SCHEDULED] [SEND] (%s) %s\n", message.Channel, message.ToDiscord()) + if sender.Fake { + return + } + sender.Send(message.ToDiscord()) +} + func Runner() { loadEnv() config := getConfig() cache := getCache() - discord_sender := getDiscordSender(config) fetchers := getFetchers(&config, &cache) + + default_discord_sender := NewDiscordSender(config.DiscordWebhook, config.DiscordFake) + wiki_discord_sender := NewDiscordSender(config.WikiDiscordWebhook, config.DiscordFake) + redmine_discord_sender := NewDiscordSender(config.RedmineDiscordWebhook, config.DiscordFake) + gita_discord_sender := NewDiscordSender(config.GiteaDiscordWebhook, config.DiscordFake) for { - log.Println("Run updater...") + log.Println("[SCHEDULED] Run updater...") messages := getMessages(fetchers) - discord_sender.SendBatch(messages) + for _, message := range messages { + switch message.Channel { + case "wiki": + sendMessageToDiscord(wiki_discord_sender, message) + case "redmine": + sendMessageToDiscord(redmine_discord_sender, message) + case "gitea": + sendMessageToDiscord(gita_discord_sender, message) + default: + sendMessageToDiscord(default_discord_sender, message) + } + } cache.Save() time.Sleep(config.Interval) } diff --git a/lib/sender.discord.go b/lib/sender.discord.go index a524340..acb9b67 100644 --- a/lib/sender.discord.go +++ b/lib/sender.discord.go @@ -3,10 +3,16 @@ package lib import ( "bytes" "encoding/json" - "log" "net/http" ) +func NewDiscordSender(webhook string, fake bool) DiscordSender { + return DiscordSender{ + Webhook: webhook, + Fake: fake, + } +} + type DiscordSender struct { Webhook string Fake bool @@ -19,13 +25,3 @@ func (d DiscordSender) Send(msg string) { } http.Post(d.Webhook, "application/json", bytes.NewBuffer(b)) } - -func (d DiscordSender) SendBatch(msgs []string) { - for _, msg := range msgs { - log.Println("Sending to Discord:", msg) - if d.Fake { - continue - } - d.Send(msg) - } -}