FlameInTheDark /
dtbot
| 1 | package main |
||
| 2 | |||
| 3 | import ( |
||
| 4 | "bytes" |
||
| 5 | "fmt" |
||
| 6 | "log" |
||
| 7 | "net/http" |
||
| 8 | "net/url" |
||
| 9 | "os" |
||
| 10 | "os/signal" |
||
| 11 | "strings" |
||
| 12 | "syscall" |
||
| 13 | "time" |
||
| 14 | |||
| 15 | "gopkg.in/robfig/cron.v2" |
||
| 16 | |||
| 17 | "github.com/FlameInTheDark/dtbot/bot" |
||
| 18 | "github.com/FlameInTheDark/dtbot/cmd" |
||
| 19 | "github.com/bwmarrin/discordgo" |
||
| 20 | ) |
||
| 21 | |||
| 22 | var ( |
||
| 23 | conf *bot.Config |
||
| 24 | // CmdHandler bot command handler. |
||
| 25 | CmdHandler *bot.CommandHandler |
||
| 26 | // Sessions bot session manager |
||
| 27 | Sessions *bot.SessionManager |
||
| 28 | botId string |
||
|
0 ignored issues
–
show
introduced
by
Loading history...
|
|||
| 29 | youtube *bot.Youtube |
||
| 30 | botMsg *bot.BotMessages |
||
| 31 | dataType *bot.DataType |
||
| 32 | dbWorker *bot.DBWorker |
||
| 33 | guilds *bot.GuildsMap |
||
| 34 | botCron *cron.Cron |
||
| 35 | twitch *bot.Twitch |
||
| 36 | albUpdater *bot.AlbionUpdater |
||
| 37 | blacklist *bot.BlackListStruct |
||
| 38 | messagesCounter int |
||
| 39 | ) |
||
| 40 | |||
| 41 | func main() { |
||
| 42 | botCron = cron.New() |
||
| 43 | conf = bot.LoadConfig() |
||
| 44 | CmdHandler = bot.NewCommandHandler() |
||
| 45 | registerCommands() |
||
| 46 | Sessions = bot.NewSessionManager() |
||
| 47 | youtube = &bot.Youtube{Conf: conf} |
||
| 48 | botMsg = bot.NewMessagesMap() |
||
| 49 | dataType = bot.NewDataType() |
||
| 50 | discord, err := discordgo.New("Bot " + os.Getenv("BOT_TOKEN")) |
||
| 51 | if err != nil { |
||
| 52 | fmt.Println("Create session error, ", err) |
||
| 53 | return |
||
| 54 | } |
||
| 55 | usr, err := discord.User("@me") |
||
| 56 | if err != nil { |
||
| 57 | fmt.Println("Error obtaining account details,", err) |
||
| 58 | return |
||
| 59 | } |
||
| 60 | botId = usr.ID |
||
| 61 | discord.AddHandler(func(discord *discordgo.Session, ready *discordgo.Ready) { |
||
| 62 | _ = discord.UpdateStatus(0, conf.General.Game) |
||
| 63 | guilds := discord.State.Guilds |
||
| 64 | fmt.Println("Ready with", len(guilds), "guilds.") |
||
| 65 | }) |
||
| 66 | |||
| 67 | err = discord.Open() |
||
| 68 | if err != nil { |
||
| 69 | fmt.Printf("Connection open error: %v", err) |
||
| 70 | return |
||
| 71 | } |
||
| 72 | defer discord.Close() |
||
| 73 | fmt.Println("Bot is now running.") |
||
| 74 | |||
| 75 | sc := make(chan os.Signal, 1) |
||
| 76 | signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) |
||
| 77 | dbWorker = bot.NewDBSession(conf.General.DatabaseName) |
||
| 78 | guilds = dbWorker.InitGuilds(discord, conf) |
||
| 79 | botCron.Start() |
||
| 80 | defer botCron.Stop() |
||
| 81 | defer dbWorker.DBSession.Close() |
||
| 82 | twitch = bot.TwitchInit(discord, conf, dbWorker) |
||
| 83 | albUpdater = bot.AlbionGetUpdater(dbWorker) |
||
| 84 | blacklist = dbWorker.GetBlacklist() |
||
| 85 | go BotUpdater(discord) |
||
| 86 | // Init command handler |
||
| 87 | discord.AddHandler(guildAddHandler) |
||
| 88 | discord.AddHandler(commandHandler) |
||
| 89 | discord.AddHandler(joinHandler) |
||
| 90 | onStart() |
||
| 91 | <-sc |
||
| 92 | } |
||
| 93 | |||
| 94 | // Handle new users |
||
| 95 | func joinHandler(discord *discordgo.Session, e *discordgo.GuildMemberAdd) { |
||
| 96 | if _, ok := guilds.Guilds[e.GuildID]; !ok { |
||
| 97 | dbWorker.InitNewGuild(e.GuildID, conf, guilds) |
||
| 98 | } else { |
||
| 99 | bot.Greetings(discord, e, guilds.Guilds[e.GuildID]) |
||
| 100 | } |
||
| 101 | } |
||
| 102 | |||
| 103 | // Handle new guilds |
||
| 104 | func guildAddHandler(discord *discordgo.Session, e *discordgo.GuildCreate) { |
||
| 105 | if _, ok := guilds.Guilds[e.ID]; !ok { |
||
| 106 | dbWorker.InitNewGuild(e.ID, conf, guilds) |
||
| 107 | } |
||
| 108 | emb := bot.NewEmbed(""). |
||
| 109 | Field(conf.GetLocaleLang("bot_joined_title", guilds.Guilds[e.ID].Language), conf.GetLocaleLang("bot_joined_text", guilds.Guilds[e.ID].Language), false) |
||
| 110 | _, _ = discord.ChannelMessageSendEmbed(e.OwnerID, emb.GetEmbed()) |
||
| 111 | } |
||
| 112 | |||
| 113 | // Handle discord messages |
||
| 114 | func commandHandler(discord *discordgo.Session, message *discordgo.MessageCreate) { |
||
| 115 | if blacklist.CheckGuild(message.GuildID) || blacklist.CheckUser(message.Author.ID) { |
||
| 116 | return |
||
| 117 | } |
||
| 118 | messagesCounter++ |
||
| 119 | user := message.Author |
||
| 120 | if user.ID == botId || user.Bot { |
||
| 121 | return |
||
| 122 | } |
||
| 123 | args := strings.Split(message.Content, " ") |
||
| 124 | name := strings.ToLower(args[0]) |
||
| 125 | command, found := CmdHandler.Get(name) |
||
| 126 | if !found { |
||
| 127 | return |
||
| 128 | } |
||
| 129 | |||
| 130 | var permission = true |
||
| 131 | var msg string |
||
| 132 | // Checking permissions |
||
| 133 | perm, err := discord.State.UserChannelPermissions(botId, message.ChannelID) |
||
| 134 | if err != nil { |
||
| 135 | msg = fmt.Sprintf("Error whilst getting bot permissions %v\n", err) |
||
| 136 | permission = false |
||
| 137 | } else { |
||
| 138 | if perm&discordgo.PermissionSendMessages != discordgo.PermissionSendMessages || |
||
| 139 | perm&discordgo.PermissionAttachFiles != discordgo.PermissionAttachFiles { |
||
| 140 | msg = "Permissions denied" |
||
| 141 | permission = false |
||
| 142 | } |
||
| 143 | } |
||
| 144 | |||
| 145 | channel, err := discord.State.Channel(message.ChannelID) |
||
| 146 | if err != nil { |
||
| 147 | fmt.Println("Error getting channel,", err) |
||
| 148 | return |
||
| 149 | } |
||
| 150 | guild, err := discord.State.Guild(channel.GuildID) |
||
| 151 | if err != nil { |
||
| 152 | fmt.Println("Error getting guild,", err) |
||
| 153 | return |
||
| 154 | } |
||
| 155 | |||
| 156 | if permission { |
||
| 157 | ctx := bot.NewContext( |
||
| 158 | botId, |
||
| 159 | discord, |
||
| 160 | guild, |
||
| 161 | channel, |
||
| 162 | user, |
||
| 163 | message, |
||
| 164 | conf, |
||
| 165 | CmdHandler, |
||
| 166 | Sessions, |
||
| 167 | youtube, |
||
| 168 | botMsg, |
||
| 169 | dataType, |
||
| 170 | dbWorker, |
||
| 171 | guilds, |
||
| 172 | botCron, |
||
| 173 | twitch, |
||
| 174 | albUpdater, |
||
| 175 | blacklist) |
||
| 176 | ctx.Args = args[1:] |
||
| 177 | c := *command |
||
| 178 | c(*ctx) |
||
| 179 | } else { |
||
| 180 | dbWorker.Log("Message", guild.ID, msg) |
||
| 181 | query := []byte(fmt.Sprintf("logs,server=%v module=\"%v\"", guild.ID, "message")) |
||
| 182 | addr := fmt.Sprintf("%v/write?db=%v", conf.Metrics.Address, conf.Metrics.Database) |
||
| 183 | r := bytes.NewReader(query) |
||
| 184 | _, _ = http.Post(addr, "", r) |
||
| 185 | } |
||
| 186 | } |
||
| 187 | |||
| 188 | // Adds bot commands |
||
| 189 | func registerCommands() { |
||
| 190 | CmdHandler.Register("!r", cmd.RadioCommand) |
||
| 191 | CmdHandler.Register("!w", cmd.WeatherCommand) |
||
| 192 | CmdHandler.Register("!ww", cmd.WeatherWeekCommand) |
||
| 193 | CmdHandler.Register("!t", cmd.TranslateCommand) |
||
| 194 | CmdHandler.Register("!n", cmd.NewsCommand) |
||
| 195 | CmdHandler.Register("!c", cmd.CurrencyCommand) |
||
| 196 | CmdHandler.Register("!y", cmd.YoutubeCommand) |
||
| 197 | CmdHandler.Register("!v", cmd.VoiceCommand) |
||
| 198 | CmdHandler.Register("!b", cmd.BotCommand) |
||
| 199 | CmdHandler.Register("!play", cmd.YoutubeShortCommand) |
||
| 200 | CmdHandler.Register("!d", cmd.DebugCommand) |
||
| 201 | CmdHandler.Register("!p", cmd.PollCommand) |
||
| 202 | CmdHandler.Register("!m", cmd.YandexmapCommand) |
||
| 203 | CmdHandler.Register("!dice", cmd.DiceCommand) |
||
| 204 | CmdHandler.Register("!help", cmd.HelpCommand) |
||
| 205 | CmdHandler.Register("!cron", cmd.CronCommand) |
||
| 206 | CmdHandler.Register("!geoip", cmd.GeoIPCommand) |
||
| 207 | CmdHandler.Register("!twitch", cmd.TwitchCommand) |
||
| 208 | CmdHandler.Register("!greetings", cmd.GreetingsCommand) |
||
| 209 | CmdHandler.Register("!alb", cmd.AlbionCommand) |
||
| 210 | CmdHandler.Register("!slap", cmd.SlapCommand) |
||
| 211 | CmdHandler.Register("!fu", cmd.FUCommand) |
||
| 212 | } |
||
| 213 | |||
| 214 | // MetricsSender sends metrics to InfluxDB and another services |
||
|
0 ignored issues
–
show
|
|||
| 215 | func BotUpdater(d *discordgo.Session) { |
||
| 216 | for { |
||
| 217 | var vregions = make(map[string]int) |
||
| 218 | go twitch.Update() |
||
| 219 | go albUpdater.Update(d, dbWorker, conf) |
||
| 220 | go clearSessions(d, Sessions) |
||
| 221 | // Calculating users count |
||
| 222 | usersCount := 0 |
||
| 223 | for _, g := range d.State.Guilds { |
||
| 224 | vregions[g.Region] += 1 |
||
|
0 ignored issues
–
show
|
|||
| 225 | if !blacklist.CheckGuild(g.ID) { |
||
| 226 | usersCount += g.MemberCount |
||
| 227 | } |
||
| 228 | } |
||
| 229 | // Metrics counters |
||
| 230 | queryCounters := []byte(fmt.Sprintf("counters guilds=%d,messages=%d,users=%d,voices=%d", len(d.State.Guilds), messagesCounter, usersCount, Sessions.Count())) |
||
| 231 | addrCounters := fmt.Sprintf("%v/write?db=%v&u=%v&p=%v", |
||
| 232 | conf.Metrics.Address, conf.Metrics.Database, conf.Metrics.User, conf.Metrics.Password) |
||
| 233 | rCounters := bytes.NewReader(queryCounters) |
||
| 234 | _, _ = http.Post(addrCounters, "", rCounters) |
||
| 235 | |||
| 236 | // Voice region metrics |
||
| 237 | for r, c := range vregions { |
||
| 238 | queryCounters := []byte(fmt.Sprintf("region_%s count=%d", r, c)) |
||
| 239 | addrCounters := fmt.Sprintf("%v/write?db=%v&u=%v&p=%v", |
||
| 240 | conf.Metrics.Address, conf.Metrics.Database, conf.Metrics.User, conf.Metrics.Password) |
||
| 241 | rCounters := bytes.NewReader(queryCounters) |
||
| 242 | _, _ = http.Post(addrCounters, "", rCounters) |
||
| 243 | } |
||
| 244 | |||
| 245 | // Bot lists |
||
| 246 | if conf.DBL.Token != "" { |
||
| 247 | sendDBL(conf.DBL.BotID, conf.DBL.Token, len(d.State.Guilds)) |
||
| 248 | } |
||
| 249 | messagesCounter = 0 |
||
| 250 | time.Sleep(time.Minute) |
||
| 251 | } |
||
| 252 | } |
||
| 253 | |||
| 254 | func sendDBL(botID, token string, guilds int) { |
||
| 255 | timeout := time.Duration(time.Duration(1) * time.Second) |
||
| 256 | client := &http.Client{ |
||
| 257 | Timeout: time.Duration(timeout), |
||
| 258 | } |
||
| 259 | query := url.Values{} |
||
| 260 | query.Add("server_count", fmt.Sprintf("%v", guilds)) |
||
| 261 | req, _ := http.NewRequest("POST", |
||
| 262 | fmt.Sprintf("https://discordbots.org/api/bots/%v/stats", |
||
| 263 | botID), strings.NewReader(query.Encode())) |
||
| 264 | req.Header.Add("Authorization", token) |
||
| 265 | req.Header.Add("Content-Type", "application/x-www-form-urlencoded") |
||
| 266 | _, _ = client.Do(req) |
||
| 267 | } |
||
| 268 | |||
| 269 | func onStart() { |
||
| 270 | queryCounters := []byte(fmt.Sprintf("starts value=1")) |
||
| 271 | addrCounters := fmt.Sprintf("%v/write?db=%v&u=%v&p=%v", |
||
| 272 | conf.Metrics.Address, conf.Metrics.Database, conf.Metrics.User, conf.Metrics.Password) |
||
| 273 | rCounters := bytes.NewReader(queryCounters) |
||
| 274 | _, _ = http.Post(addrCounters, "", rCounters) |
||
| 275 | } |
||
| 276 | |||
| 277 | func clearSessions(d *discordgo.Session, s *bot.SessionManager) { |
||
| 278 | gids := s.GetGuilds() |
||
| 279 | for _, gid := range gids { |
||
| 280 | cs := s.GetByGuild(gid) |
||
| 281 | g, gerr := d.Guild(gid) |
||
| 282 | if gerr != nil { |
||
| 283 | continue |
||
| 284 | } |
||
| 285 | var ok bool |
||
| 286 | for _, vs := range g.VoiceStates { |
||
| 287 | if vs.ChannelID == cs.ChannelID { |
||
| 288 | if vs.UserID != botId { |
||
| 289 | ok = true |
||
| 290 | } |
||
| 291 | } |
||
| 292 | } |
||
| 293 | if !ok { |
||
| 294 | s.Leave(d, *cs) |
||
| 295 | } |
||
| 296 | } |
||
| 297 | |||
| 298 | for _, sess := range s.GetAll() { |
||
| 299 | if !sess.IsOk() { |
||
| 300 | s.Leave(d, *sess) |
||
| 301 | } |
||
| 302 | } |
||
| 303 | |||
| 304 | for i,vc := range d.VoiceConnections { |
||
| 305 | if _,b := s.GetByChannel(vc.ChannelID); b == false { |
||
| 306 | err := vc.Disconnect() |
||
| 307 | if err != nil { |
||
| 308 | log.Println(err) |
||
| 309 | } |
||
| 310 | vc.Close() |
||
| 311 | delete(d.VoiceConnections, i) |
||
| 312 | } |
||
| 313 | } |
||
| 314 | } |