package main import ( "errors" "fmt" "io/ioutil" "os" "strings" "time" "github.com/nlopes/slack" "github.com/unixvoid/glogger" "gopkg.in/gcfg.v1" "gopkg.in/redis.v5" ) type Config struct { Lorebot struct { Loglevel string BootstrapDelay time.Duration APIToken string } Redis struct { Host string Password string } } var ( config = Config{} ) func main() { // read in config file readConf() // initialize the logger with the configured loglevel initLogger(config.Lorebot.Loglevel) // initialize redis connection redisClient, err := initRedisConnection() if err != nil { glogger.Debug.Printf("redis conneciton cannot be made, trying again in %d seconds", config.Lorebot.BootstrapDelay) time.Sleep(config.Lorebot.BootstrapDelay * time.Second) redisClient, err = initRedisConnection() if err != nil { glogger.Error.Println("redis connection cannot be made.") os.Exit(1) } } glogger.Debug.Println("connection to redis succeeded.") glogger.Info.Println("link to redis on", config.Redis.Host) api := slack.New(config.Lorebot.APIToken) //api.SetDebug(true) rtm := api.NewRTM() go rtm.ManageConnection() Loop: for { select { case msg := <-rtm.IncomingEvents: switch ev := msg.Data.(type) { case *slack.MessageEvent: if ev.Type == "message" { glogger.Debug.Printf("processing: %s", ev.Text) // see if the message begins with '.', it could be a command if len(ev.Text) == 0 { // nil message, dont print //glogger.Debug.Println("breaking on blank message") break } else { comm := fmt.Sprintf("%c", ev.Text[0]) if comm == "." { if strings.Count(ev.Text, " ") == 0 { // no spaces, its a static command staticCommandHandler(rtm, ev, redisClient) } else { // spaces, dynamic handler dynamicCommandHandler(rtm, ev, redisClient) } } } } case *slack.RTMError: fmt.Printf("Error: %s\n", ev.Error()) case *slack.InvalidAuthEvent: fmt.Printf("Invalid credentials") break Loop default: // ignore all other events //fmt.Printf("Unknown error") //fmt.Printf("%v\n", msg.Data) } } } } func readConf() { // init config file err := gcfg.ReadFileInto(&config, "config.gcfg") if err != nil { panic(fmt.Sprintf("Could not load config.gcfg, error: %s\n", err)) } } func initLogger(logLevel string) { // init logger if logLevel == "debug" { glogger.LogInit(os.Stdout, os.Stdout, os.Stdout, os.Stderr) } else if logLevel == "cluster" { glogger.LogInit(os.Stdout, os.Stdout, ioutil.Discard, os.Stderr) } else if logLevel == "info" { glogger.LogInit(os.Stdout, ioutil.Discard, ioutil.Discard, os.Stderr) } else { glogger.LogInit(ioutil.Discard, ioutil.Discard, ioutil.Discard, os.Stderr) } } func initRedisConnection() (*redis.Client, error) { // init redis connection redisClient := redis.NewClient(&redis.Options{ Addr: config.Redis.Host, Password: config.Redis.Password, DB: 0, }) _, redisErr := redisClient.Ping().Result() return redisClient, redisErr } func dynamicCommandHandler(rtm *slack.RTM, ev *slack.MessageEvent, redisClient *redis.Client) { message := ev.Text if strings.Count(message, " ") < 1 { glogger.Debug.Println("not proper syntax") } // verify syntax s := strings.SplitN(message, " ", 2) command, content := s[0], s[1] trimmedPrefix := strings.TrimPrefix(command, ".") switch trimmedPrefix { case "lore": s := strings.SplitN(string(ev.Text), " ", 2) lorehandler(redisClient, rtm, ev, s[1]) case "newlore": rtm.SendMessage(rtm.NewOutgoingMessage("command not yet supported", ev.Channel)) println(content) case "rmlore": rtm.SendMessage(rtm.NewOutgoingMessage("command not yet supported", ev.Channel)) case "rek": s := strings.SplitN(string(ev.Text), " ", 2) rekhandler(redisClient, rtm, ev, s[1]) case "gnu": s := strings.SplitN(string(ev.Text), " ", 2) gnuhandler(redisClient, rtm, ev, s[1]) case "created": rtm.SendMessage(rtm.NewOutgoingMessage("command not yet supported", ev.Channel)) case "owner": rtm.SendMessage(rtm.NewOutgoingMessage("command not yet supported", ev.Channel)) case "removedby": rtm.SendMessage(rtm.NewOutgoingMessage("command not yet supported", ev.Channel)) case "removed": rtm.SendMessage(rtm.NewOutgoingMessage("command not yet supported", ev.Channel)) } } func staticCommandHandler(rtm *slack.RTM, ev *slack.MessageEvent, redisClient *redis.Client) { s := strings.SplitN(ev.Text, " ", 2) command := s[0] trimmedPrefix := strings.TrimPrefix(command, ".") switch trimmedPrefix { case "help": helpmsg(rtm, ev) case "help2": advancedhelpmsg(rtm, ev) case "rng": rtm.SendMessage(rtm.NewOutgoingMessage("command not yet supported", ev.Channel)) case "version": rtm.SendMessage(rtm.NewOutgoingMessage("command not yet supported", ev.Channel)) case "lorelist": rtm.SendMessage(rtm.NewOutgoingMessage("command not yet supported", ev.Channel)) case "removedlore": rtm.SendMessage(rtm.NewOutgoingMessage("command not yet supported", ev.Channel)) case "lorestatus": rtm.SendMessage(rtm.NewOutgoingMessage("command not yet supported", ev.Channel)) } } func helpmsg(rtm *slack.RTM, ev *slack.MessageEvent) { help1 := "I am the lore archival bot, I support the following commands:\n" + "```" + ".lore: view lore\n" + ".newlore: add new lore\n" + ".rmlore: remove lore\n" + ".lorelist: view lore database\n" + "use '.help2' to see advanced lookup commands." + "```" rtm.SendMessage(rtm.NewOutgoingMessage(help1, ev.Channel)) } func advancedhelpmsg(rtm *slack.RTM, ev *slack.MessageEvent) { help2 := "```" + ".created view creation timestamp\n" + ".owner: who created the lore\n" + ".removed: view removal timestamp\n" + ".removedby: who removed the lore" + "```" rtm.SendMessage(rtm.NewOutgoingMessage(help2, ev.Channel)) } func lorehandler(redisClient *redis.Client, rtm *slack.RTM, ev *slack.MessageEvent, rawMessage string) { loreTerm := strings.Replace(rawMessage, ".lore", "", -1) println("searching for:", loreTerm) //rtm.SendMessage(rtm.NewOutgoingMessage(fmt.Sprintf("searching for '%s'\n", loreTerm), ev.Channel)) content, err := checkLore(loreTerm, redisClient) if err == nil { // lore found, print it rtm.SendMessage(rtm.NewOutgoingMessage(content, ev.Channel)) } else { // lore not found, print error rtm.SendMessage(rtm.NewOutgoingMessage(fmt.Sprintf("lore '%s' not found\n", loreTerm), ev.Channel)) } } func rekhandler(redisClient *redis.Client, rtm *slack.RTM, ev *slack.MessageEvent, target string) { rektBit, _ := redisClient.SRandMember("index:rekt").Result() rekFmt := fmt.Sprintf("%s %s", target, rektBit) rtm.SendMessage(rtm.NewOutgoingMessage(rekFmt, ev.Channel)) } func gnuhandler(redisClient *redis.Client, rtm *slack.RTM, ev *slack.MessageEvent, target string) { gnuFmt := fmt.Sprintf("slaps the nonfree software out of %s's hands", target) rtm.SendMessage(rtm.NewOutgoingMessage(gnuFmt, ev.Channel)) } func checkLore(searchTerm string, redisClient *redis.Client) (string, error) { val, err := redisClient.Get(fmt.Sprintf("lore:%s:content", searchTerm)).Result() if err != nil { return "", errors.New("String not found.") } else { return val, nil } //return "", nil }