From 1676a5e73f9ceb427b40429106572931f166d412 Mon Sep 17 00:00:00 2001 From: hydrabolt Date: Sun, 24 Apr 2016 16:30:58 +0100 Subject: [PATCH] Bridged WebSocket Events and REST Requests. Now REST Requests will respond exactly like WS Events to data --- src/client/Client.js | 2 + src/client/actions/Action.js | 27 ++++++++++++ src/client/actions/ActionsManager.js | 19 +++++++++ src/client/actions/MessageCreate.js | 31 ++++++++++++++ src/client/actions/MessageDelete.js | 42 +++++++++++++++++++ src/client/rest/RESTManager.js | 1 - src/client/rest/RESTMethods.js | 12 +++--- .../packets/handlers/MessageCreate.js | 10 ++--- .../packets/handlers/MessageDelete.js | 13 +++--- src/structures/TextChannel.js | 2 +- src/util/Constants.js | 1 + test/random.js | 2 +- 12 files changed, 139 insertions(+), 23 deletions(-) create mode 100644 src/client/actions/Action.js create mode 100644 src/client/actions/ActionsManager.js create mode 100644 src/client/actions/MessageCreate.js create mode 100644 src/client/actions/MessageDelete.js diff --git a/src/client/Client.js b/src/client/Client.js index 9a5fe5b64..d48f6c2a8 100644 --- a/src/client/Client.js +++ b/src/client/Client.js @@ -8,6 +8,7 @@ const ClientDataStore = require('../structures/DataStore/ClientDataStore'); const ClientManager = require('./ClientManager'); const ClientDataResolver = require('./ClientDataResolver'); const WebSocketManager = require('./websocket/WebSocketManager'); +const ActionsManager = require('./actions/ActionsManager'); class Client extends EventEmitter{ @@ -19,6 +20,7 @@ class Client extends EventEmitter{ this.manager = new ClientManager(this); this.ws = new WebSocketManager(this); this.resolver = new ClientDataResolver(this); + this.actions = new ActionsManager(this); } login(email, password) { diff --git a/src/client/actions/Action.js b/src/client/actions/Action.js new file mode 100644 index 000000000..795022b6d --- /dev/null +++ b/src/client/actions/Action.js @@ -0,0 +1,27 @@ +'use strict'; + +/* + +ABOUT ACTIONS + +Actions are similar to WebSocket Packet Handlers, but since introducing +the REST API methods, in order to prevent rewriting code to handle data, +"actions" have been introduced. They're basically what Packet Handlers +used to be but they're strictly for manipulating data and making sure +that WebSocket events don't clash with REST methods. + + */ + +class GenericAction { + + constructor(client) { + this.client = client; + } + + handle(data) { + + } + +}; + +module.exports = GenericAction; diff --git a/src/client/actions/ActionsManager.js b/src/client/actions/ActionsManager.js new file mode 100644 index 000000000..aef572bc4 --- /dev/null +++ b/src/client/actions/ActionsManager.js @@ -0,0 +1,19 @@ +'use strict'; + +const requireAction = name => require(`./${name}`); + +class ActionsManager { + constructor(client) { + this.client = client; + + this.register('MessageCreate'); + this.register('MessageDelete'); + } + + register(name) { + let Action = requireAction(name); + this[name] = new Action(this.client); + } +} + +module.exports = ActionsManager; diff --git a/src/client/actions/MessageCreate.js b/src/client/actions/MessageCreate.js new file mode 100644 index 000000000..55bae8b4e --- /dev/null +++ b/src/client/actions/MessageCreate.js @@ -0,0 +1,31 @@ +'use strict'; + +const Action = require('./Action'); +const Constants = require('../../util/Constants'); +const Message = require('../../structures/Message'); + +class MessageCreateAction extends Action { + + constructor(client) { + super(client); + } + + handle(data) { + + let client = this.client; + let channel = client.store.get('channels', data.channel_id); + + if (channel) { + let message = channel._cacheMessage(new Message(channel, data, client)); + return { + m: message, + }; + } + + return { + m: null, + }; + } +}; + +module.exports = MessageCreateAction; diff --git a/src/client/actions/MessageDelete.js b/src/client/actions/MessageDelete.js new file mode 100644 index 000000000..9f82f0a15 --- /dev/null +++ b/src/client/actions/MessageDelete.js @@ -0,0 +1,42 @@ +'use strict'; + +const Action = require('./Action'); +const Constants = require('../../util/Constants'); +const Message = require('../../structures/Message'); + +class MessageDeleteAction extends Action { + + constructor(client) { + super(client); + this.timeouts = []; + } + + handle(data) { + let client = this.client; + let channel = client.store.get('channels', data.channel_id); + if (channel) { + let message = channel.store.get('messages', data.id); + if (message && !message._deleted) { + message._deleted = true; + this.scheduleForDeletion(channel, message.id); + } + + return { + m: message, + }; + } + + return { + m: null, + }; + } + + scheduleForDeletion(channel, id) { + this.timeouts.push( + setTimeout(() => channel.store.remove('messages', id), + this.client.options.rest_ws_bridge_timeout) + ); + } +}; + +module.exports = MessageDeleteAction; diff --git a/src/client/rest/RESTManager.js b/src/client/rest/RESTManager.js index 926a4de82..60c021a47 100644 --- a/src/client/rest/RESTManager.js +++ b/src/client/rest/RESTManager.js @@ -57,7 +57,6 @@ class RESTManager{ let endpoint = url.replace(/\/[0-9]+/g, '/:id'); if (this.rateLimitedEndpoints[endpoint] && this.rateLimitedEndpoints[endpoint].timeout) { - console.log('adding to queue'); return new Promise((resolve, reject) => { this.addRequestToQueue(method, url, auth, data, file, resolve, reject); }); diff --git a/src/client/rest/RESTMethods.js b/src/client/rest/RESTMethods.js index e1066893d..6f8c1e6ea 100644 --- a/src/client/rest/RESTMethods.js +++ b/src/client/rest/RESTMethods.js @@ -42,10 +42,7 @@ class RESTMethods{ content, tts, nonce, }) .then(data => { - let message = new Message(channel, data, this.rest.client); - channel._cacheMessage(message); - resolve(message); - this.rest.client.emit(Constants.Events.MESSAGE_CREATE, message); + resolve(this.rest.client.actions.MessageCreate.handle(data).m); }) .catch(reject); }); @@ -54,8 +51,11 @@ class RESTMethods{ DeleteMessage(channel, message) { return new Promise((resolve, reject) => { this.rest.makeRequest('del', Constants.Endpoints.CHANNEL_MESSAGE(channel.id, message.id), true) - .then(() => { - resolve(message); + .then(data => { + resolve(this.rest.client.actions.MessageDelete.handle({ + id: message.id, + channel_id: message.channel.id, + }).m); }) .catch(reject); }); diff --git a/src/client/websocket/packets/handlers/MessageCreate.js b/src/client/websocket/packets/handlers/MessageCreate.js index d701d0a97..76241e37e 100644 --- a/src/client/websocket/packets/handlers/MessageCreate.js +++ b/src/client/websocket/packets/handlers/MessageCreate.js @@ -16,14 +16,12 @@ class MessageCreateHandler extends AbstractHandler { handle(packet) { let data = packet.d; let client = this.packetManager.client; - let channel = client.store.get('channels', data.channel_id); - if (channel) { - let message = new Message(channel, data, client); - channel._cacheMessage(message); - client.emit(Constants.Events.MESSAGE_CREATE, message); + let response = client.actions.MessageCreate.handle(data); + + if (response.m) { + client.emit(Constants.Events.MESSAGE_CREATE, response.m); } - } }; diff --git a/src/client/websocket/packets/handlers/MessageDelete.js b/src/client/websocket/packets/handlers/MessageDelete.js index 43944fcbc..c3457f920 100644 --- a/src/client/websocket/packets/handlers/MessageDelete.js +++ b/src/client/websocket/packets/handlers/MessageDelete.js @@ -16,15 +16,12 @@ class MessageDeleteHandler extends AbstractHandler { handle(packet) { let data = packet.d; let client = this.packetManager.client; - let channel = client.store.get('channels', data.channel_id); - if (channel) { - let message = channel.store.get('messages', data.id); - if (message) { - channel.store.remove('messages', message.id); - client.emit(Constants.Events.MESSAGE_DELETE, message); - } - } + let response = client.actions.MessageDelete.handle(data); + + if (response.m) { + client.emit(Constants.Events.MESSAGE_DELETE, response.m); + } } }; diff --git a/src/structures/TextChannel.js b/src/structures/TextChannel.js index a93c831be..73986118c 100644 --- a/src/structures/TextChannel.js +++ b/src/structures/TextChannel.js @@ -23,7 +23,7 @@ class TextChannel extends ServerChannel { this.store.remove(storeKeys[0]); } - this.store.add('messages', message); + return this.store.add('messages', message); } } diff --git a/src/util/Constants.js b/src/util/Constants.js index 43ad1819c..54df21ad5 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -14,6 +14,7 @@ const DefaultOptions = exports.DefaultOptions = { }, protocol_version: 4, max_message_cache: 200, + rest_ws_bridge_timeout: 5000, }; const Status = exports.Status = { diff --git a/test/random.js b/test/random.js index 52e1f57d4..f38301d9b 100644 --- a/test/random.js +++ b/test/random.js @@ -71,7 +71,7 @@ client.on('typingStop.', (channel, user, data) => { client.on('message', message => { if (message.author.username === 'hydrabolt') { message.channel.sendMessage('test').then(msg => { - msg.delete(); + msg.delete().catch(console.log); }); } });