3 title: WebSocket protocol x-afb-ws-json1
5 https://git.automotivelinux.org/src/app-framework-binder/plain/docs/protocol-x-afb-ws-json1.md?h=master
8 <!-- WARNING: This file is generated by fetch_docs.js using /home/boron/Documents/AGL/docs-webtemplate/site/_data/tocs/apis_services/master/app-framework-binder-developer-guides-api-services-book.yml -->
10 # The websocket protocol x-afb-ws-json1
12 The WebSocket protocol *x-afb-ws-json1* is used to communicate between
13 an application and a binder. It allows access to all registered apis
16 This protocol is inspired from the protocol **OCPP - SRPC** as described for
18 [OCPP transport specification - SRPC over WebSocket](http://www.gir.fr/ocppjs/ocpp_srpc_spec.shtml).
20 The registration to the IANA is still to be done, see:
21 [WebSocket Protocol Registries](https://www.iana.org/assignments/websocket/websocket.xml)
23 This document gives a short description of the protocol *x-afb-ws-json1*.
24 A more formal description has to be done.
28 The protocol is intended to be symmetric. It allows:
30 - to CALL a remote procedure that returns a result
31 - to push and receive EVENT
35 Valid messages are made of *text* frames that are all valid JSON.
42 [ 2, ID, PROCN, ARGS ]
43 [ 2, ID, PROCN, ARGS, TOKEN ]
46 Replies (3: OK, 4: ERROR):
61 | Field | Type | Description
62 |-------|--------|------------------
63 | ID | string | A string that identifies the call. A reply to that call use the ID of the CALL.
64 | PROCN | string | The procedure name to call of the form "api/verb"
65 | ARGS | any | Any argument to pass to the call (see afb_req_json that returns it)
66 | RESP | any | The response to the call
67 | TOKEN | string | The authorisation token
68 | EVTN | string | Name of the event in the form "api/event"
69 | OBJ | any | The companion object of the event
71 Below, an example of exchange:
74 C->S: [2,"156","hello/ping",null]
75 S->C: [3,"156",{"response":"Some String","jtype":"afb-reply","request":{"status":"success","info":"Ping Binder Daemon tag=pingSample count=1 query=\"null\"","uuid":"ec30120c-6997-4529-9d63-c0de0cce56c0"}}]
82 Removal of token returning. The replies
85 [ 3, ID, RESP, TOKEN ]
86 [ 4, ID, RESP, TOKEN ]
89 are removed from the specification.
93 Here are the planned extensions:
95 - add binary messages with cbor data
96 - add calls with unstructured replies
98 This could be implemented by extending the current protocol or by
99 allowing the binder to accept either protocol including the new ones.
101 ## Javascript implementation
103 The file **AFB.js** is a javascript implementation of the protocol.
109 * Copyright (C) 2017-2019 "IoT.bzh"
110 * Author: José Bollo <jose.bollo@iot.bzh>
112 * Licensed under the Apache License, Version 2.0 (the "License");
113 * you may not use this file except in compliance with the License.
114 * You may obtain a copy of the License at
116 * http://www.apache.org/licenses/LICENSE-2.0
118 * Unless required by applicable law or agreed to in writing, software
119 * distributed under the License is distributed on an "AS IS" BASIS,
120 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
121 * See the License for the specific language governing permissions and
122 * limitations under the License.
124 AFB = function(base, initialtoken){
126 if (typeof base != "object")
127 base = { base: base, token: initialtoken };
130 base: base.base || "api",
131 token: base.token || initialtoken || "HELLO",
132 host: base.host || window.location.host,
133 url: base.url || undefined
136 var urlws = initial.url || "ws://"+initial.host+"/"+initial.base;
138 /*********************************************/
140 /**** AFB_context ****/
142 /*********************************************/
145 var UUID = undefined;
146 var TOKEN = initial.token;
148 var context = function(token, uuid) {
153 context.prototype = {
154 get token() {return TOKEN;},
155 set token(tok) {if(tok) TOKEN=tok;},
156 get uuid() {return UUID;},
157 set uuid(id) {if(id) UUID=id;}
160 AFB_context = new context();
162 /*********************************************/
164 /**** AFB_websocket ****/
166 /*********************************************/
174 var PROTO1 = "x-afb-ws-json1";
176 AFB_websocket = function(on_open, on_abort) {
178 if (AFB_context.token) {
179 u = u + '?x-afb-token=' + AFB_context.token;
180 if (AFB_context.uuid)
181 u = u + '&x-afb-uuid=' + AFB_context.uuid;
183 this.ws = new WebSocket(u, [ PROTO1 ]);
188 this.ws.onopen = onopen.bind(this);
189 this.ws.onerror = onerror.bind(this);
190 this.ws.onclose = onclose.bind(this);
191 this.ws.onmessage = onmessage.bind(this);
192 this.onopen = on_open;
193 this.onabort = on_abort;
196 function onerror(event) {
197 var f = this.onabort;
203 this.onerror && this.onerror(this);
206 function onopen(event) {
213 function onclose(event) {
214 for (var id in this.pendings) {
215 try { this.pendings[id][1](); } catch (x) {/*TODO?*/}
218 this.onclose && this.onclose();
221 function fire(awaitens, name, data) {
222 var a = awaitens[name];
224 a.forEach(function(handler){handler(data);});
225 var i = name.indexOf("/");
227 a = awaitens[name.substring(0,i)];
229 a.forEach(function(handler){handler(data);});
233 a.forEach(function(handler){handler(data);});
236 function reply(pendings, id, ans, offset) {
237 if (id in pendings) {
238 var p = pendings[id];
240 try { p[offset](ans); } catch (x) {/*TODO?*/}
244 function onmessage(event) {
245 var obj = JSON.parse(event.data);
249 AFB_context.token = obj[3];
252 reply(this.pendings, id, ans, 0);
255 reply(this.pendings, id, ans, 1);
259 fire(this.awaitens, id, ans);
271 this.onabort = function(){};
274 function call(method, request, callid) {
275 return new Promise((function(resolve, reject){
279 if (id in this.pendings)
280 throw new Error("pending callid("+id+") exists");
283 id = String(this.counter = 4095 & (this.counter + 1));
284 } while (id in this.pendings);
286 this.pendings[id] = [ resolve, reject ];
287 arr = [CALL, id, method, request ];
288 if (AFB_context.token) arr.push(AFB_context.token);
289 this.ws.send(JSON.stringify(arr));
293 function onevent(name, handler) {
295 var list = this.awaitens[id] || (this.awaitens[id] = []);
299 AFB_websocket.prototype = {
305 /*********************************************/
309 /*********************************************/
311 context: AFB_context,