pomelo分布式聊天服务器详解
"development":{"connector":[{"id":"connector-server-1", "host":"127.0.0.1", "port":4050, "clientPort": 3050, "frontend": true},{"id":"connector-server-2", "host":"127.0.0.1", "port":4051, "clientPort": 3051, "frontend": true},{"id":"connector-server-3", "host":"127.0.0.1", "port":4052, "clientPort": 3052, "frontend": true}],"chat":[{"id":"chat-server-1", "host":"127.0.0.1", "port":6050},{"id":"chat-server-2", "host":"127.0.0.1", "port":6051},{"id":"chat-server-3", "host":"127.0.0.1", "port":6052}],"gate":[{"id": "gate-server-1", "host": "127.0.0.1", "clientPort": 3014, "frontend": true}]},
其中我们看到pomelo.init方法,传入了host,port和log的参数,同时在回调函数里面使用pomelo.request方法将uid发送出去,在回调函数里断开连接,最后执行callback,将返回的data数据的host和port传入callback。// query connector
function queryEntry(uid, callback) {
var route = 'gate.gateHandler.queryEntry';
pomelo.init({
host: window.location.hostname,
port: 3014,
log: true
}, function() {
pomelo.request(route, {
uid: uid
}, function(data) {
pomelo.disconnect();
if(data.code === 500) {
showError(LOGIN_ERROR);
return;
}
callback(data.host, data.port);
});
});
};
pomelo.init = function(params, cb){pomelo.params = params;params.debug = true;var host = params.host;var port = params.port;var url = 'ws://' + host;if(port) {url += ':' + port;}socket = io.connect(url, {'force new connection': true, reconnect: false});socket.on('connect', function(){console.log('[pomeloclient.init] websocket connected!');if (cb) {cb(socket);}});socket.on('reconnect', function() {console.log('reconnect');});socket.on('message', function(data){if(typeof data === 'string') {data = JSON.parse(data);}if(data instanceof Array) {processMessageBatch(pomelo, data);} else {processMessage(pomelo, data);}});socket.on('error', function(err) {console.log(err);});socket.on('disconnect', function(reason) {pomelo.emit('disconnect', reason);});};
var route = 'gate.gateHandler.queryEntry';
pomelo.request(route, {uid: uid
},function(){..
queryEntry(username, function(host, port) {pomelo.init({host: host,port: port,log: true}, function() {var route = "connector.entryHandler.enter";pomelo.request(route, {username: username,rid: rid}, function(data) {if(data.error) {showError(DUPLICATE_ERROR);return;}setName();setRoom();showChat();initUserList(data);});});});
handler.enter = function(msg, session, next) { var self = this; var rid = msg.rid; var uid = msg.username + '*' + rid var sessionService = self.app.get('sessionService'); //duplicate log in if( !! sessionService.getByUid(uid)) { next(null, { code: 500, error: true }); return; } session.bind(uid); session.set('rid', rid); session.push('rid', function(err) { if(err) { console.error('set rid for session service failed! error is : %j', err.stack); } }); session.on('closed', onUserLeave.bind(null, self.app)); //put user into channel self.app.rpc.chat.chatRemote.add(session, uid, self.app.get('serverId'), rid, true, function(users){ next(null, { users:users }); }); };
var sessionService = self.app.get('sessionService');
if( !! sessionService.getByUid(uid)) {next(null, {code: 500,error: true});return;}
session.bind(uid);session.set('rid', rid);session.push('rid', function(err) {if(err) {console.error('set rid for session service failed! error is : %j', err.stack);}});session.on('closed', onUserLeave.bind(null, self.app));
self.app.rpc.chat.chatRemote.add(session, uid, self.app.get('serverId'), rid, true, function(users){next(null, {users:users});});
var onUserLeave = function(app, session) {if(!session || !session.uid) {return;}app.rpc.chat.chatRemote.kick(session, session.uid, app.get('serverId'), session.get('rid'), null);};
var ChatRemote = function(app) {
this.app = app;
this.channelService = app.get('channelService');
};ChatRemote.prototype.add = function(uid, sid, name, flag, cb) {var channel = this.channelService.getChannel(name, flag);var username = uid.split('*')[0];var param = {route: 'onAdd',user: username};channel.pushMessage(param);if( !! channel) {channel.add(uid, sid);}cb(this.get(name, flag));};
ChatRemote.prototype.get = function(name, flag) {var users = [];var channel = this.channelService.getChannel(name, flag);if( !! channel) {users = channel.getMembers();}for(var i = 0; i < users.length; i++) {users[i] = users[i].split('*')[0];}return users;};
ChatRemote.prototype.kick = function(uid, sid, name, cb) {var channel = this.channelService.getChannel(name, false);// leave channelif( !! channel) {channel.leave(uid, sid);}var username = uid.split('*')[0];var param = {route: 'onLeave',user: username};channel.pushMessage(param);cb();};
//deal with chat mode.$("#entry").keypress(function(e) {var route = "chat.chatHandler.send";var target = $("#usersList").val();if(e.keyCode != 13 /* Return */ ) return;var msg = $("#entry").attr("value").replace("\n", "");if(!util.isBlank(msg)) {pomelo.request(route, {rid: rid,content: msg,from: username,target: target}, function(data) {$("#entry").attr("value", ""); // clear the entry field.if(target != '*' && target != username) {addMessage(username, target, msg);$("#chatHistory").show();}});}});
handler.send = function(msg, session, next) { var rid = session.get('rid'); var username = session.uid.split('*')[0]; var channelService = this.app.get('channelService'); var param = { route: 'onChat', msg: msg.content, from: username, target: msg.target }; channel = channelService.getChannel(rid, false); //the target is all users if(msg.target == '*') { channel.pushMessage(param); } //the target is specific user else { var tuid = msg.target + '*' + rid; var tsid = channel.getMember(tuid)['sid']; channelService.pushMessageByUids(param, [{ uid: tuid, sid: tsid }]); } next(null, { route: msg.route }); };
pomelo.on('onChat', function(data) { addMessage(data.from, data.target, data.msg); $("#chatHistory").show(); if(data.from !== username) tip('message', data.from); });