rewrite voice state handling

This commit is contained in:
Amish Shah
2018-08-10 14:44:59 +01:00
parent 0f63c50c06
commit be5efea461
11 changed files with 187 additions and 144 deletions

View File

@@ -12,6 +12,7 @@ const RoleStore = require('../stores/RoleStore');
const GuildEmojiStore = require('../stores/GuildEmojiStore');
const GuildChannelStore = require('../stores/GuildChannelStore');
const PresenceStore = require('../stores/PresenceStore');
const VoiceStateStore = require('../stores/VoiceStateStore');
const Base = require('./Base');
const { Error, TypeError } = require('../errors');
@@ -229,9 +230,13 @@ class Guild extends Base {
}
}
if (!this.voiceStates) this.voiceStates = new VoiceStateCollection(this);
if (!this.voiceStates) this.voiceStates = new VoiceStateStore(this);
if (data.voice_states) {
for (const voiceState of data.voice_states) this.voiceStates.set(voiceState.user_id, voiceState);
for (const voiceState of data.voice_states) {
const existing = this.voiceStates.get(voiceState.user_id);
if (existing) existing._patch(voiceState);
else this.voiceStates.add(voiceState);
}
}
if (!this.emojis) {
@@ -881,33 +886,4 @@ class Guild extends Base {
}
}
// TODO: Document this thing
class VoiceStateCollection extends Collection {
constructor(guild) {
super();
this.guild = guild;
}
set(id, voiceState) {
const member = this.guild.members.get(id);
if (member) {
if (member.voiceChannel && member.voiceChannel.id !== voiceState.channel_id) {
member.voiceChannel.members.delete(member.id);
}
const newChannel = this.guild.channels.get(voiceState.channel_id);
if (newChannel) newChannel.members.set(member.user.id, member);
}
super.set(id, voiceState);
}
delete(id) {
const voiceState = this.get(id);
if (voiceState && voiceState.channel_id) {
const channel = this.guild.channels.get(voiceState.channel_id);
if (channel) channel.members.delete(id);
}
return super.delete(id);
}
}
module.exports = Guild;

View File

