pinusmod-kcp
Version:
kcp 的 connector (基于 node-kcp-x)
156 lines (132 loc) • 4.93 kB
text/typescript
import { pinus } from 'pinusmod';
import { Package } from 'pinusmod-protocol';
import { ISocket } from '../interfaces/ISocket';
let CODE_OK = 200;
let CODE_USE_ERROR = 500;
let CODE_OLD_CLIENT = 501;
export type HanshakeFunction = (msg: any, cb: (err?: Error, resp?: any) => void, socket: ISocket) => void;
export type CheckClientFunction = (type: string, version: string) => boolean;
export interface HandshakeCommandOptions {
handshake?: HanshakeFunction;
heartbeat?: number;
checkClient?: CheckClientFunction;
useDict?: boolean;
useProtobuf?: boolean;
useCrypto?: boolean;
}
/**
* Process the handshake request.
*
* @param {Object} opts option parameters
* opts.handshake(msg, cb(err, resp)) handshake callback. msg is the handshake message from client.
* opts.hearbeat heartbeat interval (level?)
* opts.version required client level
*/
export class HandshakeCommand {
userHandshake: HanshakeFunction;
heartbeatSec: number;
heartbeat: number;
checkClient: CheckClientFunction;
useDict: boolean;
useProtobuf: boolean;
useCrypto: boolean;
constructor(opts: HandshakeCommandOptions) {
opts = opts || {};
this.userHandshake = opts.handshake;
if (opts.heartbeat) {
this.heartbeatSec = opts.heartbeat;
this.heartbeat = opts.heartbeat * 1000;
}
this.checkClient = opts.checkClient;
this.useDict = opts.useDict;
this.useProtobuf = opts.useProtobuf;
this.useCrypto = opts.useCrypto;
}
handle(socket: ISocket, msg: any) {
if (!msg.sys) {
processError(socket, CODE_USE_ERROR);
return;
}
if (typeof this.checkClient === 'function') {
if (!msg || !msg.sys || !this.checkClient(msg.sys.type, msg.sys.version)) {
processError(socket, CODE_OLD_CLIENT);
return;
}
}
let opts: any = {
heartbeat: setupHeartbeat(this)
};
if (this.useDict) {
let dictVersion = pinus.app.components.__dictionary__.getVersion();
if (!msg.sys.dictVersion || msg.sys.dictVersion !== dictVersion) {
// may be deprecated in future
opts.dict = pinus.app.components.__dictionary__.getDict();
// 用不到这个。
// opts.routeToCode = pinus.app.components.__dictionary__.getDict();
// opts.codeToRoute = pinus.app.components.__dictionary__.getAbbrs();
opts.dictVersion = dictVersion;
}
opts.useDict = true;
}
if (this.useProtobuf) {
let protoVersion = pinus.app.components.__protobuf__.getVersion();
if (!msg.sys.protoVersion || msg.sys.protoVersion !== protoVersion) {
opts.protos = pinus.app.components.__protobuf__.getProtos();
}
opts.useProto = true;
}
if (!!pinus.app.components.__decodeIO__protobuf__) {
if (!!this.useProtobuf) {
throw new Error('protobuf can not be both used in the same project.');
}
let component = pinus.app.components.__decodeIO__protobuf__ as any;
let version = component.getVersion();
if (!msg.sys.protoVersion || msg.sys.protoVersion < version) {
opts.protos = component.getProtos();
}
opts.useProto = true;
}
if (this.useCrypto) {
pinus.app.components.__connector__.setPubKey(socket.id, msg.sys.rsa);
}
if (typeof this.userHandshake === 'function') {
this.userHandshake(msg, function (err, resp) {
if (err) {
process.nextTick(function () {
processError(socket, CODE_USE_ERROR);
});
return;
}
process.nextTick(function () {
response(socket, opts, resp);
});
}, socket);
return;
}
process.nextTick(function () {
response(socket, opts);
});
}
}
let setupHeartbeat = function (self: HandshakeCommand) {
return self.heartbeatSec;
};
let response = function (socket: ISocket, sys: any, resp?: any) {
let res: any = {
code: CODE_OK,
sys: sys
};
if (resp) {
res.user = resp;
}
socket.handshakeResponse(Package.encode(Package.TYPE_HANDSHAKE, Buffer.from(JSON.stringify(res))));
};
let processError = function (socket: ISocket, code: number) {
let res = {
code: code
};
socket.sendForce(Package.encode(Package.TYPE_HANDSHAKE, Buffer.from(JSON.stringify(res))));
process.nextTick(function () {
socket.disconnect();
});
};