3db1ad591eb602ea6880a503d36fba614b6c8869
[src/app-framework-binder.git] / test / AfbAngular.js
1 (function (){'use strict';
2
3   // some default values
4   // note that how default values are defined/used may change
5   var defaults = {
6       token: '123456789',
7       api: '/api'
8     };
9
10   var CALL = 2;
11   var RETOK = 3;
12   var RETERR = 4;
13   var EVENT = 5;
14
15   var PROTO1 = "x-afb-ws-json1";
16
17   // Definition of the Angular module
18   var AfbClientModule = angular.module('AfbClient', []);
19
20   // The instanciation of the module
21   AfbClientModule.factory('AfbClient', [ '$location', function ($location) {
22     var refid = $location.host();
23     var params = $location.search();
24     return clients[refid] || (client[refid] = new AfbContext(refid, params));
25   }]);
26
27   // prototype for handling context by uuid and token
28   function AfbContext(refid, params) {
29     this.refid = refid;
30     this.api = params.api || defaults.api;
31     this.uhttp = params.uhttp || this.api+'/';
32     this.uws = params.uws || this.api;
33     this.token = params.token || defaults.token;
34     this.uuid = params.uuid;
35     this.ws = null;
36   }
37
38   AfbContext.prototype = {
39     call: function(method, query) { return getws(this).call(method, query); },
40     get: function(method, query) { return $http.get(this.uhttp+method, mixtu(this, query)); },
41     post: function(method, query) { return $http.post(this.uhttp+method, mixtu(this, query)); },
42   };
43
44   function getws(ctxt) {
45     return ctxt.ws || (ctxt.ws = new AfbWebSocket(ctxt));
46   }
47
48   function mixtu(ctxt, query) {
49     return ("token" in query) ? query : angular.extend({token:ctxt.token},query);
50   }
51
52   // prototype for websocket
53   function AfbWebSocket(ctxt) {
54     var protos = [ PROTO1 ];
55     this.context = ctxt;
56     var url = "ws:" + ctxt.refid + ctxt.uws;
57     var q = ctxt.uuid ? ("?x-afb-uuid=" + ctxt.uuid) : "";
58     if (ctxt.token)
59       q = (q ? (q + "&") : "?") + ("x-afb-token=" + ctxt.token);
60     this.pendings = {};
61     this.awaitens = {};
62     this.counter = 0;
63     this.ws = new WebSocket(url + q, protos);
64     this.ws.onopen = onopen.bind(this);
65     this.ws.onerror = onerror.bind(this);
66     this.ws.onclose = onclose.bind(this);
67     this.ws.onmessage = onmessage.bind(this);
68     this.onopen = onopen;
69     this.onabort = onabort;
70   }
71
72   AfbWebSocket.prototype = {
73     call: function(method, query) {
74         return new Promise((function(resolve, reject){
75           var id = String(this.counter = 4095 & (this.counter + 1));
76           while (id in this.pendings) id = String(this.counter = 4095 & (this.counter + 1));
77           this.pendings[id] = [ resolve, reject ];
78           var arr = [CALL, id, method, request ];
79           var tok = this.context.token; if (tok) arr.push(tok);
80           this.ws.send(angular.toJson(arr, 0));
81         }).bind(this));
82       },
83     addEvent: function (name, handler) {
84         (this.awaitens[name] || (this.awaitens[name] = [])).push(handler);
85       },
86     removeEvent: function (name, handler) {
87         var a = this.awaitens[name];
88         if (a) {
89           var i = a.indexOf(handler);
90           if (i >= 0) a.splice(i, 1);
91         }
92       }
93
94   };
95
96   function onmessage(ev) {
97     var obj = angular.fromJson(ev.data);
98     var id = obj[1];
99     var ans = obj[2];
100     if (obj[3])
101       this.context.token = obj[3];
102     switch (obj[0]) {
103     case RETOK:  reply(this.pendings, id, ans, 0); break; 
104     case RETERR: reply(this.pendings, id, ans, 1); break; 
105     case EVENT:   fire(this.awaitens, id, ans);    break; 
106
107     }
108   }
109
110   function fire(awaitens, name, data) {
111     var a = awaitens[name];
112     if (a) a.forEach(function(handler){handler(data);});
113     var i = name.indexOf("/");
114     if (i >= 0) {
115       a = awaitens[name.substring(0,i)];
116       if (a) a.forEach(function(handler){handler(data);});
117     }
118     a = awaitens["*"];
119     if (a) a.forEach(function(handler){handler(data);});
120   }
121
122   function reply(pendings, id, ans, offset) {
123     if (id in pendings) {
124       var p = pendings[id];
125       delete pendings[id];
126       var f = p[offset];
127       if (f) f(ans);
128     }
129   }
130
131
132
133
134
135
136
137
138
139
140         AFB_websocket = function(onopen, onabort) {
141         }
142
143         function onerror(event) {
144                 var f = this.onabort;
145                 if (f) {
146                         delete this.onopen;
147                         delete this.onabort;
148                         f && f(this);
149                 }
150                 this.onerror && this.onerror(this);
151         }
152
153         function onopen(event) {
154                 var f = this.onopen;
155                 delete this.onopen;
156                 delete this.onabort;
157                 f && f(this);
158         }
159
160         function onclose(event) {
161                 for (var id in this.pendings) {
162                         var ferr = this.pendings[id].onerror;
163                         ferr && ferr(null, this);
164                 }
165                 this.pendings = {};
166                 this.onclose && this.onclose();
167         }
168
169         function close() {
170                 this.ws.close();
171         }
172
173         function call(method, request) {
174         }
175
176 /*
177   // Factory is a singleton and share its context within all instances.
178   AfbClientModule.factory('AppCall', function ($http, AppConfig, $log) {
179     var myCalls = {
180       get : function(plugin, action, query, callback) {
181         if (!query.token) query.token = AppConfig.session.token; // add token to provided query
182         $http.get('/api/' + plugin + '/' + action , {params: query}).then (callback, callback);
183       }
184     };
185     return myCalls;
186   });
187 */
188
189
190
191
192
193 })();