pinusmod-kcp
Version:
kcp 的 connector (基于 node-kcp-x)
113 lines (99 loc) • 3.63 kB
text/typescript
/**
* 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.
*/
import * as dgram from 'dgram';
import { EventEmitter } from 'events';
import { KcpSocket } from './kcpsocket';
import * as pinuscoder from './pinuscoder';
import { IConnector, DictionaryComponent, ProtobufComponent, IComponent, pinus } from 'pinusmod';
import * as coder from '../common/coder';
let curId = 1;
export class Connector extends EventEmitter {
opts: any;
host: string;
port: number;
useDict: boolean;
useProtobuf: boolean;
clientsForKcp: { [conv: number]: KcpSocket };
connector: IConnector;
dictionary: DictionaryComponent;
protobuf: ProtobufComponent;
decodeIO_protobuf: IComponent;
socket: dgram.Socket;
constructor(port: number, host: string, opts: any) {
super();
this.opts = opts || {};
this.host = host;
this.port = port;
this.useDict = opts.useDict;
this.useProtobuf = opts.useProtobuf;
this.clientsForKcp = {};
this.socket = dgram.createSocket('udp4');
}
start(cb: () => void) {
const app = this.opts.app || pinus.app;
this.connector = app.components.__connector__.connector;
this.dictionary = app.components.__dictionary__;
this.protobuf = app.components.__protobuf__;
this.decodeIO_protobuf = app.components.__decodeIO__protobuf__;
this.socket.on('message', (msg, peer) => {
this.bindSocket(this.socket, peer.address, peer.port, msg);
});
this.on('disconnect', (kcpsocket) => {
const conv = kcpsocket.opts.conv;
delete this.clientsForKcp[conv];
});
this.socket.on('error', (error) => {
return;
});
this.socket.bind(this.port);
process.nextTick(cb);
}
bindSocket(socket: dgram.Socket, address: string, port: number, msg?: any) {
let conv, kcpsocket: KcpSocket | undefined;
if (msg) {
const kcpHead = pinuscoder.kcpHeadDecode(msg);
conv = kcpHead.conv;
kcpsocket = this.clientsForKcp[conv];
}
if (!kcpsocket && conv) {
kcpsocket = new KcpSocket(curId++, socket, address, port, Object.assign({ conv }, this.opts));
pinuscoder.setupHandler(this, kcpsocket, this.opts);
this.clientsForKcp[conv] = kcpsocket;
this.emit('connection', kcpsocket);
}
if (!!msg && !!kcpsocket) {
kcpsocket.emit('input', msg);
}
}
static decode(msg: Buffer | string) {
return coder.decode.bind(this)(msg);
}
decode(msg: Buffer | string) {
return Connector.decode(msg);
}
static encode(reqid: number, route: string, msg: any) {
return coder.encode.bind(this)(reqid, route, msg);
}
encode(reqid: number, route: string, msg: any) {
return Connector.encode(reqid, route, msg);
}
stop(force: any, cb: () => void) {
if (this.socket) {
this.socket.close();
}
process.nextTick(cb);
}
}