refactor(BitField): base class for Permissions, ActivityFlags, Speaking (#2765)

* abstract BitField from Permissions

* reduce useless code, improve docs

* add a ReadOnly identifier to the return type of Bitfield#freeze()

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html#partial-readonly-record-and-pick

* fix the RangeError

* update docs, convert Speaking and ActivityFlags to bitfields

* fix some docs

* Fix Speaking BitField oops

* docs for oops

* more incorrect docs

* Fix incorrectly named property

* add new classes to index

* fix missing @extends docs

* default bitfield resolve to 0, and cleanup defaulting everywhere

Also removes GuildMember#missiongPermissions() alias that had incorrect behavior

* Breaking: Rename Overwrite allowed and denied to allow and deny

To be consistent with the api's naming

* fix setSpeaking usage to bitfields instead of booleans

* fix speaking bug in playChunk

* docs: Updated typings

* fix: BitFieldResolvable should use RecursiveArray

* bugfix/requested change

* typings: Cleanup (#2)

* typings: Fix BitField#{toArray,@@iterator} output type

* typings: correct PermissionOverwrites property names and nitpicks
This commit is contained in:
bdistin
2018-08-21 04:56:41 -05:00
committed by SpaceEEC
parent 6be8172539
commit c62f01f0e4
18 changed files with 339 additions and 242 deletions

View File

@@ -355,7 +355,7 @@ class Client extends BaseClient {
* .catch(console.error);
*/
generateInvite(permissions) {
permissions = typeof permissions === 'undefined' ? 0 : Permissions.resolve(permissions);
permissions = Permissions.resolve(permissions);
return this.fetchApplication().then(application =>
`https://discordapp.com/oauth2/authorize?client_id=${application.id}&permissions=${permissions}&scope=bot`
);

View File

@@ -7,6 +7,7 @@ const VoiceReceiver = require('./receiver/Receiver');
const EventEmitter = require('events');
const { Error } = require('../../errors');
const PlayInterface = require('./util/PlayInterface');
const Speaking = require('../../util/Speaking');
const SUPPORTED_MODES = [
'xsalsa20_poly1305_lite',
@@ -49,10 +50,10 @@ class VoiceConnection extends EventEmitter {
this.status = VoiceStatus.AUTHENTICATING;
/**
* Whether we're currently transmitting audio
* @type {boolean}
* Our current speaking state
* @type {ReadOnly<Speaking>}
*/
this.speaking = false;
this.speaking = new Speaking().freeze();
/**
* The authentication data needed to connect to the voice server
@@ -96,7 +97,7 @@ class VoiceConnection extends EventEmitter {
/**
* Tracks which users are talking
* @type {Map<Snowflake, boolean>}
* @type {Map<Snowflake, ReadOnly<Speaking>>}
* @private
*/
this._speaking = new Map();
@@ -135,18 +136,18 @@ class VoiceConnection extends EventEmitter {
}
/**
* Sets whether the voice connection should display as "speaking" or not.
* @param {boolean} value Whether or not to speak
* Sets whether the voice connection should display as "speaking", "soundshare" or "none".
* @param {BitFieldResolvable} value The new speaking state
* @private
*/
setSpeaking(value) {
if (this.speaking === value) return;
if (this.speaking.equals(value)) return;
if (this.status !== VoiceStatus.CONNECTED) return;
this.speaking = value;
this.speaking = new Speaking(value).freeze();
this.sockets.ws.sendPacket({
op: VoiceOPCodes.SPEAKING,
d: {
speaking: this.speaking ? 1 : 0,
speaking: this.speaking.bitfield,
delay: 0,
ssrc: this.authentication.ssrc,
},
@@ -305,7 +306,7 @@ class VoiceConnection extends EventEmitter {
reconnect(token, endpoint) {
this.authentication.token = token;
this.authentication.endpoint = endpoint;
this.speaking = false;
this.speaking = new Speaking().freeze();
this.status = VoiceStatus.RECONNECTING;
/**
* Emitted when the voice connection is reconnecting (typically after a region change).
@@ -350,7 +351,7 @@ class VoiceConnection extends EventEmitter {
*/
cleanup() {
this.player.destroy();
this.speaking = false;
this.speaking = new Speaking().freeze();
const { ws, udp } = this.sockets;
if (ws) {
@@ -432,17 +433,17 @@ class VoiceConnection extends EventEmitter {
* @private
*/
onSpeaking({ user_id, ssrc, speaking }) {
speaking = Boolean(speaking);
speaking = new Speaking(speaking).freeze();
const guild = this.channel.guild;
const user = this.client.users.get(user_id);
this.ssrcMap.set(+ssrc, user_id);
const old = this._speaking.get(user_id);
this._speaking.set(user_id, speaking);
/**
* Emitted whenever a user starts/stops speaking.
* Emitted whenever a user changes speaking state.
* @event VoiceConnection#speaking
* @param {User} user The user that has started/stopped speaking
* @param {boolean} speaking Whether or not the user is speaking
* @param {User} user The user that has changed speaking state
* @param {ReadOnly<Speaking>} speaking The speaking state of the user
*/
if (this.status === VoiceStatus.CONNECTED) {
this.emit('speaking', user, speaking);
@@ -455,10 +456,10 @@ class VoiceConnection extends EventEmitter {
const member = guild.member(user);
if (member) {
/**
* Emitted once a guild member starts/stops speaking.
* Emitted once a guild member changes speaking state.
* @event Client#guildMemberSpeaking
* @param {GuildMember} member The member that started/stopped speaking
* @param {boolean} speaking Whether or not the member is speaking
* @param {ReadOnly<Speaking>} speaking The speaking state of the member
*/
this.client.emit(Events.GUILD_MEMBER_SPEAKING, member, speaking);
}

View File

@@ -67,7 +67,7 @@ class StreamDispatcher extends Writable {
this.on('finish', () => {
// Still emitting end for backwards compatibility, probably remove it in the future!
this.emit('end');
this._setSpeaking(false);
this._setSpeaking(0);
});
if (typeof volume !== 'undefined') this.setVolume(volume);
@@ -131,7 +131,7 @@ class StreamDispatcher extends Writable {
this.streams.silence.pipe(this);
this._silence = true;
} else {
this._setSpeaking(false);
this._setSpeaking(0);
}
this.pausedSince = Date.now();
}
@@ -243,7 +243,6 @@ class StreamDispatcher extends Writable {
_playChunk(chunk) {
if (this.player.dispatcher !== this || !this.player.voiceConnection.authentication.secret_key) return;
this._setSpeaking(true);
this._sendPacket(this._createPacket(this._sdata.sequence, this._sdata.timestamp, chunk));
}
@@ -285,7 +284,7 @@ class StreamDispatcher extends Writable {
* @event StreamDispatcher#debug
* @param {string} info The debug info
*/
this._setSpeaking(true);
this._setSpeaking(1);
while (repeats--) {
if (!this.player.voiceConnection.sockets.udp) {
this.emit('debug', 'Failed to send a packet - no UDP socket');
@@ -293,7 +292,7 @@ class StreamDispatcher extends Writable {
}
this.player.voiceConnection.sockets.udp.send(packet)
.catch(e => {
this._setSpeaking(false);
this._setSpeaking(0);
this.emit('debug', `Failed to send a packet - ${e}`);
});
}