feat(gateway): wip: Connect to the Discord Gateway
This commit is contained in:
parent
1428b79ea0
commit
b1bdc8cc14
8 changed files with 90 additions and 30 deletions
|
@ -37,6 +37,7 @@
|
|||
"dependencies": {
|
||||
"@sapphire/async-queue": "^1.1.4",
|
||||
"abort-controller": "^3.0.0",
|
||||
"fast-zlib": "^2.0.1",
|
||||
"form-data": "^4.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"node-fetch": "^2.6.1",
|
||||
|
@ -89,8 +90,7 @@
|
|||
},
|
||||
"optionalDependencies": {
|
||||
"bufferutil": "^4.0.3",
|
||||
"utf-8-validate": "^5.0.5",
|
||||
"zlib-sync": "^0.1.7"
|
||||
"utf-8-validate": "^5.0.5"
|
||||
},
|
||||
"lint-staged": {
|
||||
"src/**/*": [
|
||||
|
|
|
@ -10,7 +10,6 @@ import type { Client } from '../client/client';
|
|||
import type { IMakeRequestOptions, IRouteIdentifier } from '../utils/types';
|
||||
|
||||
function calculateReset(reset: number, resetAfter: number, serverDate: number): number {
|
||||
// Use direct reset time when available, server date becomes irrelevant in this case
|
||||
if (resetAfter) {
|
||||
return Date.now() + Number(resetAfter) * 1000;
|
||||
}
|
||||
|
@ -21,7 +20,6 @@ function getAPIOffset(serverDate: number): number {
|
|||
return new Date(serverDate).getTime() - Date.now();
|
||||
}
|
||||
|
||||
|
||||
export class ApiHandler {
|
||||
public client: Client;
|
||||
public hash: string;
|
||||
|
@ -35,7 +33,7 @@ export class ApiHandler {
|
|||
|
||||
private _token: string;
|
||||
|
||||
public constructor(client: Client, manager: ApiManager, token: string, hash: string, majorParameter: string) {
|
||||
public constructor(client: Client, token: string, manager: ApiManager, hash: string, majorParameter: string) {
|
||||
this.client = client;
|
||||
this._token = token;
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ export class ApiManager {
|
|||
let queue = this.queues.get(`${hash}:${routeId.majorParameter}`);
|
||||
|
||||
if (!queue) {
|
||||
const apiHandler = new ApiHandler(this.client, this, this._token, hash, routeId.majorParameter);
|
||||
const apiHandler = new ApiHandler(this.client, this._token, this, hash, routeId.majorParameter);
|
||||
this.queues.set(apiHandler.id, apiHandler);
|
||||
|
||||
queue = this.queues.get(`${hash}:${routeId.majorParameter}`);
|
||||
|
|
|
@ -1,20 +1,30 @@
|
|||
import _ from 'lodash';
|
||||
import EventEmitter from 'events';
|
||||
|
||||
import { ApiHelper } from '../api/apiHelper';
|
||||
import { GatewayClient } from '../gateway/gatewayClient';
|
||||
import { defaults } from '../utils/defaults';
|
||||
|
||||
import type { DeepRequired, IClientOptions } from '../utils/types';
|
||||
|
||||
export class Client {
|
||||
export class Client extends EventEmitter {
|
||||
public api: ApiHelper;
|
||||
public options: DeepRequired<IClientOptions>;
|
||||
public readonly options: DeepRequired<IClientOptions>;
|
||||
public ws: GatewayClient;
|
||||
|
||||
private _token: string;
|
||||
|
||||
public constructor(token: string, options: IClientOptions = {}) {
|
||||
super();
|
||||
|
||||
this.options = _.merge(defaults.clientOptions, options as DeepRequired<IClientOptions>);
|
||||
this._token = token;
|
||||
|
||||
this.api = new ApiHelper(this, this._token);
|
||||
this.ws = new GatewayClient(this);
|
||||
}
|
||||
|
||||
public async login(): Promise<void> {
|
||||
await this.ws.connect();
|
||||
}
|
||||
}
|
||||
|
|
44
src/gateway/gatewayClient.ts
Normal file
44
src/gateway/gatewayClient.ts
Normal file
|
@ -0,0 +1,44 @@
|
|||
import zlib from 'fast-zlib';
|
||||
import WebSocket from 'ws';
|
||||
|
||||
import type { Client } from '../client/client';
|
||||
import type { IGatewayMessage } from '../utils/types';
|
||||
|
||||
export class GatewayClient {
|
||||
public client: Client;
|
||||
public connection: WebSocket | null;
|
||||
public deflate: zlib.Deflate;
|
||||
public inflate: zlib.Inflate;
|
||||
|
||||
private _sequence: number;
|
||||
|
||||
public constructor(client: Client) {
|
||||
this.client = client;
|
||||
|
||||
this.connection = null;
|
||||
this.deflate = new zlib.Deflate();
|
||||
this.inflate = new zlib.Inflate();
|
||||
|
||||
this._sequence = 0;
|
||||
}
|
||||
|
||||
public async close(): Promise<void> {
|
||||
if (!this.connection) throw new Error('You are not connected to the Discord WebSocket Gateway!');
|
||||
|
||||
this.connection.close(1000);
|
||||
}
|
||||
|
||||
public async connect(): Promise<void> {
|
||||
if (this.connection) throw new Error('You are already connected to the Discord WebSocket Gateway!');
|
||||
|
||||
this.connection = new WebSocket(
|
||||
`${this.client.options.ws.url}/?v=${this.client.options.ws.version}${this.client.options.ws.compression ? '&compress=zlib-stream' : ''}&encoding=${this.client.options.ws.encoding}`,
|
||||
);
|
||||
|
||||
this.connection.on('message', async (msg: Buffer | string) => {
|
||||
let parsedMessage: IGatewayMessage<null>;
|
||||
|
||||
if (this.client.options.ws.compression) parsedMessage = this.inflate.process(msg);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -10,5 +10,11 @@ export const defaults: IDefaultOptions = {
|
|||
url: 'https://discord.com/api',
|
||||
version: 9,
|
||||
},
|
||||
ws: {
|
||||
compression: true,
|
||||
encoding: 'json',
|
||||
url: 'wss://gateway.discord.gg',
|
||||
version: 9,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -10,6 +10,7 @@ export interface IApiClientOptions {
|
|||
|
||||
export interface IClientOptions {
|
||||
api?: IApiClientOptions;
|
||||
ws?: IWebSocketClientOptions;
|
||||
}
|
||||
|
||||
export interface IDefaultOptions {
|
||||
|
@ -55,6 +56,13 @@ export interface IRouteIdentifier {
|
|||
route: string;
|
||||
}
|
||||
|
||||
export interface IWebSocketClientOptions {
|
||||
compression?: boolean;
|
||||
encoding?: 'json';
|
||||
url?: string;
|
||||
version?: number;
|
||||
}
|
||||
|
||||
// Api Rest Request Interfaces
|
||||
// TODO: Add message components
|
||||
export interface IApiCreateMessage {
|
||||
|
@ -76,6 +84,14 @@ export interface IApiCreateMessage {
|
|||
tts?: boolean;
|
||||
}
|
||||
|
||||
// WebSocket Gateway Message Interfaces
|
||||
export interface IGatewayMessage<T> {
|
||||
d?: T;
|
||||
op: number;
|
||||
s?: number;
|
||||
t?: string;
|
||||
}
|
||||
|
||||
// Enums
|
||||
|
||||
// Type Aliases
|
||||
|
|
30
yarn.lock
30
yarn.lock
|
@ -569,6 +569,7 @@ __metadata:
|
|||
eslint-plugin-header: ^3.1.1
|
||||
eslint-plugin-import: ^2.23.4
|
||||
eslint-plugin-unicorn: ^34.0.1
|
||||
fast-zlib: ^2.0.1
|
||||
form-data: ^4.0.0
|
||||
husky: ^7.0.0
|
||||
inquirer: ^8.1.1
|
||||
|
@ -587,14 +588,11 @@ __metadata:
|
|||
typescript: ^4.3.5
|
||||
utf-8-validate: ^5.0.5
|
||||
ws: ^7.5.2
|
||||
zlib-sync: ^0.1.7
|
||||
dependenciesMeta:
|
||||
bufferutil:
|
||||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
zlib-sync:
|
||||
optional: true
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
|
@ -3503,6 +3501,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fast-zlib@npm:^2.0.1":
|
||||
version: 2.0.1
|
||||
resolution: "fast-zlib@npm:2.0.1"
|
||||
checksum: 5019499b8aea5dea805117944cdcd4f7bf06b8d922690d4dca6384b5d6c0cc73b6e3c1488ab5c0b8add486617a2b6b2a0230f719be84362943a348c55f864a5a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fastq@npm:^1.6.0":
|
||||
version: 1.11.1
|
||||
resolution: "fastq@npm:1.11.1"
|
||||
|
@ -5907,15 +5912,6 @@ fsevents@~2.3.2:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"nan@npm:^2.14.0":
|
||||
version: 2.14.2
|
||||
resolution: "nan@npm:2.14.2"
|
||||
dependencies:
|
||||
node-gyp: latest
|
||||
checksum: 7a269139b66a7d37470effb7fb36a8de8cc3b5ffba6e40bb8e0545307911fe5ebf94797ec62f655ecde79c237d169899f8bd28256c66a32cbc8284faaf94c3f4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"nanoid@npm:3.1.23":
|
||||
version: 3.1.23
|
||||
resolution: "nanoid@npm:3.1.23"
|
||||
|
@ -8802,13 +8798,3 @@ typescript@^4.3.5:
|
|||
checksum: f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"zlib-sync@npm:^0.1.7":
|
||||
version: 0.1.7
|
||||
resolution: "zlib-sync@npm:0.1.7"
|
||||
dependencies:
|
||||
nan: ^2.14.0
|
||||
node-gyp: latest
|
||||
checksum: 8f6ef7bf5726b41fefffa4509f5679872b425ef47227a59d8c787b32518db6220961262f78b0f6eb1dcd9b52cd71bc8213d4f061b8b56a9b7e82c345a548e6f4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
|
Reference in a new issue