其實還沒有真的完成,因為這個工作幾乎等於重寫Socket.IO...不過還是來看一下目前進行的狀況
主要的改寫還是在幾個部分,跟昨天的程式比起來,還需要在Manager與Socket之間插入Namespace物件來串接
首先,Manager改成:
var Socket = require('./Socket');
var wss = require('ws').Server;
var Manager = module.exports = function(server) {
this.server = server;
this.namespaces = {};
this.store = {};
this.rooms = {};
this.handlers = {};
};
Manager.prototype.of = function(ns) {
var namespace = new Namespace(this.server, this, ns);
return namespace;
};
Manager.prototype.__defineGetter__('sockets', function() {
return this.of('/');
});
function Namespace(server, manager, ns) {
this.namespace = ns;
this.socket = Socket;
this.wss = new wss({server: server});
this.manager = manager;
this.server = server;
this.ws = null;
this.manager.handlers[ns] = {};
this.manager.namespaces[this.namespace] = {};
}
Namespace.prototype.on = function(conn, handler) {
var self = this;
if(conn == 'connection') {
this.wss.on('connection', function(ws) {
self.ws = ws;
ws.on('message', function(data, flags) {
var args = JSON.parse(data);
if(!!self.manager.handlers[self.namespace][args.name]) {
var ev = args.name;
delete args.name;
self.manager.handlers[self.namespace][ev].forEach(function(fn) {
fn.call(self, args);
});
ev = null;
} else {
console.log('no handler: ');
}
});
var sid = Math.random()*10000 + '-' + new Date().getTime();
var socket = new Socket(self.server, self.manager, self, sid, ws);
if(!!self.manager.namespaces[self.namespace]['all']) {
self.manager.namespaces[self.namespace]['all'][sid] = socket;
} else {
self.manager.namespaces[self.namespace]['all'] = {};
self.manager.namespaces[self.namespace]['all'][sid] = socket;
}
handler.call(socket, socket);
});
}
}
需要多一個Namespace做中介,才有辦法為每個連線真正產生一個獨立的Socket物件。接下來是Socket物件的調整:
var WebsocketServer = require('ws').Server;
var handlers = {};
var Socket = module.exports = function(server, manager, namespace, sid, ws) {
this.sid = sid;
this.server = server;
this.manager = manager;
this.ws = ws;
this.namespace = namespace.namespace;
this.flags = {"allnotme":false,"inroom":false};
};
Socket.prototype.on = function(name, handler) {
var self = this;
switch(name) {
default:
if(!!this.manager.handlers[this.namespace][name]) {
this.manager.handlers[this.namespace][name].push(handler);
} else {
this.manager.handlers[this.namespace][name] = [];
this.manager.handlers[this.namespace][name].push(handler);
}
}
};
Socket.prototype.emit = function(name, data, opt) {
var room = '';
if(!this.flags.inroom) {
room = 'all';
} else {
room = this.flags.inroom;
}
var targets = [];
console.log(this.sid);
for(var i in this.manager.namespaces[this.namespace][room]) {
if(this.flags.allnotme) {
if(i!=this.sid) {
console.log(i);
targets.push(this._findSocket(this.namespace, room, i));
}
} else {
targets.push(this._findSocket(this.namespace, room, i));
}
}
//console.log(targets);
if(!!opt) {
targets.forEach(function(socket) {
console.log(socket);
socket.ws.send({name:name, data:data});
})
} 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;
}
Socket.prototype.set = function(name, value, cb) {
if(!this.manager.store[this.sid]) {
this.manager.store[this.sid] = {};
}
this.manager.store[this.sid][name] = value;
cb();
};
Socket.prototype.get = function(name) {
if(!!this.manager.store[this.sid]) {
if(!!this.manager.store[this.sid][name]) {
cb(false, this.manager.store[this.sid][name]);
} else {
cb(true);
}
} else {
this.manager.store[this.sid] = {};
cb(true);
}
};
Socket.prototype.has = function(name, cb) {
if(!!this.manager.cache[this.sid]) {
if(!!this.manager.cache[this.sid][name]) {
cb(false, true);
} else {
cb(true, true);
}
} else {
this.manager.store[this.sid] = {};
cb(true, false);
}
};
主要的差別還是把事件的handler移到Manager來管理,程式碼則在Namespace物件中實作。也加入了data store以及群播...不過現在問題出在群播,因為他會傳給所有人XD。
只好明天再繼續...果然是且戰且走阿,希望不要把所有Socket.IO的物件架構都複製過來才能實現。