Passed
Push — master ( f97e1c...9f4816 )
by Viktor
01:36
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
	"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
	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(commandHandler)
59
	discord.AddHandler(func(discord *discordgo.Session, ready *discordgo.Ready) {
60
		_ = discord.UpdateStatus(0, conf.General.Game)
61
		guilds := discord.State.Guilds
62
		fmt.Println("Ready with", len(guilds), "guilds.")
63
	})
64
65
	err = discord.Open()
66
	if err != nil {
67
		fmt.Printf("Connection open error: %v", err)
68
		return
69
	}
70
	defer discord.Close()
71
	fmt.Println("Bot is now running.")
72
73
	sc := make(chan os.Signal, 1)
74
	signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
75
	dbWorker = bot.NewDBSession(conf.General.DatabaseName)
76
	guilds = dbWorker.InitGuilds(discord, conf)
77
	botCron.Start()
78
	go MetricsSender(discord)
79
	defer botCron.Stop()
80
	defer dbWorker.DBSession.Close()
81
	<-sc
82
}
83
84
// Handle discord messages
85
func commandHandler(discord *discordgo.Session, message *discordgo.MessageCreate) {
86
	messagesCounter++
87
	user := message.Author
88
	if user.ID == botId || user.Bot {
89
		return
90
	}
91
	args := strings.Split(message.Content, " ")
92
	name := strings.ToLower(args[0])
93
	command, found := CmdHandler.Get(name)
94
	if !found {
95
		return
96
	}
97
98
	var permission = true
99
	var msg string
100
	// Checking permissions
101
	perm, err := discord.State.UserChannelPermissions(botId, message.ChannelID)
102
	if err != nil {
103
		msg = fmt.Sprintf("Error whilst getting bot permissions %v\n", err)
104
		permission = false
105
	} else {
106
		if perm&discordgo.PermissionSendMessages != discordgo.PermissionSendMessages ||
107
			perm&discordgo.PermissionAttachFiles != discordgo.PermissionAttachFiles {
108
			msg = "Permissions denied"
109
			permission = false
110
		}
111
	}
112
113
	channel, err := discord.State.Channel(message.ChannelID)
114
	if err != nil {
115
		fmt.Println("Error getting channel,", err)
116
		return
117
	}
118
	guild, err := discord.State.Guild(channel.GuildID)
119
	if err != nil {
120
		fmt.Println("Error getting guild,", err)
121
		return
122
	}
123
124
	if permission {
125
		ctx := bot.NewContext(
126
			botId,
127
			discord,
128
			guild,
129
			channel,
130
			user,
131
			message,
132
			conf,
133
			CmdHandler,
134
			Sessions,
135
			youtube,
136
			botMsg,
137
			dataType,
138
			dbWorker,
139
			guilds,
140
			botCron)
141
		ctx.Args = args[1:]
142
		c := *command
143
		c(*ctx)
144
	} else {
145
		dbWorker.Log("Message", guild.ID, msg)
146
		query := []byte(fmt.Sprintf("logs,server=%v module=\"%v\"", guild.ID, "message"))
147
		addr := fmt.Sprintf("%v/write?db=%v", conf.Metrics.Address, conf.Metrics.Database)
148
		r := bytes.NewReader(query)
149
		_, _ = http.Post(addr, "", r)
150
	}
151
}
152
153
// Adds bot commands
154
func registerCommands() {
155
	CmdHandler.Register("!r", cmd.PlayerCommand)
156
	CmdHandler.Register("!w", cmd.WeatherCommand)
157
	CmdHandler.Register("!t", cmd.TranslateCommand)
158
	CmdHandler.Register("!n", cmd.NewsCommand)
159
	CmdHandler.Register("!c", cmd.CurrencyCommand)
160
	CmdHandler.Register("!y", cmd.YoutubeCommand)
161
	CmdHandler.Register("!v", cmd.VoiceCommand)
162
	CmdHandler.Register("!b", cmd.BotCommand)
163
	CmdHandler.Register("!play", cmd.YoutubeShortCommand)
164
	CmdHandler.Register("!d", cmd.DebugCommand)
165
	CmdHandler.Register("!p", cmd.PollCommand)
166
	CmdHandler.Register("!m", cmd.YandexmapCommand)
167
	CmdHandler.Register("!dice", cmd.DiceCommand)
168
	CmdHandler.Register("!help", cmd.HelpCommand)
169
	CmdHandler.Register("!cron", cmd.CronCommand)
170
	CmdHandler.Register("!geoip", cmd.GeoIPCommand)
171
}
172
173
// MetricsSender sends metrics to InfluxDB
174
func MetricsSender(d *discordgo.Session) {
175
	for {
176
		query := []byte(fmt.Sprintf("messages count=%v", messagesCounter))
177
		addr := fmt.Sprintf("%v/write?db=%v&u=%v&p=%v",
178
			conf.Metrics.Address, conf.Metrics.Database, conf.Metrics.User, conf.Metrics.Password)
179
		r := bytes.NewReader(query)
180
		_, _ = http.Post(addr, "", r)
181
		if conf.DBL.Token != "" {
182
			s := dblgo.NewDBL(conf.DBL.Token, d.State.User.ID)
183
			_ = s.PostStats(len(d.State.Guilds))
184
		}
185
		if conf.DBL.TokenDBL != "" {
186
			users := 0
187
			for _, g := range d.State.Guilds {
188
				users += len(g.Members)
189
			}
190
			data := url.Values{}
191
			data.Set("guilds", string(len(d.State.Guilds)))
192
			data.Set("users", string(users))
193
			client := &http.Client{}
194
			req, err := http.NewRequest("POST", fmt.Sprintf("https://discordbotlist.com/api/bots/%v/stats",conf.DBL.DBLID), bytes.NewBuffer([]byte(data.Encode())))
195
			if err != nil {
196
				fmt.Println(err.Error())
197
			}
198
			req.Header.Add("Authorization", fmt.Sprintf("Bot %v", conf.DBL.TokenDBL))
199
			defer req.Body.Close()
200
			_,_ = client.Do(req)
201
		}
202
		messagesCounter = 0
203
		time.Sleep(time.Minute)
204
	}
205
}
206