package sco import ( "os" "os/signal" "regexp" "strings" "github.com/mattermost/mattermost-server/v5/model" ) type Bot struct { botName string apiURL string websocketURL string accountEmail string accountPassword string accountFirstname string accountLastname string teamName string logChannelName string client *model.Client4 webSocketClient *model.WebSocketClient botUser *model.User botTeam *model.Team debuggingChannel *model.Channel } func New(options ...func(s *Bot)) *Bot { b := new(Bot) for _, opt := range options { opt(b) } return b } func (b *Bot) Main() { println(b.BotName) b.SetupGracefulShutdown() b.client = model.NewAPIv4Client(b.apiURL) // Lets test to see if the mattermost server is up and running b.MakeSureServerIsRunning() // lets attempt to login to the Mattermost server as the bot user // This will set the token required for all future calls // You can get this token with client.AuthToken b.LoginAsTheBotUser() // If the bot user doesn't have the correct information lets update his profile b.UpdateTheBotUserIfNeeded() // Lets find our bot team b.FindBotTeam() // This is an important step. Lets make sure we use the botTeam // for all future web service requests that require a team. //client.SetTeamId(botTeam.Id) // Lets create a bot channel for logging debug messages into b.CreateBotDebuggingChannelIfNeeded() b.SendMsgToDebuggingChannel("_"+SAMPLE_NAME+" has **started** running_", "") // Lets start listening to some channels via the websocket! b.webSocketClient, err = model.NewWebSocketClient4(b.websocketURL, b.client.AuthToken) if err != nil { println("We failed to connect to the web socket") PrintError(err) } b.webSocketClient.Listen() go func() { for { select { case resp := <-b.webSocketClient.EventChannel: b.HandleWebSocketResponse(resp) } } }() // You can block forever with select {} } func (b *Bot) MakeSureServerIsRunning() { if props, resp := client.GetOldClientConfig(""); resp.Error != nil { println("There was a problem pinging the Mattermost server. Are you sure it's running?") PrintError(resp.Error) os.Exit(1) } else { println("Server detected and is running version " + props["Version"]) } } func (b *Bot) LoginAsTheBotUser() { if user, resp := client.Login(USER_EMAIL, USER_PASSWORD); resp.Error != nil { println("There was a problem logging into the Mattermost server. Are you sure ran the setup steps from the README.md?") PrintError(resp.Error) os.Exit(1) } else { botUser = user } } func (b *Bot) UpdateTheBotUserIfNeeded() { if botUser.FirstName != USER_FIRST || botUser.LastName != USER_LAST || botUser.Username != USER_NAME { botUser.FirstName = USER_FIRST botUser.LastName = USER_LAST botUser.Username = USER_NAME if user, resp := client.UpdateUser(botUser); resp.Error != nil { println("We failed to update the Sample Bot user") PrintError(resp.Error) os.Exit(1) } else { botUser = user println("Looks like this might be the first run so we've updated the bots account settings") } } } func (b *Bot) FindBotTeam() { if team, resp := client.GetTeamByName(TEAM_NAME, ""); resp.Error != nil { println("We failed to get the initial load") println("or we do not appear to be a member of the team '" + TEAM_NAME + "'") PrintError(resp.Error) os.Exit(1) } else { botTeam = team } } func (b *Bot) CreateBotDebuggingChannelIfNeeded() { if rchannel, resp := client.GetChannelByName(CHANNEL_LOG_NAME, botTeam.Id, ""); resp.Error != nil { println("We failed to get the channels") PrintError(resp.Error) } else { debuggingChannel = rchannel return } // Looks like we need to create the logging channel channel := &model.Channel{} channel.Name = CHANNEL_LOG_NAME channel.DisplayName = "Debugging For Sample Bot" channel.Purpose = "This is used as a test channel for logging bot debug messages" channel.Type = model.CHANNEL_OPEN channel.TeamId = botTeam.Id if rchannel, resp := client.CreateChannel(channel); resp.Error != nil { println("We failed to create the channel " + CHANNEL_LOG_NAME) PrintError(resp.Error) } else { debuggingChannel = rchannel println("Looks like this might be the first run so we've created the channel " + CHANNEL_LOG_NAME) } } func (b *Bot) SendMsgToDebuggingChannel(msg string, replyToId string) { post := &model.Post{} post.ChannelId = debuggingChannel.Id post.Message = msg post.RootId = replyToId if _, resp := client.CreatePost(post); resp.Error != nil { println("We failed to send a message to the logging channel") PrintError(resp.Error) } } func (b *Bot) HandleWebSocketResponse(event *model.WebSocketEvent) { HandleMsgFromDebuggingChannel(event) } func (b *Bot) HandleMsgFromDebuggingChannel(event *model.WebSocketEvent) { // If this isn't the debugging channel then lets ingore it if event.Broadcast.ChannelId != debuggingChannel.Id { return } // Lets only reponded to messaged posted events if event.Event != model.WEBSOCKET_EVENT_POSTED { return } println("responding to debugging channel msg") post := model.PostFromJson(strings.NewReader(event.Data["post"].(string))) if post != nil { // ignore my events if post.UserId == botUser.Id { return } // if you see any word matching 'alive' then respond if matched, _ := regexp.MatchString(`(?:^|\W)alive(?:$|\W)`, post.Message); matched { SendMsgToDebuggingChannel("Yes I'm running", post.Id) return } // if you see any word matching 'up' then respond if matched, _ := regexp.MatchString(`(?:^|\W)up(?:$|\W)`, post.Message); matched { SendMsgToDebuggingChannel("Yes I'm running", post.Id) return } // if you see any word matching 'running' then respond if matched, _ := regexp.MatchString(`(?:^|\W)running(?:$|\W)`, post.Message); matched { SendMsgToDebuggingChannel("Yes I'm running", post.Id) return } // if you see any word matching 'hello' then respond if matched, _ := regexp.MatchString(`(?:^|\W)hello(?:$|\W)`, post.Message); matched { SendMsgToDebuggingChannel("Yes I'm running", post.Id) return } } SendMsgToDebuggingChannel("I did not understand you!", post.Id) } func PrintError(err *model.AppError) { println("\tError Details:") println("\t\t" + err.Message) println("\t\t" + err.Id) println("\t\t" + err.DetailedError) } func (b *Bot) SetupGracefulShutdown() { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) go func() { for _ = range c { if webSocketClient != nil { webSocketClient.Close() } SendMsgToDebuggingChannel("_"+SAMPLE_NAME+" has **stopped** running_", "") os.Exit(0) } }() }