From 8d42cae80b2be1796a0743c1704f896c00d39278 Mon Sep 17 00:00:00 2001 From: "Jager,Petar" Date: Wed, 10 Aug 2022 07:27:41 +0200 Subject: [PATCH 1/3] discord connector --- README.md | 21 +++- VERSION | 2 +- cmd/discoslurmbot/discoslurmbot.conf | 11 ++ cmd/discoslurmbot/discoslurmbot.go | 154 +++++++++++++++++++++++++++ cmd/matrixslurmbot/matrixslurmbot.go | 34 +++--- cmd/tgslurmbot/tgslurmbot.go | 6 +- connectors/discord/connector_data.go | 27 +++++ connectors/discord/discord.go | 144 +++++++++++++++++++++++++ go.mod | 12 ++- go.sum | 29 ++++- internal/connectors/connectors.go | 12 +++ 11 files changed, 427 insertions(+), 25 deletions(-) create mode 100644 cmd/discoslurmbot/discoslurmbot.conf create mode 100644 cmd/discoslurmbot/discoslurmbot.go create mode 100644 connectors/discord/connector_data.go create mode 100644 connectors/discord/discord.go diff --git a/README.md b/README.md index b875491..57737b7 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,11 @@ ## Drop-in notification delivery solution for slurm that can do: * message delivery to: + * [**discord**](https://discord.com/) * [**matrix**](https://matrix.org/) * [**telegram**](https://telegram.org/) * [**msteams**](https://teams.com) - * **e-mail** + * [**e-mail**](https://en.wikipedia.org/wiki/Email) * gathering of job **statistics** * generating **hints** for users on how to tune their job scripts (see examples below) * **templateable** messages ([readme](./templates/README.md)) @@ -43,6 +44,7 @@ To support future additional receiver schemes, a [connector package](connectors/ ## Currently available connectors: +* [**discord**](#discord-connector) todo. * [**matrix**](#matrix-connector) bot --mail-user=`matrix:`roomId * [**telegram**](#telegram-connector) bot --mail-user=`telegram:`chatId * [**mailto**](#mailto-connector) --mail-user=`mailto:`email-addr @@ -183,6 +185,23 @@ set content_type="text/html" See [annotated configuration example](cmd/goslmailer/goslmailer.conf.annotated_example) +--- + +### discord connector + +#### Bot setup + +1. User settings -> Advanced -> Developer mode ON +2. [Discord developer portal](https://discord.com/developers/applications) -> New Application -> Fill out BotName +3. Once the application is saved, select *Bot* from left menu -> Add Bot -> message: "A wild bot has appeared!" +4. Left menu: OAuth2 -> Copy Client ID +5. Modify this url with the Client ID from 4. and open in browser: `https://discord.com/api/oauth2/authorize?client_id=&permissions=8&scope=bot` +6. "An external application BotName wants to access your Discord Account" message -> Select server -> Continue +7. Grant Administrator permissions -> yes/no/maybe ? -> Authorize +8. [Discord developer portal](https://discord.com/developers/applications) -> Select BotName -> Bot menu -> Reset Token -> Copy and Save, to be used in discoslurmbot.conf + + + --- ### telegram connector diff --git a/VERSION b/VERSION index b1d18bc..8721bbc 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.3.0 +v2.4.0 diff --git a/cmd/discoslurmbot/discoslurmbot.conf b/cmd/discoslurmbot/discoslurmbot.conf new file mode 100644 index 0000000..1304b58 --- /dev/null +++ b/cmd/discoslurmbot/discoslurmbot.conf @@ -0,0 +1,11 @@ +{ # remember to remove comments from this json example ;) + "logfile": "", # if empty -> stderr, else log to specified file + "connectors": { + "discord": { + "name": "DiscoSlurmBot", # name that is used in the bot welcome message + "triggerString": "showmeslurm", # string (in channel or DM) that triggers the bot to respond with an instructional DM to the user + "token": "PasteBotTokenHere", # place to put the bot token + "messageTemplate": "/path/to/template.md" # template file to use + } + } +} diff --git a/cmd/discoslurmbot/discoslurmbot.go b/cmd/discoslurmbot/discoslurmbot.go new file mode 100644 index 0000000..5acf2dd --- /dev/null +++ b/cmd/discoslurmbot/discoslurmbot.go @@ -0,0 +1,154 @@ +package main + +import ( + "fmt" + "log" + "os" + "os/signal" + "syscall" + + "github.com/CLIP-HPC/goslmailer/internal/cmdline" + "github.com/CLIP-HPC/goslmailer/internal/config" + "github.com/CLIP-HPC/goslmailer/internal/logger" + "github.com/CLIP-HPC/goslmailer/internal/version" + "github.com/bwmarrin/discordgo" +) + +const app = "discoslurmbot" + +type botConfig struct { + config.ConfigContainer + l *log.Logger +} + +// This function will be called (due to AddHandler above) every time a new +// message is created on any channel that the authenticated bot has access to. +// +// It is called whenever a message is created but only when it's sent through a +// server as we did not request IntentsDirectMessages. +func messageCreate(bc botConfig) func(*discordgo.Session, *discordgo.MessageCreate) { + return func(s *discordgo.Session, m *discordgo.MessageCreate) { + + fmt.Printf("session: %#v\n", s) + fmt.Printf("message: %#v\n", m) + fmt.Printf("message content: %#v\n", m.Content) + fmt.Printf("author: %#v\n", m.Author.ID) + fmt.Printf("user.id: %#v\n", s.State.User.ID) + + // Ignore all messages created by the bot itself + // This isn't required in this specific example but it's a good practice. + if m.Author.ID == s.State.User.ID { + return + } + // In this example, we only care about messages that are "ping". + if m.Content != bc.Connectors["discord"]["triggerString"] { + return + } + + // We create the private channel with the user who sent the message. + channel, err := s.UserChannelCreate(m.Author.ID) + if err != nil { + // If an error occurred, we failed to create the channel. + // + // Some common causes are: + // 1. We don't share a server with the user (not possible here). + // 2. We opened enough DM channels quickly enough for Discord to + // label us as abusing the endpoint, blocking us from opening + // new ones. + bc.l.Println("error creating channel:", err) + s.ChannelMessageSend( + m.ChannelID, + "Something went wrong while sending the DM!", + ) + return + } + // Then we send the message through the channel we created. + msg := fmt.Sprintf("Welcome,\nI am %s,\nplease use this switch in your job submission script in addition to '--mail-type' and i'll get back to you:\n '--mail-user=discord:%s'", bc.Connectors["discord"]["botname"], channel.ID) + _, err = s.ChannelMessageSend(channel.ID, msg) + if err != nil { + // If an error occurred, we failed to send the message. + // + // It may occur either when we do not share a server with the + // user (highly unlikely as we just received a message) or + // the user disabled DM in their settings (more likely). + bc.l.Println("error sending DM message:", err) + s.ChannelMessageSend( + m.ChannelID, + "Failed to send you a DM. "+ + "Did you disable DM in your privacy settings?", + ) + } + } +} + +func main() { + + // parse command line params + cmd, err := cmdline.NewCmdArgs(app) + if err != nil { + log.Fatalf("ERROR: parse command line failed with: %q\n", err) + } + + if *(cmd.Version) { + l := log.New(os.Stderr, app+":", log.Lshortfile|log.Ldate|log.Lmicroseconds) + version.DumpVersion(l) + os.Exit(0) + } + + // read config file + cfg := config.NewConfigContainer() + err = cfg.GetConfig(*(cmd.CfgFile)) + if err != nil { + log.Fatalf("ERROR: getConfig() failed: %s\n", err) + } + + // setup logger + l, err := logger.SetupLogger(cfg.Logfile, "gobler") + if err != nil { + log.Fatalf("setuplogger(%s) failed with: %q\n", cfg.Logfile, err) + } + + l.Println("===================== discoslurmbot start ======================================") + + version.DumpVersion(l) + + if _, ok := cfg.Connectors["discord"]["token"]; !ok { + l.Fatalf("MAIN: fetching config[connectors][discord][token] failed: %s\n", err) + } + + // Create a new Discord session using the provided bot token. + dg, err := discordgo.New("Bot " + cfg.Connectors["discord"]["token"]) + if err != nil { + l.Println("error creating Discord session,", err) + return + } + + // Register the messageCreate func as a callback for MessageCreate events. + bc := botConfig{ + *cfg, + l, + } + dg.AddHandler(messageCreate(bc)) + + // In this example, we only care about receiving message events. + // pja: and DMs + dg.Identify.Intents = discordgo.IntentsGuildMessages | discordgo.IntentDirectMessages + + // Open a websocket connection to Discord and begin listening. + err = dg.Open() + if err != nil { + l.Println("error opening connection,", err) + return + } + + // Wait here until CTRL-C or other term signal is received. + l.Println("Bot is now running. Press CTRL-C to exit.") + sc := make(chan os.Signal, 1) + signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill) + <-sc + + // Cleanly close down the Discord session. + dg.Close() + + l.Println("===================== discoslurmbot end ========================================") +} diff --git a/cmd/matrixslurmbot/matrixslurmbot.go b/cmd/matrixslurmbot/matrixslurmbot.go index 79c8bd3..e6b2cf9 100644 --- a/cmd/matrixslurmbot/matrixslurmbot.go +++ b/cmd/matrixslurmbot/matrixslurmbot.go @@ -14,6 +14,8 @@ import ( "maunium.net/go/mautrix/id" ) +const app = "matrixslurmbot" + func leaveAndForgetRoom(c *mautrix.Client, rid id.RoomID, l *log.Logger) error { l.Printf("Room - leaving: %s\n", rid) _, err := c.LeaveRoom(rid) @@ -88,13 +90,13 @@ func main() { ) // parse command line params - cmd, err := cmdline.NewCmdArgs("matrixslurmbot") + cmd, err := cmdline.NewCmdArgs(app) if err != nil { log.Fatalf("ERROR: parse command line failed with: %q\n", err) } if *(cmd.Version) { - l = log.New(os.Stderr, "matrixslurmbot:", log.Lshortfile|log.Ldate|log.Lmicroseconds) + l = log.New(os.Stderr, app+":", log.Lshortfile|log.Ldate|log.Lmicroseconds) version.DumpVersion(l) os.Exit(0) } @@ -152,20 +154,20 @@ func main() { // do we need to keep any state at all? syncer.OnEvent(client.Store.(*mautrix.InMemoryStore).UpdateState) - /* - //START code for responding to user messages - //disabled for now since it only works on unencrypted channels - - syncer.OnEventType(event.EventMessage, func(source mautrix.EventSource, event *event.Event) { - //TODO: implement this for encrypted channels, only works for - //unencrypted right now - body := event.Content.Raw["body"].(string) - if strings.HasPrefix(body, "!bot"){ - client.SendText(event.RoomID, fmt.Sprintf("Sorry, I'm still a bit dumb. Use this switch in your job submission script and i'll get back to you:\n--mail-user=matrix:%s\n", string(event.RoomID))) - } - }) - //END code for responding to user messages - */ + /* + //START code for responding to user messages + //disabled for now since it only works on unencrypted channels + + syncer.OnEventType(event.EventMessage, func(source mautrix.EventSource, event *event.Event) { + //TODO: implement this for encrypted channels, only works for + //unencrypted right now + body := event.Content.Raw["body"].(string) + if strings.HasPrefix(body, "!bot"){ + client.SendText(event.RoomID, fmt.Sprintf("Sorry, I'm still a bit dumb. Use this switch in your job submission script and i'll get back to you:\n--mail-user=matrix:%s\n", string(event.RoomID))) + } + }) + //END code for responding to user messages + */ syncer.OnEventType(event.StateMember, func(source mautrix.EventSource, event *event.Event) { l.Printf("--------------------------------------------------------------------------------\n") diff --git a/cmd/tgslurmbot/tgslurmbot.go b/cmd/tgslurmbot/tgslurmbot.go index 457f168..6595cca 100644 --- a/cmd/tgslurmbot/tgslurmbot.go +++ b/cmd/tgslurmbot/tgslurmbot.go @@ -13,6 +13,8 @@ import ( tele "gopkg.in/telebot.v3" ) +const app = "tgslurmbot" + func main() { var ( @@ -21,13 +23,13 @@ func main() { ) // parse command line params - cmd, err := cmdline.NewCmdArgs("tgslurmbot") + cmd, err := cmdline.NewCmdArgs(app) if err != nil { log.Fatalf("ERROR: parse command line failed with: %q\n", err) } if *(cmd.Version) == true { - l = log.New(os.Stderr, "tgslurmbot:", log.Lshortfile|log.Ldate|log.Lmicroseconds) + l = log.New(os.Stderr, app+":", log.Lshortfile|log.Ldate|log.Lmicroseconds) version.DumpVersion(l) os.Exit(0) } diff --git a/connectors/discord/connector_data.go b/connectors/discord/connector_data.go new file mode 100644 index 0000000..e07bee3 --- /dev/null +++ b/connectors/discord/connector_data.go @@ -0,0 +1,27 @@ +package discord + +import "log" + +type Connector struct { + name string + triggerString string + token string + renderToFile string + spoolDir string + messageTemplate string + useLookup string + format string +} + +func (c *Connector) dumpConnector(l *log.Logger) { + l.Printf("discord.dumpConnector: name: %q\n", c.name) + l.Printf("discord.dumpConnector: triggerstring: %q\n", c.triggerString) + l.Printf("discord.dumpConnector: token: PRESENT\n") + l.Printf("discord.dumpConnector: renderToFile: %q\n", c.renderToFile) + l.Printf("discord.dumpConnector: spoolDir: %q\n", c.spoolDir) + l.Printf("discord.dumpConnector: messageTemplate: %q\n", c.messageTemplate) + l.Printf("discord.dumpConnector: useLookup: %q\n", c.useLookup) + l.Printf("discord.dumpConnector: format: %q\n", c.format) + l.Println("................................................................................") + +} diff --git a/connectors/discord/discord.go b/connectors/discord/discord.go new file mode 100644 index 0000000..1994508 --- /dev/null +++ b/connectors/discord/discord.go @@ -0,0 +1,144 @@ +package discord + +import ( + "bytes" + "errors" + "io" + "log" + "os" + "strconv" + "time" + + "github.com/CLIP-HPC/goslmailer/internal/lookup" + "github.com/CLIP-HPC/goslmailer/internal/message" + "github.com/CLIP-HPC/goslmailer/internal/renderer" + "github.com/CLIP-HPC/goslmailer/internal/spool" + "github.com/bwmarrin/discordgo" +) + +func NewConnector(conf map[string]string) (*Connector, error) { + // here we need some test if the connectors "minimal" configuration is satisfied, e.g. must have url at minimum + c := Connector{ + name: conf["name"], + triggerString: conf["triggerString"], + token: conf["token"], + renderToFile: conf["renderToFile"], + spoolDir: conf["spoolDir"], + messageTemplate: conf["messageTemplate"], + useLookup: conf["useLookup"], + format: conf["format"], + } + + switch { + // token must be present + case c.token == "": + return nil, errors.New("discord bot token must be defined, aborting") + // if renderToFile=="no" or "spool" then spoolDir must not be empty + case c.renderToFile == "no" || c.renderToFile == "spool": + if c.spoolDir == "" { + return nil, errors.New("discord spoolDir must be defined, aborting") + } + + } + + return &c, nil +} + +func (c *Connector) SendMessage(mp *message.MessagePack, useSpool bool, l *log.Logger) error { + + var ( + e error = nil + outFile string + dts bool = false // DumpToSpool + buffer bytes.Buffer + ) + + l.Println("................... sendTodiscord START ........................................") + + // debug purposes + c.dumpConnector(l) + + // spin up new bot + // Create a new Discord session using the provided bot token. + dg, err := discordgo.New("Bot " + c.token) + if err != nil { + l.Println("error creating Discord session,", err) + return err + } + + // lookup the end-system userid from the one sent by slurm (if lookup is set in "useLookup" config param) + enduser, err := lookup.ExtLookupUser(mp.TargetUser, c.useLookup, l) + if err != nil { + l.Printf("Lookup failed for %s with %s\n", mp.TargetUser, err) + return err + } + l.Printf("Looked up with %q %s -> %s\n", c.useLookup, mp.TargetUser, enduser) + + l.Printf("Sending to targetUserID: %s\n", enduser) + + // don't render template when using spool + if c.renderToFile != "spool" { + // buffer to place rendered json in + buffer = bytes.Buffer{} + //err := c.discordRenderTemplate(mp.JobContext, enduser, &buffer) + err := renderer.RenderTemplate(c.messageTemplate, c.format, mp.JobContext, enduser, &buffer) + if err != nil { + return err + } + } + + // this can be: "yes", "spool", anythingelse + switch c.renderToFile { + case "yes": + // render template to a file in working directory - debug purposes + // prepare outfile name + t := strconv.FormatInt(time.Now().UnixNano(), 10) + l.Printf("Time: %s\n", t) + outFile = "rendered-" + mp.JobContext.SLURM_JOB_ID + "-" + enduser + "-" + t + ".msg" + res, err := io.ReadAll(&buffer) + if err != nil { + return err + } + err = os.WriteFile(outFile, res, 0644) + if err != nil { + return err + } + l.Printf("Send successful to file: %s\n", outFile) + case "spool": + // deposit GOB to spoolDir if allowed + if useSpool { + err := spool.DepositToSpool(c.spoolDir, mp) + if err != nil { + l.Printf("DepositToSpool Failed!\n") + return err + } + } + default: + // Then we send the message through the channel we created. + //_, err = dg.ChannelMessageSend(enduser, "A successfull message at "+time.Now().String()) + _, err = dg.ChannelMessageSend(enduser, buffer.String()) + if err != nil { + l.Printf("error sending DM message: %s\n", err) + dts = true + } else { + l.Printf("bot.Send() successful\n") + dts = false + } + + dg.Close() + } + + // save mp to spool if we're allowed (not allowed when called from gobler, to prevent gobs multiplying) + if dts && useSpool { + l.Printf("Backing off to spool.\n") + err := spool.DepositToSpool(c.spoolDir, mp) + if err != nil { + l.Printf("DepositToSpool Failed!\n") + return err + } + } + + l.Println("................... sendTodiscord END ..........................................") + + return e +} diff --git a/go.mod b/go.mod index 3e9616c..7d8e44b 100644 --- a/go.mod +++ b/go.mod @@ -2,13 +2,17 @@ module github.com/CLIP-HPC/goslmailer go 1.17 -require github.com/dustin/go-humanize v1.0.0 - -require gopkg.in/telebot.v3 v3.0.0 +require ( + github.com/bwmarrin/discordgo v0.25.0 + github.com/dustin/go-humanize v1.0.0 + gopkg.in/telebot.v3 v3.0.0 + maunium.net/go/mautrix v0.11.0 +) require ( + github.com/gorilla/websocket v1.5.0 // indirect github.com/yuin/goldmark v1.4.12 // indirect golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9 // indirect golang.org/x/net v0.0.0-20220513224357-95641704303c // indirect - maunium.net/go/mautrix v0.11.0 // indirect + golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect ) diff --git a/go.sum b/go.sum index c32d017..7930701 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/bwmarrin/discordgo v0.25.0 h1:NXhdfHRNxtwso6FPdzW2i3uBvvU7UIQTghmV2T4nqAs= +github.com/bwmarrin/discordgo v0.25.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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= @@ -10,47 +12,72 @@ github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTM github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/goccy/go-yaml v1.9.5/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-sqlite3 v1.14.13/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= 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/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM= github.com/yuin/goldmark v1.4.12 h1:6hffw6vALvEDqJ19dOJvJKOoAOKe4NDaTqvd2sktGN0= github.com/yuin/goldmark v1.4.12/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9 h1:NUzdAbFtCJSXU20AOXgeqaUwg8Ypg4MPYmL+d+rsB5c= golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220513224357-95641704303c h1:nF9mHSvoKBLkQNQhJZNsc66z2UzAMUbLGjC95CF3pU0= golang.org/x/net v0.0.0-20220513224357-95641704303c/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/telebot.v3 v3.0.0 h1:UgHIiE/RdjoDi6nf4xACM7PU3TqiPVV9vvTydCEnrTo= gopkg.in/telebot.v3 v3.0.0/go.mod h1:7rExV8/0mDDNu9epSrDm/8j22KLaActH1Tbee6YjzWg= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +maunium.net/go/maulogger/v2 v2.3.2/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A= maunium.net/go/mautrix v0.11.0 h1:B1FBHcvE4Mud+AC+zgNQQOw0JxSVrt40watCejhVA7w= maunium.net/go/mautrix v0.11.0/go.mod h1:K29EcHwsNg6r7fMfwvi0GHQ9o5wSjqB9+Q8RjCIQEjA= diff --git a/internal/connectors/connectors.go b/internal/connectors/connectors.go index 8489b59..acbbd30 100644 --- a/internal/connectors/connectors.go +++ b/internal/connectors/connectors.go @@ -3,6 +3,7 @@ package connectors import ( "log" + "github.com/CLIP-HPC/goslmailer/connectors/discord" "github.com/CLIP-HPC/goslmailer/connectors/mailto" "github.com/CLIP-HPC/goslmailer/connectors/matrix" "github.com/CLIP-HPC/goslmailer/connectors/msteams" @@ -65,6 +66,17 @@ func (c *Connectors) PopulateConnectors(conf *config.ConfigContainer, l *log.Log l.Printf("%s connector configured.\n", k) // ...asign its return object value to the connectors map. (*c)[k] = con + case "discord": + // For each recognized, call the connectorpkg.NewConnector() and... + // todo: make this a little bit less ugly... + con, err := discord.NewConnector(v) + if err != nil { + l.Printf("Problem: %q with %s connector configuration. Ignoring.\n", err, k) + break + } + l.Printf("%s connector configured.\n", k) + // ...asign its return object value to the connectors map. + (*c)[k] = con default: l.Printf("Unsupported connector found. Ignoring %#v : %#v\n", k, v) } From 3b58c65571baa2f80925a21b0d35a18288ada1d7 Mon Sep 17 00:00:00 2001 From: "Jager,Petar" Date: Wed, 10 Aug 2022 13:41:13 +0200 Subject: [PATCH 2/3] new connectors initialization code --- README.md | 48 +++++++-- cmd/discoslurmbot/LICENSE | 28 ++++++ cmd/gobler/gobler.go | 14 ++- .../goslmailer.conf.annotated_example | 6 ++ cmd/goslmailer/goslmailer.go | 11 +- connectors/connectorX/README.md | 3 +- connectors/connectorX/connectorX.go | 37 ++++--- connectors/connectorX/connector_data.go | 6 ++ connectors/discord/connector_data.go | 4 + connectors/discord/discord.go | 32 +++--- connectors/mailto/connector_data.go | 4 + connectors/mailto/mailto.go | 28 ++++-- connectors/matrix/connector_data.go | 4 + connectors/matrix/matrix.go | 24 +++-- connectors/msteams/connector_data.go | 4 + connectors/msteams/msteams.go | 28 +++--- connectors/telegram/connector_data.go | 4 + connectors/telegram/telegram.go | 32 +++--- images/discord.png | Bin 0 -> 112740 bytes internal/connectors/connectors.go | 94 ++++++------------ internal/connectors/connectors_test.go | 14 +-- templates/README.md | 3 +- 22 files changed, 267 insertions(+), 161 deletions(-) create mode 100644 cmd/discoslurmbot/LICENSE create mode 100644 images/discord.png diff --git a/README.md b/README.md index 57737b7..9015f12 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,16 @@ # goslmailer -> **Info** +> **News & Info** +> +> v2.4.0 +> +> * discord connector +> * new connectors initialization code +> > Now also works with SLURM < 21.08 > > For templating differences between slurm>21.08 and slurm<21.08 see [templating guide](./templates/README.md) +> ## Drop-in notification delivery solution for slurm that can do: @@ -44,7 +51,7 @@ To support future additional receiver schemes, a [connector package](connectors/ ## Currently available connectors: -* [**discord**](#discord-connector) todo. +* [**discord**](#discord-connector) bot --mail-user=`discord`:channelId * [**matrix**](#matrix-connector) bot --mail-user=`matrix:`roomId * [**telegram**](#telegram-connector) bot --mail-user=`telegram:`chatId * [**mailto**](#mailto-connector) --mail-user=`mailto:`email-addr @@ -58,7 +65,11 @@ See each connector details below... ## Building and installing -### Build +### Option 1. Download latest precompiled binaries [here](https://github.com/CLIP-HPC/goslmailer/releases/latest) + +Unpack, follow [instructions](#install) + +### Option 2. Build #### Quick version, without end to end testing @@ -116,6 +127,13 @@ make * config file has the same format as [goslmailer](cmd/goslmailer/goslmailer.conf.annotated_example), so you can use the same one (other connectors configs are not needed) * start the service (with -c switch pointing to config file) +#### discoslurmbot + +* place binary in a path to your liking +* place [discoslurmbot.conf](./cmd/discoslurmbot/discoslurmbot.conf) in a path to your liking + * config file has the same format as [goslmailer](cmd/goslmailer/goslmailer.conf.annotated_example), so you can use the same one (other connectors configs are not needed) +* start the service (with -c switch pointing to config file) + --- @@ -152,6 +170,14 @@ On startup, gobler reads its config file and spins-up a `connector monitor` for ## Connectors +| connector | spooling/throttling capable (gobler) | +|-----------|---------------------------| +| discord | yes | +| matrix | no | +| telegram | yes | +| msteams | yes | +| mailto | no | + ### default connector Specifies which receiver scheme is the default one, in case when user didn't specify `--mail-user` and slurm sent a bare username. @@ -189,7 +215,14 @@ See [annotated configuration example](cmd/goslmailer/goslmailer.conf.annotated_e ### discord connector -#### Bot setup +Prerequisites for the discord connector: + +1. a discord bot must be created and +2. the bot daemon service **discoslurmbot** must be running ([example config file](./cmd/discoslurmbot/discoslurmbot.conf)). +3. once the bot is running, it will wake up on the configured `triggerString` and send the user a private message with slurm job submission instructions + + +#### Discord Bot setup 1. User settings -> Advanced -> Developer mode ON 2. [Discord developer portal](https://discord.com/developers/applications) -> New Application -> Fill out BotName @@ -200,8 +233,11 @@ See [annotated configuration example](cmd/goslmailer/goslmailer.conf.annotated_e 7. Grant Administrator permissions -> yes/no/maybe ? -> Authorize 8. [Discord developer portal](https://discord.com/developers/applications) -> Select BotName -> Bot menu -> Reset Token -> Copy and Save, to be used in discoslurmbot.conf +Or follow this [tutorial](https://discordpy.readthedocs.io/en/stable/discord.html) +![Discord card](./images/discord.png) +* discord bot and packaged developed using [discordgo](https://github.com/bwmarrin/discordgo) and with the help of _Discord Gophers_ --- ### telegram connector @@ -306,10 +342,6 @@ See [annotated configuration example](cmd/goslmailer/goslmailer.conf.annotated_e --- -## ToDo - ---- - ## Gotchas ### msteams diff --git a/cmd/discoslurmbot/LICENSE b/cmd/discoslurmbot/LICENSE new file mode 100644 index 0000000..8d062ea --- /dev/null +++ b/cmd/discoslurmbot/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2015, Bruce Marriner +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of discordgo nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/cmd/gobler/gobler.go b/cmd/gobler/gobler.go index e88d01f..8d13b64 100644 --- a/cmd/gobler/gobler.go +++ b/cmd/gobler/gobler.go @@ -5,6 +5,11 @@ import ( "os" "sync" + _ "github.com/CLIP-HPC/goslmailer/connectors/discord" + _ "github.com/CLIP-HPC/goslmailer/connectors/mailto" + _ "github.com/CLIP-HPC/goslmailer/connectors/matrix" + _ "github.com/CLIP-HPC/goslmailer/connectors/msteams" + _ "github.com/CLIP-HPC/goslmailer/connectors/telegram" "github.com/CLIP-HPC/goslmailer/internal/cmdline" "github.com/CLIP-HPC/goslmailer/internal/config" "github.com/CLIP-HPC/goslmailer/internal/connectors" @@ -20,8 +25,7 @@ type MsgList []message.MessagePack func main() { var ( - conns = make(connectors.Connectors) - wg sync.WaitGroup + wg sync.WaitGroup ) // parse command line params @@ -30,7 +34,7 @@ func main() { log.Fatalf("ERROR: parse command line failed with: %q\n", err) } - if *(cmd.Version) == true { + if *(cmd.Version) { l := log.New(os.Stderr, "gobler:", log.Lshortfile|log.Ldate|log.Lmicroseconds) version.DumpVersion(l) os.Exit(0) @@ -56,7 +60,7 @@ func main() { cfg.DumpConfig(l) // populate map with configured referenced connectors - err = conns.PopulateConnectors(cfg, l) + err = connectors.ConMap.PopulateConnectors(cfg, l) if err != nil { l.Printf("MAIN: PopulateConnectors() failed with: %s\n", err) } @@ -74,7 +78,7 @@ func main() { continue } // func (cm *conMon) SpinUp(conns connectors.Connectors, wg sync.WaitGroup, l *log.Logger) error { - err = cm.SpinUp(conns, &wg, l) + err = cm.SpinUp(connectors.ConMap, &wg, l) if err != nil { l.Printf("MAIN: SpinUp(%s) failed with: %s\n", con, err) } diff --git a/cmd/goslmailer/goslmailer.conf.annotated_example b/cmd/goslmailer/goslmailer.conf.annotated_example index 5a30bc3..2e0fc37 100644 --- a/cmd/goslmailer/goslmailer.conf.annotated_example +++ b/cmd/goslmailer/goslmailer.conf.annotated_example @@ -33,6 +33,12 @@ "useLookup": "no", "format": "MarkdownV2" }, + "discord": { + "name": "DiscoSlurmBot", # name that is used in the bot welcome message + "triggerString": "showmeslurm", # string (in channel or DM) that triggers the bot to respond with an instructional DM to the user + "token": "PasteBotTokenHere", # place to put the bot token + "messageTemplate": "/path/to/template.md" # template file to use + } "matrix": { "username": "@myuser:matrix.org", "token": "syt_dGRpZG9ib3QXXXXXXXEyQMBEmvOVp_10Jm93", diff --git a/cmd/goslmailer/goslmailer.go b/cmd/goslmailer/goslmailer.go index 822c24c..6b9882a 100644 --- a/cmd/goslmailer/goslmailer.go +++ b/cmd/goslmailer/goslmailer.go @@ -6,6 +6,11 @@ import ( "log" "os" + _ "github.com/CLIP-HPC/goslmailer/connectors/discord" + _ "github.com/CLIP-HPC/goslmailer/connectors/mailto" + _ "github.com/CLIP-HPC/goslmailer/connectors/matrix" + _ "github.com/CLIP-HPC/goslmailer/connectors/msteams" + _ "github.com/CLIP-HPC/goslmailer/connectors/telegram" "github.com/CLIP-HPC/goslmailer/internal/config" "github.com/CLIP-HPC/goslmailer/internal/connectors" "github.com/CLIP-HPC/goslmailer/internal/message" @@ -20,7 +25,6 @@ func main() { var ( ic invocationContext job slurmjob.JobContext - conns = make(connectors.Connectors) logFile io.Writer ) @@ -77,7 +81,8 @@ func main() { job.GenerateHints(cfg.QosMap) // populate map with configured referenced connectors - conns.PopulateConnectors(cfg, log) + //conns.PopulateConnectors(cfg, log) + connectors.ConMap.PopulateConnectors(cfg, log) // Iterate over 'Receivers' map and for each call the connector.SendMessage() (if the receiver scheme is configured in conf file AND has an object in connectors map) if ic.Receivers == nil { @@ -89,7 +94,7 @@ func main() { if err != nil { log.Printf("ERROR in message.NewMsgPack(%s): %q\n", v.scheme, err) } - con, ok := conns[v.scheme] + con, ok := connectors.ConMap[v.scheme] if !ok { log.Printf("%s connector is not initialized for target %s. Ignoring.\n", v.scheme, v.target) } else { diff --git a/connectors/connectorX/README.md b/connectors/connectorX/README.md index 29419ff..fbab8d8 100644 --- a/connectors/connectorX/README.md +++ b/connectors/connectorX/README.md @@ -14,7 +14,8 @@ Files you'll need to get started: ## Exercise for the reader: -To make this connector work, add the missing code block to the [connectors package](../../internal/connectors/connectors.go). +To make this connector work, add the missing blank import to [goslmailer main package](../../cmd/goslmailer/goslmailer.go) to trigger init(). + Recompile and try it out. To verify it works: diff --git a/connectors/connectorX/connectorX.go b/connectors/connectorX/connectorX.go index 0163414..8fc64a6 100644 --- a/connectors/connectorX/connectorX.go +++ b/connectors/connectorX/connectorX.go @@ -10,36 +10,41 @@ import ( "strconv" "time" + "github.com/CLIP-HPC/goslmailer/internal/connectors" "github.com/CLIP-HPC/goslmailer/internal/lookup" "github.com/CLIP-HPC/goslmailer/internal/message" "github.com/CLIP-HPC/goslmailer/internal/renderer" "github.com/CLIP-HPC/goslmailer/internal/spool" ) -// NewConnector instantiates a connectorX.Connector structure with values read from config file. -// Mandatory. -// Call has to be added here: ../../internal/connectors/connectors.go:25 -func NewConnector(conf map[string]string) (*Connector, error) { - // declare the Connector structure and assign the values from config file, whatever the new connector needs - c := Connector{ - name: conf["name"], - addr: conf["addr"], - port: conf["port"], - templateFile: conf["templateFile"], - renderToFile: conf["renderToFile"], - spoolDir: conf["spoolDir"], - useLookup: conf["useLookup"], - } +// init registers the new connector with the connectors package +func init() { + connectors.Register(connectorName, connConnectorX) +} + +// ConfigConnector fills out the package Connector structure with values from config file. +// Recommended to also do sanity checking of config values here. Mandatory. +// Makes connectorX.Connector type satisfy the connectors.Connector interface. +func (c *Connector) ConfigConnector(conf map[string]string) error { + // Fill out the Connector structure with values from config file + c.name = conf["name"] + c.addr = conf["addr"] + c.port = conf["port"] + c.templateFile = conf["templateFile"] + c.renderToFile = conf["renderToFile"] + c.spoolDir = conf["spoolDir"] + c.useLookup = conf["useLookup"] + // Here you can do sanity checking and defaulting if needed. // e.g. // if renderToFile=="no" or "spool" then spoolDir must not be empty switch c.renderToFile { case "no", "spool": if c.spoolDir == "" { - return nil, errors.New("spoolDir must be defined, aborting") + return errors.New("spoolDir must be defined, aborting") } } - return &c, nil + return nil } // SendMessage is the main method of the connector code, it usually does something like: diff --git a/connectors/connectorX/connector_data.go b/connectors/connectorX/connector_data.go index b36effd..b9ca831 100644 --- a/connectors/connectorX/connector_data.go +++ b/connectors/connectorX/connector_data.go @@ -10,6 +10,9 @@ package connectorX import "log" +// Name of the connector, used in the init() function to Register() it to connectors package. +const connectorName = "discord" + // Connector structure contains configuration data read in from config file with connectorX.NewConnector(). // Populate this structure with the configuration variables a new connector needs type Connector struct { @@ -35,3 +38,6 @@ func (c *Connector) dumpConnector(l *log.Logger) { l.Println("................................................................................") } + +// Variable holding the connector configuration, mandatory +var connConnectorX *Connector = new(Connector) diff --git a/connectors/discord/connector_data.go b/connectors/discord/connector_data.go index e07bee3..2ddaa80 100644 --- a/connectors/discord/connector_data.go +++ b/connectors/discord/connector_data.go @@ -2,6 +2,8 @@ package discord import "log" +const connectorName = "discord" + type Connector struct { name string triggerString string @@ -25,3 +27,5 @@ func (c *Connector) dumpConnector(l *log.Logger) { l.Println("................................................................................") } + +var connDiscord *Connector = new(Connector) diff --git a/connectors/discord/discord.go b/connectors/discord/discord.go index 1994508..306488d 100644 --- a/connectors/discord/discord.go +++ b/connectors/discord/discord.go @@ -9,6 +9,7 @@ import ( "strconv" "time" + "github.com/CLIP-HPC/goslmailer/internal/connectors" "github.com/CLIP-HPC/goslmailer/internal/lookup" "github.com/CLIP-HPC/goslmailer/internal/message" "github.com/CLIP-HPC/goslmailer/internal/renderer" @@ -16,32 +17,35 @@ import ( "github.com/bwmarrin/discordgo" ) -func NewConnector(conf map[string]string) (*Connector, error) { +func init() { + connectors.Register(connectorName, connDiscord) +} + +func (c *Connector) ConfigConnector(conf map[string]string) error { + // here we need some test if the connectors "minimal" configuration is satisfied, e.g. must have url at minimum - c := Connector{ - name: conf["name"], - triggerString: conf["triggerString"], - token: conf["token"], - renderToFile: conf["renderToFile"], - spoolDir: conf["spoolDir"], - messageTemplate: conf["messageTemplate"], - useLookup: conf["useLookup"], - format: conf["format"], - } + c.name = conf["name"] + c.triggerString = conf["triggerString"] + c.token = conf["token"] + c.renderToFile = conf["renderToFile"] + c.spoolDir = conf["spoolDir"] + c.messageTemplate = conf["messageTemplate"] + c.useLookup = conf["useLookup"] + c.format = conf["format"] switch { // token must be present case c.token == "": - return nil, errors.New("discord bot token must be defined, aborting") + return errors.New("discord bot token must be defined, aborting") // if renderToFile=="no" or "spool" then spoolDir must not be empty case c.renderToFile == "no" || c.renderToFile == "spool": if c.spoolDir == "" { - return nil, errors.New("discord spoolDir must be defined, aborting") + return errors.New("discord spoolDir must be defined, aborting") } } - return &c, nil + return nil } func (c *Connector) SendMessage(mp *message.MessagePack, useSpool bool, l *log.Logger) error { diff --git a/connectors/mailto/connector_data.go b/connectors/mailto/connector_data.go index 013c3d9..474c71e 100644 --- a/connectors/mailto/connector_data.go +++ b/connectors/mailto/connector_data.go @@ -1,5 +1,7 @@ package mailto +const connectorName = "mailto" + type Connector struct { name string mailCmd string @@ -9,3 +11,5 @@ type Connector struct { allowList string blockList string } + +var connMailto *Connector = new(Connector) diff --git a/connectors/mailto/mailto.go b/connectors/mailto/mailto.go index a231291..1e25b82 100644 --- a/connectors/mailto/mailto.go +++ b/connectors/mailto/mailto.go @@ -8,22 +8,28 @@ import ( "regexp" "text/template" + "github.com/CLIP-HPC/goslmailer/internal/connectors" "github.com/CLIP-HPC/goslmailer/internal/message" "github.com/CLIP-HPC/goslmailer/internal/renderer" ) -func NewConnector(conf map[string]string) (*Connector, error) { +func init() { + connectors.Register(connectorName, connMailto) +} + +func (c *Connector) ConfigConnector(conf map[string]string) error { + c.name = conf["name"] + c.mailCmd = conf["mailCmd"] + c.mailCmdParams = conf["mailCmdParams"] + c.mailTemplate = conf["mailTemplate"] + c.mailFormat = conf["mailFormat"] + c.allowList = conf["allowList"] + c.blockList = conf["blockList"] + // here we need some test if the connectors "minimal" configuration is satisfied, e.g. must have url at minimum - c := Connector{ - name: conf["name"], - mailCmd: conf["mailCmd"], - mailCmdParams: conf["mailCmdParams"], - mailTemplate: conf["mailTemplate"], - mailFormat: conf["mailFormat"], - allowList: conf["allowList"], - blockList: conf["blockList"], - } - return &c, nil + // + // if ok, return nil error + return nil } func (c *Connector) SendMessage(mp *message.MessagePack, useSpool bool, l *log.Logger) error { diff --git a/connectors/matrix/connector_data.go b/connectors/matrix/connector_data.go index 1dcf72f..89275e5 100644 --- a/connectors/matrix/connector_data.go +++ b/connectors/matrix/connector_data.go @@ -1,8 +1,12 @@ package matrix +const connectorName = "matrix" + type Connector struct { username string token string homeserver string template string } + +var connMatrix *Connector = new(Connector) diff --git a/connectors/matrix/matrix.go b/connectors/matrix/matrix.go index d6c1d00..261b6c0 100644 --- a/connectors/matrix/matrix.go +++ b/connectors/matrix/matrix.go @@ -4,6 +4,7 @@ import ( "bytes" "log" + "github.com/CLIP-HPC/goslmailer/internal/connectors" "github.com/CLIP-HPC/goslmailer/internal/message" "github.com/CLIP-HPC/goslmailer/internal/renderer" @@ -13,14 +14,21 @@ import ( "maunium.net/go/mautrix/id" ) -func NewConnector(conf map[string]string) (*Connector, error) { - c := Connector{ - username: conf["username"], - token: conf["token"], - homeserver: conf["homeserver"], - template: conf["template"], - } - return &c, nil +func init() { + connectors.Register(connectorName, connMatrix) +} + +func (c *Connector) ConfigConnector(conf map[string]string) error { + + c.username = conf["username"] + c.token = conf["token"] + c.homeserver = conf["homeserver"] + c.template = conf["template"] + + // here we need some test if the connectors "minimal" configuration is satisfied, e.g. must have url at minimum + // + // if ok, return nil error + return nil } func (c *Connector) SendMessage(mp *message.MessagePack, useSpool bool, l *log.Logger) error { diff --git a/connectors/msteams/connector_data.go b/connectors/msteams/connector_data.go index e848260..daa2d13 100644 --- a/connectors/msteams/connector_data.go +++ b/connectors/msteams/connector_data.go @@ -2,6 +2,8 @@ package msteams import "log" +const connectorName = "msteams" + type Connector struct { name string url string @@ -22,3 +24,5 @@ func (c *Connector) dumpConnector(l *log.Logger) { l.Println("................................................................................") } + +var connMsteams *Connector = new(Connector) diff --git a/connectors/msteams/msteams.go b/connectors/msteams/msteams.go index bed967f..83bdc75 100644 --- a/connectors/msteams/msteams.go +++ b/connectors/msteams/msteams.go @@ -10,30 +10,34 @@ import ( "strconv" "time" + "github.com/CLIP-HPC/goslmailer/internal/connectors" "github.com/CLIP-HPC/goslmailer/internal/lookup" "github.com/CLIP-HPC/goslmailer/internal/message" "github.com/CLIP-HPC/goslmailer/internal/renderer" "github.com/CLIP-HPC/goslmailer/internal/spool" ) -func NewConnector(conf map[string]string) (*Connector, error) { - // here we need some test if the connectors "minimal" configuration is satisfied, e.g. must have url at minimum - c := Connector{ - name: conf["name"], - url: conf["url"], - renderToFile: conf["renderToFile"], - spoolDir: conf["spoolDir"], - adaptiveCardTemplate: conf["adaptiveCardTemplate"], - useLookup: conf["useLookup"], - } +func init() { + connectors.Register(connectorName, connMsteams) +} + +func (c *Connector) ConfigConnector(conf map[string]string) error { + + c.name = conf["name"] + c.url = conf["url"] + c.renderToFile = conf["renderToFile"] + c.spoolDir = conf["spoolDir"] + c.adaptiveCardTemplate = conf["adaptiveCardTemplate"] + c.useLookup = conf["useLookup"] + // if renderToFile=="no" or "spool" then spoolDir must not be empty switch c.renderToFile { case "no", "spool": if c.spoolDir == "" { - return nil, errors.New("spoolDir must be defined, aborting") + return errors.New("spoolDir must be defined, aborting") } } - return &c, nil + return nil } func (c *Connector) SendMessage(mp *message.MessagePack, useSpool bool, l *log.Logger) error { diff --git a/connectors/telegram/connector_data.go b/connectors/telegram/connector_data.go index 0b9748a..7dc27c0 100644 --- a/connectors/telegram/connector_data.go +++ b/connectors/telegram/connector_data.go @@ -2,6 +2,8 @@ package telegram import "log" +const connectorName = "telegram" + type Connector struct { name string url string @@ -25,3 +27,5 @@ func (c *Connector) dumpConnector(l *log.Logger) { l.Println("................................................................................") } + +var connTelegram *Connector = new(Connector) diff --git a/connectors/telegram/telegram.go b/connectors/telegram/telegram.go index 75c75d4..2a37d1e 100644 --- a/connectors/telegram/telegram.go +++ b/connectors/telegram/telegram.go @@ -9,6 +9,7 @@ import ( "strconv" "time" + "github.com/CLIP-HPC/goslmailer/internal/connectors" "github.com/CLIP-HPC/goslmailer/internal/lookup" "github.com/CLIP-HPC/goslmailer/internal/message" "github.com/CLIP-HPC/goslmailer/internal/renderer" @@ -16,26 +17,29 @@ import ( telebot "gopkg.in/telebot.v3" ) -func NewConnector(conf map[string]string) (*Connector, error) { - // here we need some test if the connectors "minimal" configuration is satisfied, e.g. must have url at minimum - c := Connector{ - name: conf["name"], - url: conf["url"], - token: conf["token"], - renderToFile: conf["renderToFile"], - spoolDir: conf["spoolDir"], - messageTemplate: conf["messageTemplate"], - useLookup: conf["useLookup"], - format: conf["format"], - } +func init() { + connectors.Register(connectorName, connTelegram) +} + +func (c *Connector) ConfigConnector(conf map[string]string) error { + + c.name = conf["name"] + c.url = conf["url"] + c.token = conf["token"] + c.renderToFile = conf["renderToFile"] + c.spoolDir = conf["spoolDir"] + c.messageTemplate = conf["messageTemplate"] + c.useLookup = conf["useLookup"] + c.format = conf["format"] + // if renderToFile=="no" or "spool" then spoolDir must not be empty switch c.renderToFile { case "no", "spool": if c.spoolDir == "" { - return nil, errors.New("telegram spoolDir must be defined, aborting") + return errors.New("telegram spoolDir must be defined, aborting") } } - return &c, nil + return nil } func (c *Connector) SendMessage(mp *message.MessagePack, useSpool bool, l *log.Logger) error { diff --git a/images/discord.png b/images/discord.png new file mode 100644 index 0000000000000000000000000000000000000000..34d96e3d93f3d4a058447e2aca0ea81adb1577a2 GIT binary patch literal 112740 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 KC5ma^|Nj8 Date: Wed, 10 Aug 2022 14:16:49 +0200 Subject: [PATCH 3/3] actions: build on pr --- .github/workflows/{build_on_tag.yml => build_on_tag_pr.yml} | 3 +++ 1 file changed, 3 insertions(+) rename .github/workflows/{build_on_tag.yml => build_on_tag_pr.yml} (96%) diff --git a/.github/workflows/build_on_tag.yml b/.github/workflows/build_on_tag_pr.yml similarity index 96% rename from .github/workflows/build_on_tag.yml rename to .github/workflows/build_on_tag_pr.yml index 2ff60bc..0c647e1 100644 --- a/.github/workflows/build_on_tag.yml +++ b/.github/workflows/build_on_tag_pr.yml @@ -4,6 +4,9 @@ on: push: tags: - v** + pull_request: + branches: + - master jobs: