@cloudpss/ubrpc
Version:
Rpc server/client build on websocket and ubjson.
60 lines (57 loc) • 2.56 kB
text/typescript
import type { WebSocket } from '@cloudpss/fetch';
import type { ConnectionID, RpcMetadata } from './types/payload.js';
import { decodePayload, deserializeError } from './utils/serialize.js';
import { VERSION } from './version.js';
const AUTH_TIMEOUT = 5000;
/** 接受认证消息 */
export async function waitAuth(
socket: WebSocket,
seq?: number,
id?: ConnectionID,
): Promise<[seq: number, id: ConnectionID, meta: RpcMetadata]> {
return new Promise((resolve, reject) => {
const isResponse = seq != null && id != null;
const timeout = setTimeout(() => {
reject(new Error(`Failed to authenticate, no ${isResponse ? 'response' : 'request'} in ${AUTH_TIMEOUT}ms`));
finalize();
}, AUTH_TIMEOUT);
const handleMessage = (ev: MessageEvent): void => {
try {
const payload = decodePayload(ev.data);
if (!payload || payload.type !== 'auth') {
if (isResponse) return reject(new Error(`Failed to authenticate, bad response from server`));
else return reject(new Error(`Failed to authenticate, bad request from client`));
}
if (payload.version !== VERSION) {
return reject(
new Error(
`Failed to authenticate, version not match, expected ${VERSION}, got ${payload.version}`,
),
);
}
if (isResponse) {
if (payload.seq !== seq) {
return reject(new Error(`Failed to authenticate, bad response seq from server`));
}
if (payload.id !== id) {
return reject(new Error(`Failed to authenticate, bad response id from server`));
}
}
if (payload.error) {
return reject(deserializeError(payload.error));
}
const metadata = typeof payload.metadata != 'object' ? {} : (payload.metadata ?? {});
resolve([payload.seq, payload.id, metadata]);
} catch (ex) {
reject(ex as Error);
} finally {
finalize();
}
};
const finalize = (): void => {
clearTimeout(timeout);
socket.removeEventListener('message', handleMessage);
};
socket.addEventListener('message', handleMessage, { once: true });
});
}