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
![]() |
|||
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 | client := &http.Client{ |
||
256 | Timeout: time.Duration(1) * time.Second, |
||
257 | } |
||
258 | query := url.Values{} |
||
259 | query.Add("server_count", fmt.Sprintf("%v", guilds)) |
||
260 | req, _ := http.NewRequest("POST", |
||
261 | fmt.Sprintf("https://discordbots.org/api/bots/%v/stats", |
||
262 | botID), strings.NewReader(query.Encode())) |
||
263 | req.Header.Add("Authorization", token) |
||
264 | req.Header.Add("Content-Type", "application/x-www-form-urlencoded") |
||
265 | _, _ = client.Do(req) |
||
266 | } |
||
267 | |||
268 | func onStart() { |
||
269 | queryCounters := []byte(fmt.Sprintf("starts value=1")) |
||
270 | addrCounters := fmt.Sprintf("%v/write?db=%v&u=%v&p=%v", |
||
271 | conf.Metrics.Address, conf.Metrics.Database, conf.Metrics.User, conf.Metrics.Password) |
||
272 | rCounters := bytes.NewReader(queryCounters) |
||
273 | _, _ = http.Post(addrCounters, "", rCounters) |
||
274 | } |
||
275 | |||
276 | func clearSessions(d *discordgo.Session, s *bot.SessionManager) { |
||
277 | gids := s.GetGuilds() |
||
278 | for _, gid := range gids { |
||
279 | cs := s.GetByGuild(gid) |
||
280 | g, gerr := d.Guild(gid) |
||
281 | if gerr != nil { |
||
282 | continue |
||
283 | } |
||
284 | var ok bool |
||
285 | for _, vs := range g.VoiceStates { |
||
286 | if vs.ChannelID == cs.ChannelID { |
||
287 | if vs.UserID != botId { |
||
288 | ok = true |
||
289 | } |
||
290 | } |
||
291 | } |
||
292 | if !ok && cs != nil { |
||
293 | s.Leave(d, *cs) |
||
294 | } |
||
295 | } |
||
296 | |||
297 | for _, sess := range s.GetAll() { |
||
298 | if !sess.IsOk() { |
||
299 | s.Leave(d, *sess) |
||
300 | } |
||
301 | } |
||
302 | |||
303 | for i,vc := range d.VoiceConnections { |
||
304 | if _,b := s.GetByChannel(vc.ChannelID); b == false { |
||
305 | err := vc.Disconnect() |
||
306 | if err != nil { |
||
307 | log.Println(err) |
||
308 | } |
||
309 | vc.Close() |
||
310 | delete(d.VoiceConnections, i) |
||
311 | } |
||
312 | } |
||
313 | } |