Pomelo聊天室源碼分析(一)

Pomelo 0.2

node.js 0.8

由於0.3版本的不穩定,不想花時間到兼容性升級上,等等稍微穩定一下再升級,接下來的分析都是基於這個版本源碼進行分析

開篇前,先引用pomelo的wiki:https://github.com/NetEase/pomelo/wiki/tutorial1--%E5%88%86%E5%B8%83%E5%BC%8F%E8%81%8A%E5%A4%A9

本篇屬於開篇文章,wiki提到的我就不詳細說了,大概流程理順一下。


客戶端:

web-server/public/js/client.js

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);
	});
});

初始化pomelo.init ()實例,通過實例pomelo.request 調用服務器 connector.entryHandler.enter 位置的鉤子,回調成功,則創建聊天室等應用,這是客戶端對服務器端發出的請求,讓我們看看服務端到底做了什麼?

字符串’connector.entryHandler.enter’分別代表了服務器類型、服務端相應的文件名及對應的方法名。根據字符串的標記調用對應的服務器鉤子處理。


connector/handler/entryHandler.js

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
		});
	});
};

引用wiki裏面的話

服務端將用戶加到channel

通過調用rpc方法,將登錄的用戶加入到channe
l中。


app.rpc.chat.chatRemote.add(session, uid, app.get('serverId'), function(data){});


其中app是pomelo的應用對象,app.rpc表明了是前後臺服務器的Remote rpc調用,後面的參數分別代表服務器的名稱、對應的文件名稱及方法名。爲了實現這個rpc調用,則只需要在對應的chat/remote/中新建文件chatRemote.js,並實現add方法。

remote.add = function(uid, sid, cb){
    var channel = channelService.getChannel('pomelo', true); 
    if(!!channel)
        channel.add(uid, sid);
};


在add方法中,首先從pomelo提供的channelService中取出channel,然後將用戶加入到channel中即可。這樣就完成了一個完整的rpc調用,在pomelo裏複雜的rpc調用就是這麼簡單。

接下來,我們看一下另一段客戶端代碼

web-server/public/js/client.js

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();
		}
	});
}

以上這段代碼,主要處理用戶發送的聊天信息,鉤子函數chat.chatHandler.send,讓我們看看服務器的程序到底怎麼處理的

chat/chatHandler.js

/**
 * Send messages to users
 *
 * @param {Object} msg message from client
 * @param {Object} session
 * @param  {Function} next next stemp callback
 *
 */
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
	});
};

關於這段代碼,wiki描述並不詳細,也是我接下來篇章重點分析的,另外還會分析一下,怎麼編寫鉤子函數是如何處理請求的,還是session等管理。今天就這樣結束吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章