Clean up more voice stuff

This commit is contained in:
Schuyler Cebulskie
2016-10-25 20:34:57 -04:00
parent d1e9d15a1c
commit b2a4545c16
2 changed files with 122 additions and 128 deletions

View File

@@ -4,6 +4,114 @@ const Constants = require('../../util/Constants');
const VoiceConnection = require('./VoiceConnection');
const EventEmitter = require('events').EventEmitter;
/**
* Manages all the voice stuff for the Client
* @private
*/
class ClientVoiceManager {
constructor(client) {
/**
* The client that instantiated this voice manager
* @type {Client}
*/
this.client = client;
/**
* A collection mapping connection IDs to the Connection objects
* @type {Collection<string, VoiceConnection>}
*/
this.connections = new Collection();
/**
* Pending connection attempts, maps Guild ID to VoiceChannel
* @type {Collection<string, VoiceChannel>}
*/
this.pending = new Collection();
this.client.on('self.voiceServer', this.onVoiceServer.bind(this));
this.client.on('self.voiceStateUpdate', this.onVoiceStateUpdate.bind(this));
}
onVoiceServer(data) {
if (this.pending.has(data.guild_id)) this.pending.get(data.guild_id).setTokenAndEndpoint(data.token, data.endpoint);
}
onVoiceStateUpdate(data) {
if (this.pending.has(data.guild_id)) this.pending.get(data.guild_id).setSessionID(data.session_id);
}
/**
* Sends a request to the main gateway to join a voice channel
* @param {VoiceChannel} channel The channel to join
* @param {Object} [options] The options to provide
*/
sendVoiceStateUpdate(channel, options = {}) {
if (!this.client.user) throw new Error('Unable to join because there is no client user.');
if (channel.permissionsFor) {
const permissions = channel.permissionsFor(this.client.user);
if (permissions) {
if (!permissions.hasPermission('CONNECT')) {
throw new Error('You do not have permission to connect to this voice channel.');
}
} else {
throw new Error('There is no permission set for the client user in this channel - are they part of the guild?');
}
} else {
throw new Error('Channel does not support permissionsFor; is it really a voice channel?');
}
options = mergeDefault({
guild_id: channel.guild.id,
channel_id: channel.id,
self_mute: false,
self_deaf: false,
}, options);
this.client.ws.send({
op: Constants.OPCodes.VOICE_STATE_UPDATE,
d: options,
});
}
/**
* Sets up a request to join a voice channel
* @param {VoiceChannel} channel The voice channel to join
* @returns {Promise<VoiceConnection>}
*/
joinChannel(channel) {
return new Promise((resolve, reject) => {
if (this.pending.get(channel.guild.id)) throw new Error('Already connecting to this guild\'s voice server.');
const existingConnection = this.connections.get(channel.guild.id);
if (existingConnection) {
if (existingConnection.channel.id !== channel.id) {
this.sendVoiceStateUpdate(channel);
this.connections.get(channel.guild.id).channel = channel;
}
resolve(existingConnection);
return;
}
const pendingConnection = new PendingVoiceConnection(this, channel);
this.pending.set(channel.guild.id, pendingConnection);
pendingConnection.on('fail', reason => {
this.pending.delete(channel.guild.id);
reject(reason);
});
pendingConnection.on('pass', voiceConnection => {
this.pending.delete(channel.guild.id);
this.connections.set(channel.guild.id, voiceConnection);
voiceConnection.once('ready', () => resolve(voiceConnection));
voiceConnection.once('error', reject);
voiceConnection.once('disconnect', () => this.connections.delete(channel.guild.id));
});
});
}
}
/**
* Represents a Pending Voice Connection
* @private
@@ -136,112 +244,4 @@ class PendingVoiceConnection extends EventEmitter {
}
}
/**
* Manages all the voice stuff for the Client
* @private
*/
class ClientVoiceManager {
constructor(client) {
/**
* The client that instantiated this voice manager
* @type {Client}
*/
this.client = client;
/**
* A collection mapping connection IDs to the Connection objects
* @type {Collection<string, VoiceConnection>}
*/
this.connections = new Collection();
/**
* Pending connection attempts, maps Guild ID to VoiceChannel
* @type {Collection<string, VoiceChannel>}
*/
this.pending = new Collection();
this.client.on('self.voiceServer', this.onVoiceServer.bind(this));
this.client.on('self.voiceStateUpdate', this.onVoiceStateUpdate.bind(this));
}
onVoiceServer(data) {
if (this.pending.has(data.guild_id)) this.pending.get(data.guild_id).setTokenAndEndpoint(data.token, data.endpoint);
}
onVoiceStateUpdate(data) {
if (this.pending.has(data.guild_id)) this.pending.get(data.guild_id).setSessionID(data.session_id);
}
/**
* Sends a request to the main gateway to join a voice channel
* @param {VoiceChannel} channel The channel to join
* @param {Object} [options] The options to provide
*/
sendVoiceStateUpdate(channel, options = {}) {
if (!this.client.user) throw new Error('Unable to join because there is no client user.');
if (channel.permissionsFor) {
const permissions = channel.permissionsFor(this.client.user);
if (permissions) {
if (!permissions.hasPermission('CONNECT')) {
throw new Error('You do not have permission to connect to this voice channel.');
}
} else {
throw new Error('There is no permission set for the client user in this channel - are they part of the guild?');
}
} else {
throw new Error('Channel does not support permissionsFor; is it really a voice channel?');
}
options = mergeDefault({
guild_id: channel.guild.id,
channel_id: channel.id,
self_mute: false,
self_deaf: false,
}, options);
this.client.ws.send({
op: Constants.OPCodes.VOICE_STATE_UPDATE,
d: options,
});
}
/**
* Sets up a request to join a voice channel
* @param {VoiceChannel} channel The voice channel to join
* @returns {Promise<VoiceConnection>}
*/
joinChannel(channel) {
return new Promise((resolve, reject) => {
if (this.pending.get(channel.guild.id)) throw new Error('Already connecting to this guild\'s voice server.');
const existingConnection = this.connections.get(channel.guild.id);
if (existingConnection) {
if (existingConnection.channel.id !== channel.id) {
this.sendVoiceStateUpdate(channel);
this.connections.get(channel.guild.id).channel = channel;
}
resolve(existingConnection);
return;
}
const pendingConnection = new PendingVoiceConnection(this, channel);
this.pending.set(channel.guild.id, pendingConnection);
pendingConnection.on('fail', reason => {
this.pending.delete(channel.guild.id);
reject(reason);
});
pendingConnection.on('pass', voiceConnection => {
this.pending.delete(channel.guild.id);
this.connections.set(channel.guild.id, voiceConnection);
voiceConnection.once('ready', () => resolve(voiceConnection));
voiceConnection.once('error', reject);
voiceConnection.once('disconnect', () => this.connections.delete(channel.guild.id));
});
});
}
}
module.exports = ClientVoiceManager;