This repository has been archived by the owner on Jul 11, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 70
/
Copy pathvoice.go
241 lines (200 loc) · 8 KB
/
voice.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
package disgord
import (
"context"
"fmt"
"github.com/andersfylling/disgord/internal/endpoint"
"github.com/andersfylling/disgord/internal/httd"
"github.com/andersfylling/disgord/json"
)
// VoiceState Voice State structure
// https://discord.com/developers/docs/resources/voice#voice-state-object
type VoiceState struct {
GuildID Snowflake `json:"guild_id,omitempty"`
ChannelID Snowflake `json:"channel_id"`
UserID Snowflake `json:"user_id"`
Member *Member `json:"member,omitempty"`
SessionID string `json:"session_id"`
Deaf bool `json:"deaf"`
Mute bool `json:"mute"`
SelfDeaf bool `json:"self_deaf"`
SelfMute bool `json:"self_mute"`
SelfStream bool `json:"self_stream"`
SelfVideo bool `json:"self_video"`
Suppress bool `json:"suppress"`
RequestToSpeakTimestamp Time `json:"request_to_speak_timestamp"`
}
var _ Reseter = (*VoiceState)(nil)
var _ Copier = (*VoiceState)(nil)
var _ DeepCopier = (*VoiceState)(nil)
// UnmarshalJSON is used to unmarshal Discord's JSON.
func (v *VoiceState) UnmarshalJSON(data []byte) error {
type s2 VoiceState
if err := json.Unmarshal(data, (*s2)(v)); err != nil {
return err
}
if v.Member != nil {
v.Member.GuildID = v.GuildID
v.Member.UserID = v.UserID
}
return nil
}
// VoiceRegion voice region structure
// https://discord.com/developers/docs/resources/voice#voice-region
type VoiceRegion struct {
// Snowflake unique Snowflake for the region
ID string `json:"id"`
// Name name of the region
Name string `json:"name"`
// SampleHostname an example hostname for the region
SampleHostname string `json:"sample_hostname"`
// SamplePort an example port for the region
SamplePort uint `json:"sample_port"`
// VIP true if this is a vip-only server
VIP bool `json:"vip"`
// Optimal true for a single server that is closest to the current user's Client
Optimal bool `json:"optimal"`
// Deprecated whether this is a deprecated voice region (avoid switching to these)
Deprecated bool `json:"deprecated"`
// Custom whether this is a custom voice region (used for events/etc)
Custom bool `json:"custom"`
}
var _ Reseter = (*VoiceRegion)(nil)
var _ Copier = (*VoiceRegion)(nil)
var _ DeepCopier = (*VoiceRegion)(nil)
// GetVoiceRegions [REST] Returns an array of voice region objects that can be used when creating servers.
//
// Method GET
// Endpoint /voice/regions
// Discord documentation https://discord.com/developers/docs/resources/voice#list-voice-regions
// Reviewed 2018-08-21
// Comment -
func (c clientQueryBuilder) GetVoiceRegions() (regions []*VoiceRegion, err error) {
r := c.client.newRESTRequest(&httd.Request{
Endpoint: endpoint.VoiceRegions(),
Ctx: c.ctx,
}, c.flags)
r.factory = func() interface{} {
tmp := make([]*VoiceRegion, 0)
return &tmp
}
var vs interface{}
if vs, err = r.Execute(); err != nil {
return nil, err
}
if ems, ok := vs.(*[]*VoiceRegion); ok {
return *ems, nil
}
return vs.([]*VoiceRegion), nil
}
// VoiceChannel is used to handle making a voice connection.
func (g guildQueryBuilder) VoiceChannel(channelID Snowflake) VoiceChannelQueryBuilder {
vc := &voiceChannelQueryBuilder{}
vc.gid = g.gid
vc.cid = channelID
vc.client = g.client
vc.ctx = context.Background()
return vc
}
type VoiceChannelQueryBuilder interface {
WithContext(ctx context.Context) VoiceChannelQueryBuilder
WithFlags(flags ...Flag) VoiceChannelQueryBuilder
// Get Get a channel by Snowflake. Returns a channel object.
Get() (*Channel, error)
// Update a Channels settings. Requires the 'MANAGE_CHANNELS' permission for the guild. Returns
// a channel on success, and a 400 BAD REQUEST on invalid parameters. Fires a Channel Update Gateway event. If
// modifying a category, individual Channel Update events will fire for each child channel that also changes.
// For the PATCH method, all the JSON Params are optional.
Update(params *UpdateChannel) (*Channel, error)
// Delete a channel, or close a private message. Requires the 'MANAGE_CHANNELS' permission for
// the guild. Deleting a category does not delete its child Channels; they will have their parent_id removed and a
// Channel Update Gateway event will fire for each of them. Returns a channel object on success.
// Fires a Channel Delete Gateway event.
Delete() (*Channel, error)
// UpdatePermissions Edit the channel permission overwrites for a user or role in a channel. Only usable
// for guild Channels. Requires the 'MANAGE_ROLES' permission. Returns a 204 empty response on success.
// For more information about permissions, see permissions.
UpdatePermissions(overwriteID Snowflake, params *UpdateChannelPermissions) error
// GetInvites Returns a list of invite objects (with invite metadata) for the channel. Only usable for
// guild Channels. Requires the 'MANAGE_CHANNELS' permission.
GetInvites() ([]*Invite, error)
// CreateInvite Create a new invite object for the channel. Only usable for guild Channels. Requires
// the CREATE_INSTANT_INVITE permission. All JSON parameters for this route are optional, however the request
// body is not. If you are not sending any fields, you still have to send an empty JSON object ({}).
// Returns an invite object.
CreateInvite(params *CreateInvite) (*Invite, error)
// DeletePermission Delete a channel permission overwrite for a user or role in a channel. Only usable
// for guild Channels. Requires the 'MANAGE_ROLES' permission. Returns a 204 empty response on success. For more
// information about permissions,
// see permissions: https://discord.com/developers/docs/topics/permissions#permissions
DeletePermission(overwriteID Snowflake) error
// Connect param{deaf} is deprecated
Connect(mute, deaf bool) (VoiceConnection, error)
JoinManual(mute, deaf bool) (*VoiceStateUpdate, *VoiceServerUpdate, error)
}
type voiceChannelQueryBuilder struct {
channelQueryBuilder
gid Snowflake
}
func (v voiceChannelQueryBuilder) WithContext(ctx context.Context) VoiceChannelQueryBuilder {
v.ctx = ctx
return &v
}
func (v voiceChannelQueryBuilder) WithFlags(flags ...Flag) VoiceChannelQueryBuilder {
v.flags = mergeFlags(flags)
return &v
}
// Connect is used to handle making a voice connection.
func (v voiceChannelQueryBuilder) Connect(mute, deaf bool) (VoiceConnection, error) {
return v.client.voiceConnectOptions(v.gid, v.cid, deaf, mute)
}
// JoinManual Tells Discord we want to start a new voice connection. However, it is the caller that
// is responsible for handling the voice connection compared to Connect(..).
//
// Useful for cases where third party libs, like Lavalink, is the preferred way to handle voice connections.
func (v voiceChannelQueryBuilder) JoinManual(mute, deaf bool) (*VoiceStateUpdate, *VoiceServerUpdate, error) {
state := make(chan *VoiceStateUpdate, 2)
stateCtrl := &Ctrl{Channel: state}
defer stateCtrl.CloseChannel()
server := make(chan *VoiceServerUpdate, 2)
serverCtrl := &Ctrl{Channel: server}
defer serverCtrl.CloseChannel()
v.client.Gateway().WithCtrl(stateCtrl).VoiceStateUpdate(func(_ Session, evt *VoiceStateUpdate) {
if evt.GuildID != v.gid {
return
}
if evt.ChannelID != v.cid {
return
}
state <- evt
})
v.client.Gateway().WithCtrl(serverCtrl).VoiceServerUpdate(func(_ Session, evt *VoiceServerUpdate) {
if evt.GuildID != v.gid {
return
}
server <- evt
})
_, err := v.client.Gateway().Dispatch(UpdateVoiceState, &UpdateVoiceStatePayload{
GuildID: v.gid,
ChannelID: v.cid,
SelfDeaf: deaf,
SelfMute: mute,
})
if err != nil {
return nil, nil, fmt.Errorf("failed to send op 4 to discord: %w", err)
}
var (
stateData *VoiceStateUpdate
serverData *VoiceServerUpdate
)
select {
case serverData = <-server:
case <-v.ctx.Done():
return nil, nil, v.ctx.Err()
}
select {
case stateData = <-state:
case <-v.ctx.Done():
return nil, serverData, v.ctx.Err()
}
return stateData, serverData, nil
}