@@ -56,18 +56,6 @@ class GuildMember extends Base {
if (data) this._patch(data);
}
/**
* Whether this member is speaking. If the client isn't sure, then this will be undefined. Otherwise it will be
* true/false
* @type {?boolean}
* @name GuildMember#speaking
*/
get speaking() {
return this.voiceChannel && this.voiceChannel.connection ?
Boolean(this.voiceChannel.connection._speaking.get(this.id)) :
null;
}
_patch(data) {
/**
* The nickname of this member, if they have one
@@ -107,52 +95,10 @@ class GuildMember extends Base {
return (channel && channel.messages.get(this.lastMessageID)) || null;
}
get voiceState() {
return this._frozenVoiceState || this.guild.voiceStates.get(this.id) || {};
get voice() {
return this.guild.voiceStates.get(this.id);
}
/**
* Whether this member is deafened server-wide
* @type {boolean}
* @readonly
*/
get serverDeaf() { return this.voiceState.deaf; }
/**
* Whether this member is muted server-wide
* @type {boolean}
* @readonly
*/
get serverMute() { return this.voiceState.mute; }
/**
* Whether this member is self-muted
* @type {boolean}
* @readonly
*/
get selfMute() { return this.voiceState.self_mute; }
/**
* Whether this member is self-deafened
* @type {boolean}
* @readonly
*/
get selfDeaf() { return this.voiceState.self_deaf; }
/**
* The voice session ID of this member (if any)
* @type {?Snowflake}
* @readonly
*/
get voiceSessionID() { return this.voiceState.session_id; }
/**
* The voice channel ID of this member, (if any)
* @type {?Snowflake}
* @readonly
*/
get voiceChannelID() { return this.voiceState.channel_id; }
/**
* The time this member joined the guild
* @type {?Date}
@@ -191,33 +137,6 @@ class GuildMember extends Base {
return (role && role.hexColor) || '#000000';
}
/**
* Whether this member is muted in any way
* @type {boolean}
* @readonly
*/
get mute() {
return this.selfMute || this.serverMute;
}
/**
* Whether this member is deafened in any way
* @type {boolean}
* @readonly
*/
get deaf() {
return this.selfDeaf || this.serverDeaf;
}
/**
* The voice channel this member is in, if any
* @type {?VoiceChannel}
* @readonly
*/
get voiceChannel() {
return this.guild.channels.get(this.voiceChannelID) || null;
}
/**
* The ID of this member
* @type {Snowflake}
@@ -344,11 +263,6 @@ class GuildMember extends Base {
const clone = this._clone();
data.user = this.user;
clone._patch(data);
clone._frozenVoiceState = {};
Object.assign(clone._frozenVoiceState, this.voiceState);
if (typeof data.mute !== 'undefined') clone._frozenVoiceState.mute = data.mute;
if (typeof data.deaf !== 'undefined') clone._frozenVoiceState.mute = data.deaf;
if (typeof data.channel_id !== 'undefined') clone._frozenVoiceState.channel_id = data.channel_id;
return clone;
});
}

View File

@@ -1,5 +1,4 @@
const GuildChannel = require('./GuildChannel');
const Collection = require('../util/Collection');
const { browser } = require('../util/Constants');
const Permissions = require('../util/Permissions');
const { Error } = require('../errors');
@@ -9,17 +8,6 @@ const { Error } = require('../errors');
* @extends {GuildChannel}
*/
class VoiceChannel extends GuildChannel {
constructor(guild, data) {
super(guild, data);
/**
* The members in this voice channel
* @type {Collection<Snowflake, GuildMember>}
* @name VoiceChannel#members
*/
Object.defineProperty(this, 'members', { value: new Collection() });
}
_patch(data) {
super._patch(data);
/**
@@ -35,6 +23,17 @@ class VoiceChannel extends GuildChannel {
this.userLimit = data.user_limit;
}
/**
* The members in this voice channel
* @type {Collection<Snowflake, GuildMember>}
* @name VoiceChannel#members
*/
get members() {
return this.guild.voiceStates
.filter(state => state.channelID === this.id && state.member)
.map(state => state.member);
}
/**
* The voice connection for this voice channel, if the client is connected
* @type {?VoiceConnection}

View File

@@ -0,0 +1,131 @@
const Base = require('./Base');
/**
* Represents the voice state for a Guild Member.
*/
class VoiceState extends Base {
constructor(guild, data) {
super(guild.client);
/**
* The guild of this voice state
* @type {Guild}
*/
this.guild = guild;
/**
* The ID of the member of this voice state
* @type {Snowflake}
*/
this.id = data.user_id;
this._patch(data);
}
_patch(data) {
/**
* Whether this member is deafened server-wide
* @type {boolean}
*/
this.serverDeaf = data.deaf;
/**
* Whether this member is muted server-wide
* @type {boolean}
*/
this.serverMute = data.mute;
/**
* Whether this member is self-deafened
* @type {boolean}
*/
this.selfDeaf = data.self_deaf;
/**
* Whether this member is self-muted
* @type {boolean}
*/
this.selfMute = data.self_mute;
/**
* The session ID of this member's connection
* @type {String}
*/
this.sessionID = data.session_id;
/**
* The ID of the voice channel that this member is in
* @type {Snowflake}
*/
this.channelID = data.channel_id;
}
/**
* The member that this voice state belongs to
* @type {GuildMember}
*/
get member() {
return this.guild.members.get(this.id);
}
/**
* The channel that the member is connected to
* @type {VoiceChannel}
*/
get channel() {
return this.guild.channels.get(this.channelID);
}
/**
* Whether this member is either self-deafened or server-deafened
* @type {boolean}
*/
get deaf() {
return this.serverDeaf || this.selfDeaf;
}
/**
* Whether this member is either self-muted or server-muted
* @type {boolean}
*/
get mute() {
return this.serverMute || this.selfMute;
}
/**
* Whether this member is currently speaking. A boolean if the information is available (aka
* the bot is connected to any voice channel in the guild), otherwise this is null
* @type {boolean|null}
*/
get speaking() {
return this.channel && this.channel.connection ?
Boolean(this.channel.connection._speaking.get(this.id)) :
null;
}
/**
* Mutes/unmutes the member of this voice state.
* @param {boolean} mute Whether or not the member should be muted
* @param {string} [reason] Reason for muting or unmuting
* @returns {Promise<GuildMember>}
*/
setMute(mute, reason) {
return this.member ? this.member.edit({ mute }, reason) : Promise.reject(new Error('VOICE_STATE_UNCACHED_MEMBER'));
}
/**
* Deafens/undeafens the member of this voice state.
* @param {boolean} deaf Whether or not the member should be deafened
* @param {string} [reason] Reason for deafening or undeafening
* @returns {Promise<GuildMember>}
*/
setDeaf(deaf, reason) {
return this.member ? this.member.edit({ deaf }, reason) : Promise.reject(new Error('VOICE_STATE_UNCACHED_MEMBER'));
}
toJSON() {
return super.toJSON({
id: true,
serverDeaf: true,
serverMute: true,
selfDeaf: true,
selfMute: true,
sessionID: true,
channelID: 'channel',
});
}
}
module.exports = VoiceState;