Skip to content
This repository has been archived by the owner on Jul 3, 2021. It is now read-only.

Commit

Permalink
Update: Added Socket Class for Auto Reconnect. WaitList Ban event & m…
Browse files Browse the repository at this point in the history
…ethods added. Updated dependencies.
  • Loading branch information
thedark1337 committed Sep 20, 2017
1 parent de526f3 commit ba08530
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 27 deletions.
132 changes: 117 additions & 15 deletions lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const chalk = require('chalk');
const got = require('got');
const tough = require('tough-cookie');
const utils = require('./utils');
const Socket = require("./socket.js");

/**
* node.js HTTPS agent with keepAlive enabled
Expand Down Expand Up @@ -361,9 +362,7 @@ class PlugAPI extends EventEmitter3 {
return;
}

store(this)._ws = new WebSocket(this.socketUrl, {
origin: 'https://plug.dj'
});
store(this)._ws = new Socket(this.socketUrl);
store(this)._ws.on('open', () => {
this.logger.success('plug.dj Socket Server', chalk`{green Connected as a ${this.guest ? 'guest' : 'user'}}`);
store(this)._sendEvent('auth', store(this)._authCode);
Expand All @@ -384,16 +383,14 @@ class PlugAPI extends EventEmitter3 {
store(this)._ws.on('data', (data) => this.emit('tcpMessage', data));
store(this)._ws.on('error', (a) => {
this.logger.error('plug.dj Socket Server', a);
process.nextTick(() => {
store(this)._reconnect(roomSlug);
});
});
store(this)._ws.on('reconnecting', () => {
this.logger.info('Socket Server', 'Reconnecting');
});
store(this)._ws.on('close', (a) => {
this.logger.warn('plug.dj Socket Server', `Closed with Code ${a}`);
process.nextTick(() => {
store(this)._reconnect(roomSlug);
});
});
store(this)._ws.connect();
};

/**
Expand Down Expand Up @@ -701,7 +698,7 @@ class PlugAPI extends EventEmitter3 {
}
};
const handleError = (err) => {
setImmediate(() => {
process.nextTick(() => {
handleErrors.error(`Login Error: \n${err || ''}`, loginCallback);
});
};
Expand Down Expand Up @@ -766,7 +763,7 @@ class PlugAPI extends EventEmitter3 {
})
.then(handleLogin)
.catch((fbError) => {
setImmediate(() => {
process.nextTick(() => {
handleErrors.error(`${fbError}`, callback);
});
});
Expand Down Expand Up @@ -797,7 +794,7 @@ class PlugAPI extends EventEmitter3 {
})
.then(handleLogin)
.catch((err2) => {
setImmediate(() => {
process.nextTick(() => {
if (err2) {
if (err2.statusCode) {
if (Object.is(err2.statusCode, 400)) {
Expand Down Expand Up @@ -1017,7 +1014,7 @@ class PlugAPI extends EventEmitter3 {
* @private
*/
store(this)._sendEvent = (type, data) => {
if (store(this)._ws != null && Object.is(store(this)._ws.readyState, WebSocket.OPEN)) {
if (store(this)._ws != null && Object.is(store(this)._ws.connection.readyState, WebSocket.OPEN)) {
store(this)._ws.send(JSON.stringify({
a: type,
p: data,
Expand Down Expand Up @@ -1078,8 +1075,9 @@ class PlugAPI extends EventEmitter3 {

let i, slug;
const reconnect = (isAck) => {
this.logger.warn('PlugAPI', `${isAck ? 'Reconnecting because of KILL_SESSION (logging in more than once on plug.dj' : 'Reconnecting'}`);
this.logger.warn('PlugAPI', `${isAck ? 'Reconnecting' : 'Reconnecting because of KILL_SESSION (logging in more than once on plug.dj)'}`);
if (store(this)._room.getRoomMeta().slug) {
store(this)._authCode = null;
slug = store(this)._room.getRoomMeta().slug;
this.close(true);
if (isAck) {
Expand Down Expand Up @@ -1221,6 +1219,7 @@ class PlugAPI extends EventEmitter3 {
break;
case PlugAPI.events.MAINT_MODE:
case PlugAPI.events.MODERATE_BAN:
case PlugAPI.events.MODERATE_WLBAN:
case PlugAPI.events.MODERATE_ADD_DJ:
case PlugAPI.events.MODERATE_REMOVE_DJ:
case PlugAPI.events.MODERATE_MOVE_DJ:
Expand Down Expand Up @@ -1457,7 +1456,7 @@ class PlugAPI extends EventEmitter3 {
close(reconnecting) {
store(this)._connectingRoomSlug = null;

if (store(this)._ws != null && Object.is(store(this)._ws.readyState, WebSocket.OPEN)) {
if (store(this)._ws != null && Object.is(store(this)._ws.connection.readyState, WebSocket.OPEN)) {
store(this)._ws.removeAllListeners('close');
store(this)._ws.close();
}
Expand Down Expand Up @@ -2864,6 +2863,52 @@ class PlugAPI extends EventEmitter3 {
return true;
}

/**
* Ban a user from the WaitList
* @param {Number} userID User ID
* @param {Number} [reason] Reason ID
* @param {String} [duration] Duration of the ban
* @param {RESTCallback} [callback] Callback function
* @returns {Boolean} If the REST request got queued
*
* @example
* // Note for the reason / time you can either use bot. or PlugAPI.
* bot.moderateWaitListBan(123456, bot.BAN_REASON.SPAMMING_TROLLING, bot.BAN.PERMA);
*/
moderateWaitListBan(userID, reason, duration, callback) {
if (!store(this)._room.getRoomMeta().slug || this.guest) return false;

if (duration != null) {
if (!store(this)._objectContainsValue(PlugAPI.WLBAN, duration)) return false;
} else {
duration = PlugAPI.WLBAN.PERMA;
}

if (reason != null) {
if (!store(this)._objectContainsValue(PlugAPI.WLBAN_REASON, reason)) return false;
} else {
reason = PlugAPI.WLBAN_REASON.SPAMMING_TROLLING;
}

const user = this.getUser(userID);

if (!Object.is(user, null) ? store(this)._room.getPermissions(user).canModBan : this.havePermission(undefined, PlugAPI.ROOM_ROLE.BOUNCER)) {
if (Object.is(duration, PlugAPI.BAN.PERMA) && this.havePermission(undefined, PlugAPI.ROOM_ROLE.BOUNCER) && !this.havePermission(undefined, PlugAPI.ROOM_ROLE.MANAGER)) {
duration = PlugAPI.WLBAN.DAY;
}

store(this)._queueREST('POST', endpoints.MODERATE_WLBAN, {
userID,
reason,
duration
}, callback);

return true;
}

return false;
}

/**
* Unban a user
* @param {Number} uid User ID
Expand All @@ -2883,6 +2928,25 @@ class PlugAPI extends EventEmitter3 {
return true;
}

/**
* Unban a user from the WaitList
* @param {Number} uid User ID
* @param {RESTCallback} [callback] Callback function
* @returns {Boolean} If the REST request got queued
*
* @example
* bot.moderateWaitListUnban(123456);
*/
moderateWaitListUnbanUser(uid, callback) {
if (!store(this)._room.getRoomMeta().slug || !this.havePermission(undefined, PlugAPI.ROOM_ROLE.MANAGER) || this.guest) {
return false;
}

store(this)._queueREST('DELETE', endpoints.MODERATE_WLBAN + uid, undefined, callback);

return true;
}

/**
* Unmute a user
* @param {Number} uid User ID
Expand Down Expand Up @@ -3186,6 +3250,42 @@ class PlugAPI extends EventEmitter3 {
};
}

/**
* WaitList Ban Lengths
* @prop {String} WLBAN.SHORT Bans user from WaitList for 15 minutes
* @prop {String} WLBAN.MEDIUM Bans user from WaitList for 30 minutes
* @prop {String} WLBAN.LONG Bans user from WaitList for 45 minutes
* @prop {String} WLBAN.PERMA Bans user from WaitList permanently
* @static
*/
static get WLBAN() {
return {
SHORT: 's',
MEDIUM: 'm',
LONG: 'l',
PERMA: 'f'
};
}

/**
* WaitList Ban Reasons
* @prop {Number} WLBAN_REASON.SPAMMING_TROLLING Reason 1. Reason is "Spamming or Trolling".
* @prop {Number} WLBAN_REASON.VERBAL_ABUSE Reason 2. Reason is "Verbal abuse or offensive language".
* @prop {Number} WLBAN_REASON.OFFENSIVE_MEDIA Reason 3. Reason is "Playing offensive videos/songs".
* @prop {Number} WLBAN_REASON.INAPPROPRIATE_GENRE Reason 4. Reason is "Repeatedly playing inappropriate genre(s)".
* @prop {Number} WLBAN_REASON.NEGATAIVE_ATTITUDE Reason 5. Reason is "Negative Attitude".
* @static
*/
static get WLBAN_REASON() {
return {
SPAMMING_TROLLING: 1,
VERBAL_ABUSE: 2,
OFFENSIVE_MEDIA: 3,
INAPPROPRIATE_GENRE: 4,
NEGATIVE_ATTITUDE: 5
};
}

static get events() {
return require('./events.json');
}
Expand All @@ -3200,6 +3300,8 @@ PlugAPI.prototype.BAN = PlugAPI.BAN;
PlugAPI.prototype.BAN_REASON = PlugAPI.BAN_REASON;
PlugAPI.prototype.MUTE = PlugAPI.MUTE;
PlugAPI.prototype.MUTE_REASON = PlugAPI.MUTE_REASON;
PlugAPI.prototype.WLBAN = PlugAPI.WLBAN;
PlugAPI.prototype.WLBAN_REASON = PlugAPI.WLBAN_REASON;
PlugAPI.prototype.events = PlugAPI.events;
PlugAPI.prototype.moderateLockWaitList = PlugAPI.prototype.moderateLockBooth;

Expand Down
1 change: 1 addition & 0 deletions lib/endpoints.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"MODERATE_STAFF": "staff/",
"MODERATE_UNBAN": "bans/",
"MODERATE_UNMUTE": "mutes/",
"MODERATE_WLBAN": "booth/waitlistban",
"PLAYLIST": "playlists",
"ROOM_CYCLE_BOOTH": "booth/cycle",
"ROOM_INFO": "rooms/update",
Expand Down
15 changes: 15 additions & 0 deletions lib/eventObjectTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,21 @@ module.exports = {
};
},

/**
* @param {{m: String, mi: Number, i: Number, d: String, t: String, ti: Number}} data The raw socket data of the modMute event
* @param {Room} room PlugAPI's internal room.js functions
* @returns {{raw: Object, duration: String, reason: Number, moderator: Object, user: Object}} A humanized form of the modWaitListBanevent sent in from plug.dj
* @private
*/
modWaitlistBan(data, room) {
return {
raw: data,
duration: Object.is(data.d, 's') ? 'Short' : Object.is(data.d, 'm') ? 'Medium' : Object.is(data.d, 'l') ? 'Long' : Object.is(data.d, 'f') ? 'Forever' : Object.is(data.d, 'o') ? 'Unbanned' : null,
moderator: room.getUser(data.mi),
user: room.getUser(data.ti)
};
},

/**
* @param {{i: Number, v: Number}} data the raw socket data of the Vote event.
* @param {Room} room PlugAPI's internal room.js functions
Expand Down
1 change: 1 addition & 0 deletions lib/events.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"MODERATE_REMOVE_WAITLIST": "modRemoveWaitList",
"MODERATE_SKIP": "modSkip",
"MODERATE_STAFF": "modStaff",
"MODERATE_WLBAN": "modWaitlistBan",
"NOTIFY": "notify",
"PDJ_MESSAGE": "plugMessage",
"PDJ_UPDATE": "plugUpdate",
Expand Down
78 changes: 78 additions & 0 deletions lib/socket.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
'use strict';

const WebSocket = require('ws');
const autoBind = require('auto-bind');
const EventEmitter3 = require('eventemitter3');

const timerDuration = 10 * 1000; // Average Heartbeat is approximately 5 seconds

/**
* Socket Class with auto reconnect.
* @param {String} socketUrl The URL for WebSocket to connect to.
* @extends {EventEmitter3}
* @author Henchman
* @constructor
* @private
*/
class Socket extends EventEmitter3 {
constructor(socketUrl) {
super();
autoBind(this);
this.url = socketUrl;
this.alive = false;
this.downTimeout = null;
this.connectionAttempts = 0;
this.reconnectTimeout = null;
}
connect() {
this.connection = new WebSocket(this.url, {
origin: 'https://plug.dj'
});

this.connection.on('open', (data) => {
this.resetDownTimer();
this.emit('open', data);
});
this.connection.on('close', (data) => {
this.emit('close', data);
});
this.connection.on('error', (data) => {
this.reconnect();
this.emit('error', data);
});
this.connection.on('message', (data) => {
if (Object.is(data, 'h')) {
this.heartbeat();
}
this.emit('message', data);
});
}
reconnect() {
if (Object.is(this.reconnectTimeout, undefined)) {
clearTimeout(this.downTimeout);
this.reconnectTimeout = setTimeout(() => {
this.connect();
}, 5000);
}
}
heartbeat() {
this.resetDownTimer();
}
resetDownTimer() {
clearTimeout(this.downTimeout);
if (Object.is(this.reconnectTimeout, undefined)) {
this.downTimeout = setTimeout(() => {
this.reconnect();
}, timerDuration);
}
}
send(data) {
this.connection.send(data);
}
close() {
return this.connection.close();
}

}

module.exports = Socket;
Loading

0 comments on commit ba08530

Please sign in to comment.