foundkey-js: fix build errors
Some checks failed
ci/woodpecker/pr/lint-foundkey-js Pipeline was successful
ci/woodpecker/pr/lint-backend Pipeline was successful
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/lint-client Pipeline failed
ci/woodpecker/pr/test Pipeline failed

The use of `"moduleResolution": "Node16"` is to make TS use the same
module resolution as Node does when using ESM modules.

`reconnecting-websocket`'s TS definition files were copied over but
wrapped in a `declare module` block to make TS properly accept
using the default import directly without using `.default`.

I also decided to look into `autobind-decorator`'s source code and
figured that I could use the `boundMethod` annotation directly instead
of using the `autobind` default export.
This commit is contained in:
Norm 2022-09-09 00:04:26 -04:00
parent 9a34e0b2b1
commit dde6f5eb55
Signed by: norm
GPG key ID: 7123E30E441E80DE
3 changed files with 170 additions and 26 deletions

View file

@ -0,0 +1,144 @@
/*!
* Reconnecting WebSocket
* by Pedro Ladaria <pedro.ladaria@gmail.com>
* https://github.com/pladaria/reconnecting-websocket
* License MIT
*/
declare module 'reconnecting-websocket' {
import * as Events from './events';
export declare type Event = Events.Event;
export declare type ErrorEvent = Events.ErrorEvent;
export declare type CloseEvent = Events.CloseEvent;
export declare type Options = {
WebSocket?: any;
maxReconnectionDelay?: number;
minReconnectionDelay?: number;
reconnectionDelayGrowFactor?: number;
minUptime?: number;
connectionTimeout?: number;
maxRetries?: number;
maxEnqueuedMessages?: number;
startClosed?: boolean;
debug?: boolean;
};
export declare type UrlProvider = string | (() => string) | (() => Promise<string>);
export declare type Message = string | ArrayBuffer | Blob | ArrayBufferView;
export declare type ListenersMap = {
error: Array<Events.WebSocketEventListenerMap['error']>;
message: Array<Events.WebSocketEventListenerMap['message']>;
open: Array<Events.WebSocketEventListenerMap['open']>;
close: Array<Events.WebSocketEventListenerMap['close']>;
};
export default class ReconnectingWebSocket {
private _ws?;
private _listeners;
private _retryCount;
private _uptimeTimeout;
private _connectTimeout;
private _shouldReconnect;
private _connectLock;
private _binaryType;
private _closeCalled;
private _messageQueue;
private readonly _url;
private readonly _protocols?;
private readonly _options;
constructor(url: UrlProvider, protocols?: string | string[], options?: Options);
static readonly CONNECTING: number;
static readonly OPEN: number;
static readonly CLOSING: number;
static readonly CLOSED: number;
readonly CONNECTING: number;
readonly OPEN: number;
readonly CLOSING: number;
readonly CLOSED: number;
binaryType: BinaryType;
/**
* Returns the number or connection retries
*/
readonly retryCount: number;
/**
* The number of bytes of data that have been queued using calls to send() but not yet
* transmitted to the network. This value resets to zero once all queued data has been sent.
* This value does not reset to zero when the connection is closed; if you keep calling send(),
* this will continue to climb. Read only
*/
readonly bufferedAmount: number;
/**
* The extensions selected by the server. This is currently only the empty string or a list of
* extensions as negotiated by the connection
*/
readonly extensions: string;
/**
* A string indicating the name of the sub-protocol the server selected;
* this will be one of the strings specified in the protocols parameter when creating the
* WebSocket object
*/
readonly protocol: string;
/**
* The current state of the connection; this is one of the Ready state constants
*/
readonly readyState: number;
/**
* The URL as resolved by the constructor
*/
readonly url: string;
/**
* An event listener to be called when the WebSocket connection's readyState changes to CLOSED
*/
onclose: ((event: Events.CloseEvent) => void) | null;
/**
* An event listener to be called when an error occurs
*/
onerror: ((event: Events.ErrorEvent) => void) | null;
/**
* An event listener to be called when a message is received from the server
*/
onmessage: ((event: MessageEvent) => void) | null;
/**
* An event listener to be called when the WebSocket connection's readyState changes to OPEN;
* this indicates that the connection is ready to send and receive data
*/
onopen: ((event: Event) => void) | null;
/**
* Closes the WebSocket connection or connection attempt, if any. If the connection is already
* CLOSED, this method does nothing
*/
close(code?: number, reason?: string): void;
/**
* Closes the WebSocket connection or connection attempt and connects again.
* Resets retry counter;
*/
reconnect(code?: number, reason?: string): void;
/**
* Enqueue specified data to be transmitted to the server over the WebSocket connection
*/
send(data: Message): void;
/**
* Register an event handler of a specific event type
*/
addEventListener<T extends keyof Events.WebSocketEventListenerMap>(type: T, listener: Events.WebSocketEventListenerMap[T]): void;
dispatchEvent(event: Event): boolean;
/**
* Removes an event listener
*/
removeEventListener<T extends keyof Events.WebSocketEventListenerMap>(type: T, listener: Events.WebSocketEventListenerMap[T]): void;
private _debug;
private _getNextDelay;
private _wait;
private _getNextUrl;
private _connect;
private _handleTimeout;
private _disconnect;
private _acceptOpen;
private _callEventListener;
private _handleOpen;
private _handleMessage;
private _handleError;
private _handleClose;
private _removeListeners;
private _addListeners;
private _clearTimeouts;
}
}

