204 lines
7.9 KiB
JavaScript
204 lines
7.9 KiB
JavaScript
"use strict";
|
|
(function socket_js() {
|
|
var moduleName = "lib/wSocket/socket"
|
|
|
|
var defineArray = [];
|
|
defineArray.push("lib/utils/subscribable");
|
|
defineArray.push("lib/wType/event");
|
|
defineArray.push("lib/wType/bytearray");
|
|
defineArray.push("lib/wType/string");
|
|
defineArray.push("lib/wType/vocabulary");
|
|
defineArray.push("lib/wType/uint64");
|
|
defineArray.push("lib/wType/address");
|
|
defineArray.push("lib/wType/factory");
|
|
|
|
define(moduleName, defineArray, function socket_module() {
|
|
var Subscribable = require("lib/utils/subscribable");
|
|
var Event = require("lib/wType/event");
|
|
var ByteArray = require("lib/wType/bytearray");
|
|
var String = require("lib/wType/string");
|
|
var Vocabulary = require("lib/wType/vocabulary");
|
|
var Uint64 = require("lib/wType/uint64");
|
|
var Address = require("lib/wType/address");
|
|
var factory = require("lib/wType/factory");
|
|
|
|
var Socket = Subscribable.inherit({
|
|
"className": "Socket",
|
|
"constructor": function(name) {
|
|
if (!name) {
|
|
throw new Error("Can't construct a socket without a name");
|
|
}
|
|
Subscribable.fn.constructor.call(this);
|
|
|
|
this._state = DISCONNECTED;
|
|
this._dState = SIZE;
|
|
this._name = name instanceof String ? name : new String(name);
|
|
this._remoteName = new String();
|
|
this._id = new Uint64(0);
|
|
this._socket = undefined;
|
|
this._helperBuffer = new ByteArray(4);
|
|
|
|
this._initProxy();
|
|
},
|
|
"destructor": function() {
|
|
this.close();
|
|
if (this._state === DISCONNECTING) {
|
|
this.on("disconnected", function() {
|
|
Subscribable.fn.destructor.call(this);
|
|
})
|
|
} else {
|
|
Subscribable.fn.destructor.call(this);
|
|
}
|
|
},
|
|
"close": function() {
|
|
if ((this._state !== DISCONNECTED) && (this._state !== DISCONNECTING)) {
|
|
this._state = DISCONNECTING;
|
|
this._socket.close();
|
|
}
|
|
},
|
|
"_emitEvent": function(ev) {
|
|
this.trigger("message", ev);
|
|
ev.destructor();
|
|
},
|
|
"getId": function() {
|
|
return this._id;
|
|
},
|
|
"isOpened": function() {
|
|
return this._state === CONNECTED;
|
|
},
|
|
"open": function(addr, port) {
|
|
if (this._state === DISCONNECTED) {
|
|
this._state = CONNECTING;
|
|
this._socket = new WebSocket("ws://"+ addr + ":" + port);
|
|
this._socket.binaryType = "arraybuffer";
|
|
|
|
this._socket.onclose = this._proxy.onSocketClose;
|
|
this._socket.onerror = this._proxy.onSocketError;
|
|
this._socket.onmessage = this._proxy.onSocketMessage
|
|
}
|
|
},
|
|
"send": function(ev) {
|
|
var size = ev.size();
|
|
var ba = new ByteArray(size + 5);
|
|
ba.push32(size);
|
|
ba.push8(ev.getType());
|
|
ev.serialize(ba);
|
|
|
|
this._socket.send(ba.data().buffer);
|
|
},
|
|
"_initProxy": function() {
|
|
this._proxy = {
|
|
onSocketClose: this._onSocketClose.bind(this),
|
|
onSocketError: this._onSocketError.bind(this),
|
|
onSocketMessage: this._onSocketMessage.bind(this)
|
|
}
|
|
},
|
|
"_onEvent": function(ev) {
|
|
if (ev.isSystem()) {
|
|
var cmd = ev._data.at("command").toString();
|
|
|
|
switch(cmd) {
|
|
case "setId":
|
|
this._setId(ev._data.at("id"));
|
|
this._setRemoteName();
|
|
break;
|
|
case "setName":
|
|
this._setName(ev._data.at("name"));
|
|
this._state = CONNECTED;
|
|
this.trigger("connected");
|
|
break;
|
|
default:
|
|
throw new Error("Unknown system command: " + cmd);
|
|
}
|
|
ev.destructor();
|
|
} else {
|
|
setTimeout(this._emitEvent.bind(this, ev), 5); //TODO event queue
|
|
}
|
|
},
|
|
"_onSocketClose": function(ev) {
|
|
this._state = DISCONNECTED;
|
|
|
|
this._id.destructor();
|
|
this._id = new Uint64(0);
|
|
|
|
this._remoteName.destructor();
|
|
this._remoteName = new String();
|
|
|
|
console.log(ev);
|
|
this.trigger("disconnected", ev);
|
|
},
|
|
"_onSocketError": function(err) {
|
|
this.trigger("error", err);
|
|
},
|
|
"_onSocketMessage": function(mes) {
|
|
var raw = new Uint8Array(mes.data);
|
|
var i = 0;
|
|
|
|
while (i < raw.length) {
|
|
switch (this._dState) {
|
|
case SIZE:
|
|
i = this._helperBuffer.fill(raw, raw.length, i);
|
|
|
|
if (this._helperBuffer.filled()) {
|
|
var size = this._helperBuffer.pop32();
|
|
this._helperBuffer.destructor();
|
|
this._helperBuffer = new ByteArray(size + 1);
|
|
this._dState = BODY;
|
|
}
|
|
break;
|
|
case BODY:
|
|
i = this._helperBuffer.fill(raw, raw.length, i);
|
|
|
|
if (this._helperBuffer.filled()) {
|
|
var ev = factory(this._helperBuffer);
|
|
this._onEvent(ev);
|
|
this._helperBuffer.destructor();
|
|
this._helperBuffer = new ByteArray(4);
|
|
this._dState = SIZE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
"_setId": function(id) {
|
|
if (this._state === CONNECTING) {
|
|
this._id.destructor();
|
|
this._id = id.clone();
|
|
} else {
|
|
throw new Error("An attempt to set id in unexpected time");
|
|
}
|
|
},
|
|
"_setName": function(name) {
|
|
if ((this._state === CONNECTING) && (this._id.valueOf() !== 0)) {
|
|
this._remoteName.destructor();
|
|
this._remoteName = name.clone();
|
|
} else {
|
|
throw new Error("An attempt to set name in unexpected time");
|
|
}
|
|
},
|
|
"_setRemoteName": function() {
|
|
var vc = new Vocabulary();
|
|
vc.insert("command", new String("setName"));
|
|
vc.insert("name", this._name.clone());
|
|
vc.insert("yourName", this._remoteName.clone());
|
|
|
|
var ev = new Event(new Address(), vc, true);
|
|
ev.setSenderId(this._id.clone());
|
|
this.send(ev);
|
|
|
|
ev.destructor();
|
|
}
|
|
});
|
|
|
|
return Socket;
|
|
});
|
|
|
|
var DISCONNECTED = 111;
|
|
var DISCONNECTING = 110;
|
|
var CONNECTING = 101;
|
|
var CONNECTED = 100;
|
|
|
|
var SIZE = 11;
|
|
var BODY = 10;
|
|
})();
|