Passed
Push — master ( ff1349...f1973d )
by Viktor
01:40
created

main.commandHandler   C

Complexity

Conditions 10

Size

Total Lines 65
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 55
nop 2
dl 0
loc 65
rs 5.6727
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
	"github.com/DiscordBotList/dblgo"
7
	"net/http"
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
	messagesCounter int
35
)
36
37
func main() {
38
	botCron = cron.New()
39
	conf = bot.LoadConfig()
40
	CmdHandler = bot.NewCommandHandler()
41
	registerCommands()
42
	Sessions = bot.NewSessionManager()
43
	youtube = &bot.Youtube{Conf: conf}
44
	botMsg = bot.NewMessagesMap()
45
	dataType = bot.NewDataType()
46
	discord, err := discordgo.New("Bot " + os.Getenv("BOT_TOKEN"))
47
	if err != nil {
48
		fmt.Println("Create session error, ", err)
49
		return
50
	}
51
	usr, err := discord.User("@me")
52
	if err != nil {
53
		fmt.Println("Error obtaining account details,", err)
54
		return
55
	}
56
	botId = usr.ID
57
	discord.AddHandler(commandHandler)
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
	go MetricsSender(discord)
78
	defer botCron.Stop()
79
	defer dbWorker.DBSession.Close()
80
	<-sc
81
}
82
83
// Handle discord messages
84
func commandHandler(discord *discordgo.Session, message *discordgo.MessageCreate) {
85
	messagesCounter++
86
	user := message.Author
87
	if user.ID == botId || user.Bot {
88
		return
89
	}
90
	args := strings.Split(message.Content, " ")
91
	name := strings.ToLower(args[0])
92
	command, found := CmdHandler.Get(name)
93
	if !found {
94
		return
95
	}
96
97
	var permission = true
98
	var msg string
99
	// Checking permissions
100
	perm, err := discord.State.UserChannelPermissions(botId, message.ChannelID)
101
	if err != nil {
102
		msg = fmt.Sprintf("Error whilst getting bot permissions %v\n", err)
103
		permission = false
104
	} else {
105
		if perm&discordgo.PermissionSendMessages != discordgo.PermissionSendMessages ||
106
			perm&discordgo.PermissionAttachFiles != discordgo.PermissionAttachFiles {
107
			msg = "Permissions denied"
108
			permission = false
109
		}
110
	}
111
112
	channel, err := discord.State.Channel(message.ChannelID)
113
	if err != nil {
114
		fmt.Println("Error getting channel,", err)
115
		return
116
	}
117
	guild, err := discord.State.Guild(channel.GuildID)
118
	if err != nil {
119
		fmt.Println("Error getting guild,", err)
120
		return
121
	}
122
123
	if permission {
124
		ctx := bot.NewContext(
125
			botId,
126
			discord,
127
			guild,
128
			channel,
129
			user,
130
			message,
131
			conf,
132
			CmdHandler,
133
			Sessions,
134
			youtube,
135
			botMsg,
136
			dataType,
137
			dbWorker,
138
			guilds,
139
			botCron)
140
		ctx.Args = args[1:]
141
		c := *command
142
		c(*ctx)
143
	} else {
144
		dbWorker.Log("Message", guild.ID, msg)
145
		query := []byte(fmt.Sprintf("logs,server=%v module=\"%v\"", guild.ID, "message"))
146
		addr := fmt.Sprintf("%v/write?db=%v", conf.Metrics.Address, conf.Metrics.Database)
147
		r := bytes.NewReader(query)
148
		_, _ = http.Post(addr, "", r)
149
	}
150
}
151
152
// Adds bot commands
153
func registerCommands() {
154
	CmdHandler.Register("!r", cmd.PlayerCommand)
155
	CmdHandler.Register("!w", cmd.WeatherCommand)
156
	CmdHandler.Register("!t", cmd.TranslateCommand)
157
	CmdHandler.Register("!n", cmd.NewsCommand)
158
	CmdHandler.Register("!c", cmd.CurrencyCommand)
159
	CmdHandler.Register("!y", cmd.YoutubeCommand)
160
	CmdHandler.Register("!v", cmd.VoiceCommand)
161
	CmdHandler.Register("!b", cmd.BotCommand)
162
	CmdHandler.Register("!play", cmd.YoutubeShortCommand)
163
	CmdHandler.Register("!d", cmd.DebugCommand)
164
	CmdHandler.Register("!p", cmd.PollCommand)
165
	CmdHandler.Register("!m", cmd.YandexmapCommand)
166
	CmdHandler.Register("!dice", cmd.DiceCommand)
167
	CmdHandler.Register("!help", cmd.HelpCommand)
168
	CmdHandler.Register("!cron", cmd.CronCommand)
169
	CmdHandler.Register("!geoip", cmd.GeoIPCommand)
170
}
171
172
// MetricsSender sends metrics to InfluxDB
173
func MetricsSender(d *discordgo.Session) {
174
	for {
175
		usersCount := 0
176
		for _,g := range d.State.Guilds {
177
			usersCount += len(g.Members)
178
		}
179
180
		// Metrics counters
181
		queryCounters := []byte(fmt.Sprintf("counters guilds=%v,messages=%v,users=%v", len(d.State.Guilds), messagesCounter, usersCount))
182
		addrCounters := fmt.Sprintf("%v/write?db=%v&u=%v&p=%v",
183
			conf.Metrics.Address, conf.Metrics.Database, conf.Metrics.User, conf.Metrics.Password)
184
		rCounters := bytes.NewReader(queryCounters)
185
		_, _ = http.Post(addrCounters, "", rCounters)
186
187
		// Bot lists
188
		if conf.DBL.Token != "" {
189
			s := dblgo.NewDBL(conf.DBL.Token, d.State.User.ID)
190
			_ = s.PostStats(len(d.State.Guilds))
191
		}
192
		messagesCounter = 0
193
		time.Sleep(time.Minute)
194
	}
195
}