From 8b74713fe9d51004a502fe02d435338587a8bfa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Fri, 5 Mar 2021 18:31:29 -0300 Subject: [PATCH] :construction: WIP for websocket connection --- .../nodes-base/nodes/Discord/Discord.node.ts | 78 +++++++++++++++++++ .../nodes/Discord/GenericFunctions.ts | 32 +++++--- .../descriptions/MessageDescription.ts | 4 + packages/nodes-base/package.json | 2 + 4 files changed, 106 insertions(+), 10 deletions(-) diff --git a/packages/nodes-base/nodes/Discord/Discord.node.ts b/packages/nodes-base/nodes/Discord/Discord.node.ts index dc3e722cba..e2f9c593dd 100644 --- a/packages/nodes-base/nodes/Discord/Discord.node.ts +++ b/packages/nodes-base/nodes/Discord/Discord.node.ts @@ -11,6 +11,7 @@ import { import { discordApiRequest, + setHeartbeatInterval, } from './GenericFunctions'; import { @@ -20,6 +21,12 @@ import { userOperations, } from './descriptions'; +import WebSocket = require('ws'); + +import { + clearInterval, +} from 'timers'; + export class Discord implements INodeType { description: INodeTypeDescription = { displayName: 'Discord', @@ -75,6 +82,44 @@ export class Discord implements INodeType { let responseData; const returnData: IDataObject[] = []; + const { url } = await discordApiRequest.call(this, 'GET', '/gateway'); + + const ws = new WebSocket(`${url}?v=8&encoding=json`); + + await new Promise((resolve) => { + ws.on('open', () => { + console.log('*** WEBSOCKET CONNECTION OPEN ***'); + }); + + let heartbeatInterval: NodeJS.Timeout; + + ws.on('message', (data: string) => { + const op = JSON.parse(data).op; + const mapping: { [key: number]: 'hello' | 'acknowledgment' } = { + 10: 'hello', + 11: 'acknowledgment', + }; + + console.log(`--- MESSAGE RECEIVED: ${mapping[op]} ---`); + + if (mapping[op] === 'hello') { + console.log('--- SET HEARTBEAT ---'); + heartbeatInterval = setHeartbeatInterval(ws, data); + resolve(); + } + + // TODO close connection if heartbeat acknowledgment does not arrive + console.log(`--- MESSAGE CONTENTS FOR ${mapping[op]} ---`); + console.log(JSON.parse(data)); + }); + + ws.on('close', () => { + console.log('*** WEBSOCKET CONNECTION CLOSED ***'); + console.log('--- UNSET HEARTBEAT ---'); + clearInterval(heartbeatInterval); + }); + }); + for (let i = 0; i < items.length; i++) { if (resource === 'message') { @@ -104,7 +149,31 @@ export class Discord implements INodeType { await discordApiRequest.call(this, 'POST', '', body, {}, webhookUrl); responseData = { success: true }; + + } else if (operation === 'ws') { + + const { oauthTokenData } = this.getCredentials('discordOAuth2Api') as { + oauthTokenData: { access_token: string } + }; + + const payload = JSON.stringify({ + op: 2, + d: { + token: oauthTokenData.access_token, + intents: 513, + properties: { + $os: 'linux', + $browser: 'firefox', + $device: 'n8n', + }, + }, + }); + + // ws.send(payload); + } + + } if (resource === 'user') { @@ -136,6 +205,15 @@ export class Discord implements INodeType { : returnData.push(responseData); } + await new Promise(resolve => { + setTimeout(resolve, 3 * 60 * 1000); + }); + + ws.terminate(); + + + // console.log(ws.); + return [this.helpers.returnJsonArray(returnData)]; } } diff --git a/packages/nodes-base/nodes/Discord/GenericFunctions.ts b/packages/nodes-base/nodes/Discord/GenericFunctions.ts index 45721adb64..97ca9b1cd3 100644 --- a/packages/nodes-base/nodes/Discord/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Discord/GenericFunctions.ts @@ -12,6 +12,8 @@ import { IDataObject, } from 'n8n-workflow'; +import WebSocket = require('ws'); + export async function discordApiRequest( this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions, method: string, @@ -21,9 +23,15 @@ export async function discordApiRequest( uri?: string, option: IDataObject = {}, ) { + + const { oauthTokenData } = this.getCredentials('discordOAuth2Api') as { + oauthTokenData: { access_token: string } + }; + const options: OptionsWithUri = { headers: { 'Content-Type': 'application/json', + Authorization: `Bearer ${oauthTokenData.access_token}`, }, method, body, @@ -49,20 +57,24 @@ export async function discordApiRequest( }; try { - console.log(options); + // console.log(options); return await this.helpers.requestOAuth2!.call(this, 'discordOAuth2Api', options, oAuth2Options); + // return await this.helpers.request!.call(this, options); } catch (error) { - const errors = error.response.body.context_info.errors; - const message = error.response.body.message; - - if (errors) { - const errorMessage = errors.map((e: IDataObject) => e.message).join('|'); - throw new Error(`Discord error response [${error.statusCode}]: ${errorMessage}`); - } else if (message) { - throw new Error(`Discord error response [${error.statusCode}]: ${message}`); - } + // TODO throw error; } } + +export function setHeartbeatInterval(ws: WebSocket, data: string) { + const interval = JSON.parse(data).d.heartbeat_interval; + + const payload = JSON.stringify({ + op: 1, // opcode + d: 251, // last sequence number `s` received by client + }); + + return setInterval(() => ws.send(payload), interval); +} diff --git a/packages/nodes-base/nodes/Discord/descriptions/MessageDescription.ts b/packages/nodes-base/nodes/Discord/descriptions/MessageDescription.ts index 17d451e846..44887d067d 100644 --- a/packages/nodes-base/nodes/Discord/descriptions/MessageDescription.ts +++ b/packages/nodes-base/nodes/Discord/descriptions/MessageDescription.ts @@ -20,6 +20,10 @@ export const messageOperations = [ value: 'create', description: 'Create a message', }, + { + name: 'WS', + value: 'ws', + }, ], default: 'create', description: 'The operation to perform.', diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index b5f766eba2..5d280b2baa 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -555,6 +555,7 @@ "@types/ssh2-sftp-client": "^5.1.0", "@types/tmp": "^0.2.0", "@types/uuid": "^3.4.6", + "@types/ws": "^7.4.0", "@types/xml2js": "^0.4.3", "gulp": "^4.0.0", "jest": "^26.4.2", @@ -609,6 +610,7 @@ "tmp-promise": "^3.0.2", "uuid": "^3.4.0", "vm2": "^3.6.10", + "ws": "^7.4.3", "xlsx": "^0.16.7", "xml2js": "^0.4.22" },