ClientVoiceManager.js (3283B)
1 'use strict'; 2 3 const VoiceBroadcast = require('./VoiceBroadcast'); 4 const VoiceConnection = require('./VoiceConnection'); 5 const { Error } = require('../../errors'); 6 const Collection = require('../../util/Collection'); 7 8 /** 9 * Manages voice connections for the client 10 */ 11 class ClientVoiceManager { 12 constructor(client) { 13 /** 14 * The client that instantiated this voice manager 15 * @type {Client} 16 * @readonly 17 * @name ClientVoiceManager#client 18 */ 19 Object.defineProperty(this, 'client', { value: client }); 20 21 /** 22 * A collection mapping connection IDs to the Connection objects 23 * @type {Collection<Snowflake, VoiceConnection>} 24 */ 25 this.connections = new Collection(); 26 27 /** 28 * Active voice broadcasts that have been created 29 * @type {VoiceBroadcast[]} 30 */ 31 this.broadcasts = []; 32 } 33 34 /** 35 * Creates a voice broadcast. 36 * @returns {VoiceBroadcast} 37 */ 38 createBroadcast() { 39 const broadcast = new VoiceBroadcast(this.client); 40 this.broadcasts.push(broadcast); 41 return broadcast; 42 } 43 44 onVoiceServer({ guild_id, token, endpoint }) { 45 this.client.emit('debug', `[VOICE] voiceServer guild: ${guild_id} token: ${token} endpoint: ${endpoint}`); 46 const connection = this.connections.get(guild_id); 47 if (connection) connection.setTokenAndEndpoint(token, endpoint); 48 } 49 50 onVoiceStateUpdate({ guild_id, session_id, channel_id }) { 51 const connection = this.connections.get(guild_id); 52 this.client.emit('debug', `[VOICE] connection? ${!!connection}, ${guild_id} ${session_id} ${channel_id}`); 53 if (!connection) return; 54 if (!channel_id) { 55 connection._disconnect(); 56 this.connections.delete(guild_id); 57 return; 58 } 59 connection.channel = this.client.channels.cache.get(channel_id); 60 connection.setSessionID(session_id); 61 } 62 63 /** 64 * Sets up a request to join a voice channel. 65 * @param {VoiceChannel} channel The voice channel to join 66 * @returns {Promise<VoiceConnection>} 67 * @private 68 */ 69 joinChannel(channel) { 70 return new Promise((resolve, reject) => { 71 if (!channel.joinable) { 72 throw new Error('VOICE_JOIN_CHANNEL', channel.full); 73 } 74 75 let connection = this.connections.get(channel.guild.id); 76 77 if (connection) { 78 if (connection.channel.id !== channel.id) { 79 this.connections.get(channel.guild.id).updateChannel(channel); 80 } 81 resolve(connection); 82 return; 83 } else { 84 connection = new VoiceConnection(this, channel); 85 connection.on('debug', msg => 86 this.client.emit('debug', `[VOICE (${channel.guild.id}:${connection.status})]: ${msg}`), 87 ); 88 connection.authenticate(); 89 this.connections.set(channel.guild.id, connection); 90 } 91 92 connection.once('failed', reason => { 93 this.connections.delete(channel.guild.id); 94 reject(reason); 95 }); 96 97 connection.on('error', reject); 98 99 connection.once('authenticated', () => { 100 connection.once('ready', () => { 101 resolve(connection); 102 connection.removeListener('error', reject); 103 }); 104 connection.once('disconnect', () => this.connections.delete(channel.guild.id)); 105 }); 106 }); 107 } 108 } 109 110 module.exports = ClientVoiceManager;