之前看到网易公司开源了一个服务端平台,叫做pomelo。粗粗看了一下,感觉还是挺不错的。赞一个,希望越来越多的国内公司可以开源。
这两天抽时间研究了一下,因为之前对node.js并不熟悉,所以就边学边记录了。
pomelo是基于node.js写的,所以node.js是必须安装的。值得一提的是,我用Ubuntu的apt-get安装node.js,好像不太行,因为安装的是0.10.xx版本。后来手工下载node.js 0.8.22版,编译源代码安装node.js,然后再安装pomelo就可以了。有关pomelo的安装网易已经写了挺详细的文档了,google一下就知道了。
这里假设pomelo已经成功安装了,然后我们就可以创建一个pomelo工程,参考网易文档。
看了一下网易的chat例子,然后自己写了一个更加简易的聊天室。
服务端:
简单修改了一下例子程序:
module.exports = function(app) { return new Handler(app); }; var Handler = function(app) { this.app = app; }; /** * New client entry chat server. * * @param {Object} msg request message * @param {Object} session current session object * @param {Function} next next stemp callback * @return {Void} */ Handler.prototype.entry = function(msg, session, next) { var self = this; if(!!msg.chat) {//给所有用户广播 self.app.rpc.chat.chatRemote.chat(session,"c1", msg.uid + ' says: ' + msg.content, null); } else {//处理登录 var sessionService = self.app.get('sessionService'); var s = sessionService.getByUid(msg.uid); if(!!s) {//已经登录过了,不需要做任何事情 next(null, {code: 200, msg: msg.uid +' exists '}); } else { //将当前的session绑定一个ID session.bind(msg.uid); //将新登录的用户加入到channel里面。这里使用一个固定的channel: c1. //并且将channel里面所有用户回传。 self.app.rpc.chat.chatRemote.add(session, msg.uid, self.app.get('serverId'), "c1", true, function(users){ console.log('users' + users); next(null, {code: 2, users:users});//把channel里面的所有其他用户告诉给新登录的用户 }); } } };
如果是第一次登录,则丢入channel中,这里简单使用一个固定的channel。
我们可以看到代码self.app.rpc.chat.chatRemote.add(),其实这个是在调用后台server。
看看后天server,
module.exports = function(app) { return new ChatRemote(app); }; var ChatRemote = function(app) { this.app = app; this.channelService = app.get('channelService'); }; /** * Add user into chat channel. * * @param {String} uid unique id for user * @param {String} sid server id * @param {String} name channel name * @param {boolean} flag channel parameter * */ ChatRemote.prototype.add = function(uid, sid, name, flag, cb) { var channel = this.channelService.getChannel(name, flag);//得到channel //组织一段数据,告诉channel里面所有其他的用户,有新用户登录了。 var param = { route: 'onAdd', user: uid }; //给channel里面所有的用户广播。 channel.pushMessage(param); if( !! channel) { channel.add(uid, sid);//把当前用户加入到channel } //获取当前channel里面所有的用户信息,并且调用回调函数。 cb(this.get(name, flag)); }; ChatRemote.prototype.chat = function(channel_name, content, cb) { var channel = this.channelService.getChannel(channel_name, false); console.log('chatRemote, channel ' + channel_name + ' content: ' + content + ' cb: ' + cb); if(!!channel) { var param = { route: 'onChat', msg: content }; console.log('broadcast: ' + param.msg); //给channel里面所有的用户广播。 channel.pushMessage(param); } }; /** * Get user from chat channel. * * @param {Object} opts parameters for request * @param {String} name channel name * @param {boolean} flag channel parameter * @return {Array} users uids in channel * */ 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; };
代码还是挺简单的,就是在add函数里面
1. 把新用户到达的信息广播给channel里面其他的用户
2. 将新用户丢入channel中
3. 将channel里面所有的用户回传给新登录用户。
配置
因为增加了一个server,那么就得修改一下配置文件:
servers.json
{ "development":{ "connector": [ {"id": "connector-server-1", "host": "115.28.53.90", "port": 3150, "clientPort": 3010, "frontend": true} ], "chat":[ {"id":"chat-server-1", "host":"115.28.53.90", "port":6050} ] }, "production":{ "connector": [ {"id": "connector-server-1", "host": "115.28.53.90", "port": 3150, "clientPort": 3010, "frontend": true} ], "chat":[ {"id":"chat-server-1", "host":"115.28.53.90", "port":6050} ] } }
增加了一个后台server。
adminServer.json
[{ "type": "connector", "token": "agarxhqb98rpajloaxn34ga8xrunpagkjwlaw3ruxnpaagl29w4rxn" }, { "type":"chat", "token":"agarxhqb98rpajloaxn34ga8xrunpagkjwlaw3ruxnpaagl29w4rmm" } ]
token随便取了一个。
客户端
非常简单,当用户按下login的时候,就初始化pomelo对象,并且用request函数向服务端发送一个请求,这样就和pomelo的前台server建立了一个session。
注册两个回调,onAdd, onChat.这样当服务端广播的时候,客户端就可以收到信息了。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <script src="js/lib/build/build.js" type="text/javascript"></script> <script type="text/javascript"> require('boot'); </script> <script type="text/javascript"> var pomelo = window.pomelo; var host = "115.28.53.90"; var port = "3010"; function onLogin() { pomelo.disconnect(); pomelo.init({ host: host, port: port, log: true }, function() { pomelo.request("connector.entryHandler.entry", {uid:myform.uid.value}, function(data) { myform.login_status.value= 'all users:' + data.users; }); }); pomelo.on('onAdd', function(data) { myform.login_status.value = data.user + ' enters'; }); pomelo.on('onChat', function(data){ myform2.chat_content.value=data.msg; }); return false; } function onSend() { if(!myform.uid.value) { alert('login please'); return false; } pomelo.request("connector.entryHandler.entry", {uid:myform.uid.value, chat:"1", content: myform2.content.value}, function(data) { myform2.chat_content.value = data.msg; }); return false; } </script> <head> <title>Untitled Document</title> <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> </head> <body> <table width="75%" border="1"> <form action="" method="get" name="myform"> <tr> <td><input type="text" name="uid"></td> <td><input type="submit" name="Login" value="Login" onClick="return onLogin()"></td> <td> </td> </tr> <tr> <td>system hint:<input type="text" name="login_status"></td> <td> </td> <td> </td> </tr> </form> <form action="" method="get" name="myform2"> <tr> <td><input type="text" name="content"></td> <td><input type="submit" name="chat" value="Send" onClick="return onSend()"></td> <td> </td> </tr> <tr> <td><input type="text" name="chat_content"></td> <td> </td> <td> </td> </tr> </form> <tr> <td> </td> <td> </td> <td> </td> </tr> </table> </body> </html>
目录结构
主要就是3个文件,entryHandler.js, chatRemote.js 和index2.html
HelloWorld/game-server/app/servers/connector/handler/entryHandler.js
HelloWorld/game-server/app/servers/chat/remote/chatRemote.js
HelloWorld/web-server/public/index2.html
测试效果
随便输入个名字,点击login,然后输入写内容,点击send,就可以收到信息了。
一个非常简单的例子,希望是个好的开始,以后再慢慢分析。之前很少写javascript,为了pomelo,看来得好好学一下了。