iT邦幫忙

DAY 23
3

且戰且走HTML5系列 第 23

且戰且走HTML5(23) 加入類似Socket.IO的on與emit方法

先把類似Socket.IO的操作方式加進來,然後開始測試,先從echo開始。
雖然先把namespace、room、broadcast等功能都先加進來,不過目前先測試一下與http伺服器整合以及基本的echo WebSocket伺服器。

先把昨天寫的程式加強一下,主要的變動都在Socket.js:

 var WebsocketServer = require('ws').Server;
 
 var handlers = {};
 
 var Socket = module.exports = function(server, manager, namespace, sid) {
 	this.server = server;
 	this.manager = manager;
 	this.sid = sid;
 	this.wss = new WebsocketServer({server:this.server});
 	this.ws = null;
 	this.namespace = namespace;
 	this.flags = {"allnotme":false,"inroom":false};
 };
 
 Socket.prototype.on = function(name, handler) {
 	var self = this;
 	switch(name) {
 		case 'connection':
 			this.wss.on('connection', function(ws) {
 				self.ws = ws;
 				ws.on('message', function(data, flags) {
 					if(flags.binary) {
 						handlers['data'].forEach(function(fn) {
 							fn.call(self, data);
 						});
 					} else {
 						var args = JSON.parse(data);
 						if(!!handlers[args.name]) {
 							var ev = args.name;
 							delete args.name;
 							handlers[ev].forEach(function(fn) {
 								fn.call(self, args);
 							});
 							ev = null;
 						} else {
 							console.log('no handler: ');
 						}
 					}
 				});
 				process.nextTick(function(){handler.call(self, self);});
 			});
 			break;
 		default:
 			if(!!handlers[name]) {
 				handlers[name].push(handler);
 			} else {
 				handlers[name] = [];
 				handlers[name].push(handler);
 			}
 	}
 };
 
 Socket.prototype.emit = function(name, data, opt) {
 	if(!!opt) {
 		this.ws.send(data, opt);
 	} else {
 		data['name'] = name;
 		this.ws.send(JSON.stringify(data));
 	}
 	this.flags['allnotme'] = false;
 	this.flags['inroom'] = false;
 };
 
 Socket.prototype.__defineGetter__('broadcast', function() {
 	this.flags['allnotme'] = true
 	return this;
 });
 
 Socket.prototype._findSocket = function(ns, room, sid) {
 	if(!!this.manager) {
 		if(!!this.manager.namespaces[ns]) {
 			if(!!this.manager.namespaces[ns][room]) {
 				if(!!this.manager.namespaces[ns][room][sid]) {
 					return this.manager.namespaces[ns][room][sid];
 				}
 			}
 		}
 	}
 };
 
 Socket.prototype.join = function(room) {
 	if(!!this.manager.namespaces[this.namespace][room]) {
 		this.manager.namespaces[this.namespace][room][this.sid] = this;
 	} else {
 		this.manager.namespaces[this.ns][room] = {};
 		this.manager.namespaces[this.namespace][room][this.sid] = this;
 	}
 };
 
 Socket.prototype.leave = function(room) {
 	if(!!this.manager.namespaces[this.namespace][room]) {
 		if(!!this.manager.namespaces[this.namespace][room][this.sid]) {
 			delete this.manager.namespaces[this.namespace][room][this.sid];
 		}
 	}
 	var i = 0;
 	for(var a in this.manager.namespaces[this.namespace][room]) {
 		i++
 	}
 	if(i===0) {
 		delete this.manager.namespaces[this.namespace][room];
 	}
 }
 
 Socket.prototype.in = function(room) {
 	var check = false;
 	if(!!this.manager.namespaces[this.namespace][room]) {
 		if(!!this.manager.namespaces[this.namespace][room][this.sid]) {
 			check = true;
 		}
 	}
 	if(check) {
 		this.flags['inroom'] = room;
 	}
 	return this;
 }

然後撰寫測試程式,測試的伺服器程式(test001.js,位在ws.io目錄中的tests子目錄):

 var app = require('http').createServer(function(req, res) {
 	console.log('http server ok.');
 	res.writeHead(200);
 	res.end('hello world.');
 });
 
 var io = require('../').listen(app);
 
 io.sockets.on('connection', function(socket) {
 	socket.on('echo', function(data) {
 		console.log('onecho: '+data);
 		socket.emit('echo', data);
 	});  
 });
 
 app.listen(8443);

http伺服器收到request,一律回復hello world.。WebSocket伺服器,則直接轉送收到的訊息。可以看到這裡是使用echo事件來處理瀏覽器觸發的echo事件,然後emit回去觸發瀏覽器端的echo事件,不過因為瀏覽器端的程式還沒包裝,所以先手寫。(在Socket.IO中,傳遞的事件名稱,其實就是送出物件的name屬性)

瀏覽器端的程式也很簡單,還沒有包裝成Socket.IO風格:

 	<button onclick='ws.send(JSON.stringify({"name":"echo","msg":"hello"}));'>test</button>
 
 
 <script>
 var ws = new WebSocket('ws://127.0.0.1:8443');
 ws.addEventListener('message', function(msg) {
 	var data = JSON.parse(msg.data);
 	alert(data.msg);
 }, false);
 </script>

執行伺服器程式後,打開測試網頁,然後按下test按鈕,就會alert伺服器echo回來的訊息:

直接打開http://localhost:8443 的話,還是有http伺服器:

明天接著把群播、room等功能做測試,也實作簡單的storage,功能就大致上完成了。


上一篇
且戰且走HTML5(22) 調整ws模組
下一篇
且戰且走HTML5(24) 完成ws模組的包裝
系列文
且戰且走HTML530

1 則留言

我要留言

立即登入留言