pinusmod-kcp
Version:
kcp 的 connector (基于 node-kcp-x)
209 lines (208 loc) • 8.64 kB
JavaScript
;
/**
* Copyright 2016 leenjewel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.coders = exports.kcpHeadDecode = exports.isKickPackage = exports.isDataPackage = exports.isHeartbeatPackage = exports.isHandshakeACKPackage = exports.isHandshakePackage = exports.messagePackage = exports.heartbeatPackage = exports.handshakeAckPackage = exports.handshakePackage = exports.initProtocol = exports.getHeartbeatTimeout = exports.getHeartbeatInterval = exports.handlePackage = exports.setupHandler = void 0;
const handler_1 = require("../common/handler");
const Kick = require("../commands/kick");
const handshake_1 = require("../commands/handshake");
const heartbeat_1 = require("../commands/heartbeat");
const pinusmod_protocol_1 = require("pinusmod-protocol");
const pinusmod_protobuf_1 = require("pinusmod-protobuf");
const RES_OK = 200;
let protobuf;
const setupHandler = function (connector, socket, opts) {
connector.handshake = connector.handshake || new handshake_1.HandshakeCommand(opts);
if (!connector.heartbeat) {
if (!opts.heartbeat) {
opts.heartbeat = opts.interval / 1000;
opts.timeout = opts.heartbeat * 2;
}
if (opts.heartbeat * 1000 < opts.interval) {
console.warn('heartbeat interval must longer than kcp interval');
opts.heartbeat = opts.interval / 1000;
}
if (opts.timeout * 1000 < 2 * opts.interval) {
console.warn('timeout must longer than kcp interval * 2');
opts.timeout = opts.heartbeat * 2;
}
connector.heartbeat = new heartbeat_1.HeartbeatCommand(Object.assign(opts, { disconnectOnTimeout: true }));
}
socket.on('handshake', connector.handshake.handle.bind(connector.handshake, socket));
socket.on('heartbeat', connector.heartbeat.handle.bind(connector.heartbeat, socket));
socket.on('heartbeatreset', connector.heartbeat.reset.bind(connector.heartbeat, socket));
socket.on('disconnect', connector.heartbeat.clear.bind(connector.heartbeat, socket.id));
socket.on('disconnect', connector.emit.bind(connector, 'disconnect', socket));
socket.on('closing', Kick.handle.bind(null, socket));
};
exports.setupHandler = setupHandler;
const handlePackage = function (socket, pkg) {
if (!pkg) {
return 1;
}
pkg = pinusmod_protocol_1.Package.decode(pkg);
if (pkg.type == 6) {
return 0;
}
if (Array.isArray(pkg)) {
let result;
for (let p in pkg) {
result = (0, handler_1.default)(socket, pkg[p]);
if (result !== 0) {
return result;
}
}
}
else {
return (0, handler_1.default)(socket, pkg);
}
};
exports.handlePackage = handlePackage;
let heartbeatInterval = 0;
const getHeartbeatInterval = function () { return heartbeatInterval; };
exports.getHeartbeatInterval = getHeartbeatInterval;
let heartbeatTimeout = 0;
const getHeartbeatTimeout = function () { return heartbeatTimeout; };
exports.getHeartbeatTimeout = getHeartbeatTimeout;
let pomeloCoderData = { dict: null, abbrs: null, protos: null };
const initProtocol = function (data) {
if (!!data) {
if (data.code !== RES_OK) {
console.warn('Handshake response code : ' + data.code);
return;
}
if (!data || !data.sys) {
console.warn('Handshake response sys is undefained');
return;
}
if (!!data.sys && !!data.sys.heartbeat) {
heartbeatInterval = data.sys.heartbeat * 1000;
heartbeatTimeout = heartbeatInterval * 2;
}
let dict = data.sys.dict;
let protos = data.sys.protos;
if (!!dict) {
pomeloCoderData.dict = dict;
pomeloCoderData.abbrs = {};
for (let route in dict) {
pomeloCoderData.abbrs[dict[route]] = route;
}
}
if (!!protos) {
pomeloCoderData.protos = {
server: protos.server || {},
client: protos.client || {}
};
if (!!pinusmod_protobuf_1.Protobuf) {
protobuf = new pinusmod_protobuf_1.Protobuf({
encoderProtos: protos.client,
decoderProtos: protos.server
});
}
}
}
};
exports.initProtocol = initProtocol;
const handshakePackage = function (userdata) {
userdata = userdata || {};
return (pinusmod_protocol_1.Package.encode(pinusmod_protocol_1.Package.TYPE_HANDSHAKE, pinusmod_protocol_1.Protocol.strencode(JSON.stringify({
sys: {
version: '1.1.1',
type: 'socket'
},
user: userdata
}))));
};
exports.handshakePackage = handshakePackage;
let pomeloHandshakeAckPkg = pinusmod_protocol_1.Package.encode(pinusmod_protocol_1.Package.TYPE_HANDSHAKE_ACK);
const handshakeAckPackage = function () {
return pomeloHandshakeAckPkg;
};
exports.handshakeAckPackage = handshakeAckPackage;
let pomeloHeartbeatPkg = pinusmod_protocol_1.Package.encode(pinusmod_protocol_1.Package.TYPE_HEARTBEAT);
const heartbeatPackage = function () {
return pomeloHeartbeatPkg;
};
exports.heartbeatPackage = heartbeatPackage;
const messagePackage = function (reqid, route, msg) {
let type = reqid ? pinusmod_protocol_1.Message.TYPE_REQUEST : pinusmod_protocol_1.Message.TYPE_NOTIFY;
let protos = !!pomeloCoderData.protos ? pomeloCoderData.protos.client : {};
if (!!protos[route]) {
msg = protobuf.encode(route, msg);
}
else {
msg = pinusmod_protocol_1.Protocol.strencode(JSON.stringify(msg));
}
let compressRoute = 0;
if (!!pomeloCoderData.dict && !!pomeloCoderData.dict[route]) {
route = pomeloCoderData.dict[route];
compressRoute = 1;
}
msg = pinusmod_protocol_1.Message.encode(reqid, type, !!compressRoute, route, msg);
return pinusmod_protocol_1.Package.encode(pinusmod_protocol_1.Package.TYPE_DATA, msg);
};
exports.messagePackage = messagePackage;
const isHandshakePackage = function (type) {
return type == pinusmod_protocol_1.Package.TYPE_HANDSHAKE;
};
exports.isHandshakePackage = isHandshakePackage;
const isHandshakeACKPackage = function (type) {
return type == pinusmod_protocol_1.Package.TYPE_HANDSHAKE_ACK;
};
exports.isHandshakeACKPackage = isHandshakeACKPackage;
const isHeartbeatPackage = function (type) {
return type == pinusmod_protocol_1.Package.TYPE_HEARTBEAT;
};
exports.isHeartbeatPackage = isHeartbeatPackage;
const isDataPackage = function (type) {
return type == pinusmod_protocol_1.Package.TYPE_DATA;
};
exports.isDataPackage = isDataPackage;
const isKickPackage = function (type) {
return type == pinusmod_protocol_1.Package.TYPE_KICK;
};
exports.isKickPackage = isKickPackage;
const kcpHeadDecode = function (bytes) {
//小端
let offset = 0;
let conv = ((bytes[offset++]) | (bytes[offset++] << 8) | (bytes[offset++] << 16) | (bytes[offset++] << 24)) >>> 0;
let cmd = bytes[offset++];
let frg = bytes[offset++];
let wnd = ((bytes[offset++]) | (bytes[offset++] << 8)) >>> 0;
let ts = ((bytes[offset++]) | (bytes[offset++] << 8) | (bytes[offset++] << 16) | (bytes[offset++] << 24)) >>> 0;
let sn = ((bytes[offset++]) | (bytes[offset++] << 8) | (bytes[offset++] << 16) | (bytes[offset++] << 24)) >>> 0;
let una = ((bytes[offset++]) | (bytes[offset++] << 8) | (bytes[offset++] << 16) | (bytes[offset++] << 24)) >>> 0;
let len = ((bytes[offset++]) | (bytes[offset++] << 8) | (bytes[offset++] << 16) | (bytes[offset++] << 24)) >>> 0;
let rs = {
conv: conv,
cmd: cmd,
frg: frg,
wnd: wnd,
ts: ts,
sn: sn,
una: una,
len: len
};
// if (bytes.length >= len + 24) {
// rs.data = Buffer.from(bytes, 24, len);
// }
return rs;
};
exports.kcpHeadDecode = kcpHeadDecode;
exports.coders = {
decodePackage: pinusmod_protocol_1.Package.decode,
decodeMessage: pinusmod_protocol_1.Message.decode,
};