Remove Common, Rework External Chat Support, & Bugfixes (!5)

Co-authored-by: Layla <layla@layla.gg>
Reviewed-on: https://gitea.sumulayla.synology.me/layla/birdbot/pulls/5
This commit is contained in:
Layla 2023-06-19 03:08:24 -04:00
parent 5e4698495c
commit 6cbe4df36c
28 changed files with 81 additions and 146 deletions

View File

@ -20,7 +20,7 @@ jobs:
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v3 uses: actions/setup-go@v3
with: with:
go-version: '>=1.19.0' go-version: '1.20'
- name: Version - name: Version
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Test - name: Test

View File

@ -14,7 +14,7 @@ jobs:
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v3 uses: actions/setup-go@v3
with: with:
go-version: '>=1.19.0' go-version: '1.20'
- name: Test - name: Test
run: | run: |
make test make test

View File

@ -16,7 +16,7 @@ go-full-build: go-clean go-get go-build
go-build: go-build:
@echo " > Building binary..." @echo " > Building binary..."
@mkdir -p $(GOBIN) @mkdir -p $(GOBIN)
@CGO_ENABLED=1 go build -ldflags "-X github.com/yeslayla/birdbot/app.Version=$(VERSION) -X github.com/yeslayla/birdbot/app.Build=$(BUILD_NUMBER)" -o $(GOBIN)/$(PROJECT_BIN) $(GOFILES) @GOOS=linux CGO_ENABLED=1 go build -ldflags "-X github.com/yeslayla/birdbot/app.Version=$(VERSION) -X github.com/yeslayla/birdbot/app.Build=$(BUILD_NUMBER)" -o $(GOBIN)/$(PROJECT_BIN) $(GOFILES)
@chmod 755 $(GOBIN)/$(PROJECT_BIN) @chmod 755 $(GOBIN)/$(PROJECT_BIN)
go-generate: go-generate:

View File

