先把類似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,功能就大致上完成了。