Helperbot & the AoC Plugin are working pretty well
This commit is contained in:
parent
0bbab771ce
commit
8f70393598
@ -57,7 +57,7 @@ func (a *App) initialize() error {
|
||||
slackToken, _ = reader.ReadString('\n')
|
||||
a.m.setSlackToken(strings.TrimSpace(slackToken))
|
||||
}
|
||||
slackDMid, err = a.m.getSlackAdminDMId()
|
||||
slackDMid, err = a.m.GetSlackAdminDMId()
|
||||
if err != nil || slackDMid == "" {
|
||||
fmt.Print("Slack Admin DM ID: ")
|
||||
slackDMid, _ = reader.ReadString('\n')
|
||||
@ -79,6 +79,8 @@ func (a *App) watchMessageChannel() {
|
||||
if slackMsg.Type == "control" && slackMsg.Name == "quit" {
|
||||
a.running = false
|
||||
break
|
||||
} else if msg.GetDestination() == "error" {
|
||||
fmt.Printf("ERROR: %s: %s\n", msg.GetSource(), msg.GetMessage().Text)
|
||||
} else if msg.GetDestination() == "slack" {
|
||||
a.m.SendSlackChannelMessage(&slackMsg)
|
||||
}
|
||||
|
@ -17,18 +17,10 @@ func (m *BotModel) setSlackAdminDMId(adminId string) error {
|
||||
return m.SetString([]string{"slack", "config", "admin_dm_id"}, adminId)
|
||||
}
|
||||
|
||||
func (m *BotModel) getSlackAdminDMId() (string, error) {
|
||||
func (m *BotModel) GetSlackAdminDMId() (string, error) {
|
||||
return m.GetString([]string{"slack", "config", "admin_dm_id"})
|
||||
}
|
||||
|
||||
func (m *BotModel) setSlackChannelId(chanId string) error {
|
||||
return m.SetString([]string{"slack", "config", "channel_id"}, chanId)
|
||||
}
|
||||
|
||||
func (m *BotModel) getSlackChannelId() (string, error) {
|
||||
return m.GetString([]string{"slack", "config", "channel_id"})
|
||||
}
|
||||
|
||||
/* End DB Functions */
|
||||
|
||||
func (m *BotModel) NewSlack() error {
|
||||
@ -66,7 +58,7 @@ func (m *BotModel) SendSlackChannelMessage(msg *slack.Message) error {
|
||||
func (m *BotModel) SendSlackAdminMessage(msg *slack.Message) error {
|
||||
// Send message to slack admin
|
||||
var err error
|
||||
msg.Channel, err = m.getSlackAdminDMId()
|
||||
msg.Channel, err = m.GetSlackAdminDMId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import slack "git.bullercodeworks.com/brian/go-slack"
|
||||
|
||||
type Model interface {
|
||||
SendMessage(src, dest string, message slack.Message)
|
||||
GetSlackAdminDMId() (string, error)
|
||||
GetBytes(path []string) ([]byte, error)
|
||||
SetBytes(path []string, val []byte) error
|
||||
GetString(path []string) (string, error)
|
||||
|
@ -20,9 +20,10 @@ import (
|
||||
|
||||
/* Plugin State */
|
||||
type AoCState struct {
|
||||
model helperbot.Model
|
||||
boardId string
|
||||
sessionCookie string
|
||||
model helperbot.Model
|
||||
boardId string
|
||||
sessionCookie string
|
||||
sessionNeedsUpdate bool
|
||||
|
||||
aoc *aoc.AoC
|
||||
}
|
||||
@ -47,6 +48,8 @@ func (s *AoCState) Initialize(m helperbot.Model) error {
|
||||
aocSession = strings.TrimSpace(aocSession)
|
||||
if err != nil || aocSession == "" {
|
||||
s.RequestSessionCookie()
|
||||
} else {
|
||||
s.sessionCookie = aocSession
|
||||
}
|
||||
|
||||
aocChannelId, err = s.getChannelId()
|
||||
@ -64,44 +67,27 @@ func (s *AoCState) Initialize(m helperbot.Model) error {
|
||||
func (s *AoCState) ProcessMessage(m helperbot.Message) {
|
||||
if m.GetSource() == "slack" {
|
||||
slackMsg := m.GetMessage()
|
||||
msgPts := strings.Fields(slackMsg.Text)
|
||||
if len(msgPts) < 1 {
|
||||
if len(slackMsg.Channel) == 0 {
|
||||
return
|
||||
}
|
||||
if msgPts[0] != "!aoc" || len(msgPts) < 2 {
|
||||
return
|
||||
}
|
||||
msgPts = msgPts[1:]
|
||||
yr, err := strconv.Atoi(msgPts[0])
|
||||
if err != nil {
|
||||
yr = s.GetLatestYear()
|
||||
} else {
|
||||
msgPts = msgPts[1:]
|
||||
}
|
||||
switch msgPts[0] {
|
||||
case "ping":
|
||||
s.model.SendMessage(s.Name(), "slack", slack.Message{
|
||||
Type: "message",
|
||||
Channel: slackMsg.Channel,
|
||||
Text: ":christmas_tree: PONG :christmas_tree:",
|
||||
})
|
||||
case "top":
|
||||
var txt string
|
||||
if yr == -1 {
|
||||
var err error
|
||||
txt, err = s.DoTopForAll()
|
||||
if err != nil {
|
||||
txt = "Error calculating all-time tops"
|
||||
}
|
||||
} else {
|
||||
txt = s.DoTopForYear(yr)
|
||||
switch slackMsg.Channel[0] {
|
||||
case 'C':
|
||||
s.ProcessChannelMessage(slackMsg)
|
||||
case 'D':
|
||||
admin, err := s.model.GetSlackAdminDMId()
|
||||
if err != nil {
|
||||
s.model.SendMessage(s.Name(), "error", slack.Message{
|
||||
Type: "error",
|
||||
Text: "Error getting Admin DM Id",
|
||||
Time: time.Now(),
|
||||
})
|
||||
return
|
||||
}
|
||||
if slackMsg.Channel == admin {
|
||||
s.ProcessAdminDirectMessage(slackMsg)
|
||||
} else {
|
||||
s.ProcessDirectMessage(slackMsg)
|
||||
}
|
||||
s.model.SendMessage(s.Name(), "slack", slack.Message{
|
||||
Type: "message",
|
||||
Channel: slackMsg.Channel,
|
||||
Text: txt,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -130,47 +116,18 @@ func (s *AoCState) NewAoC() error {
|
||||
|
||||
func (s *AoCState) runLoop() {
|
||||
for {
|
||||
channelId, err := s.getChannelId()
|
||||
_, err := s.getChannelId()
|
||||
if err != nil {
|
||||
// This plugin fails without a channel id
|
||||
return
|
||||
}
|
||||
for _, yr := range s.GetListOfAoCYears() {
|
||||
l, err := s.aoc.GetLeaderboard(yr)
|
||||
if err != nil {
|
||||
msg := slack.Message{
|
||||
Type: "error",
|
||||
Text: fmt.Sprintf("Error processing leaderboard (%d)", yr),
|
||||
Time: time.Now(),
|
||||
}
|
||||
s.model.SendMessage(s.Name(), "main", msg)
|
||||
} else {
|
||||
msg := slack.Message{
|
||||
Type: "success",
|
||||
Text: fmt.Sprintf("Received leaderboard (%d)", yr),
|
||||
Time: time.Now(),
|
||||
}
|
||||
s.model.SendMessage(s.Name(), "main", msg)
|
||||
// Compare the new leaderboard to the saved one
|
||||
for _, v := range l.Members {
|
||||
mbr, err := s.getMember(l.Event, v.ID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if mbr.Stars != v.Stars {
|
||||
s.model.SendMessage(s.Name(), "slack", slack.Message{
|
||||
Type: "message",
|
||||
Channel: channelId,
|
||||
Text: ":christmas_tree: " + v.Name + " now has " + strconv.Itoa(v.Stars) + " stars! :christmas_tree:",
|
||||
})
|
||||
}
|
||||
}
|
||||
// Save the leaderboard to the db
|
||||
s.saveLeaderboard(l)
|
||||
if !s.sessionNeedsUpdate {
|
||||
s.AoCBoardCheckAndUpdate(yr)
|
||||
time.Sleep(time.Minute)
|
||||
}
|
||||
time.Sleep(time.Minute)
|
||||
}
|
||||
time.Sleep(time.Minute * 10)
|
||||
time.Sleep(time.Minute)
|
||||
}
|
||||
s.model.SendMessage(s.Name(), "main", slack.Message{
|
||||
Type: "status",
|
||||
@ -179,6 +136,152 @@ func (s *AoCState) runLoop() {
|
||||
})
|
||||
}
|
||||
|
||||
func (s *AoCState) ProcessDirectMessage(slackMsg slack.Message) {
|
||||
msgPts := strings.Fields(slackMsg.Text)
|
||||
if len(msgPts) < 2 || msgPts[0] != "!aoc" {
|
||||
return
|
||||
}
|
||||
switch msgPts[1] {
|
||||
case "help":
|
||||
s.DoHelpCmd(slackMsg)
|
||||
case "ping":
|
||||
s.DoPingCmd(slackMsg)
|
||||
case "top":
|
||||
s.DoTopCmd(slackMsg)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *AoCState) ProcessAdminDirectMessage(slackMsg slack.Message) {
|
||||
msgPts := strings.Fields(slackMsg.Text)
|
||||
if len(msgPts) < 2 || msgPts[0] != "!aoc" {
|
||||
return
|
||||
}
|
||||
switch msgPts[1] {
|
||||
case "help":
|
||||
s.DoHelpAdminCmd(slackMsg)
|
||||
case "ping":
|
||||
s.DoPingCmd(slackMsg)
|
||||
case "top":
|
||||
s.DoTopCmd(slackMsg)
|
||||
case "session":
|
||||
s.DoSessionCmd(slackMsg)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *AoCState) ProcessChannelMessage(slackMsg slack.Message) {
|
||||
msgPts := strings.Fields(slackMsg.Text)
|
||||
if len(msgPts) < 2 || msgPts[0] != "!aoc" {
|
||||
return
|
||||
}
|
||||
switch msgPts[1] {
|
||||
case "top":
|
||||
s.DoTopCmd(slackMsg)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *AoCState) DoHelpCmd(slackMsg slack.Message) {
|
||||
txt := fmt.Sprint(":christmas_tree: AoC Help :christmas_tree:\n",
|
||||
"-- WiP --",
|
||||
)
|
||||
s.model.SendMessage(s.Name(), "slack", slack.Message{
|
||||
Type: "message",
|
||||
Channel: slackMsg.Channel,
|
||||
Text: txt,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *AoCState) DoHelpAdminCmd(slackMsg slack.Message) {
|
||||
txt := fmt.Sprint(":christmas_tree: AoC Help :christmas_tree:\n",
|
||||
"-- WiP --",
|
||||
)
|
||||
s.model.SendMessage(s.Name(), "slack", slack.Message{
|
||||
Type: "message",
|
||||
Channel: slackMsg.Channel,
|
||||
Text: txt,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *AoCState) DoPingCmd(slackMsg slack.Message) {
|
||||
s.model.SendMessage(s.Name(), "slack", slack.Message{
|
||||
Type: "message",
|
||||
Channel: slackMsg.Channel,
|
||||
Text: ":christmas_tree: PONG :christmas_tree:",
|
||||
})
|
||||
}
|
||||
|
||||
func (s *AoCState) DoSessionCmd(slackMsg slack.Message) {
|
||||
msgPts := strings.Fields(slackMsg.Text)
|
||||
if len(msgPts) == 3 && msgPts[1] == "session" {
|
||||
// Set the session cookie
|
||||
admin, err := s.model.GetSlackAdminDMId()
|
||||
if err != nil {
|
||||
s.model.SendMessage(s.Name(), "error", slack.Message{
|
||||
Type: "error",
|
||||
Text: "Error getting Admin DM Id",
|
||||
Time: time.Now(),
|
||||
})
|
||||
return
|
||||
}
|
||||
aocSession := msgPts[2]
|
||||
s.setAoCSessionCookie(strings.TrimSpace(aocSession))
|
||||
s.sessionCookie = aocSession
|
||||
s.sessionNeedsUpdate = false
|
||||
s.model.SendMessage(s.Name(), "slack", slack.Message{
|
||||
Type: "message",
|
||||
Channel: admin,
|
||||
Text: ":christmas_tree: New Session: " + s.sessionCookie,
|
||||
})
|
||||
} else if len(msgPts) == 2 && msgPts[1] == "session" {
|
||||
// Print the session cookie
|
||||
admin, err := s.model.GetSlackAdminDMId()
|
||||
if err != nil {
|
||||
s.model.SendMessage(s.Name(), "error", slack.Message{
|
||||
Type: "error",
|
||||
Text: "Error getting Admin DM Id",
|
||||
Time: time.Now(),
|
||||
})
|
||||
return
|
||||
}
|
||||
// We only send the session cookie to the admin
|
||||
s.model.SendMessage(s.Name(), "slack", slack.Message{
|
||||
Type: "message",
|
||||
Channel: admin,
|
||||
Text: ":christmas_tree: session: " + s.sessionCookie,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *AoCState) DoTopCmd(slackMsg slack.Message) {
|
||||
msgPts := strings.Fields(slackMsg.Text)
|
||||
var err error
|
||||
var yr int
|
||||
if len(msgPts) > 2 {
|
||||
yr, err = strconv.Atoi(msgPts[2])
|
||||
if err != nil {
|
||||
if msgPts[2] == "all" {
|
||||
yr = -1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
yr = s.GetLatestYear()
|
||||
}
|
||||
var txt string
|
||||
if yr == -1 {
|
||||
var err error
|
||||
txt, err = s.DoTopForAll()
|
||||
if err != nil {
|
||||
txt = "Error calculating all-time tops"
|
||||
}
|
||||
} else {
|
||||
txt = s.DoTopForYear(yr)
|
||||
}
|
||||
s.model.SendMessage(s.Name(), "slack", slack.Message{
|
||||
Type: "message",
|
||||
Channel: slackMsg.Channel,
|
||||
Text: txt,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *AoCState) DoTopForAll() (string, error) {
|
||||
mbrMap := make(map[string]aoc.Member)
|
||||
for _, yr := range s.GetListOfAoCYears() {
|
||||
@ -269,6 +372,74 @@ func (s *AoCState) GetAoCBoard(yr int) (*aoc.Leaderboard, error) {
|
||||
return s.aoc.GetLeaderboard(yr)
|
||||
}
|
||||
|
||||
func (s *AoCState) AoCBoardCheckAndUpdate(yr int) {
|
||||
channelId, _ := s.getChannelId()
|
||||
if s.AoCBoardNeedsUpdate(yr) {
|
||||
l, err := s.aoc.GetLeaderboard(yr)
|
||||
if err != nil {
|
||||
admin, adminErr := s.model.GetSlackAdminDMId()
|
||||
if adminErr != nil {
|
||||
s.model.SendMessage(s.Name(), "error", slack.Message{
|
||||
Type: "error",
|
||||
Text: "Error getting Admin DM Id",
|
||||
Time: time.Now(),
|
||||
})
|
||||
return
|
||||
}
|
||||
if err.Error() == "Invalid Session Cookie" {
|
||||
s.sessionNeedsUpdate = true
|
||||
}
|
||||
s.model.SendMessage(s.Name(), "slack", slack.Message{
|
||||
Type: "message",
|
||||
Channel: admin,
|
||||
Text: fmt.Sprintf(":warning: AoC Error processing leaderboard (%d) - %s", yr, err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
msg := slack.Message{
|
||||
Type: "success",
|
||||
Text: fmt.Sprintf("Received leaderboard (%d)", yr),
|
||||
Time: time.Now(),
|
||||
}
|
||||
s.model.SendMessage(s.Name(), "main", msg)
|
||||
// Compare the new leaderboard to the saved one
|
||||
for _, v := range l.Members {
|
||||
mbr, err := s.getMember(l.Event, v.ID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if mbr.Stars != v.Stars {
|
||||
s.model.SendMessage(s.Name(), "slack", slack.Message{
|
||||
Type: "message",
|
||||
Channel: channelId,
|
||||
Text: ":christmas_tree: " + v.Name + " now has " + strconv.Itoa(v.Stars) + " stars! :christmas_tree:",
|
||||
})
|
||||
}
|
||||
}
|
||||
// Save the leaderboard to the db
|
||||
s.saveLeaderboard(l)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *AoCState) AoCBoardNeedsUpdate(yr int) bool {
|
||||
var freshDt time.Duration
|
||||
if yr == s.GetLatestYear() {
|
||||
freshDt, _ = time.ParseDuration("10m")
|
||||
} else {
|
||||
freshDt, _ = time.ParseDuration("1h")
|
||||
}
|
||||
l, err := s.aoc.GetCachedLeaderboard(yr)
|
||||
if err != nil {
|
||||
if err.Error() == "Invalid Year" {
|
||||
return false
|
||||
}
|
||||
// This board is not cached, we need to pull it
|
||||
return true
|
||||
}
|
||||
return time.Since(l.LastFetch) > freshDt
|
||||
}
|
||||
|
||||
func (s *AoCState) RequestBoardId() {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
fmt.Print("Advent of Code Board ID: ")
|
||||
@ -281,6 +452,7 @@ func (s *AoCState) RequestSessionCookie() {
|
||||
fmt.Print("Advent of Code Session Cookie: ")
|
||||
aocSession, _ := reader.ReadString('\n')
|
||||
s.setAoCSessionCookie(strings.TrimSpace(aocSession))
|
||||
s.sessionCookie = aocSession
|
||||
}
|
||||
|
||||
// The channel that we post updates to
|
||||
@ -327,7 +499,7 @@ func (s *AoCState) saveLeaderboard(l *aoc.Leaderboard) error {
|
||||
}
|
||||
for _, v := range l.Members {
|
||||
if err = s.saveMember(l.Event, &v); err != nil {
|
||||
s.model.SendMessage(s.Name(), "main", slack.Message{
|
||||
s.model.SendMessage(s.Name(), "error", slack.Message{
|
||||
Type: "error",
|
||||
Text: fmt.Sprintf("Error Saving Member (%s)", v.Name),
|
||||
Time: time.Now(),
|
||||
|
Reference in New Issue
Block a user