@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"log" "log"
"github.com/yeslayla/birdbot/common" "github.com/yeslayla/birdbot-common/common"
"github.com/yeslayla/birdbot/core" "github.com/yeslayla/birdbot/core"
"github.com/yeslayla/birdbot/discord" "github.com/yeslayla/birdbot/discord"
"github.com/yeslayla/birdbot/mastodon" "github.com/yeslayla/birdbot/mastodon"
@ -34,6 +34,8 @@ type Bot struct {
onEventUpdatedHandlers [](func(common.Event) error) onEventUpdatedHandlers [](func(common.Event) error)
onEventCompletedHandlers [](func(common.Event) error) onEventCompletedHandlers [](func(common.Event) error)
chatLinks map[string][]string
chatHandlers map[string]common.ExternalChatModule
channelChats map[string][]common.ExternalChatModule channelChats map[string][]common.ExternalChatModule
} }
@ -45,6 +47,7 @@ func (app *Bot) Initialize(cfg *core.Config) error {
app.eventCategoryID = cfg.Discord.EventCategory app.eventCategoryID = cfg.Discord.EventCategory
app.archiveCategoryID = cfg.Discord.ArchiveCategory app.archiveCategoryID = cfg.Discord.ArchiveCategory
app.notificationChannelID = cfg.Discord.NotificationChannel app.notificationChannelID = cfg.Discord.NotificationChannel
app.chatLinks = cfg.Discord.ChatLinks
if app.guildID == "" { if app.guildID == "" {
return fmt.Errorf("discord Guild ID is not set") return fmt.Errorf("discord Guild ID is not set")
@ -62,29 +65,21 @@ func (app *Bot) Initialize(cfg *core.Config) error {
app.Session = discord.New(cfg.Discord.ApplicationID, app.guildID, cfg.Discord.Token, app.Database) app.Session = discord.New(cfg.Discord.ApplicationID, app.guildID, cfg.Discord.Token, app.Database)
// Intialize submodules
for channelID, chats := range app.channelChats {
channel := app.Session.NewChannelFromID(channelID)
for _, chat := range chats {
app.InitalizeExternalChat(channel, chat)
}
}
// Register Event Handlers // Register Event Handlers
app.Session.OnReady(app.onReady) app.Session.OnReady(app.onReady)
app.Session.OnEventCreate(app.onEventCreate) app.Session.OnEventCreate(app.onEventCreate)
app.Session.OnEventDelete(app.onEventDelete) app.Session.OnEventDelete(app.onEventDelete)
app.Session.OnEventUpdate(app.onEventUpdate) app.Session.OnEventUpdate(app.onEventUpdate)
if len(app.channelChats) > 0 {
app.Session.OnMessageRecieved(app.onMessageRecieved)
}
return nil return nil
} }
// Run opens the session with Discord until exit // Run opens the session with Discord until exit
func (app *Bot) Run() error { func (app *Bot) Run() error {
// Intialize submodules
app.prepareChat()
return app.Session.Run() return app.Session.Run()
} }
@ -186,10 +181,40 @@ func (app *Bot) onMessageRecieved(d *discord.Discord, channelID string, user com
} }
} }
func (app *Bot) prepareChat() {
// Associate channels with chat modules
for channelID, chatHandelerIDs := range app.chatLinks {
if _, ok := app.channelChats[channelID]; !ok {
app.channelChats[channelID] = []common.ExternalChatModule{}
}
for _, chatHandlerID := range chatHandelerIDs {
if handler, ok := app.chatHandlers[chatHandlerID]; ok {
app.channelChats[channelID] = append(app.channelChats[channelID], handler)
}
}
}
// Initialize chat modules
for channelID, chats := range app.channelChats {
channel := app.Session.NewChannelFromID(channelID)
for _, chat := range chats {
app.InitalizeExternalChat(channel, chat)
}
}
// Register listener if needed
if len(app.channelChats) > 0 {
app.Session.OnMessageRecieved(app.onMessageRecieved)
}
}
// NewBot creates a new bot instance // NewBot creates a new bot instance
func NewBot(db persistence.Database) *Bot { func NewBot(db persistence.Database) *Bot {
return &Bot{ return &Bot{
Database: db, Database: db,
channelChats: make(map[string][]common.ExternalChatModule), channelChats: make(map[string][]common.ExternalChatModule),
chatHandlers: make(map[string]common.ExternalChatModule),
} }
} }

View File

@ -2,17 +2,20 @@ package app
import ( import (
"log" "log"
"path/filepath"
"github.com/yeslayla/birdbot/common" "github.com/yeslayla/birdbot-common/common"
) )
type ComponentLoader struct { type ComponentLoader struct {
bot *Bot bot *Bot
configDir string
} }
func NewComponentLoader(bot *Bot) *ComponentLoader { func NewComponentLoader(bot *Bot, configDir string) *ComponentLoader {
return &ComponentLoader{ return &ComponentLoader{
bot: bot, bot: bot,
configDir: configDir,
} }
} }
@ -49,13 +52,8 @@ func (loader *ComponentLoader) OnEventComplete(handler func(common.Event) error)
return nil return nil
} }
func (loader *ComponentLoader) RegisterExternalChat(channelID string, chat common.ExternalChatModule) error { func (loader *ComponentLoader) RegisterExternalChat(ID string, chat common.ExternalChatModule) error {
if _, ok := loader.bot.channelChats[channelID]; !ok { loader.bot.chatHandlers[ID] = chat
loader.bot.channelChats[channelID] = []common.ExternalChatModule{}
}
loader.bot.channelChats[channelID] = append(loader.bot.channelChats[channelID], chat)
return nil return nil
} }
@ -71,3 +69,7 @@ func (loader *ComponentLoader) Notify(message string) error {
func (loader *ComponentLoader) RegisterCommand(name string, config common.ChatCommandConfiguration, handler func(common.User, map[string]any) string) { func (loader *ComponentLoader) RegisterCommand(name string, config common.ChatCommandConfiguration, handler func(common.User, map[string]any) string) {
loader.bot.Session.RegisterCommand(name, config, handler) loader.bot.Session.RegisterCommand(name, config, handler)
} }
func (loader *ComponentLoader) GetConfigPath(fileName string) string {
return filepath.Join(loader.configDir, "birdbot", fileName)
}

View File

@ -1,7 +1,7 @@
package app package app
import ( import (
"github.com/yeslayla/birdbot/common" "github.com/yeslayla/birdbot-common/common"
"github.com/yeslayla/birdbot/core" "github.com/yeslayla/birdbot/core"
) )

View File

@ -3,9 +3,10 @@ package app
import ( import (
"log" "log"
"os" "os"
"path/filepath"
"plugin" "plugin"
"github.com/yeslayla/birdbot/common" "github.com/yeslayla/birdbot-common/common"
) )
// LoadPlugin loads a plugin and returns its component if successful // LoadPlugin loads a plugin and returns its component if successful
@ -49,7 +50,7 @@ func LoadPlugins(directory string) []common.Module {
continue continue
} }
if comp := LoadPlugin(path.Name()); comp != nil { if comp := LoadPlugin(filepath.Join(directory, path.Name())); comp != nil {
components = append(components, comp) components = append(components, comp)
} }
} }

