nxkit
Version:
This is a collection of tools, independent of any other libraries
214 lines (213 loc) • 7.55 kB
JavaScript
;
/* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license:
*
* Copyright (c) 2015, xuewen.chu
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of xuewen.chu nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL xuewen.chu BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ***** END LICENSE BLOCK ***** */
Object.defineProperty(exports, "__esModule", { value: true });
const util_1 = require("../util");
const service_1 = require("../service");
const session_1 = require("../session");
const errno_1 = require("../errno");
const data_1 = require("./data");
exports.METHOD_CALL_TIMEOUT = 12e4; // 120s
/**
* @class WSService
*/
class WSService extends service_1.Service {
constructor(conv) {
super(conv.request);
this.m_session = null;
this.m_calls = new Map();
this.m_loaded = false;
this.m_conv = conv;
this.m_Intervalid = setInterval(() => this._checkInterval(), 3e4); // 30s
this.m_conv.onClose.on(async () => {
var err = Error.new(errno_1.default.ERR_CONNECTION_DISCONNECTION);
for (var [, handle] of this.m_calls) {
handle.cancel = true;
handle.err(err);
}
clearInterval(this.m_Intervalid);
});
}
get conv() {
return this.m_conv;
}
get session() {
if (!this.m_session) {
this.m_session = new session_1.Session(this);
}
return this.m_session;
}
get loaded() {
return this.m_loaded;
}
async load() { }
async destroy() { }
_checkMethodName(method) {
util_1.default.assert(/^[a-z]/i.test(method), errno_1.default.ERR_FORBIDDEN_ACCESS);
}
/**
* @fun receiveMessage() # 消息处理器
*/
async receiveMessage(msg) {
if (!this.m_loaded)
console.warn('Unable to process message WSService.receiveMessage, loaded=false');
var self = this;
var { data, name = '', cb, sender } = msg;
if (msg.isCallback()) {
var handle = this.m_calls.get(cb);
if (handle) {
if (msg.error) { // throw error
handle.err(Error.new(msg.error));
}
else {
handle.ok(data);
}
}
}
else {
var r = {};
if (msg.isCall()) {
this._checkMethodName(name);
if (this.server.printLog)
console.log('WSClient.Call', `${self.name}.${name}(${JSON.stringify(data, null, 2)})`);
try {
r.data = await self.handleCall(name, data || {}, sender || '');
}
catch (e) {
r.error = e;
}
} /*else if (msg.isEvent()) { // none event
try {
this.trigger(name, data);
} catch(err) {
console.error(err);
}
} */
else {
return;
}
if (cb) {
self.m_conv.sendFormatData(Object.assign(r, {
service: self.m_conv._service(self.name),
type: data_1.Types.T_CALLBACK,
cb: cb,
})).catch(console.warn); // callback
}
}
}
/**
* @func handleCall
*/
handleCall(method, data, sender) {
if (method in WSService.prototype)
throw Error.new(errno_1.default.ERR_FORBIDDEN_ACCESS);
var fn = this[method];
if (typeof fn != 'function')
throw Error.new(String.format('"{0}" no defined function', method));
return fn.call(this, data, sender);
}
async _send(data) {
await this.m_conv.sendFormatData(data);
delete data.data;
return data;
}
_checkInterval() {
var now = Date.now();
for (var [, handle] of this.m_calls) {
if (handle.timeout) {
if (handle.timeout < now) { // timeouted
handle.err(Error.new([...errno_1.default.ERR_METHOD_CALL_TIMEOUT,
`Method call timeout, ${this.name}/${handle.name}`]));
handle.cancel = true;
}
}
}
}
_call(type, name, data, timeout, sender) {
return util_1.default.promise(async (resolve, reject) => {
var id = util_1.default.id;
var calls = this.m_calls;
calls.set(id, await this._send({
timeout: timeout ? timeout + Date.now() : 0,
ok: (e) => (calls.delete(id), resolve(e)),
err: (e) => (calls.delete(id), reject(e)),
service: this.conv._service(this.name),
type: type,
name: name,
data: data,
cb: id,
sender: sender,
}));
// console.log('SER send', name);
});
}
async _trigger(event, data, sender) {
await this._send({
ok: () => { },
err: () => { },
service: this.conv._service(this.name),
type: data_1.Types.T_EVENT,
name: event,
data: data,
sender: sender,
});
}
/**
* @func call(method, data)
* @async
*/
call(method, data, timeout = exports.METHOD_CALL_TIMEOUT, sender) {
return this._call(data_1.Types.T_CALL, method, data, timeout, sender);
}
/**
* @func trigger(event, data)
* @async
*/
trigger(event, data, sender) {
return this._trigger(event, data, sender);
}
/**
* @func send(method, data, sender) method call, No response
* @async
*/
async send(method, data, sender) {
await this._send({
ok: () => { },
err: () => { },
service: this.conv._service(this.name),
type: data_1.Types.T_CALL,
name: method,
data: data,
sender: sender,
});
}
}
exports.WSService = WSService;
WSService.type = 'event';