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