mirror of
https://github.com/omniscale/magnacarto.git
synced 2025-06-16 13:00:22 +02:00
379 lines
No EOL
11 KiB
JavaScript
379 lines
No EOL
11 KiB
JavaScript
'use strict';
|
|
|
|
(function () {
|
|
/**
|
|
* @ngdoc provider
|
|
* @name $websocketProvider
|
|
* @module ngWebsocket
|
|
* @description
|
|
* HTML5 WebSocket provider for AngularJS
|
|
*/
|
|
function $websocketProvider () {
|
|
var wsp = this;
|
|
|
|
wsp.$$config = {
|
|
lazy: false,
|
|
reconnect: true,
|
|
reconnectInterval: 2000,
|
|
mock: false,
|
|
enqueue: false,
|
|
protocols: null
|
|
};
|
|
|
|
wsp.$setup = function (cfg) {
|
|
cfg = cfg || {};
|
|
wsp.$$config = angular.extend({}, wsp.$$config, cfg);
|
|
|
|
return wsp;
|
|
};
|
|
|
|
wsp.$get = ['$http', function ($http) {
|
|
return new $websocketService(wsp.$$config, $http);
|
|
}];
|
|
}
|
|
|
|
/**
|
|
* @ngdoc service
|
|
* @name $websocketService
|
|
* @module ngWebsocketService
|
|
* @description
|
|
* HTML5 Websocket service for AngularJS
|
|
*/
|
|
function $websocketService (cfg, $http) {
|
|
var wss = this;
|
|
|
|
wss.$$websocketList = {};
|
|
wss.$$config = cfg || {};
|
|
|
|
wss.$get = function (url) {
|
|
return wss.$$websocketList[url];
|
|
};
|
|
|
|
wss.$new = function (cfg) {
|
|
cfg = cfg || {};
|
|
|
|
// Url or url + protocols initialization
|
|
if (typeof cfg === 'string') {
|
|
cfg = {url: cfg};
|
|
|
|
// url + protocols
|
|
if (arguments.length > 1) {
|
|
if (typeof arguments[1] === 'string' && arguments[1].length > 0) cfg.protocols = [arguments[1]];
|
|
else if (typeof arguments[1] === 'object' && arguments[1].length > 0) cfg.protocols = arguments[1];
|
|
}
|
|
}
|
|
|
|
// If the websocket already exists, return that instance
|
|
var ws = wss.$get(cfg.url);
|
|
if (typeof ws === 'undefined') {
|
|
var wsCfg = angular.extend({}, wss.$$config, cfg);
|
|
|
|
ws = new $websocket(wsCfg, $http);
|
|
wss.$$websocketList[wsCfg.url] = ws;
|
|
}
|
|
|
|
return ws;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @ngdoc class
|
|
* @name $websocket
|
|
* @module ngWebsocket
|
|
* @description
|
|
* HTML5 Websocket wrapper class for AngularJS
|
|
*/
|
|
function $websocket (cfg, $http) {
|
|
var me = this;
|
|
|
|
if (typeof cfg === 'undefined' || (typeof cfg === 'object' && typeof cfg.url === 'undefined')) throw new Error('An url must be specified for WebSocket');
|
|
|
|
me.$$eventMap = {};
|
|
me.$$ws = undefined;
|
|
me.$$reconnectTask = undefined;
|
|
me.$$reconnectCopy = true;
|
|
me.$$queue = [];
|
|
me.$$config = {
|
|
url: undefined,
|
|
lazy: false,
|
|
reconnect: true,
|
|
reconnectInterval: 2000,
|
|
enqueue: false,
|
|
mock: false,
|
|
protocols: null
|
|
};
|
|
|
|
me.$$fireEvent = function () {
|
|
var args = [];
|
|
|
|
Array.prototype.push.apply(args, arguments);
|
|
|
|
var event = args.shift(),
|
|
handlers = me.$$eventMap[event];
|
|
|
|
if (typeof handlers !== 'undefined') {
|
|
for (var i = 0; i < handlers.length; i++) {
|
|
if (typeof handlers[i] === 'function') handlers[i].apply(me, args);
|
|
}
|
|
}
|
|
};
|
|
|
|
me.$$init = function (cfg) {
|
|
|
|
if (cfg.mock) {
|
|
me.$$ws = new $$mockWebsocket(cfg.mock, $http);
|
|
}
|
|
else if (cfg.protocols) {
|
|
me.$$ws = new WebSocket(cfg.url, cfg.protocols);
|
|
}
|
|
else {
|
|
me.$$ws = new WebSocket(cfg.url);
|
|
}
|
|
|
|
me.$$ws.onmessage = function (message) {
|
|
try {
|
|
var decoded = JSON.parse(message.data);
|
|
me.$$fireEvent(decoded.event, decoded.data);
|
|
me.$$fireEvent('$message', decoded);
|
|
}
|
|
catch (err) {
|
|
me.$$fireEvent('$message', message.data);
|
|
}
|
|
};
|
|
|
|
me.$$ws.onerror = function (error) {
|
|
me.$$fireEvent('$error', error);
|
|
};
|
|
|
|
me.$$ws.onopen = function () {
|
|
// Clear the reconnect task if exists
|
|
if (me.$$reconnectTask) {
|
|
clearInterval(me.$$reconnectTask);
|
|
delete me.$$reconnectTask;
|
|
}
|
|
|
|
// Flush the message queue
|
|
if (me.$$config.enqueue && me.$$queue.length > 0) {
|
|
while (me.$$queue.length > 0) {
|
|
if (me.$ready()) me.$$send(me.$$queue.shift());
|
|
else break;
|
|
}
|
|
}
|
|
|
|
me.$$fireEvent('$open');
|
|
};
|
|
|
|
me.$$ws.onclose = function () {
|
|
// Activate the reconnect task
|
|
if (me.$$config.reconnect && !me.$$reconnectTask) {
|
|
me.$$reconnectTask = setInterval(function () {
|
|
if (me.$status() === me.$CLOSED) me.$open();
|
|
}, me.$$config.reconnectInterval);
|
|
}
|
|
|
|
me.$$fireEvent('$close');
|
|
};
|
|
|
|
return me;
|
|
};
|
|
|
|
me.$CONNECTING = 0;
|
|
me.$OPEN = 1;
|
|
me.$CLOSING = 2;
|
|
me.$CLOSED = 3;
|
|
|
|
// TODO: it doesn't refresh the view (maybe $apply on something?)
|
|
/*me.$bind = function (event, scope, model) {
|
|
me.$on(event, function (message) {
|
|
model = message;
|
|
scope.$apply();
|
|
});
|
|
};*/
|
|
|
|
me.$on = function () {
|
|
var handlers = [];
|
|
|
|
Array.prototype.push.apply(handlers, arguments);
|
|
|
|
var event = handlers.shift();
|
|
if (typeof event !== 'string' || handlers.length === 0) throw new Error('$on accept two parameters at least: a String and a Function or an array of Functions');
|
|
|
|
me.$$eventMap[event] = me.$$eventMap[event] || [];
|
|
for (var i = 0; i < handlers.length; i++) {
|
|
me.$$eventMap[event].push(handlers[i]);
|
|
}
|
|
|
|
return me;
|
|
};
|
|
|
|
me.$un = function (event) {
|
|
if (typeof event !== 'string') throw new Error('$un needs a String representing an event.');
|
|
|
|
if (typeof me.$$eventMap[event] !== 'undefined') delete me.$$eventMap[event];
|
|
|
|
return me;
|
|
};
|
|
|
|
me.$$send = function (message) {
|
|
if (me.$ready()) me.$$ws.send(JSON.stringify(message));
|
|
else if (me.$$config.enqueue) me.$$queue.push(message);
|
|
};
|
|
|
|
me.$emit = function (event, data) {
|
|
if (typeof event !== 'string') throw new Error('$emit needs two parameter: a String and a Object or a String');
|
|
|
|
var message = {
|
|
event: event,
|
|
data: data
|
|
};
|
|
|
|
me.$$send(message);
|
|
|
|
return me;
|
|
};
|
|
|
|
me.$open = function () {
|
|
me.$$config.reconnect = me.$$reconnectCopy;
|
|
|
|
if (me.$status() !== me.$OPEN) me.$$init(me.$$config);
|
|
return me;
|
|
};
|
|
|
|
me.$close = function () {
|
|
if (me.$status() !== me.$CLOSED) me.$$ws.close();
|
|
|
|
if (me.$$reconnectTask) {
|
|
clearInterval(me.$$reconnectTask);
|
|
delete me.$$reconnectTask;
|
|
}
|
|
|
|
me.$$config.reconnect = false;
|
|
|
|
return me;
|
|
};
|
|
|
|
me.$status = function () {
|
|
if (typeof me.$$ws === 'undefined') return me.$CLOSED;
|
|
else return me.$$ws.readyState;
|
|
};
|
|
|
|
me.$ready = function () {
|
|
return me.$status() === me.$OPEN;
|
|
};
|
|
|
|
me.$mockup = function () {
|
|
return me.$$config.mock;
|
|
};
|
|
|
|
// setup
|
|
me.$$config = angular.extend({}, me.$$config, cfg);
|
|
me.$$reconnectCopy = me.$$config.reconnect;
|
|
|
|
if (!me.$$config.lazy) me.$$init(me.$$config);
|
|
|
|
return me;
|
|
}
|
|
|
|
function $$mockWebsocket (cfg, $http) {
|
|
cfg = cfg || {};
|
|
|
|
var me = this,
|
|
openTimeout = cfg.openTimeout || 500,
|
|
closeTimeout = cfg.closeTimeout || 1000,
|
|
messageInterval = cfg.messageInterval || 2000,
|
|
fixtures = cfg.fixtures || {},
|
|
messageQueue = [];
|
|
|
|
me.CONNECTING = 0;
|
|
me.OPEN = 1;
|
|
me.CLOSING = 2;
|
|
me.CLOSED = 3;
|
|
|
|
me.readyState = me.CONNECTING;
|
|
|
|
me.send = function (message) {
|
|
if (me.readyState === me.OPEN) {
|
|
messageQueue.push(message);
|
|
return me;
|
|
}
|
|
else throw new Error('WebSocket is already in CLOSING or CLOSED state.');
|
|
};
|
|
|
|
me.close = function () {
|
|
if (me.readyState === me.OPEN) {
|
|
me.readyState = me.CLOSING;
|
|
|
|
setTimeout(function () {
|
|
me.readyState = me.CLOSED;
|
|
|
|
me.onclose();
|
|
}, closeTimeout);
|
|
}
|
|
|
|
return me;
|
|
};
|
|
|
|
me.onmessage = function () {};
|
|
me.onerror = function () {};
|
|
me.onopen = function () {};
|
|
me.onclose = function () {};
|
|
|
|
setInterval(function () {
|
|
if (messageQueue.length > 0) {
|
|
var message = messageQueue.shift(),
|
|
msgObj = JSON.parse(message);
|
|
|
|
switch (msgObj.event) {
|
|
case '$close':
|
|
me.close();
|
|
break;
|
|
default:
|
|
// Check for a custom response
|
|
if (typeof fixtures[msgObj.event] !== 'undefined') {
|
|
msgObj.data = fixtures[msgObj.event].data || msgObj.data;
|
|
msgObj.event = fixtures[msgObj.event].event || msgObj.event;
|
|
}
|
|
|
|
message = JSON.stringify(msgObj);
|
|
|
|
me.onmessage({
|
|
data: message
|
|
});
|
|
}
|
|
}
|
|
}, messageInterval);
|
|
|
|
var start = function (fixs) {
|
|
fixs = fixs || {};
|
|
fixs = fixs instanceof Error ? {} : fixs;
|
|
|
|
fixtures = fixs;
|
|
|
|
setTimeout(function () {
|
|
me.readyState = me.OPEN;
|
|
me.onopen();
|
|
}, openTimeout);
|
|
};
|
|
|
|
// Get fixtures from a server or a file if it's a string
|
|
if (typeof fixtures === 'string') {
|
|
$http.get(fixtures)
|
|
.success(start)
|
|
.error(start);
|
|
}
|
|
else start(fixtures);
|
|
|
|
return me;
|
|
}
|
|
|
|
/**
|
|
* @ngdoc module
|
|
* @name $websocket
|
|
* @module ngWebsocket
|
|
* @description
|
|
* HTML5 WebSocket module for AngularJS
|
|
*/
|
|
angular
|
|
.module('ngWebsocket', [])
|
|
.provider('$websocket', $websocketProvider);
|
|
})(); |