Passed
Push — master ( 95cb3d...b8949d )
by Viktor
01:32
created
Severity
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
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(guildAddHandler)
83
	discord.AddHandler(commandHandler)
84
	discord.AddHandler(joinHandler)
85
	onStart()
86
	<-sc
87
}
88
89
// Handle new users
90
func joinHandler(discord *discordgo.Session, e *discordgo.GuildMemberAdd) {
91
	if _, ok := guilds.Guilds[e.GuildID]; !ok {
92
		dbWorker.InitNewGuild(e.GuildID, conf, guilds)
93
	} else {
94
		bot.Greetings(discord, e, guilds.Guilds[e.GuildID])
95
	}
96
}
97
98
// Handle new guilds
99
func guildAddHandler(discord *discordgo.Session, e *discordgo.GuildCreate) {
100
	if _, ok := guilds.Guilds[e.ID]; !ok {
101
		dbWorker.InitNewGuild(e.ID, conf, guilds)
102
	}
103
	emb := bot.NewEmbed("").
104
		Field(conf.GetLocaleLang("bot_joined_title", guilds.Guilds[e.ID].Language), conf.GetLocaleLang("bot_joined_text", guilds.Guilds[e.ID].Language), false)
105
	_, _ = discord.ChannelMessageSendEmbed(e.OwnerID, emb.GetEmbed())
106
}
107
108
// Handle discord messages
109
func commandHandler(discord *discordgo.Session, message *discordgo.MessageCreate) {
110
	messagesCounter++
111
	user := message.Author
112
	if user.ID == botId || user.Bot {
113
		return
114
	}
115
	args := strings.Split(message.Content, " ")
116
	name := strings.ToLower(args[0])
117
	command, found := CmdHandler.Get(name)
118
	if !found {
119
		return
120
	}
121
122
	var permission = true
123
	var msg string
124
	// Checking permissions
125
	perm, err := discord.State.UserChannelPermissions(botId, message.ChannelID)
126
	if err != nil {
127
		msg = fmt.Sprintf("Error whilst getting bot permissions %v\n", err)
128
		permission = false
129
	} else {
130
		if perm&discordgo.PermissionSendMessages != discordgo.PermissionSendMessages ||
131
			perm&discordgo.PermissionAttachFiles != discordgo.PermissionAttachFiles {
132
			msg = "Permissions denied"
133
			permission = false
134
		}
135
	}
136
137
	channel, err := discord.State.Channel(message.ChannelID)
138
	if err != nil {
139
		fmt.Println("Error getting channel,", err)
140
		return
141
	}
142
	guild, err := discord.State.Guild(channel.GuildID)
143
	if err != nil {
144
		fmt.Println("Error getting guild,", err)
145
		return
146
	}
147
148
	if permission {
149
		ctx := bot.NewContext(
150
			botId,
151
			discord,
152
			guild,
153
			channel,
154
			user,
155
			message,
156
			conf,
157
			CmdHandler,
158
			Sessions,
159
			youtube,
160
			botMsg,
161
			dataType,
162
			dbWorker,
163
			guilds,
164
			botCron,
165
			twitch)
166
		ctx.Args = args[1:]
167
		c := *command
168
		c(*ctx)
169
	} else {
170
		dbWorker.Log("Message", guild.ID, msg)
171
		query := []byte(fmt.Sprintf("logs,server=%v module=\"%v\"", guild.ID, "message"))
172
		addr := fmt.Sprintf("%v/write?db=%v", conf.Metrics.Address, conf.Metrics.Database)
173
		r := bytes.NewReader(query)
174
		_, _ = http.Post(addr, "", r)
175
	}
176
}
177
178
// Adds bot commands
179
func registerCommands() {
180
	CmdHandler.Register("!r", cmd.RadioCommand)
181
	CmdHandler.Register("!w", cmd.WeatherCommand)
182
	CmdHandler.Register("!t", cmd.TranslateCommand)
183
	CmdHandler.Register("!n", cmd.NewsCommand)
184
	CmdHandler.Register("!c", cmd.CurrencyCommand)
185
	CmdHandler.Register("!y", cmd.YoutubeCommand)
186
	CmdHandler.Register("!v", cmd.VoiceCommand)
187
	CmdHandler.Register("!b", cmd.BotCommand)
188
	CmdHandler.Register("!play", cmd.YoutubeShortCommand)
189
	CmdHandler.Register("!d", cmd.DebugCommand)
190
	CmdHandler.Register("!p", cmd.PollCommand)
191
	CmdHandler.Register("!m", cmd.YandexmapCommand)
192
	CmdHandler.Register("!dice", cmd.DiceCommand)
193
	CmdHandler.Register("!help", cmd.HelpCommand)
194
	CmdHandler.Register("!cron", cmd.CronCommand)
195
	CmdHandler.Register("!geoip", cmd.GeoIPCommand)
196
	CmdHandler.Register("!twitch", cmd.TwitchCommand)
197
	CmdHandler.Register("!greetings", cmd.GreetingsCommand)
198
}
199
200
// MetricsSender sends metrics to InfluxDB and another services
201
func MetricsSender(d *discordgo.Session) {
202
	for {
203
		go twitch.Update()
204
205
		// Calculating users count
206
		usersCount := 0
207
		for _, g := range d.State.Guilds {
208
			usersCount += len(g.Members)
209
		}
210
211
		// Metrics counters
212
		queryCounters := []byte(fmt.Sprintf("counters guilds=%v,messages=%v,users=%v", len(d.State.Guilds), messagesCounter, usersCount))
213
		addrCounters := fmt.Sprintf("%v/write?db=%v&u=%v&p=%v",
214
			conf.Metrics.Address, conf.Metrics.Database, conf.Metrics.User, conf.Metrics.Password)
215
		rCounters := bytes.NewReader(queryCounters)
216
		_, _ = http.Post(addrCounters, "", rCounters)
217
218
		// Bot lists
219
		if conf.DBL.Token != "" {
220
			sendDBL(conf.DBL.BotID, conf.DBL.Token, len(d.State.Guilds))
221
		}
222
		messagesCounter = 0
223
		time.Sleep(time.Minute)
224
	}
225
}
226
227
func sendDBL(botID, token string, guilds int) {
228
	timeout := time.Duration(time.Duration(1) * time.Second)
229
	client := &http.Client{
230
		Timeout: time.Duration(timeout),
231
	}
232
	query := url.Values{}
233
	query.Add("server_count", fmt.Sprintf("%v", guilds))
234
	req, _ := http.NewRequest("POST",
235
		fmt.Sprintf("https://discordbots.org/api/bots/%v/stats",
236
			botID), strings.NewReader(query.Encode()))
237
	req.Header.Add("Authorization", token)
238
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
239
	_, _ = client.Do(req)
240
}
241
242
func onStart() {
243
	queryCounters := []byte(fmt.Sprintf("starts value=1"))
244
	addrCounters := fmt.Sprintf("%v/write?db=%v&u=%v&p=%v",
245
		conf.Metrics.Address, conf.Metrics.Database, conf.Metrics.User, conf.Metrics.Password)
246
	rCounters := bytes.NewReader(queryCounters)
247
	_, _ = http.Post(addrCounters, "", rCounters)
248
}
249