chatofpomelo简析之二——聊天
torial----分布式聊天服务器 --- https://github.com/NetEase/pomelo/wiki/tutorial1--%E5%88%86%E5%B8%83%E5%BC%8F%E8%81%8A%E5%A4%A9
方给的tutorial真是简单明了,简的刚开始学pomelo,压根就不知道代码写在哪。所以还是自己研究研究。
connector:frontend前端服务器,承载连接,并把请求转发到后端的服务器群
gate:客户端线连接gate服务器,然后再由gate决定客户端和哪个connector连接
chat:backend后端服务器,真正处理业务逻辑的地方
1: $("#login").click(function () {
2: username = $("#loginUser").attr("value");
3: rid = $('#channelList').val();//Channel的ID
4:
5: if (username.length > 20 || username.length == 0 || rid.length > 20 || rid.length == 0) {
6: showError(LENGTH_ERROR);
7: return false;
8: }
9:
10: if (!reg.test(username) || !reg.test(rid)) {
11: showError(NAME_ERROR);
12: return false;
13: }
14:
15://query entry of connection
16: queryEntry(username, function (host, port) {//host,post是gate服务器分配给该客户端的connector服务器的host和clientPort
17: pomelo.init({//pomeloclient.js中的init()方法
18: host: host,
19: port: port,
20: log: true
21: }, function () {//根据返回的connector服务器的host和port,连接connector
22: var route = "connector.entryHandler.enter";
23: pomelo.request(route, {//向connector的服务器发送username和channel(roomid = rid)
24: username: username,
25: rid: rid
26: }, function (data) {//data是connector返回给客户端的数据(对象),是同一channel的用户列表
27: if (data.error) {
28: showError(DUPLICATE_ERROR);
29: return;
30: }
31: setName();
32: setRoom();
33: showChat();
34: initUserList(data);
35: });
36: });
37: });
38: });
1:function queryEntry(uid, callback) {
2:var route = 'gate.gateHandler.queryEntry';
3: pomelo.init({//连接game服务器
4: host: window.location.hostname,
5: port: 3014,
6: log: true
7: }, function () {
8: pomelo.request(route, {
9: uid: uid
10: }, function (data) {//data是gate服务器返回给客户端的数据(对象)
11: pomelo.disconnect();//断开gate服务器,连接connector服务器
12: if (data.code === 500) {
13: showError(LOGIN_ERROR);
14: return;
15: }
16: callback(data.host, data.port);//调用回调函数 并将data数据传给回调方法
17: });
18: });
19: };
1: handler.queryEntry = function(msg, session, next) {
2: var uid = msg.uid;
3: if(!uid) {//uid为空 说明用户不存在
4: next(null, {
5: code: 500
6: });
7: return;
8: }
9:// get all connectors 获取所有的connector
10:var connectors = this.app.getServersByType('connector');
11:if(!connectors || connectors.length === 0) {
12: next(null, {
13: code: 500
14: });
15: return;
16: }
17:// select connector
18:var res = dispatcher.dispatch(uid, connectors);//根据算法 返回一个服务器
19: next(null, {
20: code: 200,
21: host: res.host,
22: port: res.clientPort
23: });//将该服务器的host和客户端端口clientPort返回给客户端
24: };
1: var crc = require('crc');
2:
3: module.exports.dispatch = function(uid, connectors) {
4: var index = Math.abs(crc.crc32(uid)) % connectors.length;
5: return connectors[index];
6: };
1: handler.enter = function(msg, session, next) {
2: var self = this;
3: var rid = msg.rid;
4: var uid = msg.username + '*' + rid
5: var sessionService = self.app.get('sessionService');
6:
7://duplicate log in 如果session中已经存在sessionService 说明已登陆
8: if( !! sessionService.getByUid(uid)) {
9: next(null, {
10: code: 500,
11: error: true
12: });
13: return;
14: }
15:
16: session.bind(uid);//将uid(username*rid)绑定到当前的session
17: session.set('rid', rid);//session.settings[rid] = rid;
18: session.push('rid', function(err) {
19:if(err) {
20: console.error('set rid for session service failed! error is : %j', err.stack);
21: }
22: });
23: session.on('closed', onUserLeave.bind(null, self.app));//监听“close”事件 调用onUserLeave()
24:
25://put user into channel
26: self.app.rpc.chat.chatRemote.add(session, uid, self.app.get('serverId'), rid, true, function(users){
27: next(null, {//得到的user是同一channel的用户列表(数组),将这用户列表传给客户端
28: users:users
29: });
30: });
31: };
1:ChatRemote.prototype.add = function(uid, sid, name, flag, cb) {
2:var channel = this.channelService.getChannel(name, flag);
3:var username = uid.split('*')[0];
4:var param = {
5: route: 'onAdd',
6: user: username
7: };
8: channel.pushMessage(param);//Push message to all the members in the channel
9:
10:if( !! channel) {
11: channel.add(uid, sid);
12:}
13:
14:cb(this.get(name, flag));//this.get()返回(name,flag)标记的Channel的用户
15: }
1: ChatRemote.prototype.get = function(name, flag) {
2:var users = [];
3:var channel = this.channelService.getChannel(name, flag);
4:if( !! channel) {
5: users = channel.getMembers();
6:}
7:for(var i = 0; i < users.length; i++) {
8: users[i] = users[i].split('*')[0];
9: }
10:return users;
11: };
客户端连接gate服务器,gate返回给客户端connector的port和clientPort
客户端连接connector服务器,connector将新登录的用户添加到channel里,通知channel里的所用用户,并返回该channel的所有用户名
客户端根据得到的用户名,更界面
搬运工)Pomelo官方demo Chatofpomelo简析之二——聊天
1: $("#entry").keypress(function (e) {
2:var route = "chat.chatHandler.send";
3:var target = $("#usersList").val();
4:if (e.keyCode != 13 /* Return */) return;
5:var msg = $("#entry").attr("value").replace("\n", "");
6:if (!util.isBlank(msg)) {
7: pomelo.request(route, {//route = "chat.chatHandler.send"
8: rid: rid,
9: content: msg,
10: from: username,
11: target: target
12: }, function (data) {
13: $("#entry").attr("value", ""); // clear the entry field.
14:if (target != '*' && target != username) {
15: addMessage(username, target, msg);
16: $("#chatHistory").show();
17: }
18: });
19: }
20: });
1: handler.send = function(msg, session, next) {
2:var rid = session.get('rid');
3:var username = session.uid.split('*')[0];
4:var channelService = this.app.get('channelService');
5:var param = {
6: route: 'onChat',
7: msg: msg.content,
8: from: username,
9: target: msg.target
10: };
11: channel = channelService.getChannel(rid, false);
12:
13://the target is all users
14:if(msg.target == '*') {
15: channel.pushMessage(param);
16: }
17://the target is specific user
18:else {
19:var tuid = msg.target + '*' + rid;
20:var tsid = channel.getMember(tuid)['sid'];
21: channelService.pushMessageByUids(param, [{
22: uid: tuid,
23: sid: tsid
24: }]);
25: }
26: next(null, {
27: route: msg.route
28: });
29: };
1: channel = channelService.getChannel(rid, false);
1: app.configure('production|development', function () {
2:// route configures
3: app.route('chat', routeUtil.chat);//routes的chat属性对应routeUtil.chat()方法
4: app.filter(pomelo.timeout());
5: });
1: exp.chat = function(session, msg, app, cb) {
2:
3: console.log("uid = " + session.uid + " rid = " + session.get("rid"));
4:var chatServers = app.getServersByType('chat');//根据类型 获取服务器列表
5:
6:if(!chatServers || chatServers.length === 0) {//如果服务器列表不存在或为空,则调用回调函数cb,将错误传给该回调
7: cb(new Error('can not find chat servers.'));
8:return;
9: }
10:
11:var res = dispatcher.dispatch(session.get('rid'), chatServers);//通过rid获得具体的chat服务器
12: console.log("chat服务器:" + res.id);
13: cb(null, res.id);
14: };
1: app.route('chat', routeUtil.chat);