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.ConnectedEvent: // //botId = ev.Info.User.ID //case *slack.TeamJoinEvent: // // Handle new user to client case *slack.MessageEvent: if ev.Type == "message" { //if ev.Text == "test" { // rtm.SendMessage(rtm.NewOutgoingMessage("MY NAME IS ..JHEFFFFF", ev.Channel)) //} //if strings.Contains(ev.Text, ".lore") { // //rtm.SendMessage(rtm.NewOutgoingMessage("THA LORE", ev.Channel)) // s := strings.SplitN(string(ev.Text), " ", 2) // //command, content := s[0], s[1] // lorehandler(redisClient, rtm, ev, s[1]) //} //if strings.Contains(ev.Text, ".help") { // helpmsg(rtm, ev) //} //if strings.Contains(ev.Text, ".help2") { // helpmsg(rtm, ev) //} // see if the message begins with '.', it could be a command 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: //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": rtm.SendMessage(rtm.NewOutgoingMessage("command not yet supported", ev.Channel)) 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 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 }