Passed
Push — master ( 5d908c...87bfc6 )
by Viktor
01:59
created

main.commandHandler   C

Complexity

Conditions 10

Size

Total Lines 66
Code Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 56
nop 2
dl 0
loc 66
rs 5.6399
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like main.commandHandler 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
	"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
	messagesCounter int
36
)
37
38
func main() {
39
	botCron = cron.New()
40
	conf = bot.LoadConfig()
41
	CmdHandler = bot.NewCommandHandler()
42
	registerCommands()
43
	Sessions = bot.NewSessionManager()
44
	youtube = &bot.Youtube{Conf: conf}
45
	botMsg = bot.NewMessagesMap()
46
	dataType = bot.NewDataType()
47
	discord, err := discordgo.New("Bot " + os.Getenv("BOT_TOKEN"))
48
	if err != nil {
49
		fmt.Println("Create session error, ", err)
50
		return
51
	}
52
	usr, err := discord.User("@me")
53
	if err != nil {
54
		fmt.Println("Error obtaining account details,", err)
55
		return
56
	}
57
	botId = usr.ID
58
	discord.AddHandler(func(discord *discordgo.Session, ready *discordgo.Ready) {
59
		_ = discord.UpdateStatus(0, conf.General.Game)
60
		guilds := discord.State.Guilds
61
		fmt.Println("Ready with", len(guilds), "guilds.")
62
	})
63
64
	err = discord.Open()
65
	if err != nil {
66
		fmt.Printf("Connection open error: %v", err)
67
		return
68
	}
69
	defer discord.Close()
70
	fmt.Println("Bot is now running.")
71
72
	sc := make(chan os.Signal, 1)
73
	signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
74
	dbWorker = bot.NewDBSession(conf.General.DatabaseName)
75
	guilds = dbWorker.InitGuilds(discord, conf)
76
	botCron.Start()
77
	defer botCron.Stop()
78
	defer dbWorker.DBSession.Close()
79
	twitch = bot.TwitchInit(discord, conf, dbWorker)
80
	go MetricsSender(discord)
81
	// Init command handler
82
	discord.AddHandler(commandHandler)
83
	discord.AddHandler(joinHandler)
84
	onStart()
85
	<-sc
86
}
87
88
func joinHandler(disord *discordgo.Session, e *discordgo.GuildMemberAdd) {
89
	bot.Greeting(disord, e, guilds.Guilds[e.GuildID], conf)
90
}
91
92
// Handle discord messages
93
func commandHandler(discord *discordgo.Session, message *discordgo.MessageCreate) {
94
	messagesCounter++
95
	user := message.Author
96
	if user.ID == botId || user.Bot {
97
		return
98
	}
99
	args := strings.Split(message.Content, " ")
100
	name := strings.ToLower(args[0])
101
	command, found := CmdHandler.Get(name)
102
	if !found {
103
		return
104
	}
105
106
	var permission = true
107
	var msg string
108
	// Checking permissions
109
	perm, err := discord.State.UserChannelPermissions(botId, message.ChannelID)
110
	if err != nil {
111
		msg = fmt.Sprintf("Error whilst getting bot permissions %v\n", err)
112
		permission = false
113
	} else {
114
		if perm&discordgo.PermissionSendMessages != discordgo.PermissionSendMessages ||
115
			perm&discordgo.PermissionAttachFiles != discordgo.PermissionAttachFiles {
116
			msg = "Permissions denied"
117
			permission = false
118
		}
119
	}
120
121
	channel, err := discord.State.Channel(message.ChannelID)
122
	if err != nil {
123
		fmt.Println("Error getting channel,", err)
124
		return
125
	}
126
	guild, err := discord.State.Guild(channel.GuildID)
127
	if err != nil {
128
		fmt.Println("Error getting guild,", err)
129
		return
130
	}
131
132
	if permission {
133
		ctx := bot.NewContext(
134
			botId,
135
			discord,
136
			guild,
137
			channel,
138
			user,
139
			message,
140
			conf,
141
			CmdHandler,
142
			Sessions,
143
			youtube,
144
			botMsg,
145
			dataType,
146
			dbWorker,
147
			guilds,
148
			botCron,
149
			twitch)
150
		ctx.Args = args[1:]
151
		c := *command
152
		c(*ctx)
153
	} else {
154
		dbWorker.Log("Message", guild.ID, msg)
155
		query := []byte(fmt.Sprintf("logs,server=%v module=\"%v\"", guild.ID, "message"))
156
		addr := fmt.Sprintf("%v/write?db=%v", conf.Metrics.Address, conf.Metrics.Database)
157
		r := bytes.NewReader(query)
158
		_, _ = http.Post(addr, "", r)
159
	}
160
}
161
162
// Adds bot commands
163
func registerCommands() {
164
	CmdHandler.Register("!r", cmd.PlayerCommand)
165
	CmdHandler.Register("!w", cmd.WeatherCommand)
166
	CmdHandler.Register("!t", cmd.TranslateCommand)
167
	CmdHandler.Register("!n", cmd.NewsCommand)
168
	CmdHandler.Register("!c", cmd.CurrencyCommand)
169
	CmdHandler.Register("!y", cmd.YoutubeCommand)
170
	CmdHandler.Register("!v", cmd.VoiceCommand)
171
	CmdHandler.Register("!b", cmd.BotCommand)
172
	CmdHandler.Register("!play", cmd.YoutubeShortCommand)
173
	CmdHandler.Register("!d", cmd.DebugCommand)
174
	CmdHandler.Register("!p", cmd.PollCommand)
175
	CmdHandler.Register("!m", cmd.YandexmapCommand)
176
	CmdHandler.Register("!dice", cmd.DiceCommand)
177
	CmdHandler.Register("!help", cmd.HelpCommand)
178
	CmdHandler.Register("!cron", cmd.CronCommand)
179
	CmdHandler.Register("!geoip", cmd.GeoIPCommand)
180
	CmdHandler.Register("!twitch", cmd.TwitchCommand)
181
}
182
183
// MetricsSender sends metrics to InfluxDB and another services
184
func MetricsSender(d *discordgo.Session) {
185
	for {
186
		go twitch.Update()
187
188
		// Calculating users count
189
		usersCount := 0
190
		for _, g := range d.State.Guilds {
191
			usersCount += len(g.Members)
192
		}
193
194
		// Metrics counters
195
		queryCounters := []byte(fmt.Sprintf("counters guilds=%v,messages=%v,users=%v", len(d.State.Guilds), messagesCounter, usersCount))
196
		addrCounters := fmt.Sprintf("%v/write?db=%v&u=%v&p=%v",
197
			conf.Metrics.Address, conf.Metrics.Database, conf.Metrics.User, conf.Metrics.Password)
198
		rCounters := bytes.NewReader(queryCounters)
199
		_, _ = http.Post(addrCounters, "", rCounters)
200
201
		// Bot lists
202
		if conf.DBL.Token != "" {
203
			sendDBL(conf.DBL.BotID, conf.DBL.Token, len(d.State.Guilds))
204
		}
205
		messagesCounter = 0
206
		time.Sleep(time.Minute)
207
	}
208
}
209
210
func sendDBL(botID, token string, guilds int) {
211
	timeout := time.Duration(time.Duration(1) * time.Second)
212
	client := &http.Client{
213
		Timeout: time.Duration(timeout),
214
	}
215
	query := url.Values{}
216
	query.Add("server_count", fmt.Sprintf("%v", guilds))
217
	req, _ := http.NewRequest("POST",
218
		fmt.Sprintf("https://discordbots.org/api/bots/%v/stats",
219
			botID), strings.NewReader(query.Encode()))
220
	req.Header.Add("Authorization", token)
221
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
222
	_, _ = client.Do(req)
223
}
224
225
func onStart() {
226
	queryCounters := []byte(fmt.Sprintf("starts value=1"))
227
	addrCounters := fmt.Sprintf("%v/write?db=%v&u=%v&p=%v",
228
		conf.Metrics.Address, conf.Metrics.Database, conf.Metrics.User, conf.Metrics.Password)
229
	rCounters := bytes.NewReader(queryCounters)
230
	_, _ = http.Post(addrCounters, "", rCounters)
231
}
232