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')
|
slackToken, _ = reader.ReadString('\n')
|
||||||
a.m.setSlackToken(strings.TrimSpace(slackToken))
|
a.m.setSlackToken(strings.TrimSpace(slackToken))
|
||||||
}
|
}
|
||||||
slackDMid, err = a.m.getSlackAdminDMId()
|
slackDMid, err = a.m.GetSlackAdminDMId()
|
||||||
if err != nil || slackDMid == "" {
|
if err != nil || slackDMid == "" {
|
||||||
fmt.Print("Slack Admin DM ID: ")
|
fmt.Print("Slack Admin DM ID: ")
|
||||||
slackDMid, _ = reader.ReadString('\n')
|
slackDMid, _ = reader.ReadString('\n')
|
||||||
@ -79,6 +79,8 @@ func (a *App) watchMessageChannel() {
|
|||||||
if slackMsg.Type == "control" && slackMsg.Name == "quit" {
|
if slackMsg.Type == "control" && slackMsg.Name == "quit" {
|
||||||
a.running = false
|
a.running = false
|
||||||
break
|
break
|
||||||
|
} else if msg.GetDestination() == "error" {
|
||||||
|
fmt.Printf("ERROR: %s: %s\n", msg.GetSource(), msg.GetMessage().Text)
|
||||||
} else if msg.GetDestination() == "slack" {
|
} else if msg.GetDestination() == "slack" {
|
||||||
a.m.SendSlackChannelMessage(&slackMsg)
|
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)
|
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"})
|
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 */
|
/* End DB Functions */
|
||||||
|
|
||||||
func (m *BotModel) NewSlack() error {
|
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 {
|
func (m *BotModel) SendSlackAdminMessage(msg *slack.Message) error {
|
||||||
// Send message to slack admin
|
// Send message to slack admin
|
||||||
var err error
|
var err error
|
||||||
msg.Channel, err = m.getSlackAdminDMId()
|
msg.Channel, err = m.GetSlackAdminDMId()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import slack "git.bullercodeworks.com/brian/go-slack"
|
|||||||
|
|
||||||
type Model interface {
|
type Model interface {
|
||||||
SendMessage(src, dest string, message slack.Message)
|
SendMessage(src, dest string, message slack.Message)
|
||||||
|
GetSlackAdminDMId() (string, error)
|
||||||
GetBytes(path []string) ([]byte, error)
|
GetBytes(path []string) ([]byte, error)
|
||||||
SetBytes(path []string, val []byte) error
|
SetBytes(path []string, val []byte) error
|
||||||
GetString(path []string) (string, error)
|
GetString(path []string) (string, error)
|
||||||
|
@ -20,9 +20,10 @@ import (
|
|||||||
|
|
||||||
/* Plugin State */
|
/* Plugin State */
|
||||||
type AoCState struct {
|
type AoCState struct {
|
||||||
model helperbot.Model
|
model helperbot.Model
|
||||||
boardId string
|
boardId string
|
||||||
sessionCookie string
|
sessionCookie string
|
||||||
|
sessionNeedsUpdate bool
|
||||||
|
|
||||||
aoc *aoc.AoC
|
aoc *aoc.AoC
|
||||||
}
|
}
|
||||||
@ -47,6 +48,8 @@ func (s *AoCState) Initialize(m helperbot.Model) error {
|
|||||||
aocSession = strings.TrimSpace(aocSession)
|
aocSession = strings.TrimSpace(aocSession)
|
||||||
if err != nil || aocSession == "" {
|
if err != nil || aocSession == "" {
|
||||||
s.RequestSessionCookie()
|
s.RequestSessionCookie()
|
||||||
|
} else {
|
||||||
|
s.sessionCookie = aocSession
|
||||||
}
|
}
|
||||||
|
|
||||||
aocChannelId, err = s.getChannelId()
|
aocChannelId, err = s.getChannelId()
|
||||||
@ -64,44 +67,27 @@ func (s *AoCState) Initialize(m helperbot.Model) error {
|
|||||||
func (s *AoCState) ProcessMessage(m helperbot.Message) {
|
func (s *AoCState) ProcessMessage(m helperbot.Message) {
|
||||||
if m.GetSource() == "slack" {
|
if m.GetSource() == "slack" {
|
||||||
slackMsg := m.GetMessage()
|
slackMsg := m.GetMessage()
|
||||||
msgPts := strings.Fields(slackMsg.Text)
|
if len(slackMsg.Channel) == 0 {
|
||||||
if len(msgPts) < 1 {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if msgPts[0] != "!aoc" || len(msgPts) < 2 {
|
switch slackMsg.Channel[0] {
|
||||||
return
|
case 'C':
|
||||||
}
|
s.ProcessChannelMessage(slackMsg)
|
||||||
msgPts = msgPts[1:]
|
case 'D':
|
||||||
yr, err := strconv.Atoi(msgPts[0])
|
admin, err := s.model.GetSlackAdminDMId()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
yr = s.GetLatestYear()
|
s.model.SendMessage(s.Name(), "error", slack.Message{
|
||||||
} else {
|
Type: "error",
|
||||||
msgPts = msgPts[1:]
|
Text: "Error getting Admin DM Id",
|
||||||
}
|
Time: time.Now(),
|
||||||
switch msgPts[0] {
|
})
|
||||||
case "ping":
|
return
|
||||||
s.model.SendMessage(s.Name(), "slack", slack.Message{
|
}
|
||||||
Type: "message",
|
if slackMsg.Channel == admin {
|
||||||
Channel: slackMsg.Channel,
|
s.ProcessAdminDirectMessage(slackMsg)
|
||||||
Text: ":christmas_tree: PONG :christmas_tree:",
|
} else {
|
||||||
})
|
s.ProcessDirectMessage(slackMsg)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
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() {
|
func (s *AoCState) runLoop() {
|
||||||
for {
|
for {
|
||||||
channelId, err := s.getChannelId()
|
_, err := s.getChannelId()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// This plugin fails without a channel id
|
// This plugin fails without a channel id
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, yr := range s.GetListOfAoCYears() {
|
for _, yr := range s.GetListOfAoCYears() {
|
||||||
l, err := s.aoc.GetLeaderboard(yr)
|
if !s.sessionNeedsUpdate {
|
||||||
if err != nil {
|
s.AoCBoardCheckAndUpdate(yr)
|
||||||
msg := slack.Message{
|
time.Sleep(time.Minute)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
time.Sleep(time.Minute)
|
|
||||||
}
|
}
|
||||||
time.Sleep(time.Minute * 10)
|
time.Sleep(time.Minute)
|
||||||
}
|
}
|
||||||
s.model.SendMessage(s.Name(), "main", slack.Message{
|
s.model.SendMessage(s.Name(), "main", slack.Message{
|
||||||
Type: "status",
|
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) {
|
func (s *AoCState) DoTopForAll() (string, error) {
|
||||||
mbrMap := make(map[string]aoc.Member)
|
mbrMap := make(map[string]aoc.Member)
|
||||||
for _, yr := range s.GetListOfAoCYears() {
|
for _, yr := range s.GetListOfAoCYears() {
|
||||||
@ -269,6 +372,74 @@ func (s *AoCState) GetAoCBoard(yr int) (*aoc.Leaderboard, error) {
|
|||||||
return s.aoc.GetLeaderboard(yr)
|
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() {
|
func (s *AoCState) RequestBoardId() {
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
fmt.Print("Advent of Code Board ID: ")
|
fmt.Print("Advent of Code Board ID: ")
|
||||||
@ -281,6 +452,7 @@ func (s *AoCState) RequestSessionCookie() {
|
|||||||
fmt.Print("Advent of Code Session Cookie: ")
|
fmt.Print("Advent of Code Session Cookie: ")
|
||||||
aocSession, _ := reader.ReadString('\n')
|
aocSession, _ := reader.ReadString('\n')
|
||||||
s.setAoCSessionCookie(strings.TrimSpace(aocSession))
|
s.setAoCSessionCookie(strings.TrimSpace(aocSession))
|
||||||
|
s.sessionCookie = aocSession
|
||||||
}
|
}
|
||||||
|
|
||||||
// The channel that we post updates to
|
// The channel that we post updates to
|
||||||
@ -327,7 +499,7 @@ func (s *AoCState) saveLeaderboard(l *aoc.Leaderboard) error {
|
|||||||
}
|
}
|
||||||
for _, v := range l.Members {
|
for _, v := range l.Members {
|
||||||
if err = s.saveMember(l.Event, &v); err != nil {
|
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",
|
Type: "error",
|
||||||
Text: fmt.Sprintf("Error Saving Member (%s)", v.Name),
|
Text: fmt.Sprintf("Error Saving Member (%s)", v.Name),
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
|
Loading…
Reference in New Issue
Block a user