View file

@ -1,6 +1,6 @@
import autobind from 'autobind-decorator'; import { boundMethod } from 'autobind-decorator';
import EventEmitter from 'eventemitter3'; import EventEmitter from 'eventemitter3';
import ReconnectingWebsocket from 'reconnecting-websocket'; import ReconnectingWebSocket from 'reconnecting-websocket';
import { BroadcastEvents, Channels } from './streaming.types.js'; import { BroadcastEvents, Channels } from './streaming.types.js';
export function urlQuery(obj: Record<string, string | number | boolean | undefined>): string { export function urlQuery(obj: Record<string, string | number | boolean | undefined>): string {
@ -25,7 +25,7 @@ type StreamEvents = {
* Misskey stream connection * Misskey stream connection
*/ */
export default class Stream extends EventEmitter<StreamEvents> { export default class Stream extends EventEmitter<StreamEvents> {
private stream: ReconnectingWebsocket; private stream: ReconnectingWebSocket;
public state: 'initializing' | 'reconnecting' | 'connected' = 'initializing'; public state: 'initializing' | 'reconnecting' | 'connected' = 'initializing';
private sharedConnectionPools: Pool[] = []; private sharedConnectionPools: Pool[] = [];
private sharedConnections: SharedConnection[] = []; private sharedConnections: SharedConnection[] = [];
@ -47,7 +47,7 @@ export default class Stream extends EventEmitter<StreamEvents> {
const wsOrigin = origin.replace('http://', 'ws://').replace('https://', 'wss://'); const wsOrigin = origin.replace('http://', 'ws://').replace('https://', 'wss://');
this.stream = new ReconnectingWebsocket(`${wsOrigin}/streaming?${query}`, '', { this.stream = new ReconnectingWebSocket(`${wsOrigin}/streaming?${query}`, '', {
minReconnectionDelay: 1, // https://github.com/pladaria/reconnecting-websocket/issues/91 minReconnectionDelay: 1, // https://github.com/pladaria/reconnecting-websocket/issues/91
WebSocket: options.WebSocket, WebSocket: options.WebSocket,
}); });
@ -56,12 +56,12 @@ export default class Stream extends EventEmitter<StreamEvents> {
this.stream.addEventListener('message', this.onMessage); this.stream.addEventListener('message', this.onMessage);
} }
@autobind @boundMethod
private genId(): string { private genId(): string {
return (++this.idCounter).toString(); return (++this.idCounter).toString();
} }
@autobind @boundMethod
public useChannel<C extends keyof Channels>(channel: C, params?: Channels[C]['params'], name?: string): Connection<Channels[C]> { public useChannel<C extends keyof Channels>(channel: C, params?: Channels[C]['params'], name?: string): Connection<Channels[C]> {
if (params) { if (params) {
return this.connectToChannel(channel, params); return this.connectToChannel(channel, params);
@ -70,7 +70,7 @@ export default class Stream extends EventEmitter<StreamEvents> {
} }
} }
@autobind @boundMethod
private useSharedConnection<C extends keyof Channels>(channel: C, name?: string): SharedConnection<Channels[C]> { private useSharedConnection<C extends keyof Channels>(channel: C, name?: string): SharedConnection<Channels[C]> {
let pool = this.sharedConnectionPools.find(p => p.channel === channel); let pool = this.sharedConnectionPools.find(p => p.channel === channel);
@ -84,24 +84,24 @@ export default class Stream extends EventEmitter<StreamEvents> {
return connection; return connection;
} }
@autobind @boundMethod
public removeSharedConnection(connection: SharedConnection): void { public removeSharedConnection(connection: SharedConnection): void {
this.sharedConnections = this.sharedConnections.filter(c => c !== connection); this.sharedConnections = this.sharedConnections.filter(c => c !== connection);
} }
@autobind @boundMethod
public removeSharedConnectionPool(pool: Pool): void { public removeSharedConnectionPool(pool: Pool): void {
this.sharedConnectionPools = this.sharedConnectionPools.filter(p => p !== pool); this.sharedConnectionPools = this.sharedConnectionPools.filter(p => p !== pool);
} }
@autobind @boundMethod
private connectToChannel<C extends keyof Channels>(channel: C, params: Channels[C]['params']): NonSharedConnection<Channels[C]> { private connectToChannel<C extends keyof Channels>(channel: C, params: Channels[C]['params']): NonSharedConnection<Channels[C]> {
const connection = new NonSharedConnection(this, channel, this.genId(), params); const connection = new NonSharedConnection(this, channel, this.genId(), params);
this.nonSharedConnections.push(connection); this.nonSharedConnections.push(connection);
return connection; return connection;
} }
@autobind @boundMethod
public disconnectToChannel(connection: NonSharedConnection): void { public disconnectToChannel(connection: NonSharedConnection): void {
this.nonSharedConnections = this.nonSharedConnections.filter(c => c !== connection); this.nonSharedConnections = this.nonSharedConnections.filter(c => c !== connection);
} }
@ -109,7 +109,7 @@ export default class Stream extends EventEmitter<StreamEvents> {
/** /**
* Callback of when open connection * Callback of when open connection
*/ */
@autobind @boundMethod
private onOpen(): void { private onOpen(): void {
const isReconnect = this.state === 'reconnecting'; const isReconnect = this.state === 'reconnecting';
@ -126,7 +126,7 @@ export default class Stream extends EventEmitter<StreamEvents> {
/** /**
* Callback of when close connection * Callback of when close connection
*/ */
@autobind @boundMethod
private onClose(): void { private onClose(): void {
if (this.state === 'connected') { if (this.state === 'connected') {
this.state = 'reconnecting'; this.state = 'reconnecting';
@ -137,7 +137,7 @@ export default class Stream extends EventEmitter<StreamEvents> {
/** /**
* Callback of when received a message from connection * Callback of when received a message from connection
*/ */
@autobind @boundMethod
private onMessage(message: { data: string; }): void { private onMessage(message: { data: string; }): void {
const { type, body } = JSON.parse(message.data); const { type, body } = JSON.parse(message.data);
@ -167,7 +167,7 @@ export default class Stream extends EventEmitter<StreamEvents> {
/** /**
* Send a message to connection * Send a message to connection
*/ */
@autobind @boundMethod
public send(typeOrPayload: any, payload?: any): void { public send(typeOrPayload: any, payload?: any): void {
const data = payload === undefined ? typeOrPayload : { const data = payload === undefined ? typeOrPayload : {
type: typeOrPayload, type: typeOrPayload,
@ -180,7 +180,7 @@ export default class Stream extends EventEmitter<StreamEvents> {
/** /**
* Close this connection * Close this connection
*/ */
@autobind @boundMethod
public close(): void { public close(): void {
this.stream.close(); this.stream.close();
} }
@ -204,12 +204,12 @@ class Pool {
this.stream.on('_disconnected_', this.onStreamDisconnected); this.stream.on('_disconnected_', this.onStreamDisconnected);
} }
@autobind @boundMethod
private onStreamDisconnected(): void { private onStreamDisconnected(): void {
this.isConnected = false; this.isConnected = false;
} }
@autobind @boundMethod
public inc(): void { public inc(): void {
if (this.users === 0 && !this.isConnected) { if (this.users === 0 && !this.isConnected) {
this.connect(); this.connect();
@ -224,7 +224,7 @@ class Pool {
} }
} }
@autobind @boundMethod
public dec(): void { public dec(): void {
this.users--; this.users--;
@ -238,7 +238,7 @@ class Pool {
} }
} }
@autobind @boundMethod
public connect(): void { public connect(): void {
if (this.isConnected) return; if (this.isConnected) return;
this.isConnected = true; this.isConnected = true;
@ -248,7 +248,7 @@ class Pool {
}); });
} }
@autobind @boundMethod
private disconnect(): void { private disconnect(): void {
this.stream.off('_disconnected_', this.onStreamDisconnected); this.stream.off('_disconnected_', this.onStreamDisconnected);
this.stream.send('disconnect', { id: this.id }); this.stream.send('disconnect', { id: this.id });
@ -273,7 +273,7 @@ export abstract class Connection<Channel extends AnyOf<Channels> = any> extends
this.name = name; this.name = name;
} }
@autobind @boundMethod
public send<T extends keyof Channel['receives']>(type: T, body: Channel['receives'][T]): void { public send<T extends keyof Channel['receives']>(type: T, body: Channel['receives'][T]): void {
this.stream.send('ch', { this.stream.send('ch', {
id: this.id, id: this.id,
@ -301,7 +301,7 @@ class SharedConnection<Channel extends AnyOf<Channels> = any> extends Connection
this.pool.inc(); this.pool.inc();
} }
@autobind @boundMethod
public dispose(): void { public dispose(): void {
this.pool.dec(); this.pool.dec();
this.removeAllListeners(); this.removeAllListeners();
@ -322,7 +322,7 @@ class NonSharedConnection<Channel extends AnyOf<Channels> = any> extends Connect
this.connect(); this.connect();
} }
@autobind @boundMethod
public connect(): void { public connect(): void {
this.stream.send('connect', { this.stream.send('connect', {
channel: this.channel, channel: this.channel,
@ -331,7 +331,7 @@ class NonSharedConnection<Channel extends AnyOf<Channels> = any> extends Connect
}); });
} }
@autobind @boundMethod
public dispose(): void { public dispose(): void {
this.removeAllListeners(); this.removeAllListeners();
this.stream.send('disconnect', { id: this.id }); this.stream.send('disconnect', { id: this.id });

View file

@ -15,7 +15,7 @@
"experimentalDecorators": true, "experimentalDecorators": true,
"noImplicitReturns": true, "noImplicitReturns": true,
"esModuleInterop": true, "esModuleInterop": true,
"moduleResolution": "node" "moduleResolution": "Node16"
}, },
"include": [ "include": [
"src/**/*" "src/**/*"