Plugins, Bugfixes & Cleanup
This commit is contained in:
		@ -1,20 +1,2 @@
 | 
				
			|||||||
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/go/.devcontainer/base.Dockerfile
 | 
					ARG VARIANT="1.20-bullseye"
 | 
				
			||||||
 | 
					 | 
				
			||||||
# [Choice] Go version (use -bullseye variants on local arm64/Apple Silicon): 1, 1.19, 1.18, 1-bullseye, 1.19-bullseye, 1.18-bullseye, 1-buster, 1.19-buster, 1.18-buster
 | 
					 | 
				
			||||||
ARG VARIANT="1.19-bullseye"
 | 
					 | 
				
			||||||
FROM mcr.microsoft.com/vscode/devcontainers/go:0-${VARIANT}
 | 
					FROM mcr.microsoft.com/vscode/devcontainers/go:0-${VARIANT}
 | 
				
			||||||
 | 
					 | 
				
			||||||
# [Choice] Node.js version: none, lts/*, 18, 16, 14
 | 
					 | 
				
			||||||
ARG NODE_VERSION="none"
 | 
					 | 
				
			||||||
RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# [Optional] Uncomment this section to install additional OS packages.
 | 
					 | 
				
			||||||
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
 | 
					 | 
				
			||||||
#     && apt-get -y install --no-install-recommends <your-package-list-here>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# [Optional] Uncomment the next lines to use go get to install anything else you need
 | 
					 | 
				
			||||||
# USER vscode
 | 
					 | 
				
			||||||
