Files
ZYZ/game-server/channelService.js
2022-01-07 18:55:28 +08:00

522 lines
35 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const countDownLatch = require("../../util/countDownLatch");
const utils = require("../../util/utils");
const channelRemote_1 = require("../remote/frontend/channelRemote");
const pinus_logger_1 = require("pinus-logger");
const path = require("path");
let logger = pinus_logger_1.getLogger('pinus', path.basename(__filename));
let infoLogger = pinus_logger_1.getLogger('info', path.basename(__filename));
/**
* constant
*/
let ST_INITED = 0;
let ST_DESTROYED = 1;
/**
* Create and maintain channels for server local.
*
* ChannelService is created by channel component which is a default loaded
* component of pinus and channel service would be accessed by `app.get('channelService')`.
*
* @class
* @constructor
*/
class ChannelService {
constructor(app, opts) {
this.apushMessageByUids = utils.promisify(this.pushMessageByUids);
this.abroadcast = utils.promisify(this.broadcast);
opts = opts || {};
this.app = app;
this.channels = {};
this.prefix = opts.prefix;
this.store = opts.store;
this.broadcastFilter = opts.broadcastFilter;
this.channelRemote = new channelRemote_1.ChannelRemote(app);
}
start(cb) {
restoreChannel(this, cb);
}
/**
* Create channel with name.
*
* @param {String} name channel's name
* @memberOf ChannelService
*/
createChannel(name) {
if (this.channels[name]) {
return this.channels[name];
}
let c = new Channel(name, this);
addToStore(this, genKey(this), genKey(this, name));
this.channels[name] = c;
return c;
}
/**
* Get channel by name.
*
* @param {String} name channel's name
* @param {Boolean} create if true, create channel
* @return {Channel}
* @memberOf ChannelService
*/
getChannel(name, create) {
let channel = this.channels[name];
if (!channel && !!create) {
channel = this.channels[name] = new Channel(name, this);
addToStore(this, genKey(this), genKey(this, name));
}
return channel;
}
/**
* Destroy channel by name.
*
* @param {String} name channel name
* @memberOf ChannelService
*/
destroyChannel(name) {
delete this.channels[name];
removeFromStore(this, genKey(this), genKey(this, name));
removeAllFromStore(this, genKey(this, name));
}
pushMessageByUids(route, msg, uids, opts, cb) {
if (typeof route !== 'string') {
cb = opts;
opts = uids;
uids = msg;
msg = route;
route = msg.route;
}
if (!cb && typeof opts === 'function') {
cb = opts;
opts = {};
}
if (!uids || uids.length === 0) {
utils.invokeCallback(cb, new Error('uids should not be empty'));
return;
}
let groups = {}, record;
for (let i = 0, l = uids.length; i < l; i++) {
record = uids[i];
add(record.uid, record.sid, groups);
}
sendMessageByGroup(this, route, msg, groups, opts, cb);
}
broadcast(stype, route, msg, opts, cb) {
let app = this.app;
let namespace = 'sys';
let service = 'channelRemote';
let method = 'broadcast';
let servers = app.getServersByType(stype);
if (!servers || servers.length === 0) {
// server list is empty
utils.invokeCallback(cb);
return;
}
if (!cb && typeof opts === 'function') {
cb = opts;
opts = undefined;
}
let count = servers.length;
let successFlag = false;
let latch = countDownLatch.createCountDownLatch(count, function () {
if (!successFlag) {
utils.invokeCallback(cb, new Error('broadcast fails'));
return;
}
utils.invokeCallback(cb, null);
});
let genCB = function (serverId) {
return function (err) {
if (err) {
logger.error('[broadcast] fail to push message to serverId: ' + serverId + ', err:' + err.stack);
infoLogger.error('[broadcast] fail to push message to serverId: ' + serverId + ', err:' + err.stack);
latch.done();
return;
}
successFlag = true;
latch.done();
};
};
opts = { type: 'broadcast', userOptions: opts || {} };
// for compatiblity
opts.isBroadcast = true;
if (opts.userOptions) {
opts.binded = opts.userOptions.binded;
opts.filterParam = opts.userOptions.filterParam;
}
let self = this;
let sendMessage = function (serverId) {
return (function () {
if (serverId === app.serverId) {
self.channelRemote[method](route, msg, opts).then(() => genCB(serverId)(null)).catch((err) => genCB(serverId)(err));
}
else {
app.rpcInvoke(serverId, {
namespace: namespace, service: service,
method: method, args: [route, msg, opts]
}, genCB(serverId));
}
}());
};
for (let i = 0, l = count; i < l; i++) {
sendMessage(servers[i].id);
}
}
}
exports.ChannelService = ChannelService;
/**
* Channel maintains the receiver collection for a subject. You can
* add users into a channel and then broadcast message to them by channel.
*
* @class channel
* @constructor
*/
class Channel {
constructor(name, service) {
this.apushMessage = utils.promisify(this.pushMessage);
this.name = name;
this.groups = {}; // group map for uids. key: sid, value: [uid]
this.records = {}; // member records. key: uid
this.__channelService__ = service;
this.state = ST_INITED;
this.userAmount = 0;
}
/**
* Add user to channel.
*
* @param {Number} uid user id
* @param {String} sid frontend server id which user has connected to
*/
add(uid, sid) {
if (this.state > ST_INITED) {
return false;
}
else {
let res = add(uid, sid, this.groups);
if (res) {
this.records[uid] = { sid: sid, uid: uid };
this.userAmount = this.userAmount + 1;
addToStore(this.__channelService__, genKey(this.__channelService__, this.name), genValue(sid, uid));
}
return res;
}
}
/**
* Remove user from channel.
*
* @param {Number} uid user id
* @param {String} sid frontend server id which user has connected to.
* @return [Boolean] true if success or false if fail
*/
leave(uid, sid) {
if (!uid || !sid) {
return false;
}
let res = deleteFrom(uid, sid, this.groups[sid]);
if (res) {
delete this.records[uid];
this.userAmount = this.userAmount - 1;
removeFromStore(this.__channelService__, genKey(this.__channelService__, this.name), genValue(sid, uid));
}
if (this.userAmount < 0)
this.userAmount = 0; // robust
if (this.groups[sid] && this.groups[sid].length === 0) {
delete this.groups[sid];
}
return res;
}
/**
* Get channel UserAmount in a channel.
*
* @return {number } channel member amount
*/
getUserAmount() {
return this.userAmount;
}
/**
* Get channel members.
*
* <b>Notice:</b> Heavy operation.
*
* @return {Array} channel member uid list
*/
getMembers() {
let res = [], groups = this.groups;
let group, i, l;
for (let sid in groups) {
group = groups[sid];
for (i = 0, l = group.length; i < l; i++) {
res.push(group[i]);
}
}
return res;
}
/**
* Get Member info.
*
* @param {String} uid user id
* @return {Object} member info
*/
getMember(uid) {
return this.records[uid];
}
/**
* Remove member by uid
* @param uid member to removed
*/
removeMember(uid) {
let member = this.getMember(uid);
if (member)
return this.leave(member.uid, member.sid);
else
return false;
}
/**
* Destroy channel.
*/
destroy() {
this.state = ST_DESTROYED;
this.__channelService__.destroyChannel(this.name);
}
/**
* Push message to all the members in the channel
*
* @param {String} route message route
* @param {Object} msg message that would be sent to client
* @param {Object} opts user-defined push options, optional
* @param {Function} cb callback function
*/
pushMessage(route, msg, opts, cb) {
if (this.state !== ST_INITED) {
utils.invokeCallback(cb, new Error('channel is not running now'));
return;
}
if (typeof route !== 'string') {
cb = opts;
opts = msg;
msg = route;
route = msg.route;
}
if (!cb && typeof opts === 'function') {
cb = opts;
opts = {};
}
sendMessageByGroup(this.__channelService__, route, msg, this.groups, opts, cb);
}
}
exports.Channel = Channel;
/**
* add uid and sid into group. ignore any uid that uid not specified.
*
* @param uid user id
* @param sid server id
* @param groups {Object} grouped uids, , key: sid, value: [uid]
*/
let add = function (uid, sid, groups) {
if (!sid) {
logger.warn('ignore uid %j for sid not specified.', uid);
infoLogger.warn('ignore uid %j for sid not specified.', uid);
return false;
}
let group = groups[sid];
if (!group) {
group = [];
groups[sid] = group;
}
group.push(uid);
return true;
};
/**
* delete element from array
*/
let deleteFrom = function (uid, sid, group) {
if (!uid || !sid || !group) {
return false;
}
for (let i = 0, l = group.length; i < l; i++) {
if (group[i] === uid) {
group.splice(i, 1);
return true;
}
}
return false;
};
/**
* push message by group
*
* @param route {String} route route message
* @param msg {Object} message that would be sent to client
* @param groups {Object} grouped uids, , key: sid, value: [uid]
* @param opts {Object} push options
* @param cb {Function} cb(err)
*
* @api private
*/
let sendMessageByGroup = function (channelService, route, msg, groups, opts, cb) {
let app = channelService.app;
let namespace = 'sys';
let service = 'channelRemote';
let method = 'pushMessage';
let count = Object.keys(groups).length;
let successFlag = false;
let failIds = [];
logger.debug('[%s] channelService sendMessageByGroup route: %s, msg: %j, groups: %j, opts: %j', app.serverId, route, msg, groups, opts);
infoLogger.debug('[%s] channelService sendMessageByGroup route: %s, msg: %j, groups: %j, opts: %j', app.serverId, route, msg, groups, opts);
if (count === 0) {
// group is empty
utils.invokeCallback(cb);
return;
}
let latch = countDownLatch.createCountDownLatch(count, function () {
if (!successFlag) {
utils.invokeCallback(cb, new Error('all uids push message fail'));
return;
}
utils.invokeCallback(cb, null, failIds);
});
let rpcCB = function (serverId) {
return function (err, fails) {
if (err) {
logger.error('[pushMessage] fail to dispatch msg to serverId: ' + serverId + ', err:' + err.stack);
infoLogger.error('[pushMessage] fail to dispatch msg to serverId: ' + serverId + ', err:' + err.stack);
latch.done();
return;
}
if (fails) {
failIds = failIds.concat(fails);
}
successFlag = true;
latch.done();
};
};
opts = { type: 'push', userOptions: opts || {} };
// for compatiblity
opts.isPush = true;
let sendMessage = function (sid) {
return (function () {
if (sid === app.serverId) {
channelService.channelRemote[method](route, msg, groups[sid], opts).then((fails) => {
rpcCB(sid)(null, fails);
}, (err) => {
rpcCB(sid)(err, null);
});
}
else {
app.rpcInvoke(sid, {
namespace: namespace, service: service,
method: method, args: [route, msg, groups[sid], opts]
}, rpcCB(sid));
}
})();
};
let group;
for (let sid in groups) {
group = groups[sid];
if (group && group.length > 0) {
sendMessage(sid);
}
else {
// empty group
process.nextTick(rpcCB(sid));
}
}
};
let restoreChannel = function (self, cb) {
if (!self.store) {
utils.invokeCallback(cb);
return;
}
else {
loadAllFromStore(self, genKey(self), function (err, list) {
if (!!err) {
utils.invokeCallback(cb, err);
return;
}
else {
if (!list.length || !Array.isArray(list)) {
utils.invokeCallback(cb);
return;
}
let load = function (key, name) {
return (function () {
let channelName = name;
loadAllFromStore(self, key, function (err, items) {
for (let j = 0; j < items.length; j++) {
let array = items[j].split(':');
let sid = array[0];
let uid = array[1];
let channel = self.channels[channelName];
let res = add(uid, sid, channel.groups);
if (res) {
channel.records[uid] = { sid: sid, uid: uid };
}
}
});
})();
};
for (let i = 0; i < list.length; i++) {
let name = list[i].slice(genKey(self).length + 1);
self.channels[name] = new Channel(name, self);
load(list[i], name);
}
utils.invokeCallback(cb);
}
});
}
};
let addToStore = function (self, key, value) {
if (!!self.store) {
self.store.add(key, value, function (err) {
if (!!err) {
logger.error('add key: %s value: %s to store, with err: %j', key, value, err);
infoLogger.error('add key: %s value: %s to store, with err: %j', key, value, err);
}
});
}
};
let removeFromStore = function (self, key, value) {
if (!!self.store) {
self.store.remove(key, value, function (err) {
if (!!err) {
logger.error('remove key: %s value: %s from store, with err: %j', key, value, err);
infoLogger.error('remove key: %s value: %s from store, with err: %j', key, value, err);
}
});
}
};
let loadAllFromStore = function (self, key, cb) {
if (!!self.store) {
self.store.load(key, function (err, list) {
if (!!err) {
logger.error('load key: %s from store, with err: %j', key, err);
infoLogger.error('load key: %s from store, with err: %j', key, err);
utils.invokeCallback(cb, err);
}
else {
utils.invokeCallback(cb, null, list);
}
});
}
};
let removeAllFromStore = function (self, key) {
if (!!self.store) {
self.store.removeAll(key, function (err) {
if (!!err) {
logger.error('remove key: %s all members from store, with err: %j', key, err);
infoLogger.error('remove key: %s all members from store, with err: %j', key, err);
}
});
}
};
let genKey = function (self, name) {
if (!!name) {
return self.prefix + ':' + self.app.serverId + ':' + name;
}
else {
return self.prefix + ':' + self.app.serverId;
}
};
let genValue = function (sid, uid) {
return sid + ':' + uid;
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhbm5lbFNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9saWIvY29tbW9uL3NlcnZpY2UvY2hhbm5lbFNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSw0REFBNEQ7QUFDNUQsMENBQTBDO0FBQzFDLG9FQUFpRTtBQUNqRSwrQ0FBeUM7QUFNekMsNkJBQTZCO0FBRTdCLElBQUksTUFBTSxHQUFHLHdCQUFTLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztBQUUzRDs7R0FFRztBQUNILElBQUksU0FBUyxHQUFHLENBQUMsQ0FBQztBQUNsQixJQUFJLFlBQVksR0FBRyxDQUFDLENBQUM7QUFRckI7Ozs7Ozs7O0dBUUc7QUFDSCxNQUFhLGNBQWM7SUFTdkIsWUFBWSxHQUFnQixFQUFFLElBQTZCO1FBdUwzRCx1QkFBa0IsR0FBb0csS0FBSyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUM5SixlQUFVLEdBQTBFLEtBQUssQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBdkxoSCxJQUFJLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUNsQixJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQztRQUNmLElBQUksQ0FBQyxRQUFRLEdBQUcsRUFBRSxDQUFDO1FBQ25CLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQztRQUMxQixJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUM7UUFDeEIsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDO1FBQzVDLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSw2QkFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2hELENBQUM7SUFHRCxLQUFLLENBQUMsRUFBeUI7UUFDM0IsY0FBYyxD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