From 9ec3357780ff9dd76993194a6aebee932cab0e86 Mon Sep 17 00:00:00 2001 From: Kichiyaki Date: Sat, 30 May 2020 12:43:11 +0200 Subject: [PATCH] v0.1 --- cron/cron.go | 99 +++++++++++++++++++++++++++++++++++++++++++++ discord/commands.go | 6 +-- discord/discord.go | 24 +++++------ go.mod | 1 + go.sum | 2 + main.go | 42 +++++++------------ models/server.go | 8 ++-- models/tribe.go | 11 +++++ scraper/scraper.go | 28 +++++++++++-- 9 files changed, 172 insertions(+), 49 deletions(-) create mode 100644 cron/cron.go diff --git a/cron/cron.go b/cron/cron.go new file mode 100644 index 0000000..c65d7a3 --- /dev/null +++ b/cron/cron.go @@ -0,0 +1,99 @@ +package cron + +import ( + "context" + "fmt" + "log" + "time" + "twdcbot/discord" + "twdcbot/scraper" + "twdcbot/server" + "twdcbot/tribe" + + "github.com/robfig/cron/v3" +) + +type Config struct { + ServerRepo server.Repository + TribeRepo tribe.Repository + Discord *discord.Session +} + +type handler struct { + since time.Time + serverRepo server.Repository + tribeRepo tribe.Repository + discord *discord.Session +} + +func AttachHandlers(c *cron.Cron, cfg Config) { + h := &handler{ + since: time.Now(), + serverRepo: cfg.ServerRepo, + tribeRepo: cfg.TribeRepo, + discord: cfg.Discord, + } + c.AddFunc("@every 1m", h.checkConquers) +} + +func (h *handler) checkConquers() { + worlds, err := h.tribeRepo.FetchWorlds(context.Background()) + if err != nil { + log.Print("checkConquers: " + err.Error()) + return + } + log.Print("checkConquers: worlds: ", worlds) + servers, total, err := h.serverRepo.Fetch(context.Background(), nil) + if err != nil { + log.Print("checkConquers: " + err.Error()) + return + } + log.Print("checkConquers: total number of servers: ", total) + data := scraper.New(worlds, h.since).Scrap() + h.since = time.Now() + log.Print("checkConquers: scrapped data: ", data) + for _, server := range servers { + if server.ConqueredVillagesChannelID == "" && server.LostVillagesChannelID == "" { + continue + } + for _, tribe := range server.Tribes { + conquers, ok := data[tribe.World] + if ok { + if server.LostVillagesChannelID != "" { + for _, conquer := range conquers.LostVillages(tribe.TribeID) { + if server.Tribes.Contains(tribe.World, conquer.NewOwnerTribeID) { + continue + } + h.discord.SendMessage(server.LostVillagesChannelID, formatMsgAboutVillageLost(conquer)) + } + } + if server.ConqueredVillagesChannelID != "" { + for _, conquer := range conquers.ConqueredVillages(tribe.TribeID) { + if server.Tribes.Contains(tribe.World, conquer.OldOwnerTribeID) { + continue + } + h.discord.SendMessage(server.ConqueredVillagesChannelID, formatMsgAboutVillageConquered(conquer)) + } + } + } + } + } +} + +func formatMsgAboutVillageLost(conquer *scraper.Conquer) string { + return fmt.Sprintf(`Wioska %s (właściciel: %s [%s]) została stracona na rzecz gracza %s (%s)`, + conquer.Village, + conquer.OldOwnerName, + conquer.OldOwnerTribeName, + conquer.NewOwnerName, + conquer.NewOwnerTribeName) +} + +func formatMsgAboutVillageConquered(conquer *scraper.Conquer) string { + return fmt.Sprintf(`Gracz %s (%s) podbił wioskę %s od gracza %s (%s)`, + conquer.NewOwnerName, + conquer.NewOwnerTribeName, + conquer.Village, + conquer.OldOwnerName, + conquer.OldOwnerTribeName) +} diff --git a/discord/commands.go b/discord/commands.go index daca4c8..8bf9082 100644 --- a/discord/commands.go +++ b/discord/commands.go @@ -24,13 +24,13 @@ func (cmd Command) WithPrefix(prefix string) string { } func (s *Session) sendHelpMessage(mention, channelID string) { - s.sendMessage(channelID, mention+" zaraz ogarnę help cmd") + s.SendMessage(channelID, mention+" zaraz ogarnę help cmd") } func (s *Session) sendUnknownCommandError(mention, channelID string, command ...string) { - s.sendMessage(channelID, mention+` Nieznana komenda: `+strings.Join(command, " ")) + s.SendMessage(channelID, mention+` Nieznana komenda: `+strings.Join(command, " ")) } -func (s *Session) sendMessage(channelID, message string) { +func (s *Session) SendMessage(channelID, message string) { s.dg.ChannelMessageSend(channelID, message) } diff --git a/discord/discord.go b/discord/discord.go index e552eae..e87e872 100644 --- a/discord/discord.go +++ b/discord/discord.go @@ -98,7 +98,7 @@ func (s *Session) handleLostVillagesCommand(m *discordgo.MessageCreate) { } server.LostVillagesChannelID = m.ChannelID go s.cfg.ServerRepository.Update(context.Background(), server) - s.sendMessage(m.ChannelID, + s.SendMessage(m.ChannelID, fmt.Sprintf("%s Pomyślnie zmieniono kanał na którym będą się wyświetlać informacje o straconych wioskach.", m.Author.Mention())) } @@ -112,7 +112,7 @@ func (s *Session) handleConqueredVillagesCommand(m *discordgo.MessageCreate) { } server.ConqueredVillagesChannelID = m.ChannelID go s.cfg.ServerRepository.Update(context.Background(), server) - s.sendMessage(m.ChannelID, + s.SendMessage(m.ChannelID, fmt.Sprintf("%s Pomyślnie zmieniono kanał na którym będą się wyświetlać informacje o podbitych wioskach.", m.Author.Mention())) } @@ -122,7 +122,7 @@ func (s *Session) handleAddCommand(m *discordgo.MessageCreate, args ...string) { s.sendUnknownCommandError(m.Author.Mention(), m.ChannelID, args[2:argsLength]...) return } else if argsLength < 2 { - s.sendMessage(m.ChannelID, + s.SendMessage(m.ChannelID, fmt.Sprintf("%s %s [świat] [id plemienia]", m.Author.Mention(), AddCommand.WithPrefix(s.cfg.CommandPrefix))) @@ -131,7 +131,7 @@ func (s *Session) handleAddCommand(m *discordgo.MessageCreate, args ...string) { world := args[0] id, err := strconv.Atoi(args[1]) if err != nil { - s.sendMessage(m.ChannelID, + s.SendMessage(m.ChannelID, fmt.Sprintf("%s %s [świat] [id plemienia]", m.Author.Mention(), AddCommand.WithPrefix(s.cfg.CommandPrefix))) @@ -142,11 +142,11 @@ func (s *Session) handleAddCommand(m *discordgo.MessageCreate, args ...string) { } err = s.cfg.ServerRepository.Store(context.Background(), server) if err != nil { - s.sendMessage(m.ChannelID, m.Author.Mention()+` Nie udało się dodać plemienia do obserwowanych.`) + s.SendMessage(m.ChannelID, m.Author.Mention()+` Nie udało się dodać plemienia do obserwowanych.`) return } if len(server.Tribes) >= TribesPerServer { - s.sendMessage(m.ChannelID, m.Author.Mention()+fmt.Sprintf(` Osiągnięto limit plemion (%d/%d).`, TribesPerServer, TribesPerServer)) + s.SendMessage(m.ChannelID, m.Author.Mention()+fmt.Sprintf(` Osiągnięto limit plemion (%d/%d).`, TribesPerServer, TribesPerServer)) return } err = s.cfg.TribeRepository.Store(context.Background(), &models.Tribe{ @@ -155,11 +155,11 @@ func (s *Session) handleAddCommand(m *discordgo.MessageCreate, args ...string) { ServerID: server.ID, }) if err != nil { - s.sendMessage(m.ChannelID, m.Author.Mention()+` Nie udało się dodać plemienia do obserwowanych.`) + s.SendMessage(m.ChannelID, m.Author.Mention()+` Nie udało się dodać plemienia do obserwowanych.`) return } - s.sendMessage(m.ChannelID, m.Author.Mention()+` Dodano.`) + s.SendMessage(m.ChannelID, m.Author.Mention()+` Dodano.`) } func (s *Session) handleDeleteCommand(m *discordgo.MessageCreate, args ...string) { @@ -168,7 +168,7 @@ func (s *Session) handleDeleteCommand(m *discordgo.MessageCreate, args ...string s.sendUnknownCommandError(m.Author.Mention(), m.ChannelID, args[1:argsLength]...) return } else if argsLength < 1 { - s.sendMessage(m.ChannelID, + s.SendMessage(m.ChannelID, fmt.Sprintf(`%s %s [id z tw!list]`, m.Author.Mention(), DeleteCommand.WithPrefix(s.cfg.CommandPrefix))) @@ -177,7 +177,7 @@ func (s *Session) handleDeleteCommand(m *discordgo.MessageCreate, args ...string id, err := strconv.Atoi(args[0]) if err != nil { - s.sendMessage(m.ChannelID, + s.SendMessage(m.ChannelID, fmt.Sprintf(`%s %s [id z tw!list]`, m.Author.Mention(), DeleteCommand.WithPrefix(s.cfg.CommandPrefix))) @@ -189,7 +189,7 @@ func (s *Session) handleDeleteCommand(m *discordgo.MessageCreate, args ...string ID: []int{id}, }) - s.sendMessage(m.ChannelID, m.Author.Mention()+` Usunięto.`) + s.SendMessage(m.ChannelID, m.Author.Mention()+` Usunięto.`) } func (s *Session) handleListCommand(m *discordgo.MessageCreate) { @@ -204,7 +204,7 @@ func (s *Session) handleListCommand(m *discordgo.MessageCreate) { msg += fmt.Sprintf(">>> %d - %s - %d\n", tribe.ID, tribe.World, tribe.TribeID) } msg += "```" - s.sendMessage(m.ChannelID, msg) + s.SendMessage(m.ChannelID, msg) } func (s *Session) Close() error { diff --git a/go.mod b/go.mod index 94a66b3..a58ff51 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/joho/godotenv v1.3.0 github.com/kennygrant/sanitize v1.2.4 // indirect github.com/pkg/errors v0.9.1 + github.com/robfig/cron/v3 v3.0.1 github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect github.com/sirupsen/logrus v1.6.0 github.com/temoto/robotstxt v1.1.1 // indirect diff --git a/go.sum b/go.sum index 9f41489..f72ac20 100644 --- a/go.sum +++ b/go.sum @@ -105,6 +105,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI= github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= github.com/segmentio/encoding v0.1.10/go.mod h1:RWhr02uzMB9gQC1x+MfYxedtmBibb9cZ6Vv9VxRSSbw= diff --git a/main.go b/main.go index 8b08469..26657ad 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,7 @@ import ( "os" "os/signal" "syscall" + _cron "twdcbot/cron" "twdcbot/discord" "twdcbot/mode" server_repository "twdcbot/server/repository" @@ -12,6 +13,7 @@ import ( "github.com/go-pg/pg/v10" "github.com/joho/godotenv" + "github.com/robfig/cron/v3" "github.com/sirupsen/logrus" ) @@ -47,7 +49,7 @@ func main() { sess, err := discord.New(discord.SessionConfig{ Token: os.Getenv("BOT_TOKEN"), CommandPrefix: "tw!", - Status: "Twstats", + Status: "Tribalwars | tw!help", TribeRepository: tribeRepo, ServerRepository: serverRepo, }) @@ -56,32 +58,18 @@ func main() { } defer sess.Close() - // for world, conquers := range scraper.New([]string{"pl149", "pl150"}, time.Now().Add(time.Minute*-10)).Scrap() { - // fmt.Print("\n\n", world, "\n\n") - // for _, c := range conquers { - // log.Print(c.ConqueredAt, - // " | ", - // c.VillageID, - // " | ", - // c.Village, - // " | ", - // c.OldOwnerID, - // " | ", - // c.OldOwnerName, - // " | ", - // c.OldOwnerTribeID, - // " | ", - // c.OldOwnerTribeName, - // " | ", - // c.NewOwnerID, - // " | ", - // c.NewOwnerName, - // " | ", - // c.NewOwnerTribeID, - // " | ", - // c.NewOwnerTribeName) - // } - // } + c := cron.New(cron.WithChain( + cron.SkipIfStillRunning(cron.VerbosePrintfLogger(log.New(os.Stdout, "cron: ", log.LstdFlags))), + )) + _cron.AttachHandlers(c, _cron.Config{ + ServerRepo: serverRepo, + TribeRepo: tribeRepo, + Discord: sess, + }) + go func() { + c.Run() + }() + defer c.Stop() log.Print("Bot is waiting for your actions!") diff --git a/models/server.go b/models/server.go index d6e7370..1885eb7 100644 --- a/models/server.go +++ b/models/server.go @@ -1,10 +1,10 @@ package models type Server struct { - ID string `pg:",pk" json:"id" gqlgen:"id"` - ConqueredVillagesChannelID string `json:"conqueredVillagesChannelID" gqlgen:"conqueredVillagesChannelID"` - LostVillagesChannelID string `json:"lostVillagesChannelID" gqlgen:"lostVillagesChannelID"` - Tribes []*Tribe `json:"tribes,omitempty" gqlgen:"tribes"` + ID string `pg:",pk" json:"id" gqlgen:"id"` + ConqueredVillagesChannelID string `json:"conqueredVillagesChannelID" gqlgen:"conqueredVillagesChannelID"` + LostVillagesChannelID string `json:"lostVillagesChannelID" gqlgen:"lostVillagesChannelID"` + Tribes Tribes `json:"tribes,omitempty" gqlgen:"tribes"` } type ServerFilter struct { diff --git a/models/tribe.go b/models/tribe.go index 2d55b0f..f0e6257 100644 --- a/models/tribe.go +++ b/models/tribe.go @@ -8,6 +8,17 @@ type Tribe struct { Server *Server `json:"server,omitempty" gqlgen:"server"` } +type Tribes []*Tribe + +func (t Tribes) Contains(world string, id int) bool { + for _, tribe := range t { + if tribe.TribeID == id && tribe.World == world { + return true + } + } + return false +} + type TribeFilter struct { ID []int ServerID []string diff --git a/scraper/scraper.go b/scraper/scraper.go index 8663a91..b2a17f8 100644 --- a/scraper/scraper.go +++ b/scraper/scraper.go @@ -31,12 +31,34 @@ type Conquer struct { ConqueredAt time.Time } +type Conquers []*Conquer + +func (c Conquers) LostVillages(tribeID int) Conquers { + filtered := Conquers{} + for _, conquer := range c { + if conquer.OldOwnerTribeID == tribeID && conquer.OldOwnerTribeID != conquer.NewOwnerTribeID { + filtered = append(filtered, conquer) + } + } + return filtered +} + +func (c Conquers) ConqueredVillages(tribeID int) Conquers { + filtered := Conquers{} + for _, conquer := range c { + if conquer.NewOwnerTribeID == tribeID && conquer.NewOwnerTribeID != conquer.OldOwnerTribeID { + filtered = append(filtered, conquer) + } + } + return filtered +} + type Scraper struct { worlds []string since time.Time collector *colly.Collector mutex sync.Mutex - result map[string][]*Conquer + result map[string]Conquers } func New(worlds []string, since time.Time) *Scraper { @@ -117,8 +139,8 @@ func (s *Scraper) handleHTML(row *colly.HTMLElement) { s.mutex.Unlock() } -func (s *Scraper) Scrap() map[string][]*Conquer { - s.result = make(map[string][]*Conquer) +func (s *Scraper) Scrap() map[string]Conquers { + s.result = make(map[string]Conquers) s.collector.OnHTML(".r1", s.handleHTML) s.collector.OnHTML(".r2", s.handleHTML)