UNPKG

pinusmod-kcp

Version:

kcp 的 connector (基于 node-kcp-x)

209 lines (208 loc) 8.64 kB
"use strict"; /** * 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, };