View File

@ -1,24 +0,0 @@
package common
import "github.com/bwmarrin/discordgo"
type CommandOptionType uint64
const (
CommandTypeString CommandOptionType = CommandOptionType(discordgo.ApplicationCommandOptionString)
CommandTypeInt CommandOptionType = CommandOptionType(discordgo.ApplicationCommandOptionInteger)
CommandTypeBool CommandOptionType = CommandOptionType(discordgo.ApplicationCommandOptionBoolean)
CommandTypeFloat CommandOptionType = CommandOptionType(discordgo.ApplicationCommandOptionNumber)
)
type ChatCommandConfiguration struct {
Description string
EphemeralResponse bool
Options map[string]ChatCommandOption
}
type ChatCommandOption struct {
Description string
Type CommandOptionType
Required bool
}

View File

@ -1,19 +0,0 @@
package common
import (
"time"
)
// Event represents a calendar event
type Event struct {
Name string
ID string
Location string
Completed bool
DateTime time.Time
CompleteDateTime time.Time
Description string
ImageURL string
Organizer User
}

View File

@ -1,11 +0,0 @@
package common
type ExternalChatManager interface {
SendMessage(user string, message string)
}
type ExternalChatModule interface {
Initialize(ExternalChatManager)
RecieveMessage(user User, message string)
}

View File

@ -1,29 +0,0 @@
package common
type Module interface {
Initialize(birdbot ModuleManager) error
}
// ModuleManager is the primary way for a module to interact with BirdBot
// by listening to events and committing actions
type ModuleManager interface {
OnReady(func() error) error
OnNotify(func(string) error) error
// Event events
OnEventCreate(func(Event) error) error
OnEventDelete(func(Event) error) error
OnEventUpdate(func(Event) error) error
OnEventComplete(func(Event) error) error
// Actions
CreateEvent(event Event) error
Notify(message string) error
// Commands
RegisterCommand(string, ChatCommandConfiguration, func(User, map[string]any) string)
// Submodules
RegisterExternalChat(channelID string, chat ExternalChatModule) error
}

View File

@ -1,19 +0,0 @@
package common
import "fmt"
// User represents a user within BirdBot
type User struct {
ID string
AvatarURL string
DisplayName string
}
// DiscordMention generated a Discord mention string for the user
func (user *User) DiscordMention() string {
if user == nil {
return "<NULL>"
}
return fmt.Sprintf("<@%s>", user.ID)
}

View File