# RUN go get -x <your-dependency-or-tool>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# [Optional] Uncomment this line to install global node packages.
 | 
					 | 
				
			||||||
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,25 +1,12 @@
 | 
				
			|||||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
 | 
					 | 
				
			||||||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/go
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	"name": "Go",
 | 
						"name": "Go",
 | 
				
			||||||
	"build": {
 | 
						"build": {
 | 
				
			||||||
		"dockerfile": "Dockerfile",
 | 
							"dockerfile": "Dockerfile"
 | 
				
			||||||
		"args": {
 | 
					 | 
				
			||||||
			// Update the VARIANT arg to pick a version of Go: 1, 1.19, 1.18
 | 
					 | 
				
			||||||
			// Append -bullseye or -buster to pin to an OS version.
 | 
					 | 
				
			||||||
			// Use -bullseye variants on local arm64/Apple Silicon.
 | 
					 | 
				
			||||||
			"VARIANT": "1.19-bullseye",
 | 
					 | 
				
			||||||
			// Options
 | 
					 | 
				
			||||||
			"NODE_VERSION": "none"
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	"runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ],
 | 
						"runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Configure tool-specific properties.
 | 
					 | 
				
			||||||
	"customizations": {
 | 
						"customizations": {
 | 
				
			||||||
		// Configure properties specific to VS Code.
 | 
					 | 
				
			||||||
		"vscode": {
 | 
							"vscode": {
 | 
				
			||||||
			// Set *default* container specific settings.json values on container create.
 | 
					 | 
				
			||||||
			"settings": { 
 | 
								"settings": { 
 | 
				
			||||||
				"go.toolsManagement.checkForUpdates": "local",
 | 
									"go.toolsManagement.checkForUpdates": "local",
 | 
				
			||||||
				"go.useLanguageServer": true,
 | 
									"go.useLanguageServer": true,
 | 
				
			||||||
@ -33,15 +20,9 @@
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Use 'forwardPorts' to make a list of ports inside the container available locally.
 | 
					 | 
				
			||||||
	// "forwardPorts": [],
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Use 'postCreateCommand' to run commands after the container is created.
 | 
					 | 
				
			||||||
	// "postCreateCommand": "go version",
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
 | 
					 | 
				
			||||||
	"remoteUser": "vscode",
 | 
						"remoteUser": "vscode",
 | 
				
			||||||
	"features": {
 | 
						"features": {
 | 
				
			||||||
		"git": "os-provided"
 | 
							"git": "os-provided",
 | 
				
			||||||
 | 
							"ghcr.io/guiyomh/features/mage:0": "latest"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							@ -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)
 | 
				
			||||||
	@GOOS=linux CGO_ENABLED=0 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)
 | 
						@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:
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										59
									
								
								app/plugin_loader.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								app/plugin_loader.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					package app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"plugin"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/yeslayla/birdbot/common"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type PluginLoader struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewPluginLoader() PluginLoader {
 | 
				
			||||||
 | 
						return PluginLoader{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (loader PluginLoader) LoadPlugin(pluginPath string) common.Component {
 | 
				
			||||||
 | 
						plug, err := plugin.Open(pluginPath)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Printf("Failed to load plugin '%s': %s", pluginPath, err)
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sym, err := plug.Lookup("Component")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Printf("Failed to load plugin '%s': failed to get Component: %s", pluginPath, err)
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var component common.Component
 | 
				
			||||||
 | 
						component, ok := sym.(common.Component)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							log.Printf("Failed to load plugin '%s': Plugin component does not properly implement interface!", pluginPath)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return component
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (loader PluginLoader) LoadPlugins(directory string) []common.Component {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						paths, err := os.ReadDir(directory)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Printf("Failed to load plugins: %s", err)
 | 
				
			||||||
 | 
							return []common.Component{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var components []common.Component = make([]common.Component, 0)
 | 
				
			||||||
 | 
						for _, path := range paths {
 | 
				
			||||||
 | 
							if path.IsDir() {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if comp := loader.LoadPlugin(path.Name()); comp != nil {
 | 
				
			||||||
 | 
								components = append(components, comp)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return components
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,5 +1,7 @@
 | 
				
			|||||||
package core
 | 
					package core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Config struct {
 | 
					type Config struct {
 | 
				
			||||||
	Discord  DiscordConfig  `yaml:"discord"`
 | 
						Discord  DiscordConfig  `yaml:"discord"`
 | 
				
			||||||
	Mastodon MastodonConfig `yaml:"mastodon"`
 | 
						Mastodon MastodonConfig `yaml:"mastodon"`
 | 
				
			||||||
@ -24,8 +26,22 @@ type MastodonConfig struct {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Features struct {
 | 
					type Features struct {
 | 
				
			||||||
	ManageEventChannels bool `yaml:"manage_event_channels" env:"BIRD_EVENT_CHANNELS" env-default:"true"`
 | 
						ManageEventChannels Feature `yaml:"manage_event_channels" env:"BIRD_EVENT_CHANNELS"`
 | 
				
			||||||
	AnnounceEvents      bool `yaml:"announce_events" env:"BIRD_ANNOUNCE_EVENTS" env-default:"true"`
 | 
						AnnounceEvents      Feature `yaml:"announce_events" env:"BIRD_ANNOUNCE_EVENTS"`
 | 
				
			||||||
	ReccurringEvents    bool `yaml:"recurring_events" env:"BIRD_RECURRING_EVENTS" env-default:"true"`
 | 
						ReccurringEvents    Feature `yaml:"recurring_events" env:"BIRD_RECURRING_EVENTS"`
 | 
				
			||||||
	LoadGamePlugins     bool `yaml:"load_game_plugins" env:"BIRD_LOAD_GAME_PLUGINS" env-default:"true"`
 | 
						LoadGamePlugins     Feature `yaml:"load_game_plugins" env:"BIRD_LOAD_GAME_PLUGINS"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Feature string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (value Feature) IsEnabled() bool {
 | 
				
			||||||
 | 
						return strings.ToLower(string(value)) == "true"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (value Feature) IsEnabledByDefault() bool {
 | 
				
			||||||
 | 
						v := strings.ToLower(string(value))
 | 
				
			||||||
 | 
						if v == "" {
 | 
				
			||||||
 | 
							v = "true"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return Feature(v).IsEnabled()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -24,6 +24,7 @@ func (c *AnnounceEventsComponent) Initialize(birdbot common.ComponentManager) er
 | 
				
			|||||||
	c.bot = birdbot
 | 
						c.bot = birdbot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_ = birdbot.OnEventCreate(c.OnEventCreate)
 | 
						_ = birdbot.OnEventCreate(c.OnEventCreate)
 | 
				
			||||||
 | 
						_ = birdbot.OnEventDelete(c.OnEventDelete)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -11,12 +11,14 @@ import (
 | 
				
			|||||||
type ManageEventChannelsComponent struct {
 | 
					type ManageEventChannelsComponent struct {
 | 
				
			||||||
	session           *discord.Discord
 | 
						session           *discord.Discord
 | 
				
			||||||
	categoryID        string
 | 
						categoryID        string
 | 
				
			||||||
 | 
						archiveCategoryID string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewManageEventChannelsComponent(categoryID string, session *discord.Discord) *ManageEventChannelsComponent {
 | 
					func NewManageEventChannelsComponent(categoryID string, archiveCategoryID string, session *discord.Discord) *ManageEventChannelsComponent {
 | 
				
			||||||
	return &ManageEventChannelsComponent{
 | 
						return &ManageEventChannelsComponent{
 | 
				
			||||||
		session:           session,
 | 
							session:           session,
 | 
				
			||||||
		categoryID:        categoryID,
 | 
							categoryID:        categoryID,
 | 
				
			||||||
 | 
							archiveCategoryID: archiveCategoryID,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -54,9 +56,9 @@ func (c *ManageEventChannelsComponent) OnEventDelete(e common.Event) error {
 | 
				
			|||||||
func (c *ManageEventChannelsComponent) OnEventComplete(e common.Event) error {
 | 
					func (c *ManageEventChannelsComponent) OnEventComplete(e common.Event) error {
 | 
				
			||||||
	channel := core.GenerateChannel(e)
 | 
						channel := core.GenerateChannel(e)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if c.categoryID != "" {
 | 
						if c.archiveCategoryID != "" {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := c.session.MoveChannelToCategory(channel, c.categoryID); err != nil {
 | 
							if err := c.session.MoveChannelToCategory(channel, c.archiveCategoryID); err != nil {
 | 
				
			||||||
			log.Print("Failed to move channel to archive category: ", err)
 | 
								log.Print("Failed to move channel to archive category: ", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										3
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								go.mod
									
									
									
									
									
								
							@ -1,6 +1,6 @@
 | 
				
			|||||||
module github.com/yeslayla/birdbot
 | 
					module github.com/yeslayla/birdbot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
go 1.19
 | 
					go 1.20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require (
 | 
					require (
 | 
				
			||||||
	github.com/bwmarrin/discordgo v0.26.1
 | 
						github.com/bwmarrin/discordgo v0.26.1
 | 
				
			||||||
@ -13,6 +13,7 @@ require (
 | 
				
			|||||||
	github.com/davecgh/go-spew v1.1.1 // indirect
 | 
						github.com/davecgh/go-spew v1.1.1 // indirect
 | 
				
			||||||
	github.com/gorilla/websocket v1.5.0 // indirect
 | 
						github.com/gorilla/websocket v1.5.0 // indirect
 | 
				
			||||||
	github.com/joho/godotenv v1.4.0 // indirect
 | 
						github.com/joho/godotenv v1.4.0 // indirect
 | 
				
			||||||
 | 
						github.com/magefile/mage v1.14.0 // indirect
 | 
				
			||||||
	github.com/mattn/go-mastodon v0.0.5 // indirect
 | 
						github.com/mattn/go-mastodon v0.0.5 // indirect
 | 
				
			||||||
	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
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							@ -14,6 +14,8 @@ github.com/ilyakaznacheev/cleanenv v1.4.0 h1:Gvwxt6wAPUo9OOxyp5Xz9eqhLsAey4AtbCF
 | 
				
			|||||||
github.com/ilyakaznacheev/cleanenv v1.4.0/go.mod h1:i0owW+HDxeGKE0/JPREJOdSCPIyOnmh6C0xhWAkF/xA=
 | 
					github.com/ilyakaznacheev/cleanenv v1.4.0/go.mod h1:i0owW+HDxeGKE0/JPREJOdSCPIyOnmh6C0xhWAkF/xA=
 | 
				
			||||||
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
 | 
					github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
 | 
				
			||||||
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
 | 
					github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
 | 
				
			||||||
 | 
					github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
 | 
				
			||||||
 | 
					github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
 | 
				
			||||||
github.com/mattn/go-mastodon v0.0.5 h1:P0e1/R2v3ho6kM7BUW0noQm8gAqHE0p8Gq1TMapIVAc=
 | 
					github.com/mattn/go-mastodon v0.0.5 h1:P0e1/R2v3ho6kM7BUW0noQm8gAqHE0p8Gq1TMapIVAc=
 | 
				
			||||||
github.com/mattn/go-mastodon v0.0.5/go.mod h1:cg7RFk2pcUfHZw/IvKe1FUzmlq5KnLFqs7eV2PHplV8=
 | 
					github.com/mattn/go-mastodon v0.0.5/go.mod h1:cg7RFk2pcUfHZw/IvKe1FUzmlq5KnLFqs7eV2PHplV8=
 | 
				
			||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 | 
					github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										18
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								main.go
									
									
									
									
									
								
							@ -14,6 +14,8 @@ import (
 | 
				
			|||||||
	"github.com/yeslayla/birdbot/events"
 | 
						"github.com/yeslayla/birdbot/events"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const PluginsDirectory = "./plugins"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	configDir, _ := os.UserConfigDir()
 | 
						configDir, _ := os.UserConfigDir()
 | 
				
			||||||
@ -56,16 +58,24 @@ func main() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	loader := app.NewComponentLoader(bot)
 | 
						loader := app.NewComponentLoader(bot)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if cfg.Features.AnnounceEvents {
 | 
						if cfg.Features.AnnounceEvents.IsEnabledByDefault() {
 | 
				
			||||||
		loader.LoadComponent(events.NewAnnounceEventsComponent(bot.Mastodon, cfg.Discord.NotificationChannel))
 | 
							loader.LoadComponent(events.NewAnnounceEventsComponent(bot.Mastodon, cfg.Discord.NotificationChannel))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if cfg.Features.ManageEventChannels {
 | 
						if cfg.Features.ManageEventChannels.IsEnabledByDefault() {
 | 
				
			||||||
		loader.LoadComponent(events.NewManageEventChannelsComponent(cfg.Discord.EventCategory, bot.Session))
 | 
							loader.LoadComponent(events.NewManageEventChannelsComponent(cfg.Discord.EventCategory, cfg.Discord.ArchiveCategory, bot.Session))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if cfg.Features.ReccurringEvents {
 | 
						if cfg.Features.ReccurringEvents.IsEnabledByDefault() {
 | 
				
			||||||
		loader.LoadComponent(events.NewRecurringEventsComponent())
 | 
							loader.LoadComponent(events.NewRecurringEventsComponent())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, err := os.Stat(PluginsDirectory); !os.IsNotExist(err) {
 | 
				
			||||||
 | 
							pluginLoader := app.NewPluginLoader()
 | 
				
			||||||
 | 
							components := pluginLoader.LoadPlugins(PluginsDirectory)
 | 
				
			||||||
 | 
							for _, comp := range components {
 | 
				
			||||||
 | 
								loader.LoadComponent(comp)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := bot.Run(); err != nil {
 | 
						if err := bot.Run(); err != nil {
 | 
				
			||||||
		log.Fatal(err)
 | 
							log.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user