Passed
Push — master ( 67951a...37a2ed )
by Viktor
01:42
created

main.clearSessions   B

Complexity

Conditions 6

Size

Total Lines 16
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 13
nop 2
dl 0
loc 16
rs 8.6666
c 0
b 0
f 0
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
introduced by
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
introduced by
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
		go clearSessions(d, Sessions)
220
		// Calculating users count
221
		usersCount := 0
222
		for _, g := range d.State.Guilds {
223
			vregions[g.Region] += 1
0 ignored issues
show
introduced by
should replace vregions[g.Region] += 1 with vregions[g.Region]++
Loading history...
224
			if !blacklist.CheckGuild(g.ID) {
225
				usersCount += g.MemberCount
226
			}
227
		}
228
		// Metrics counters
229
		queryCounters := []byte(fmt.Sprintf("counters guilds=%d,messages=%d,users=%d,voices=%d", len(d.State.Guilds), messagesCounter, usersCount, Sessions.Count()))
230
		addrCounters := fmt.Sprintf("%v/write?db=%v&u=%v&p=%v",
231
			conf.Metrics.Address, conf.Metrics.Database, conf.Metrics.User, conf.Metrics.Password)
232
		rCounters := bytes.NewReader(queryCounters)
233
		_, _ = http.Post(addrCounters, "", rCounters)
234
235
		// Voice region metrics
236
		for r, c := range vregions {
237
			queryCounters := []byte(fmt.Sprintf("region_%s count=%d", r, c))
238
			addrCounters := fmt.Sprintf("%v/write?db=%v&u=%v&p=%v",
239
				conf.Metrics.Address, conf.Metrics.Database, conf.Metrics.User, conf.Metrics.Password)
240
			rCounters := bytes.NewReader(queryCounters)
241
			_, _ = http.Post(addrCounters, "", rCounters)
242
		}
243
244
		// Bot lists
245
		if conf.DBL.Token != "" {
246
			sendDBL(conf.DBL.BotID, conf.DBL.Token, len(d.State.Guilds))
247
		}
248
		messagesCounter = 0
249
		time.Sleep(time.Minute)
250
	}
251
}
252
253
func sendDBL(botID, token string, guilds int) {
254
	timeout := time.Duration(time.Duration(1) * time.Second)
255
	client := &http.Client{
256
		Timeout: time.Duration(timeout),
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
	ids := s.GetChannels()
278
	for _, id := range ids {
279
		c, err := d.Channel(id)
280
		if err != nil {
281
			continue
282
		}
283
		var ok bool
284
		for _,u := range c.Recipients {
285
			if !u.Bot {
286
				ok = true
287
			}
288
		}
289
		if !ok {
290
			sc,_ := s.GetByChannel(id)
291
			s.Leave(d, *sc)
292
		}
293
	}
294
}