This commit is contained in:
Dawid Wysokiński 2020-05-30 12:43:11 +02:00
parent 7c4104c9ad
commit 9ec3357780
9 changed files with 172 additions and 49 deletions

99
cron/cron.go Normal file
View File

@ -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)
}

View File

@ -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)
}

View File

@ -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 {

1
go.mod
View File

@ -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

2
go.sum
View File

@ -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=

42
main.go
View File

@ -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!")

View File

@ -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 {

View File

@ -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

View File

@ -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)