I believe it's all working
This commit is contained in:
parent
de126011c4
commit
ff58d1ddf4
25
app/app.go
25
app/app.go
@ -2,9 +2,9 @@ package app
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
|
|
||||||
"git.bullercodeworks.com/brian/helperbot/models"
|
"git.bullercodeworks.com/brian/helperbot/models"
|
||||||
|
"git.bullercodeworks.com/brian/helperbot/plugins"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ type App struct {
|
|||||||
|
|
||||||
m *models.BotModel
|
m *models.BotModel
|
||||||
|
|
||||||
plugins []HelperPlugin
|
plugins []models.PluginState
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewApp(debugMode bool) (*App, error) {
|
func NewApp(debugMode bool) (*App, error) {
|
||||||
@ -29,6 +29,7 @@ func NewApp(debugMode bool) (*App, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
a.Running = true
|
a.Running = true
|
||||||
|
go a.watchMessageChannel()
|
||||||
return a, err
|
return a, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,14 +56,14 @@ func (a *App) initialize() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load up the plugins
|
// Load up the plugins
|
||||||
pluginDir := a.m.GetPluginDir()
|
a.plugins = append(a.plugins, &plugins.StatsState{}, &plugins.AoCState{})
|
||||||
a.loadPluginsFromDirectory(pluginDir)
|
for _, p := range a.plugins {
|
||||||
if err != nil {
|
p.Initialize(a.m)
|
||||||
fmt.Println("Error loading plugins")
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
a.setupMessageWatchers()
|
a.setupMessageWatchers()
|
||||||
|
for _, p := range a.plugins {
|
||||||
|
p.Run()
|
||||||
|
}
|
||||||
|
|
||||||
a.m.SendSlackAdminMessage(":robot_face: Helperbot Initialized :robot_face:")
|
a.m.SendSlackAdminMessage(":robot_face: Helperbot Initialized :robot_face:")
|
||||||
return err
|
return err
|
||||||
@ -71,9 +72,10 @@ func (a *App) initialize() error {
|
|||||||
func (a *App) SendQuitMessage() { a.m.SendMessage(models.QuitMessage) }
|
func (a *App) SendQuitMessage() { a.m.SendMessage(models.QuitMessage) }
|
||||||
|
|
||||||
func (a *App) setupMessageWatchers() {
|
func (a *App) setupMessageWatchers() {
|
||||||
a.m.AddMessageWatcher(func(msg models.BotMessage) bool {
|
a.m.AddMessageWatcher("main", func(msg models.BotMessage) bool {
|
||||||
if msg.Is(models.QuitMessage) {
|
if msg.Is(models.QuitMessage) {
|
||||||
// App is shutting down
|
// App is shutting down
|
||||||
|
fmt.Println("Received QuitMessage")
|
||||||
a.Running = false
|
a.Running = false
|
||||||
} else if msg.IsError() {
|
} else if msg.IsError() {
|
||||||
// Received an Error Message
|
// Received an Error Message
|
||||||
@ -87,8 +89,9 @@ func (a *App) setupMessageWatchers() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
for _, v := range a.plugins {
|
for _, v := range a.plugins {
|
||||||
a.m.AddMessageWatcher(v.State.ProcessMessage)
|
fmt.Println("Setting up watchers for", v.Name())
|
||||||
a.m.AddRTMWatcher(v.State.ProcessRTMEvent)
|
a.m.AddMessageWatcher(fmt.Sprintf("plugin-%s", v.Name()), v.ProcessMessage)
|
||||||
|
a.m.AddRTMWatcher(fmt.Sprintf("plugin-%s", v.Name()), v.ProcessRTMEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"plugin"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"git.bullercodeworks.com/brian/helperbot/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HelperPlugin struct {
|
|
||||||
p *plugin.Plugin
|
|
||||||
State models.PluginState
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) loadPluginsFromDirectory(dir string) error {
|
|
||||||
fmt.Println("Loading Plugins (", dir, ")")
|
|
||||||
files, err := ioutil.ReadDir(dir)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error loading plugins")
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
for _, f := range files {
|
|
||||||
if !strings.HasSuffix(f.Name(), ".so") {
|
|
||||||
fmt.Printf("Skipping file (%s)\n", f.Name())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
p, err := plugin.Open(dir + f.Name())
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(fmt.Sprintf("Error loading plugin (%s)\n", f.Name()))
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
hp, err := NewHelperPlugin(p)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(fmt.Sprintf("Error loading plugin (%s)\n", f.Name()))
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
hp.State.Initialize(a.m)
|
|
||||||
hp.State.Run()
|
|
||||||
fmt.Printf("Plugin Loaded (%s)\n", f.Name())
|
|
||||||
a.plugins = append(a.plugins, *hp)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHelperPlugin(p *plugin.Plugin) (*HelperPlugin, error) {
|
|
||||||
h := &HelperPlugin{p: p}
|
|
||||||
|
|
||||||
// Parse the plugin's state
|
|
||||||
pluginStateSymbol, err := p.Lookup("State")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
h.State = pluginStateSymbol.(models.PluginState)
|
|
||||||
return h, nil
|
|
||||||
}
|
|
@ -1,6 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright © 2023 Brian Buller <brian@bullercodeworks.com>
|
Copyright © 2023 Brian Buller <brian@bullercodeworks.com>
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
@ -13,7 +12,6 @@ import (
|
|||||||
|
|
||||||
"git.bullercodeworks.com/brian/helperbot/app"
|
"git.bullercodeworks.com/brian/helperbot/app"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var debug = false
|
var debug = false
|
||||||
@ -38,6 +36,7 @@ var rootCmd = &cobra.Command{
|
|||||||
// Save the changes when the app quits
|
// Save the changes when the app quits
|
||||||
fmt.Println("\nFinishing up...")
|
fmt.Println("\nFinishing up...")
|
||||||
a.SendQuitMessage()
|
a.SendQuitMessage()
|
||||||
|
a.Running = false
|
||||||
}()
|
}()
|
||||||
for a.Running {
|
for a.Running {
|
||||||
time.Sleep(time.Second * 1)
|
time.Sleep(time.Second * 1)
|
||||||
@ -58,5 +57,4 @@ func Execute() {
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.Flags().BoolVarP(&debug, "debug", "d", false, "Debug mode")
|
rootCmd.Flags().BoolVarP(&debug, "debug", "d", false, "Debug mode")
|
||||||
viper.SetDefault("plugin_dir", "plugins")
|
|
||||||
}
|
}
|
||||||
|
3
go.mod
3
go.mod
@ -2,6 +2,8 @@ module git.bullercodeworks.com/brian/helperbot
|
|||||||
|
|
||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
|
replace git.bullercodeworks.com/brian/boltease => ../boltease
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.bullercodeworks.com/brian/boltease v1.0.0
|
git.bullercodeworks.com/brian/boltease v1.0.0
|
||||||
github.com/slack-go/slack v0.12.3
|
github.com/slack-go/slack v0.12.3
|
||||||
@ -10,6 +12,7 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
git.bullercodeworks.com/brian/go-adventofcode v1.1.1 // indirect
|
||||||
github.com/boltdb/bolt v1.3.1 // indirect
|
github.com/boltdb/bolt v1.3.1 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||||
github.com/gorilla/websocket v1.4.2 // indirect
|
github.com/gorilla/websocket v1.4.2 // indirect
|
||||||
|
2
go.sum
2
go.sum
@ -38,6 +38,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
|
|||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
git.bullercodeworks.com/brian/boltease v1.0.0 h1:kSCdJi+qfnPwdCP2oNUfQ6P4JKWaSWoh10Mx51uuD+Y=
|
git.bullercodeworks.com/brian/boltease v1.0.0 h1:kSCdJi+qfnPwdCP2oNUfQ6P4JKWaSWoh10Mx51uuD+Y=
|
||||||
git.bullercodeworks.com/brian/boltease v1.0.0/go.mod h1:3EuVzLDHy1zrjBEYc7RsaBohUzYrH1bx2aKM2Fk6t98=
|
git.bullercodeworks.com/brian/boltease v1.0.0/go.mod h1:3EuVzLDHy1zrjBEYc7RsaBohUzYrH1bx2aKM2Fk6t98=
|
||||||
|
git.bullercodeworks.com/brian/go-adventofcode v1.1.1 h1:5pp9bPVpTKdErkEcIAqoyuMsvmpQkO8upJ+NUQ+MUv0=
|
||||||
|
git.bullercodeworks.com/brian/go-adventofcode v1.1.1/go.mod h1:h/W8Nm8zsrVSjnoA6BRlf38LbaXHR/m6dIq804LOO3w=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
|
github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
package helperbot
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.bullercodeworks.com/brian/helperbot/models"
|
|
||||||
"github.com/slack-go/slack"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Model interface {
|
|
||||||
SendMessage(msg models.BotMessage)
|
|
||||||
GetSlackAdminDMId() string
|
|
||||||
GetSlackLatency() time.Duration
|
|
||||||
GetBytes(path []string) ([]byte, error)
|
|
||||||
SetBytes(path []string, val []byte) error
|
|
||||||
GetString(path []string) (string, error)
|
|
||||||
SetString(path []string, val string) error
|
|
||||||
GetInt(path []string) (int, error)
|
|
||||||
SetInt(path []string, val int) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type Message interface {
|
|
||||||
GetSource() string
|
|
||||||
GetDestination() string
|
|
||||||
GetType() string
|
|
||||||
GetTarget() string
|
|
||||||
GetText() string
|
|
||||||
}
|
|
||||||
|
|
||||||
type PluginState interface {
|
|
||||||
Name() string
|
|
||||||
Initialize(Model) error
|
|
||||||
ProcessMessage(models.BotMessage) bool
|
|
||||||
ProcessRTMEvent(*slack.RTMEvent) bool
|
|
||||||
Run()
|
|
||||||
Exit()
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/slack-go/slack"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Model interface {
|
|
||||||
SendMessage(msg BotMessage)
|
|
||||||
GetSlackAdminDMId() string
|
|
||||||
GetSlackLatency() time.Duration
|
|
||||||
GetBytes(path []string) ([]byte, error)
|
|
||||||
SetBytes(path []string, val []byte) error
|
|
||||||
GetString(path []string) (string, error)
|
|
||||||
SetString(path []string, val string) error
|
|
||||||
GetInt(path []string) (int, error)
|
|
||||||
SetInt(path []string, val int) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type Message interface {
|
|
||||||
GetSource() string
|
|
||||||
GetDestination() string
|
|
||||||
GetType() string
|
|
||||||
GetTarget() string
|
|
||||||
GetText() string
|
|
||||||
}
|
|
||||||
|
|
||||||
type PluginState interface {
|
|
||||||
Name() string
|
|
||||||
Initialize(Model) error
|
|
||||||
ProcessMessage(BotMessage) bool
|
|
||||||
ProcessRTMEvent(*slack.RTMEvent) bool
|
|
||||||
Run()
|
|
||||||
Exit()
|
|
||||||
}
|
|
@ -9,6 +9,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
MsgSrcApp = "app"
|
MsgSrcApp = "app"
|
||||||
MsgSrcSlack = "slack"
|
MsgSrcSlack = "slack"
|
||||||
|
MsgTpStatus = "status"
|
||||||
MsgTpControl = "control"
|
MsgTpControl = "control"
|
||||||
MsgTpError = "error"
|
MsgTpError = "error"
|
||||||
MsgTpMessage = "message"
|
MsgTpMessage = "message"
|
||||||
|
@ -22,8 +22,8 @@ type BotModel struct {
|
|||||||
incomingSlackMessages chan *slack.MessageEvent
|
incomingSlackMessages chan *slack.MessageEvent
|
||||||
otherRTMEvents chan *slack.RTMEvent
|
otherRTMEvents chan *slack.RTMEvent
|
||||||
|
|
||||||
messageWatchers []func(msg BotMessage) bool
|
messageWatchers map[string]func(msg BotMessage) bool
|
||||||
rtmWatchers []func(event *slack.RTMEvent) bool
|
rtmWatchers map[string]func(event *slack.RTMEvent) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBotModel(debug bool) (*BotModel, error) {
|
func NewBotModel(debug bool) (*BotModel, error) {
|
||||||
@ -31,9 +31,10 @@ func NewBotModel(debug bool) (*BotModel, error) {
|
|||||||
m := new(BotModel)
|
m := new(BotModel)
|
||||||
m.debug = debug
|
m.debug = debug
|
||||||
m.messages = make(chan BotMessage, 100)
|
m.messages = make(chan BotMessage, 100)
|
||||||
m.messageWatchers = make([]func(msg BotMessage) bool, 1)
|
m.messageWatchers = make(map[string]func(msg BotMessage) bool)
|
||||||
m.AddMessageWatcher(m.DebugMessageWatcher)
|
m.rtmWatchers = make(map[string]func(even *slack.RTMEvent) bool)
|
||||||
m.AddRTMWatcher(m.DebugRTMWatcher)
|
m.AddMessageWatcher("debug", m.DebugMessageWatcher)
|
||||||
|
m.AddRTMWatcher("debug", m.DebugRTMWatcher)
|
||||||
m.db, err = boltease.Create("helperbot.db", 0600, nil)
|
m.db, err = boltease.Create("helperbot.db", 0600, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -63,26 +64,32 @@ func (m *BotModel) SendMessage(msg BotMessage) {
|
|||||||
m.messages <- msg
|
m.messages <- msg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *BotModel) AddMessageWatcher(watcher func(msg BotMessage) bool) {
|
func (m *BotModel) AddMessageWatcher(name string, watcher func(msg BotMessage) bool) {
|
||||||
m.messageWatchers = append(m.messageWatchers, watcher)
|
m.messageWatchers[name] = watcher
|
||||||
}
|
}
|
||||||
func (m *BotModel) AddRTMWatcher(watcher func(event *slack.RTMEvent) bool) {
|
func (m *BotModel) AddRTMWatcher(name string, watcher func(event *slack.RTMEvent) bool) {
|
||||||
m.rtmWatchers = append(m.rtmWatchers, watcher)
|
m.rtmWatchers[name] = watcher
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *BotModel) ProcessMessageChannel() {
|
func (m *BotModel) ProcessMessageChannel() {
|
||||||
|
fmt.Println(">> ProcessMessageChannel")
|
||||||
msg := <-m.messages
|
msg := <-m.messages
|
||||||
for _, v := range m.messageWatchers {
|
fmt.Println(">>>> Received Message", msg)
|
||||||
|
for k, v := range m.messageWatchers {
|
||||||
|
fmt.Printf(">>>> Message Watcher [%s]\n", k)
|
||||||
// Pass the message to the watcher
|
// Pass the message to the watcher
|
||||||
if v(msg) {
|
if v != nil && v(msg) {
|
||||||
// if a watcher returns true, the message was consumed
|
// if a watcher returns true, the message was consumed
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (m *BotModel) ProcessRTMChannel() {
|
func (m *BotModel) ProcessRTMChannel() {
|
||||||
|
fmt.Println(">> ProcessRTMChannel")
|
||||||
msg := <-m.otherRTMEvents
|
msg := <-m.otherRTMEvents
|
||||||
for _, v := range m.rtmWatchers {
|
fmt.Println(">>>> Received Message", msg)
|
||||||
|
for k, v := range m.rtmWatchers {
|
||||||
|
fmt.Printf(">>>> RTM Watcher [%s]\n", k)
|
||||||
// Pass the event to the watcher
|
// Pass the event to the watcher
|
||||||
if v(msg) {
|
if v(msg) {
|
||||||
// if a watcher returns true, the message was consumed
|
// if a watcher returns true, the message was consumed
|
||||||
|
@ -12,13 +12,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
keyPluginDir = "plugin_dir"
|
|
||||||
keySlackToken = "slack.token"
|
keySlackToken = "slack.token"
|
||||||
keySlackAdminDmId = "slack.admin_dm_id"
|
keySlackAdminDmId = "slack.admin_dm_id"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *BotModel) GetPluginDir() string { return viper.GetString(keyPluginDir) }
|
|
||||||
|
|
||||||
/* Slack Config Functions */
|
/* Slack Config Functions */
|
||||||
func (m *BotModel) getSlackToken() string { return viper.GetString(keySlackToken) }
|
func (m *BotModel) getSlackToken() string { return viper.GetString(keySlackToken) }
|
||||||
func (m *BotModel) setSlackToken(token string) error {
|
func (m *BotModel) setSlackToken(token string) error {
|
||||||
|
14
models/plugin_model.go
Normal file
14
models/plugin_model.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/slack-go/slack"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PluginState interface {
|
||||||
|
Name() string
|
||||||
|
Initialize(*BotModel) error
|
||||||
|
ProcessMessage(BotMessage) bool
|
||||||
|
ProcessRTMEvent(*slack.RTMEvent) bool
|
||||||
|
Run()
|
||||||
|
Exit()
|
||||||
|
}
|
@ -1,8 +1,5 @@
|
|||||||
package main
|
package plugins
|
||||||
|
|
||||||
import (
|
|
||||||
"C"
|
|
||||||
)
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"errors"
|
"errors"
|
||||||
@ -14,13 +11,13 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
aoc "git.bullercodeworks.com/brian/go-adventofcode"
|
aoc "git.bullercodeworks.com/brian/go-adventofcode"
|
||||||
"git.bullercodeworks.com/brian/helperbot"
|
"git.bullercodeworks.com/brian/helperbot/models"
|
||||||
"github.com/slack-go/slack"
|
"github.com/slack-go/slack"
|
||||||
)
|
)
|
||||||
|
|
||||||
/* Plugin State */
|
/* Plugin State */
|
||||||
type AoCState struct {
|
type AoCState struct {
|
||||||
model helperbot.Model
|
model *models.BotModel
|
||||||
boardId string
|
boardId string
|
||||||
sessionCookie string
|
sessionCookie string
|
||||||
sessionNeedsUpdate bool
|
sessionNeedsUpdate bool
|
||||||
@ -29,11 +26,9 @@ type AoCState struct {
|
|||||||
lastYear int
|
lastYear int
|
||||||
}
|
}
|
||||||
|
|
||||||
var State AoCState
|
|
||||||
|
|
||||||
/* Plugin Interface Functions */
|
/* Plugin Interface Functions */
|
||||||
func (s *AoCState) Name() string { return "advent-of-code" }
|
func (s *AoCState) Name() string { return "advent-of-code" }
|
||||||
func (s *AoCState) Initialize(m helperbot.Model) error {
|
func (s *AoCState) Initialize(m *models.BotModel) error {
|
||||||
// Initialize AoC stuff
|
// Initialize AoC stuff
|
||||||
var err error
|
var err error
|
||||||
var boardId, aocSession, aocChannelId string
|
var boardId, aocSession, aocChannelId string
|
||||||
@ -65,31 +60,29 @@ func (s *AoCState) Initialize(m helperbot.Model) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AoCState) ProcessMessage(m helperbot.Message) {
|
func (s *AoCState) ProcessMessage(m models.BotMessage) bool {
|
||||||
if m.GetSource() == "slack" {
|
if m.Source == models.MsgSrcSlack {
|
||||||
slackMsg := m.GetMessage()
|
if len(m.Target) == 0 {
|
||||||
if len(slackMsg.Channel) == 0 {
|
return false
|
||||||
return
|
|
||||||
}
|
}
|
||||||
switch slackMsg.Channel[0] {
|
switch m.Target[0] {
|
||||||
case 'C', 'G':
|
case 'C', 'G':
|
||||||
s.ProcessChannelMessage(slackMsg)
|
return s.ProcessChannelMessage(m)
|
||||||
case 'D':
|
case 'D':
|
||||||
admin, err := s.model.GetSlackAdminDMId()
|
admin := s.model.GetSlackAdminDMId()
|
||||||
if err != nil {
|
if m.Target == admin {
|
||||||
s.SendAdminIdError()
|
return s.ProcessAdminDirectMessage(m)
|
||||||
return
|
|
||||||
}
|
|
||||||
if slackMsg.Channel == admin {
|
|
||||||
s.ProcessAdminDirectMessage(slackMsg)
|
|
||||||
} else {
|
} else {
|
||||||
s.ProcessDirectMessage(slackMsg)
|
return s.ProcessDirectMessage(m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AoCState) ProcessRTMEvent(msg slack.RTMEvent) {}
|
func (s *AoCState) ProcessRTMEvent(msg *slack.RTMEvent) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (s *AoCState) Run() {
|
func (s *AoCState) Run() {
|
||||||
go s.runLoop()
|
go s.runLoop()
|
||||||
@ -140,8 +133,8 @@ func (s *AoCState) runLoop() {
|
|||||||
if s.GetLatestYear() != s.lastYear {
|
if s.GetLatestYear() != s.lastYear {
|
||||||
// Latest year changed. Grab that board first.
|
// Latest year changed. Grab that board first.
|
||||||
s.lastYear = s.GetLatestYear()
|
s.lastYear = s.GetLatestYear()
|
||||||
admin, adminErr := s.model.GetSlackAdminDMId()
|
admin := s.model.GetSlackAdminDMId()
|
||||||
if adminErr != nil {
|
if admin == "" {
|
||||||
s.SendAdminIdError()
|
s.SendAdminIdError()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -156,78 +149,88 @@ func (s *AoCState) runLoop() {
|
|||||||
time.Sleep(time.Minute)
|
time.Sleep(time.Minute)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.model.SendMessage(s.Name(), "main", s.BuildMessage("status", "done", ""))
|
s.model.SendMessage(models.NewBotMessage(s.Name(), models.MsgSrcApp, "status", "done", ""))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AoCState) ProcessDirectMessage(slackMsg slack.Message) {
|
func (s *AoCState) ProcessDirectMessage(m models.BotMessage) bool {
|
||||||
msgPts := strings.Fields(slackMsg.Text)
|
msgPts := strings.Fields(m.Text)
|
||||||
if len(msgPts) < 2 || msgPts[0] != "!aoc" {
|
if len(msgPts) < 2 || msgPts[0] != "!aoc" {
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
switch msgPts[1] {
|
switch msgPts[1] {
|
||||||
case "help":
|
case "help":
|
||||||
s.DoHelpCmd(slackMsg)
|
return s.DoHelpCmd(m)
|
||||||
case "ping":
|
case "ping":
|
||||||
s.DoPingCmd(slackMsg)
|
return s.DoPingCmd(m)
|
||||||
case "top":
|
case "top":
|
||||||
s.DoTopCmd(slackMsg)
|
return s.DoTopCmd(m)
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AoCState) ProcessAdminDirectMessage(slackMsg slack.Message) {
|
func (s *AoCState) ProcessAdminDirectMessage(m models.BotMessage) bool {
|
||||||
msgPts := strings.Fields(slackMsg.Text)
|
msgPts := strings.Fields(m.Text)
|
||||||
if len(msgPts) < 2 || msgPts[0] != "!aoc" {
|
if len(msgPts) < 2 || msgPts[0] != "!aoc" {
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
switch msgPts[1] {
|
switch msgPts[1] {
|
||||||
case "help":
|
case "help":
|
||||||
s.DoHelpAdminCmd(slackMsg)
|
s.DoHelpAdminCmd(m)
|
||||||
|
return true
|
||||||
case "ping":
|
case "ping":
|
||||||
s.DoPingCmd(slackMsg)
|
s.DoPingCmd(m)
|
||||||
|
return true
|
||||||
case "top":
|
case "top":
|
||||||
s.DoTopCmd(slackMsg)
|
s.DoTopCmd(m)
|
||||||
|
return true
|
||||||
case "session":
|
case "session":
|
||||||
s.DoSessionCmd(slackMsg)
|
s.DoSessionCmd(m)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AoCState) ProcessChannelMessage(slackMsg slack.Message) {
|
func (s *AoCState) ProcessChannelMessage(m models.BotMessage) bool {
|
||||||
msgPts := strings.Fields(slackMsg.Text)
|
msgPts := strings.Fields(m.Text)
|
||||||
if len(msgPts) < 2 || msgPts[0] != "!aoc" {
|
if len(msgPts) < 2 || msgPts[0] != "!aoc" {
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
switch msgPts[1] {
|
switch msgPts[1] {
|
||||||
case "top":
|
case "top":
|
||||||
s.DoTopCmd(slackMsg)
|
return s.DoTopCmd(m)
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AoCState) DoHelpCmd(slackMsg slack.Message) {
|
func (s *AoCState) DoHelpCmd(m models.BotMessage) bool {
|
||||||
txt := fmt.Sprint(":christmas_tree: AoC Help :christmas_tree:\n",
|
txt := fmt.Sprint(":christmas_tree: AoC Help :christmas_tree:\n",
|
||||||
"-- WiP --",
|
"-- WiP --",
|
||||||
)
|
)
|
||||||
s.SendSlackMessage(txt, slackMsg.Channel)
|
s.SendSlackMessage(txt, m.Target)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AoCState) DoHelpAdminCmd(slackMsg slack.Message) {
|
func (s *AoCState) DoHelpAdminCmd(m models.BotMessage) bool {
|
||||||
txt := fmt.Sprint(":christmas_tree: AoC Help :christmas_tree:\n",
|
txt := fmt.Sprint(":christmas_tree: AoC Help :christmas_tree:\n",
|
||||||
"-- WiP --",
|
"-- WiP --",
|
||||||
)
|
)
|
||||||
s.SendSlackMessage(txt, slackMsg.Channel)
|
s.SendSlackMessage(txt, m.Target)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AoCState) DoPingCmd(slackMsg slack.Message) {
|
func (s *AoCState) DoPingCmd(m models.BotMessage) bool {
|
||||||
s.SendSlackMessage(":christmas_tree: PONG :christmas_tree:", slackMsg.Channel)
|
s.SendSlackMessage(":christmas_tree: PONG :christmas_tree:", m.Target)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AoCState) DoSessionCmd(slackMsg slack.Message) {
|
func (s *AoCState) DoSessionCmd(m models.BotMessage) bool {
|
||||||
msgPts := strings.Fields(slackMsg.Text)
|
msgPts := strings.Fields(m.Text)
|
||||||
if len(msgPts) == 3 && msgPts[1] == "session" {
|
if len(msgPts) == 3 && msgPts[1] == "session" {
|
||||||
// Set the session cookie
|
// Set the session cookie
|
||||||
admin, err := s.model.GetSlackAdminDMId()
|
admin := s.model.GetSlackAdminDMId()
|
||||||
if err != nil {
|
if admin == "" {
|
||||||
s.SendAdminIdError()
|
s.SendAdminIdError()
|
||||||
return
|
return true
|
||||||
}
|
}
|
||||||
aocSession := msgPts[2]
|
aocSession := msgPts[2]
|
||||||
s.setAoCSessionCookie(strings.TrimSpace(aocSession))
|
s.setAoCSessionCookie(strings.TrimSpace(aocSession))
|
||||||
@ -236,18 +239,19 @@ func (s *AoCState) DoSessionCmd(slackMsg slack.Message) {
|
|||||||
s.SendSlackMessage(":christmas_tree: New Session: "+s.sessionCookie, admin)
|
s.SendSlackMessage(":christmas_tree: New Session: "+s.sessionCookie, admin)
|
||||||
} else if len(msgPts) == 2 && msgPts[1] == "session" {
|
} else if len(msgPts) == 2 && msgPts[1] == "session" {
|
||||||
// Print the session cookie
|
// Print the session cookie
|
||||||
admin, err := s.model.GetSlackAdminDMId()
|
admin := s.model.GetSlackAdminDMId()
|
||||||
if err != nil {
|
if admin == "" {
|
||||||
s.SendAdminIdError()
|
s.SendAdminIdError()
|
||||||
return
|
return true
|
||||||
}
|
}
|
||||||
// We only send the session cookie to the admin
|
// We only send the session cookie to the admin
|
||||||
s.SendSlackMessage(":christmas_tree: session: "+s.sessionCookie, admin)
|
s.SendSlackMessage(":christmas_tree: session: "+s.sessionCookie, admin)
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AoCState) DoTopCmd(slackMsg slack.Message) {
|
func (s *AoCState) DoTopCmd(m models.BotMessage) bool {
|
||||||
msgPts := strings.Fields(slackMsg.Text)
|
msgPts := strings.Fields(m.Text)
|
||||||
var err error
|
var err error
|
||||||
var yr int
|
var yr int
|
||||||
if len(msgPts) > 2 {
|
if len(msgPts) > 2 {
|
||||||
@ -270,7 +274,8 @@ func (s *AoCState) DoTopCmd(slackMsg slack.Message) {
|
|||||||
} else {
|
} else {
|
||||||
txt = s.DoTopForYear(yr)
|
txt = s.DoTopForYear(yr)
|
||||||
}
|
}
|
||||||
s.SendSlackMessage(txt, slackMsg.Channel)
|
s.SendSlackMessage(txt, m.Target)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AoCState) DoTopForAll() (string, error) {
|
func (s *AoCState) DoTopForAll() (string, error) {
|
||||||
@ -367,8 +372,8 @@ func (s *AoCState) AoCSilentBoardCheckAndUpdate(yr int) {
|
|||||||
if s.AoCBoardNeedsUpdate(yr) {
|
if s.AoCBoardNeedsUpdate(yr) {
|
||||||
l, err := s.aoc.GetLeaderboard(yr)
|
l, err := s.aoc.GetLeaderboard(yr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
admin, adminErr := s.model.GetSlackAdminDMId()
|
admin := s.model.GetSlackAdminDMId()
|
||||||
if adminErr != nil {
|
if admin == "" {
|
||||||
s.SendAdminIdError()
|
s.SendAdminIdError()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -379,8 +384,7 @@ func (s *AoCState) AoCSilentBoardCheckAndUpdate(yr int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.model.SendMessage(s.Name(), "main",
|
s.model.SendMessage(models.NewBotMessage(s.Name(), models.MsgSrcApp, models.MsgTpStatus, "", fmt.Sprintf("Received leaderboard (%d)", yr)))
|
||||||
s.BuildMessage("success", fmt.Sprintf("Received leaderboard (%d)", yr), ""))
|
|
||||||
// Save the leaderboard to the db
|
// Save the leaderboard to the db
|
||||||
s.saveLeaderboard(l)
|
s.saveLeaderboard(l)
|
||||||
}
|
}
|
||||||
@ -392,8 +396,8 @@ func (s *AoCState) AoCBoardCheckAndUpdate(yr int) {
|
|||||||
if s.AoCBoardNeedsUpdate(yr) {
|
if s.AoCBoardNeedsUpdate(yr) {
|
||||||
l, err := s.aoc.GetLeaderboard(yr)
|
l, err := s.aoc.GetLeaderboard(yr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
admin, adminErr := s.model.GetSlackAdminDMId()
|
admin := s.model.GetSlackAdminDMId()
|
||||||
if adminErr != nil {
|
if admin == "" {
|
||||||
s.SendAdminIdError()
|
s.SendAdminIdError()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -404,8 +408,7 @@ func (s *AoCState) AoCBoardCheckAndUpdate(yr int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.model.SendMessage(s.Name(), "main",
|
s.model.SendMessage(models.NewBotMessage(s.Name(), models.MsgSrcApp, models.MsgTpStatus, "", fmt.Sprintf("Received leaderboard (%d)", yr)))
|
||||||
s.BuildMessage("success", fmt.Sprintf("Received leaderboard (%d)", yr), ""))
|
|
||||||
// Compare the new leaderboard to the saved one
|
// Compare the new leaderboard to the saved one
|
||||||
for _, v := range l.Members {
|
for _, v := range l.Members {
|
||||||
mbr, err := s.getMember(l.Event, v.ID)
|
mbr, err := s.getMember(l.Event, v.ID)
|
||||||
@ -538,7 +541,7 @@ func (s *AoCState) saveLeaderboard(l *aoc.Leaderboard) error {
|
|||||||
}
|
}
|
||||||
for _, v := range l.Members {
|
for _, v := range l.Members {
|
||||||
if err = s.saveMember(l.Event, &v); err != nil {
|
if err = s.saveMember(l.Event, &v); err != nil {
|
||||||
s.model.SendMessage(s.Name(), "error", s.BuildMessage("error", fmt.Sprintf("Error Saving Member (%s)", v.Name), ""))
|
s.model.SendMessage(models.NewErrorBotMessage(s.Name(), models.MsgSrcApp, fmt.Sprintf("Error Saving Member (%s)", v.Name)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -629,17 +632,9 @@ func (s *AoCState) getMember(event string, memberId int) (*aoc.Member, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *AoCState) SendAdminIdError() {
|
func (s *AoCState) SendAdminIdError() {
|
||||||
s.model.SendMessage(s.Name(), "error", s.BuildMessage("error", "Error getting Admin DM Id", ""))
|
s.model.SendMessage(models.NewBotMessage(s.Name(), models.MsgSrcApp, models.MsgTpError, models.MsgSrcApp, "No Admin ID Found"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AoCState) SendSlackMessage(text, dest string) {
|
func (s *AoCState) SendSlackMessage(text, dest string) {
|
||||||
s.model.SendMessage(s.Name(), "slack", s.BuildMessage("message", text, dest))
|
s.model.SendMessage(models.NewBotMessage(s.Name(), models.MsgSrcSlack, models.MsgTpMessage, dest, text))
|
||||||
}
|
|
||||||
|
|
||||||
func (s *AoCState) BuildMessage(tp, text, ch string) slack.Message {
|
|
||||||
ret := slack.Message{}
|
|
||||||
ret.Type = tp
|
|
||||||
ret.Text = text
|
|
||||||
ret.Channel = ch
|
|
||||||
return ret
|
|
||||||
}
|
}
|
@ -1,27 +1,20 @@
|
|||||||
package main
|
package plugins
|
||||||
|
|
||||||
import (
|
|
||||||
"C"
|
|
||||||
)
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.bullercodeworks.com/brian/helperbot/models"
|
"git.bullercodeworks.com/brian/helperbot/models"
|
||||||
"github.com/slack-go/slack"
|
"github.com/slack-go/slack"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StatsState struct {
|
type StatsState struct {
|
||||||
model models.Model
|
model *models.BotModel
|
||||||
lag time.Duration
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var State StatsState
|
|
||||||
|
|
||||||
/* Plugin Interface Functions */
|
/* Plugin Interface Functions */
|
||||||
func (s *StatsState) Name() string { return "slack-stats" }
|
func (s *StatsState) Name() string { return "slack-stats" }
|
||||||
func (s *StatsState) Initialize(m models.Model) error {
|
func (s *StatsState) Initialize(m *models.BotModel) error {
|
||||||
s.model = m
|
s.model = m
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -37,11 +30,7 @@ func (s *StatsState) ProcessMessage(m models.BotMessage) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StatsState) ProcessRTMEvent(msg slack.RTMEvent) bool {
|
func (s *StatsState) ProcessRTMEvent(msg *slack.RTMEvent) bool {
|
||||||
switch ev := msg.Data.(type) {
|
|
||||||
case *slack.LatencyReport:
|
|
||||||
s.lag = ev.Value
|
|
||||||
}
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,11 +52,11 @@ func (s *StatsState) ProcessAdminDirectMessage(m models.BotMessage) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *StatsState) DoLatencyCommand() {
|
func (s *StatsState) DoLatencyCommand() {
|
||||||
if s.lag == 0 {
|
if s.model.GetSlackLatency() == 0 {
|
||||||
s.SendSlackMessage("Unknown")
|
s.SendSlackMessage("Latency is Unknown")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.SendSlackMessage(s.lag.String())
|
s.SendSlackMessage(s.model.GetSlackLatency().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StatsState) SendSlackMessage(text string) {
|
func (s *StatsState) SendSlackMessage(text string) {
|
@ -1,15 +0,0 @@
|
|||||||
module git.bullercodeworks.com/brian/helperbot/plugins_src/plugin_aoc
|
|
||||||
|
|
||||||
go 1.20
|
|
||||||
|
|
||||||
require (
|
|
||||||
git.bullercodeworks.com/brian/go-adventofcode v1.1.1
|
|
||||||
git.bullercodeworks.com/brian/helperbot v0.0.0-20221201132802-09a662a8cd4b
|
|
||||||
github.com/slack-go/slack v0.12.3
|
|
||||||
)
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/gorilla/websocket v1.4.2 // indirect
|
|
||||||
github.com/nlopes/slack v0.6.0 // indirect
|
|
||||||
github.com/pkg/errors v0.8.0 // indirect
|
|
||||||
)
|
|
@ -1,24 +0,0 @@
|
|||||||
git.bullercodeworks.com/brian/go-adventofcode v1.1.1 h1:5pp9bPVpTKdErkEcIAqoyuMsvmpQkO8upJ+NUQ+MUv0=
|
|
||||||
git.bullercodeworks.com/brian/go-adventofcode v1.1.1/go.mod h1:h/W8Nm8zsrVSjnoA6BRlf38LbaXHR/m6dIq804LOO3w=
|
|
||||||
git.bullercodeworks.com/brian/helperbot v0.0.0-20221201132802-09a662a8cd4b h1:2BCAIENJo1r+h/+qHBJ3eCQTsa1kdsxwYFGTrPdZX3o=
|
|
||||||
git.bullercodeworks.com/brian/helperbot v0.0.0-20221201132802-09a662a8cd4b/go.mod h1:mjMh+IvDRLyD1WscFcZ1OC78C3CgVUi9zIz5trnFK0Y=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho=
|
|
||||||
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
|
||||||
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
|
|
||||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
|
||||||
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
|
||||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
|
||||||
github.com/nlopes/slack v0.6.0 h1:jt0jxVQGhssx1Ib7naAOZEZcGdtIhTzkP0nopK0AsRA=
|
|
||||||
github.com/nlopes/slack v0.6.0/go.mod h1:JzQ9m3PMAqcpeCam7UaHSuBuupz7CmpjehYMayT6YOk=
|
|
||||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/slack-go/slack v0.12.3 h1:92/dfFU8Q5XP6Wp5rr5/T5JHLM5c5Smtn53fhToAP88=
|
|
||||||
github.com/slack-go/slack v0.12.3/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw=
|
|
||||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
@ -1 +0,0 @@
|
|||||||
go 1.20
|
|
@ -1,3 +0,0 @@
|
|||||||
module git.bullercodeworks.com/brian/helperbot/plugins_src/plugin_stats
|
|
||||||
|
|
||||||
go 1.20
|
|
@ -1 +0,0 @@
|
|||||||
go 1.20
|
|
Loading…
Reference in New Issue
Block a user