Passed
Push — master ( aa5c79...fb5b4f )
by Viktor
01:41
created

main.clearSessions   C

Complexity

Conditions 10

Size

Total Lines 27
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 20
nop 2
dl 0
loc 27
rs 5.9999
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like main.clearSessions often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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
var botId should be botID
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
introduced by
comment on exported function BotUpdater should be of the form "BotUpdater ..."
Loading history...
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
introduced by
should replace vregions[g.Region] += 1 with vregions[g.Region]++
Loading history...
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
	for _,vc := range d.VoiceConnections {
298
		if _,b := s.GetByChannel(vc.ChannelID); b == false {
299
			err := vc.Disconnect()
300
			if err != nil {
301
				log.Println(err)
302
			}
303
			vc.Close()
304
		}
305
	}
306
}