Passed
Push — master ( 73b11f...9f2199 )
by Viktor
01:41
created

main.BotUpdater   B

Complexity

Conditions 6

Size

Total Lines 35
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 25
nop 1
dl 0
loc 35
rs 8.3466
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("!t", cmd.TranslateCommand)
192
	CmdHandler.Register("!n", cmd.NewsCommand)
193
	CmdHandler.Register("!c", cmd.CurrencyCommand)
194
	CmdHandler.Register("!y", cmd.YoutubeCommand)
195
	CmdHandler.Register("!v", cmd.VoiceCommand)
196
	CmdHandler.Register("!b", cmd.BotCommand)
197
	CmdHandler.Register("!play", cmd.YoutubeShortCommand)
198
	CmdHandler.Register("!d", cmd.DebugCommand)
199
	CmdHandler.Register("!p", cmd.PollCommand)
200
	CmdHandler.Register("!m", cmd.YandexmapCommand)
201
	CmdHandler.Register("!dice", cmd.DiceCommand)
202
	CmdHandler.Register("!help", cmd.HelpCommand)
203
	CmdHandler.Register("!cron", cmd.CronCommand)
204
	CmdHandler.Register("!geoip", cmd.GeoIPCommand)
205
	CmdHandler.Register("!twitch", cmd.TwitchCommand)
206
	CmdHandler.Register("!greetings", cmd.GreetingsCommand)
207
	CmdHandler.Register("!alb", cmd.AlbionCommand)
208
	CmdHandler.Register("!slap", cmd.SlapCommand)
209
	CmdHandler.Register("!fu", cmd.FUCommand)
210
}
211
212
// 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...
213
func BotUpdater(d *discordgo.Session) {
214
	for {
215
		var vregions = make(map[string]int)
216
		go twitch.Update()
217
		go albUpdater.Update(d, dbWorker, conf)
218
		// Calculating users count
219
		usersCount := 0
220
		for _, g := range d.State.Guilds {
221
			vregions[g.Region] += 1
0 ignored issues
show
introduced by
should replace vregions[g.Region] += 1 with vregions[g.Region]++
Loading history...
222
			if !blacklist.CheckGuild(g.ID) {
223
				usersCount += g.MemberCount
224
			}
225
		}
226
		// Metrics counters
227
		queryCounters := []byte(fmt.Sprintf("counters guilds=%v,messages=%v,users=%v", len(d.State.Guilds), messagesCounter, usersCount))
228
		addrCounters := fmt.Sprintf("%v/write?db=%v&u=%v&p=%v",
229
			conf.Metrics.Address, conf.Metrics.Database, conf.Metrics.User, conf.Metrics.Password)
230
		rCounters := bytes.NewReader(queryCounters)
231
		_, _ = http.Post(addrCounters, "", rCounters)
232
233
		// Voice region metrics
234
		for r, c := range vregions {
235
			queryCounters := []byte(fmt.Sprintf("region_%v count=%d", r, c))
236
			addrCounters := fmt.Sprintf("%v/write?db=%v&u=%v&p=%v",
237
				conf.Metrics.Address, conf.Metrics.Database, conf.Metrics.User, conf.Metrics.Password)
238
			rCounters := bytes.NewReader(queryCounters)
239
			_, _ = http.Post(addrCounters, "", rCounters)
240
		}
241
242
		// Bot lists
243
		if conf.DBL.Token != "" {
244
			sendDBL(conf.DBL.BotID, conf.DBL.Token, len(d.State.Guilds))
245
		}
246
		messagesCounter = 0
247
		time.Sleep(time.Minute)
248
	}
249
}
250
251
func sendDBL(botID, token string, guilds int) {
252
	timeout := time.Duration(time.Duration(1) * time.Second)
253
	client := &http.Client{
254
		Timeout: time.Duration(timeout),
255
	}
256
	query := url.Values{}
257
	query.Add("server_count", fmt.Sprintf("%v", guilds))
258
	req, _ := http.NewRequest("POST",
259
		fmt.Sprintf("https://discordbots.org/api/bots/%v/stats",
260
			botID), strings.NewReader(query.Encode()))
261
	req.Header.Add("Authorization", token)
262
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
263
	_, _ = client.Do(req)
264
}
265
266
func onStart() {
267
	queryCounters := []byte(fmt.Sprintf("starts value=1"))
268
	addrCounters := fmt.Sprintf("%v/write?db=%v&u=%v&p=%v",
269
		conf.Metrics.Address, conf.Metrics.Database, conf.Metrics.User, conf.Metrics.Password)
270
	rCounters := bytes.NewReader(queryCounters)
271
	_, _ = http.Post(addrCounters, "", rCounters)
272
}
273