import { w3cwebsocket } from 'websocket';
import { IWebSocketClient } from './types';
import { randomUUID } from 'crypto';
import { EventEmitter } from 'stream';
import { pack } from '@/utils/transfer';
import debug from 'debug';
import * as CryptoJS from 'crypto-js';
import { exit } from 'process';
const dMsg = debug('client');
interface EventData<T = any> {
requestToken?: string;
eventType: string;
result: T;
}
type Fn = (...args: any[]) => any;
export class WebSocketClient extends w3cwebsocket implements IWebSocketClient {
public evCount = new Map<string, number>();
public evPool: EventEmitter;
public algo: 'aes' | 'hmac';
public secret: string = '';
public timeoutMilli: number = 3000;
public hstSize: number = 30;
constructor(url: string, algo: 'aes' | 'hmac') {
super(url);
[Link] = new EventEmitter();
[Link] = algo;
[Link] = () => {
dMsg('CLIENT CONNECTED!');
[Link]([Link]);
};
[Link] = () => {
dMsg('BYE BYE');
exit(0);
};
[Link]();
}
dispatch(eventType: string, payload?: any): void {
[Link](eventType, payload);
}
on(eventType: string, listener: Fn): number {
let currentCount = [Link](eventType) ?? 0;
[Link](eventType, listener);
[Link](eventType, ++currentCount);
return currentCount;
}
once(eventType: string, listener: Fn): number {
let currentCount = [Link](eventType) ?? 0;
[Link](eventType, (...args: any[]) => {
listener(...args);
const count = [Link](eventType) ?? 0;
if (count) [Link](eventType, count - 1);
});
[Link](eventType, ++currentCount);
return currentCount;
}
off(eventType: string): boolean {
const containEvent = [Link]().includes(eventType);
[Link](eventType);
return containEvent;
}
async ready() {
return new Promise<string>((resolve) => {
if ([Link] !== '') return resolve([Link]);
[Link] = ({ data }) => resolve([Link]());
});
}
async initial() {
[Link]().then((secret) => {
[Link] = secret;
[Link] = ({ data }) => {
dMsg("Receive Raw'%s'", data);
try {
const { requestToken = '', eventType, result } =
[Link]([Link]()) as EventData;
dMsg('Resolve: %O', {
requestToken,
eventType,
result,
});
if (requestToken !== '') {
[Link](requestToken, result);
} else {
[Link](eventType, result);
}
} catch (e) {
dMsg('ERROR_REASON: ', (e as Error).message);
}
};
});
}
async sendout(payload: any, requestToken: string = '$NONE') {
await [Link]();
const signature =
[Link] === 'hmac'
? CryptoJS.HmacSHA1(requestToken, [Link]).toString()
: [Link](requestToken, [Link]).toString();
[Link](pack({ requestToken, signature, payload }));
}
async request<T = any>(eventType: string, params?: any): Promise<T> {
const requestToken = `request::${randomUUID()}`;
[Link]({ eventType, params }, requestToken);
return new Promise((resolve, failed) => {
const timer = setTimeout(() => {
[Link](requestToken);
resolve('TIMEOUT' as any);
}, [Link]);
[Link](requestToken, (data) => {
clearTimeout(timer);
resolve(data);
});
});
}
history() {
return [];
}
}