(function (){'use strict'; // some default values // note that how default values are defined/used may change var defaults = { token: '123456789', api: '/api' }; var CALL = 2; var RETOK = 3; var RETERR = 4; var EVENT = 5; var PROTO1 = "x-afb-ws-json1"; // Definition of the Angular module var AfbClientModule = angular.module('AfbClient', []); // The instanciation of the module AfbClientModule.factory('AfbClient', [ '$location', function ($location) { var refid = $location.host(); var params = $location.search(); return clients[refid] || (client[refid] = new AfbContext(refid, params)); }]); // prototype for handling context by uuid and token function AfbContext(refid, params) { this.refid = refid; this.api = params.api || defaults.api; this.uhttp = params.uhttp || this.api+'/'; this.uws = params.uws || this.api; this.token = params.token || defaults.token; this.uuid = params.uuid; this.ws = null; } AfbContext.prototype = { call: function(method, query) { return getws(this).call(method, query); }, get: function(method, query) { return $http.get(this.uhttp+method, mixtu(this, query)); }, post: function(method, query) { return $http.post(this.uhttp+method, mixtu(this, query)); }, }; function getws(ctxt) { return ctxt.ws || (ctxt.ws = new AfbWebSocket(ctxt)); } function mixtu(ctxt, query) { return ("token" in query) ? query : angular.extend({token:ctxt.token},query); } // prototype for websocket function AfbWebSocket(ctxt) { var protos = [ PROTO1 ]; this.context = ctxt; var url = "ws:" + ctxt.refid + ctxt.uws; var q = ctxt.uuid ? ("?x-afb-uuid=" + ctxt.uuid) : ""; if (ctxt.token) q = (q ? (q + "&") : "?") + ("x-afb-token=" + ctxt.token); this.pendings = {}; this.awaitens = {}; this.counter = 0; this.ws = new WebSocket(url + q, protos); this.ws.onopen = onopen.bind(this); this.ws.onerror = onerror.bind(this); this.ws.onclose = onclose.bind(this); this.ws.onmessage = onmessage.bind(this); this.onopen = onopen; this.onabort = onabort; } AfbWebSocket.prototype = { call: function(method, query) { return new Promise((function(resolve, reject){ var id = String(this.counter = 4095 & (this.counter + 1)); while (id in this.pendings) id = String(this.counter = 4095 & (this.counter + 1)); this.pendings[id] = [ resolve, reject ]; var arr = [CALL, id, method, request ]; var tok = this.context.token; if (tok) arr.push(tok); this.ws.send(angular.toJson(arr, 0)); }).bind(this)); }, addEvent: function (name, handler) { (this.awaitens[name] || (this.awaitens[name] = [])).push(handler); }, removeEvent: function (name, handler) { var a = this.awaitens[name]; if (a) { var i = a.indexOf(handler); if (i >= 0) a.splice(i, 1); } } }; function onmessage(ev) { var obj = angular.fromJson(ev.data); var id = obj[1]; var ans = obj[2]; if (obj[3]) this.context.token = obj[3]; switch (obj[0]) { case RETOK: reply(this.pendings, id, ans, 0); break; case RETERR: reply(this.pendings, id, ans, 1); break; case EVENT: fire(this.awaitens, id, ans); break; } } function fire(awaitens, name, data) { var a = awaitens[name]; if (a) a.forEach(function(handler){handler(data);}); var i = name.indexOf("/"); if (i >= 0) { a = awaitens[name.substring(0,i)]; if (a) a.forEach(function(handler){handler(data);}); } a = awaitens["*"]; if (a) a.forEach(function(handler){handler(data);}); } function reply(pendings, id, ans, offset) { if (id in pendings) { var p = pendings[id]; delete pendings[id]; var f = p[offset]; if (f) f(ans); } } AFB_websocket = function(onopen, onabort) { } function onerror(event) { var f = this.onabort; if (f) { delete this.onopen; delete this.onabort; f && f(this); } this.onerror && this.onerror(this); } function onopen(event) { var f = this.onopen; delete this.onopen; delete this.onabort; f && f(this); } function onclose(event) { for (var id in this.pendings) { var ferr = this.pendings[id].onerror; ferr && ferr(null, this); } this.pendings = {}; this.onclose && this.onclose(); } function close() { this.ws.close(); } function call(method, request) { } /* // Factory is a singleton and share its context within all instances. AfbClientModule.factory('AppCall', function ($http, AppConfig, $log) { var myCalls = { get : function(plugin, action, query, callback) { if (!query.token) query.token = AppConfig.session.token; // add token to provided query $http.get('/api/' + plugin + '/' + action , {params: query}).then (callback, callback); } }; return myCalls; }); */ })();