Add internal rate limiter for acknowledgements.

Fix Ping format.
Internally calculate ping.
This commit is contained in:
Paul
2021-09-14 17:09:50 +01:00
parent bae63b82d1
commit 358765b2bf
8 changed files with 46 additions and 13 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "revolt.js",
"version": "5.1.0-alpha.2",
"version": "5.1.0-alpha.3",
"main": "dist/index.js",
"repository": "https://gitlab.insrt.uk/revolt/revolt.js",
"author": "Paul Makles <insrt.uk>",
+3 -1
View File
@@ -30,6 +30,8 @@ export interface ClientOptions {
heartbeat: number
autoReconnect: boolean
ackRateLimiter: boolean
}
export declare interface Client {
@@ -63,9 +65,9 @@ export class Client extends EventEmitter {
session?: Session | string;
user?: User;
options: ClientOptions;
websocket: WebSocketClient;
private Axios: AxiosInstance;
private options: ClientOptions;
configuration?: RevoltConfiguration;
users: Users;
+1
View File
@@ -497,6 +497,7 @@ type Routes =
banner?: string,
categories?: Category[],
system_messages?: SystemMessageChannels,
nsfw?: boolean,
remove?: RemoveServerField
},
response: undefined
+3 -1
View File
@@ -5,5 +5,7 @@ export const defaultConfig = {
autoReconnect: true,
heartbeat: 30,
debug: false,
cache: false
cache: false,
ackRateLimiter: true,
};
+22 -2
View File
@@ -414,13 +414,33 @@ export class Channel {
return await this.client.req('POST', `/channels/${this._id}/join_call` as '/channels/id/join_call');
}
private ackTimeout?: number;
private ackLimit?: number;
/**
* Mark a channel as read
* @param message Last read message or its ID
*/
async ack(message?: Message | string) {
const id = (typeof message === 'string' ? message : message?._id) ?? ulid();
return await this.client.req('PUT', `/channels/${this._id}/ack/${id}` as '/channels/id/ack/id');
const id = (typeof message === 'string' ? message : message?._id) ?? this.last_message_id ?? ulid();
const performAck = () => {
delete this.ackLimit;
this.client.req('PUT', `/channels/${this._id}/ack/${id}` as '/channels/id/ack/id');
}
if (!this.client.options.ackRateLimiter) return performAck();
clearTimeout(this.ackTimeout);
if (this.ackLimit && + new Date() > this.ackLimit) {
performAck();
}
// We need to use setTimeout here for both Node.js and browser.
this.ackTimeout = setTimeout(performAck, 5000) as unknown as number;
if (!this.ackLimit) {
this.ackLimit = + new Date() + 15e3;
}
}
/**
+2 -2
View File
@@ -40,7 +40,7 @@ function user() {
}
});
// client.login({ email: process.env.EMAIL as string, password: process.env.PASSWORD as string })
client.login({ email: process.env.EMAIL as string, password: process.env.PASSWORD as string })
}
function bot() {
@@ -58,7 +58,7 @@ function bot() {
}
});
client.loginBot(process.env.BOT_TOKEN as string)
// client.loginBot(process.env.BOT_TOKEN as string)
}
user();
+10 -2
View File
@@ -16,6 +16,8 @@ export class WebSocketClient {
connected: boolean;
ready: boolean;
ping?: number;
constructor(client: Client) {
this.client = client;
@@ -136,8 +138,9 @@ export class WebSocketClient {
resolve();
if (this.client.heartbeat > 0) {
this.send({ type: 'Ping', data: + new Date() });
this.heartbeat = setInterval(
() => this.send({ type: 'Ping', time: + new Date() }),
() => this.send({ type: 'Ping', data: + new Date() }),
this.client.heartbeat * 1e3
) as any;
}
@@ -351,7 +354,12 @@ export class WebSocketClient {
case "ChannelAck": break;
default: console.warn(`Warning: Unhandled packet! ${packet.type}`);
case "Pong": {
this.ping = + new Date() - packet.data;
break;
}
default: this.client.debug && console.warn(`Warning: Unhandled packet! ${packet.type}`);
}
}
+4 -4
View File
@@ -11,8 +11,8 @@ type WebSocketError = {
};
export type ServerboundNotification = (
{ type: 'Ping', time: number } |
{ type: 'Pong', time: number } |
{ type: 'Ping', data: number } |
{ type: 'Pong', data: number } |
({ type: 'Authenticate' } & Session) |
({ type: 'Authenticate', token: string }) |
({ type: 'BeginTyping', channel: string }) |
@@ -28,8 +28,8 @@ export type ReadyPacket = {
}
export type ClientboundNotification = (
{ type: 'Ping', time: number } |
{ type: 'Pong', time: number } |
{ type: 'Ping', data: number } |
{ type: 'Pong', data: number } |
({ type: 'Error' } & WebSocketError) |
{ type: 'Authenticated' } |
ReadyPacket |