mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2024-11-21 09:36:35 +00:00
feat: handle clientSideHandshake
This commit is contained in:
parent
e5518b7284
commit
ca9614f8e3
@ -3,7 +3,7 @@ import { NapCatLaanaAdapter } from '..';
|
|||||||
import { RawData, WebSocket, WebSocketServer } from 'ws';
|
import { RawData, WebSocket, WebSocketServer } from 'ws';
|
||||||
import { Mutex } from 'async-mutex';
|
import { Mutex } from 'async-mutex';
|
||||||
import { NapCatCore } from '@/core';
|
import { NapCatCore } from '@/core';
|
||||||
import { LaanaDataWrapper, LaanaEventWrapper, LaanaMessage } from '@laana-proto/def';
|
import { LaanaDataWrapper, LaanaEventWrapper, LaanaMessage, LaanaServerSideHandshake_Result } from '@laana-proto/def';
|
||||||
|
|
||||||
export class LaanaWsServerAdapter implements ILaanaNetworkAdapter {
|
export class LaanaWsServerAdapter implements ILaanaNetworkAdapter {
|
||||||
wsServer: WebSocketServer;
|
wsServer: WebSocketServer;
|
||||||
@ -26,79 +26,47 @@ export class LaanaWsServerAdapter implements ILaanaNetworkAdapter {
|
|||||||
port: port,
|
port: port,
|
||||||
host: ip,
|
host: ip,
|
||||||
});
|
});
|
||||||
this.wsServer.on('connection', async (wsClient) => {
|
this.wsServer.on('connection', async (wsClient, request) => {
|
||||||
if (!this.isOpen) {
|
if (!this.isOpen) {
|
||||||
wsClient.close();
|
wsClient.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.core.context.logger.log(`接收到来自 ${request.socket.remoteAddress} 的连接`);
|
||||||
|
|
||||||
wsClient.on('error', (err) =>
|
wsClient.on('error', (err) =>
|
||||||
this.core.context.logger.log('连接出现错误', err.message));
|
this.core.context.logger.log('连接出现错误', err.message));
|
||||||
|
|
||||||
wsClient.on('message', (message) => {
|
wsClient.once('message', (message) => {
|
||||||
let binaryData: Uint8Array;
|
const data = this.handleRawData(message);
|
||||||
if (message instanceof Buffer) {
|
if (data.data.oneofKind === 'clientSideHandshake') {
|
||||||
binaryData = message;
|
// TODO: verify protocol version
|
||||||
} else if (message instanceof ArrayBuffer) {
|
const token = data.data.clientSideHandshake.token;
|
||||||
binaryData = new Uint8Array(message);
|
if (token !== this.token) {
|
||||||
} else { // message is an array of Buffers
|
this.core.context.logger.logWarn(`与 ${request.socket.remoteAddress} 的客户端握手失败,token 不匹配`);
|
||||||
binaryData = Buffer.concat(message);
|
this.checkStateAndReply(LaanaDataWrapper.toBinary({
|
||||||
}
|
data: {
|
||||||
this.wsClientsMutex.runExclusive(async () => {
|
oneofKind: 'serverSideHandshake',
|
||||||
const data = LaanaDataWrapper.fromBinary(
|
serverSideHandshake: {
|
||||||
Uint8Array.from(binaryData),
|
serverVersion: '',
|
||||||
);
|
result: LaanaServerSideHandshake_Result.wrongToken,
|
||||||
if (data.data.oneofKind === 'actionPing') {
|
},
|
||||||
const actionName = data.data.actionPing.ping.oneofKind;
|
},
|
||||||
if (actionName === undefined) {
|
}), wsClient);
|
||||||
this.core.context.logger.logError('未知的动作名', actionName);
|
wsClient.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const actionHandler = this.laana.actions[actionName];
|
|
||||||
if (!actionHandler) {
|
|
||||||
this.core.context.logger.logError('未实现的动作名', actionName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
// eslint-disable-next-line
|
|
||||||
// @ts-ignore
|
|
||||||
const ret = await actionHandler(data.data.actionPing.ping[actionName]);
|
|
||||||
this.checkStateAndReply(LaanaDataWrapper.toBinary({
|
this.checkStateAndReply(LaanaDataWrapper.toBinary({
|
||||||
data: {
|
data: {
|
||||||
oneofKind: 'actionPong',
|
oneofKind: 'serverSideHandshake',
|
||||||
actionPong: {
|
serverSideHandshake: {
|
||||||
clientPingId: data.data.actionPing.clientPingId,
|
serverVersion: '',
|
||||||
// eslint-disable-next-line
|
result: LaanaServerSideHandshake_Result.success,
|
||||||
// @ts-ignore
|
|
||||||
pong: {
|
|
||||||
oneofKind: actionName,
|
|
||||||
[actionName]: ret,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}), wsClient);
|
}), wsClient);
|
||||||
} catch (e: any) {
|
this.addClient(wsClient);
|
||||||
this.core.context.logger.logError('处理动作时出现错误', e);
|
|
||||||
this.checkStateAndReply(LaanaDataWrapper.toBinary({
|
|
||||||
data: {
|
|
||||||
oneofKind: 'actionPong',
|
|
||||||
actionPong: {
|
|
||||||
clientPingId: data.data.actionPing.clientPingId,
|
|
||||||
pong: {
|
|
||||||
oneofKind: 'failed',
|
|
||||||
failed: {
|
|
||||||
reason: e.toString(),
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}), wsClient);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.core.context.logger.logWarn('未知的数据包类型', data.data.oneofKind);
|
|
||||||
}
|
|
||||||
}).catch((e) => this.core.context.logger.logError('处理请求时出现错误', e));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
wsClient.on('ping', () => {
|
wsClient.on('ping', () => {
|
||||||
@ -110,10 +78,6 @@ export class LaanaWsServerAdapter implements ILaanaNetworkAdapter {
|
|||||||
this.wsClients = this.wsClients.filter(client => client !== wsClient);
|
this.wsClients = this.wsClients.filter(client => client !== wsClient);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.wsClientsMutex.runExclusive(async () => {
|
|
||||||
this.wsClients.push(wsClient);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.wsServer.on('error', (err) => {
|
this.wsServer.on('error', (err) => {
|
||||||
@ -172,6 +136,78 @@ export class LaanaWsServerAdapter implements ILaanaNetworkAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private handleRawData(message: RawData) {
|
||||||
|
let binaryData: Uint8Array;
|
||||||
|
if (message instanceof Buffer) {
|
||||||
|
binaryData = message;
|
||||||
|
} else if (message instanceof ArrayBuffer) {
|
||||||
|
binaryData = new Uint8Array(message);
|
||||||
|
} else { // message is an array of Buffers
|
||||||
|
binaryData = Buffer.concat(message);
|
||||||
|
}
|
||||||
|
return LaanaDataWrapper.fromBinary(binaryData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async addClient(wsClient: WebSocket) {
|
||||||
|
wsClient.on('message', (message) => {
|
||||||
|
const data = this.handleRawData(message);
|
||||||
|
|
||||||
|
if (data.data.oneofKind === 'actionPing') {
|
||||||
|
const actionName = data.data.actionPing.ping.oneofKind;
|
||||||
|
if (actionName === undefined) {
|
||||||
|
this.core.context.logger.logError('未知的动作名', actionName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const actionHandler = this.laana.actions[actionName];
|
||||||
|
if (!actionHandler) {
|
||||||
|
this.core.context.logger.logError('未实现的动作名', actionName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
// @ts-ignore
|
||||||
|
const ret = await actionHandler(data.data.actionPing.ping[actionName]);
|
||||||
|
this.checkStateAndReply(LaanaDataWrapper.toBinary({
|
||||||
|
data: {
|
||||||
|
oneofKind: 'actionPong',
|
||||||
|
actionPong: {
|
||||||
|
clientPingId: data.data.actionPing.clientPingId,
|
||||||
|
// eslint-disable-next-line
|
||||||
|
// @ts-ignore
|
||||||
|
pong: {
|
||||||
|
oneofKind: actionName,
|
||||||
|
[actionName]: ret,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}), wsClient);
|
||||||
|
} catch (e: any) {
|
||||||
|
this.core.context.logger.logError('处理动作时出现错误', e);
|
||||||
|
this.checkStateAndReply(LaanaDataWrapper.toBinary({
|
||||||
|
data: {
|
||||||
|
oneofKind: 'actionPong',
|
||||||
|
actionPong: {
|
||||||
|
clientPingId: data.data.actionPing.clientPingId,
|
||||||
|
pong: {
|
||||||
|
oneofKind: 'failed',
|
||||||
|
failed: {
|
||||||
|
reason: e.toString(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}), wsClient);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.core.context.logger.logWarn('未知的数据包类型', data.data.oneofKind);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await this.wsClientsMutex.runExclusive(async () => {
|
||||||
|
this.wsClients.push(wsClient);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private checkStateAndReply(data: RawData, wsClient: WebSocket) {
|
private checkStateAndReply(data: RawData, wsClient: WebSocket) {
|
||||||
if (wsClient.readyState === WebSocket.OPEN) {
|
if (wsClient.readyState === WebSocket.OPEN) {
|
||||||
wsClient.send(data);
|
wsClient.send(data);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user