forked from andersfylling/disgord
-
Notifications
You must be signed in to change notification settings - Fork 0
/
session.go
334 lines (298 loc) · 12.9 KB
/
session.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
package disgord
import (
"errors"
"net/http"
"time"
"github.com/andersfylling/disgord/constant"
"github.com/andersfylling/disgord/httd"
"github.com/andersfylling/disgord/websocket"
)
// NewSession create a client and return the Session interface
func NewSession(conf *Config) (Session, error) {
// ensure valid api version
if conf.APIVersion == 0 {
conf.APIVersion = 6 // the current discord API, for now v6
}
switch conf.APIVersion { // todo: simplify
case 1:
fallthrough
case 2:
fallthrough
case 3:
fallthrough
case 4:
fallthrough
case 5:
return nil, errors.New("outdated API version")
case 6: // supported
default:
return nil, errors.New("Discord API version is not yet supported")
}
if conf.HTTPClient == nil {
// http client configuration
conf.HTTPClient = &http.Client{
Timeout: time.Second * 10,
}
}
// Use websocket to keep the socket connection going
// default communication encoding to json
if conf.APIEncoding == "" {
conf.APIEncoding = JSONEncoding
}
if conf.ProjectName == "" {
conf.ProjectName = LibraryInfo()
}
dws, err := websocket.NewClient(&websocket.Config{
// user settings
Token: conf.Token,
HTTPClient: conf.HTTPClient,
Debug: conf.Debug,
// identity
Browser: LibraryInfo(),
Device: conf.ProjectName,
GuildLargeThreshold: 250, // TODO: config
// lib specific
DAPIVersion: conf.APIVersion,
DAPIEncoding: conf.APIEncoding,
ChannelBuffer: 1,
})
if err != nil {
return nil, err
}
// request client
reqConf := &httd.Config{
APIVersion: conf.APIVersion,
BotToken: conf.Token,
UserAgentSourceURL: GitHubURL,
UserAgentVersion: constant.Version,
HTTPClient: conf.HTTPClient,
CancelRequestWhenRateLimited: conf.CancelRequestWhenRateLimited,
}
reqClient := httd.NewClient(reqConf)
// event dispatcher
evtDispatcher := NewDispatch(dws)
// create a disgord client/instance/session
c := &Client{
config: conf,
httpClient: conf.HTTPClient,
ws: dws,
socketEvtChan: dws.DiscordWSEventChan(),
token: conf.Token,
evtDispatch: evtDispatcher,
state: NewCache(),
req: reqClient,
}
return c, nil
}
// NewSessionMustCompile same as NewClientMustCompile, but with the Session
// interface
func NewSessionMustCompile(conf *Config) (session Session) {
var err error
session, err = NewSession(conf)
if err != nil {
panic(err)
}
return
}
type EventChannels interface {
All() <-chan interface{} // any event
Ready() <-chan *Ready
Resumed() <-chan *Resumed
ChannelCreate() <-chan *ChannelCreate
ChannelUpdate() <-chan *ChannelUpdate
ChannelDelete() <-chan *ChannelDelete
ChannelPinsUpdate() <-chan *ChannelPinsUpdate
GuildCreate() <-chan *GuildCreate
GuildUpdate() <-chan *GuildUpdate
GuildDelete() <-chan *GuildDelete
GuildBanAdd() <-chan *GuildBanAdd
GuildBanRemove() <-chan *GuildBanRemove
GuildEmojisUpdate() <-chan *GuildEmojisUpdate
GuildIntegrationsUpdate() <-chan *GuildIntegrationsUpdate
GuildMemberAdd() <-chan *GuildMemberAdd
GuildMemberRemove() <-chan *GuildMemberRemove
GuildMemberUpdate() <-chan *GuildMemberUpdate
GuildMembersChunk() <-chan *GuildMembersChunk
GuildRoleUpdate() <-chan *GuildRoleUpdate
GuildRoleCreate() <-chan *GuildRoleCreate
GuildRoleDelete() <-chan *GuildRoleDelete
MessageCreate() <-chan *MessageCreate
MessageUpdate() <-chan *MessageUpdate
MessageDelete() <-chan *MessageDelete
MessageDeleteBulk() <-chan *MessageDeleteBulk
MessageReactionAdd() <-chan *MessageReactionAdd
MessageReactionRemove() <-chan *MessageReactionRemove
MessageReactionRemoveAll() <-chan *MessageReactionRemoveAll
PresenceUpdate() <-chan *PresenceUpdate
PresencesReplace() <-chan *PresencesReplace
TypingStart() <-chan *TypingStart
UserUpdate() <-chan *UserUpdate
VoiceStateUpdate() <-chan *VoiceStateUpdate
VoiceServerUpdate() <-chan *VoiceServerUpdate
WebhooksUpdate() <-chan *WebhooksUpdate
}
type SocketHandler interface {
Connect() error
Disconnect() error
DisconnectOnInterrupt() error
// event handlers
On(event string, handler ...interface{})
Emit(command SocketCommand, dataPointer interface{})
//Use(middleware ...interface{}) // TODO: is this useful?
// event channels
EventChan(event string) (channel interface{}, err error)
EventChannels() EventChannels
}
type AuditLogsRESTer interface {
GetGuildAuditLogs(guildID Snowflake, params *GuildAuditLogsParams) (log *AuditLog, err error)
}
type ChannelRESTer interface {
GetChannel(id Snowflake) (ret *Channel, err error)
ModifyChannel(changes *ModifyChannelParams) (ret *Channel, err error)
DeleteChannel(id Snowflake) (err error)
EditChannelPermissions(chanID, overwriteID Snowflake, params *EditChannelPermissionsParams) (err error)
GetChannelInvites(id Snowflake) (ret []*Invite, err error)
CreateChannelInvites(id Snowflake, params *CreateChannelInvitesParams) (ret *Invite, err error)
DeleteChannelPermission(channelID, overwriteID Snowflake) (err error)
TriggerTypingIndicator(channelID Snowflake) (err error)
GetPinnedMessages(channelID Snowflake) (ret []*Message, err error)
AddPinnedChannelMessage(channelID, msgID Snowflake) (err error)
DeletePinnedChannelMessage(channelID, msgID Snowflake) (err error)
GroupDMAddRecipient(channelID, userID Snowflake, params *GroupDMAddRecipientParams) (err error)
GroupDMRemoveRecipient(channelID, userID Snowflake) (err error)
GetChannelMessages(channelID Snowflake, params URLParameters) (ret []*Message, err error)
GetChannelMessage(channelID, messageID Snowflake) (ret *Message, err error)
CreateChannelMessage(channelID Snowflake, params *CreateChannelMessageParams) (ret *Message, err error)
EditMessage(chanID, msgID Snowflake, params *EditMessageParams) (ret *Message, err error)
DeleteMessage(channelID, msgID Snowflake) (err error)
BulkDeleteMessages(chanID Snowflake, params *BulkDeleteMessagesParams) (err error)
CreateReaction(channelID, messageID Snowflake, emoji interface{}) (ret *Reaction, err error)
DeleteOwnReaction(channelID, messageID Snowflake, emoji interface{}) (err error)
DeleteUserReaction(channelID, messageID, userID Snowflake, emoji interface{}) (err error)
GetReaction(channelID, messageID Snowflake, emoji interface{}, params URLParameters) (ret []*User, err error)
DeleteAllReactions(channelID, messageID Snowflake) (err error)
}
type EmojiRESTer interface {
GetGuildEmojis(id Snowflake) (ret []*Emoji, err error)
GetGuildEmoji(guildID, emojiID Snowflake) (ret *Emoji, err error)
CreateGuildEmoji(guildID Snowflake, params *CreateGuildEmojiParams) (ret *Emoji, err error)
ModifyGuildEmoji(guildID, emojiID Snowflake, params *ModifyGuildEmojiParams) (ret *Emoji, err error)
DeleteGuildEmoji(guildID, emojiID Snowflake) (err error)
}
type GuildRESTer interface {
CreateGuild(params *CreateGuildParams) (ret *Guild, err error)
GetGuild(id Snowflake) (ret *Guild, err error)
ModifyGuild(id Snowflake, params *ModifyGuildParams) (ret *Guild, err error)
DeleteGuild(id Snowflake) (err error)
GetGuildChannels(id Snowflake) (ret []*Channel, err error)
CreateGuildChannel(id Snowflake, params *CreateGuildChannelParams) (ret *Channel, err error)
GetGuildMember(guildID, userID Snowflake) (ret *Member, err error)
GetGuildMembers(guildID, after Snowflake, limit int) (ret []*Member, err error)
AddGuildMember(guildID, userID Snowflake, params *AddGuildMemberParams) (ret *Member, err error)
ModifyGuildMember(guildID, userID Snowflake, params *ModifyGuildMemberParams) (err error)
ModifyCurrentUserNick(id Snowflake, params *ModifyCurrentUserNickParams) (nick string, err error)
AddGuildMemberRole(guildID, userID, roleID Snowflake) (err error)
RemoveGuildMemberRole(guildID, userID, roleID Snowflake) (err error)
RemoveGuildMember(guildID, userID Snowflake) (err error)
GetGuildBans(id Snowflake) (ret []*Ban, err error)
GetGuildBan(guildID, userID Snowflake) (ret *Ban, err error)
CreateGuildBan(guildID, userID Snowflake, params *CreateGuildBanParams) (err error)
RemoveGuildBan(guildID, userID Snowflake) (err error)
GetGuildRoles(guildID Snowflake) (ret []*Role, err error)
CreateGuildRole(id Snowflake, params *CreateGuildRoleParams) (ret *Role, err error)
ModifyGuildRolePositions(guildID Snowflake, params *ModifyGuildRolePositionsParams) (ret []*Role, err error)
ModifyGuildRole(guildID, roleID Snowflake, params *ModifyGuildRoleParams) (ret *Role, err error)
DeleteGuildRole(guildID, roleID Snowflake) (err error)
GetGuildPruneCount(id Snowflake, params *GuildPruneParams) (ret *GuildPruneCount, err error)
BeginGuildPrune(id Snowflake, params *GuildPruneParams) (ret *GuildPruneCount, err error)
GetGuildVoiceRegions(id Snowflake) (ret []*VoiceRegion, err error)
GetGuildInvites(id Snowflake) (ret []*Invite, err error)
GetGuildIntegrations(id Snowflake) (ret []*Integration, err error)
CreateGuildIntegration(guildID Snowflake, params *CreateGuildIntegrationParams) (err error)
ModifyGuildIntegration(guildID, integrationID Snowflake, params *ModifyGuildIntegrationParams) (err error)
DeleteGuildIntegration(guildID, integrationID Snowflake) (err error)
SyncGuildIntegration(guildID, integrationID Snowflake) (err error)
GetGuildEmbed(guildID Snowflake) (ret *GuildEmbed, err error)
ModifyGuildEmbed(guildID Snowflake, params *GuildEmbed) (ret *GuildEmbed, err error)
GetGuildVanityURL(guildID Snowflake) (ret *PartialInvite, err error)
}
type InviteRESTer interface {
GetInvite(inviteCode string, withCounts bool) (invite *Invite, err error)
DeleteInvite(inviteCode string) (invite *Invite, err error)
}
type UserRESTer interface {
GetCurrentUser() (ret *User, err error)
GetUser(id Snowflake) (ret *User, err error)
ModifyCurrentUser(params *ModifyCurrentUserParams) (ret *User, err error)
GetCurrentUserGuilds(params *GetCurrentUserGuildsParams) (ret []*Guild, err error)
LeaveGuild(id Snowflake) (err error)
GetUserDMs() (ret []*Channel, err error)
CreateDM(recipientID Snowflake) (ret *Channel, err error)
CreateGroupDM(params *CreateGroupDMParams) (ret *Channel, err error)
GetUserConnections() (ret []*UserConnection, err error)
}
type VoiceRESTer interface {
GetVoiceRegions() (ret []*VoiceRegion, err error)
}
type WebhookRESTer interface {
CreateWebhook(channelID Snowflake, params *CreateWebhookParams) (ret *Webhook, err error)
GetChannelWebhooks(channelID Snowflake) (ret []*Webhook, err error)
GetGuildWebhooks(guildID Snowflake) (ret []*Webhook, err error)
GetWebhook(id Snowflake) (ret *Webhook, err error)
GetWebhookWithToken(id Snowflake, token string) (ret *Webhook, err error)
ModifyWebhook(newWebhook *Webhook) (ret *Webhook, err error)
ModifyWebhookWithToken(newWebhook *Webhook) (ret *Webhook, err error)
DeleteWebhook(webhookID Snowflake) (err error)
DeleteWebhookWithToken(id Snowflake, token string) (err error)
ExecuteWebhook(params *ExecuteWebhookParams, wait bool, URLSuffix string) (err error)
ExecuteSlackWebhook(params *ExecuteWebhookParams, wait bool) (err error)
ExecuteGitHubWebhook(params *ExecuteWebhookParams, wait bool) (err error)
}
type RESTer interface {
AuditLogsRESTer
ChannelRESTer
EmojiRESTer
GuildRESTer
InviteRESTer
UserRESTer
VoiceRESTer
WebhookRESTer
}
// Session the discord api is split in two. socket for keeping the client up to date, and http api for requests.
type Session interface {
// give information about the bot/connected user
Myself() *User
// Request For interacting with Discord. Sending messages, creating channels, guilds, etc.
// To read object state such as guilds, State() should be used in stead. However some data
// might not exist in the state. If so it should be requested. Note that this only holds http
// CRUD operation and not the actual rest endpoints for discord (See Rest()).
Req() httd.Requester
// State reflects the latest changes received from Discord gateway.
// Should be used instead of requesting objects.
State() Cacher
// RateLimiter the rate limiter for the discord REST API
RateLimiter() httd.RateLimiter
// Discord Gateway, web socket
SocketHandler
// Generic CRUD operations for Discord interaction
DeleteFromDiscord(obj discordDeleter) error
SaveToDiscord(obj discordSaver) error
// state/caching module
// checks the cache first, otherwise do a http request
RESTer
// Custom REST functions
SendMsg(channelID Snowflake, message *Message) (msg *Message, err error)
SendMsgString(channelID Snowflake, content string) (msg *Message, err error)
UpdateMessage(message *Message) (msg *Message, err error)
UpdateChannel(channel *Channel) (err error)
// same as above. Except these returns a channel
// WARNING: none below should be assumed to be working.
// TODO: implement in the future!
//GuildChan(guildID Snowflake) <-chan *Guild
//ChannelChan(channelID Snowflake) <-chan *Channel
//ChannelsChan(guildID Snowflake) <-chan map[Snowflake]*Channel
//MsgChan(msgID Snowflake) <-chan *Message
//UserChan(userID Snowflake) <-chan *UserChan
//MemberChan(guildID, userID Snowflake) <-chan *Member
//MembersChan(guildID Snowflake) <-chan map[Snowflake]*Member
}