@ -6,7 +6,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/yeslayla/birdbot/common" "github.com/yeslayla/birdbot-common/common"
) )
type Channel struct { type Channel struct {

View File

@ -21,6 +21,8 @@ type DiscordConfig struct {
NotificationChannel string `yaml:"notification_channel" env:"DISCORD_NOTIFICATION_CHANNEL"` NotificationChannel string `yaml:"notification_channel" env:"DISCORD_NOTIFICATION_CHANNEL"`
RoleSelections []RoleSelectionConfig `yaml:"role_selection"` RoleSelections []RoleSelectionConfig `yaml:"role_selection"`
ChatLinks map[string][]string `yaml:"chat_links"`
} }
type Feedback struct { type Feedback struct {

View File

@ -4,7 +4,7 @@ import (
"log" "log"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"github.com/yeslayla/birdbot/common" "github.com/yeslayla/birdbot-common/common"
) )
// RegisterCommand creates an new command that can be used to interact with bird bot // RegisterCommand creates an new command that can be used to interact with bird bot

View File

@ -2,7 +2,7 @@ package discord
import ( import (
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"github.com/yeslayla/birdbot/common" "github.com/yeslayla/birdbot-common/common"
) )
type Button struct { type Button struct {

View File

@ -8,7 +8,7 @@ import (
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"github.com/stretchr/testify/mock" "github.com/stretchr/testify/mock"
"github.com/yeslayla/birdbot/common" "github.com/yeslayla/birdbot-common/common"
"github.com/yeslayla/birdbot/persistence" "github.com/yeslayla/birdbot/persistence"
) )
@ -125,7 +125,7 @@ func (discord *Discord) OnEventUpdate(handler func(*Discord, common.Event)) {
// OnMessageRecieved registers a handler when a message is recieved // OnMessageRecieved registers a handler when a message is recieved
func (discord *Discord) OnMessageRecieved(handler func(*Discord, string, common.User, string)) { func (discord *Discord) OnMessageRecieved(handler func(*Discord, string, common.User, string)) {
discord.session.AddHandler(func(s *discordgo.Session, r *discordgo.MessageCreate) { discord.session.AddHandler(func(s *discordgo.Session, r *discordgo.MessageCreate) {
if r.GuildID != discord.guildID { if r.GuildID != discord.guildID || r.Author.Bot {
return return
} }

View File

@ -4,7 +4,7 @@ import (
"time" "time"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"github.com/yeslayla/birdbot/common" "github.com/yeslayla/birdbot-common/common"
"github.com/yeslayla/birdbot/core" "github.com/yeslayla/birdbot/core"
) )

View File

@ -4,7 +4,7 @@ import (
"log" "log"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"github.com/yeslayla/birdbot/common" "github.com/yeslayla/birdbot-common/common"
) )
// NewUser creates a new user object from a discordgo.User object // NewUser creates a new user object from a discordgo.User object

1
go.mod
View File

@ -21,6 +21,7 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/objx v0.5.0 // indirect github.com/stretchr/objx v0.5.0 // indirect
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect
github.com/yeslayla/birdbot-common v0.1.0 // indirect
golang.org/x/crypto v0.10.0 // indirect golang.org/x/crypto v0.10.0 // indirect
golang.org/x/sys v0.9.0 // indirect golang.org/x/sys v0.9.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect

6
go.sum
View File

@ -394,6 +394,12 @@ github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFy
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yeslayla/birdbot-common v0.0.0-20230619031144-7238d1b18f76 h1:lfZb/m0Ckc6FiAiCSAlJ/6coyx3CkEnnHZXhPLWqQa4=
github.com/yeslayla/birdbot-common v0.0.0-20230619031144-7238d1b18f76/go.mod h1:zyvQi9lqnd8tKudJW75FRyBONnAa2JwYk43vLECJqO0=
github.com/yeslayla/birdbot-common v0.0.0-20230619053929-5d690affa770 h1:tKCGApCuP7j8VrkZkq8XnN2nFFN/o/IuiRojTCaqpRo=
github.com/yeslayla/birdbot-common v0.0.0-20230619053929-5d690affa770/go.mod h1:zyvQi9lqnd8tKudJW75FRyBONnAa2JwYk43vLECJqO0=
github.com/yeslayla/birdbot-common v0.1.0 h1:Ozj9E8CP50iBqMviEpHxpKwdyCr7jkBMQonncHRvnqM=
github.com/yeslayla/birdbot-common v0.1.0/go.mod h1:zyvQi9lqnd8tKudJW75FRyBONnAa2JwYk43vLECJqO0=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=

View File

@ -65,7 +65,7 @@ func main() {
log.Fatal("Failed to initialize: ", err) log.Fatal("Failed to initialize: ", err)
} }
loader := app.NewComponentLoader(bot) loader := app.NewComponentLoader(bot, configDir)
if cfg.Features.AnnounceEvents.IsEnabledByDefault() { if cfg.Features.AnnounceEvents.IsEnabledByDefault() {
loader.LoadComponent(modules.NewAnnounceEventsComponent(bot.Mastodon, cfg.Discord.NotificationChannel)) loader.LoadComponent(modules.NewAnnounceEventsComponent(bot.Mastodon, cfg.Discord.NotificationChannel))

View File

@ -3,7 +3,7 @@ package modules
import ( import (
"fmt" "fmt"
"github.com/yeslayla/birdbot/common" "github.com/yeslayla/birdbot-common/common"
"github.com/yeslayla/birdbot/mastodon" "github.com/yeslayla/birdbot/mastodon"
) )

View File

@ -8,7 +8,7 @@ import (
"log" "log"
"net/http" "net/http"
"github.com/yeslayla/birdbot/common" "github.com/yeslayla/birdbot-common/common"
) )
type feedbackWebhookModule struct { type feedbackWebhookModule struct {

View File

@ -3,7 +3,7 @@ package modules
import ( import (
"log" "log"
"github.com/yeslayla/birdbot/common" "github.com/yeslayla/birdbot-common/common"
"github.com/yeslayla/birdbot/core" "github.com/yeslayla/birdbot/core"
"github.com/yeslayla/birdbot/discord" "github.com/yeslayla/birdbot/discord"
) )

View File

@ -4,7 +4,7 @@ import (
"log" "log"
"strings" "strings"
"github.com/yeslayla/birdbot/common" "github.com/yeslayla/birdbot-common/common"
"github.com/yeslayla/birdbot/discord" "github.com/yeslayla/birdbot/discord"
) )

View File

@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"log" "log"
"github.com/yeslayla/birdbot/common" "github.com/yeslayla/birdbot-common/common"
"github.com/yeslayla/birdbot/core" "github.com/yeslayla/birdbot/core"
"github.com/yeslayla/birdbot/discord" "github.com/yeslayla/birdbot/discord"
"github.com/yeslayla/birdbot/persistence" "github.com/yeslayla/birdbot/persistence"

View File

@ -140,7 +140,7 @@ func (db *Sqlite3Database) GetDiscordWebhook(id string) (*DBDiscordWebhook, erro
// SetDiscordWebhook stores a discord webhook based on a given local id // SetDiscordWebhook stores a discord webhook based on a given local id
func (db *Sqlite3Database) SetDiscordWebhook(id string, data *DBDiscordWebhook) error { func (db *Sqlite3Database) SetDiscordWebhook(id string, data *DBDiscordWebhook) error {
statement, err := db.db.Prepare("INSERT OR IGNORE INTO discord_webhooks (id, webhook_id, webhook_token) VALUES (?, ?)") statement, err := db.db.Prepare("INSERT OR IGNORE INTO discord_webhooks (id, webhook_id, webhook_token) VALUES (?, ?, ?)")
if err != nil { if err != nil {
return err return err
} }