Created
January 13, 2016 19:03
-
-
Save philpennock/773ecabd5445de5c9aaf to your computer and use it in GitHub Desktop.
A simple Slack responder to the /uuid command
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"flag" | |
"fmt" | |
"log" | |
"os" | |
"os/signal" | |
"strconv" | |
"strings" | |
"github.com/apcera/util/uuid" | |
"github.com/brettbuddin/victor" | |
) | |
var programOptions struct { | |
listenSpec string | |
victorChatSystem string | |
} | |
func init() { | |
port := os.Getenv("PORT") | |
if port == "" { | |
port = ":8042" | |
} else if _, err := strconv.Atoi(port); err == nil { | |
port = ":" + port | |
} | |
flag.StringVar(&programOptions.listenSpec, "listen", port, | |
"webserver listen spec") | |
flag.StringVar(&programOptions.victorChatSystem, "chat-system", "slack", | |
"victor chat system; 'slack' for prod, 'shell' for console testing") | |
} | |
type slackBot struct { | |
// victor.New() returns a pointer to a private type, but that should | |
// satisfy this interface: | |
bot victor.Robot | |
stop chan struct{} | |
sigChan chan os.Signal | |
} | |
var variantMap map[string]func() uuid.UUID | |
func init() { | |
variantMap = map[string]func() uuid.UUID{ | |
// 3 & 5 require parameters, TODO | |
"default": uuid.Generate, | |
"generate": uuid.Generate, | |
"1": uuid.Variant1, | |
"4": uuid.Variant4, | |
"variant1": uuid.Variant1, | |
"variant4": uuid.Variant4, | |
"v1": uuid.Variant1, | |
"v4": uuid.Variant4, | |
} | |
} | |
func handleUUID(s victor.State) { | |
var k string | |
if len(s.Params()) == 0 || s.Params()[0] == "" { | |
k = "default" | |
} else { | |
k = strings.ToLower(s.Params()[0]) | |
} | |
if generator, ok := variantMap[k]; ok { | |
u := generator() | |
log.Printf("[user %q channel %q] issuing UUID/%q: %s", | |
s.Message().UserName(), s.Message().ChannelName(), | |
k, u) | |
s.Chat().Send( | |
s.Message().ChannelID(), | |
fmt.Sprintf("%s [requested by %q]", u.String(), s.Message().UserName())) | |
return | |
} | |
if k == "help" { | |
log.Printf("[user %q] help requested", s.Message().UserName()) | |
s.Chat().Send(s.Message().UserID(), "No parameters, or `v1` or `v4` for those variants") | |
return | |
} | |
log.Printf("[user %q] unknown UUID type: %q", s.Message().UserName(), k) | |
s.Chat().Send(s.Message().UserID(), fmt.Sprintf("Sorry, don't know how to make a %q UUID", k)) | |
} | |
func handleAnything(s victor.State) { | |
log.Printf("[user %q] saw 'anything': %v", s.Message().UserName(), s.Params()) | |
s.Chat().Send(s.Message().UserID(), fmt.Sprintf("debug fallthru: matched on %v", s.Params())) | |
} | |
func makeSlackBot() *slackBot { | |
sb := &slackBot{ | |
bot: victor.New(victor.Config{ | |
Name: "uuidbot", | |
ChatAdapter: programOptions.victorChatSystem, | |
StoreAdapter: "memory", | |
HTTPAddr: programOptions.listenSpec, | |
}), | |
stop: make(chan struct{}), | |
} | |
// This one would be used for messages in some kinds of integrations | |
//sb.bot.HandleFunc(`(?i)uuid(?:\s+(\S+))?`, handleUUID) | |
// but for a slack command, we just get the parameters to the command | |
sb.bot.HandleFunc(`(\S+)?`, handleUUID) | |
// uncomment this one for debugging: | |
//sb.bot.HandleFunc(`(.+)`, handleAnything) | |
return sb | |
} | |
func (b *slackBot) Run() { | |
go b.bot.Run() | |
_ = <-b.stop | |
b.bot.Stop() | |
} | |
func (b *slackBot) StopOnSignals(sigList ...os.Signal) { | |
if b.sigChan == nil { | |
b.sigChan = make(chan os.Signal, 1) | |
go func(sigIn <-chan os.Signal, stopOut chan<- struct{}) { | |
for { | |
_, ok := <-sigIn | |
if !ok { | |
break | |
} | |
stopOut <- struct{}{} | |
} | |
}(b.sigChan, b.stop) | |
} | |
for _, s := range sigList { | |
signal.Notify(b.sigChan, s) | |
} | |
} | |
func main() { | |
flag.Parse() | |
bot := makeSlackBot() | |
bot.StopOnSignals(os.Interrupt) | |
log.Printf("Starting server listening at %q", programOptions.listenSpec) | |
bot.Run() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment