Simon Hunt

GUI -- Added websock open listeners mechanism.

- made event handler structure parsing a little cleverer.

Change-Id: I15120dabd0aade28e6ee3680faf96f408aed1450
...@@ -30,10 +30,13 @@ ...@@ -30,10 +30,13 @@
30 sid = 0, // event sequence identifier 30 sid = 0, // event sequence identifier
31 handlers = {}, // event handler bindings 31 handlers = {}, // event handler bindings
32 pendingEvents = [], // events TX'd while socket not up 32 pendingEvents = [], // events TX'd while socket not up
33 + host, // web socket host
33 url, // web socket URL 34 url, // web socket URL
34 clusterNodes = [], // ONOS instances data for failover 35 clusterNodes = [], // ONOS instances data for failover
35 clusterIndex = -1, // the instance to which we are connected 36 clusterIndex = -1, // the instance to which we are connected
36 - connectRetries = 0; 37 + connectRetries = 0, // limit our attempts at reconnecting
38 + openListeners = {}, // registered listeners for websocket open()
39 + nextListenerId = 1; // internal ID for open listeners
37 40
38 // ======================= 41 // =======================
39 // === Bootstrap Handler 42 // === Bootstrap Handler
...@@ -55,7 +58,7 @@ ...@@ -55,7 +58,7 @@
55 // === Web socket callbacks 58 // === Web socket callbacks
56 59
57 function handleOpen() { 60 function handleOpen() {
58 - $log.info('Web socket open'); 61 + $log.info('Web socket open - ', url);
59 vs.hide(); 62 vs.hide();
60 63
61 $log.debug('Sending ' + pendingEvents.length + ' pending event(s)...'); 64 $log.debug('Sending ' + pendingEvents.length + ' pending event(s)...');
...@@ -66,6 +69,7 @@ ...@@ -66,6 +69,7 @@
66 69
67 connectRetries = 0; 70 connectRetries = 0;
68 wsUp = true; 71 wsUp = true;
72 + informListeners(host, url);
69 } 73 }
70 74
71 // Handles the specified (incoming) message using handler bindings. 75 // Handles the specified (incoming) message using handler bindings.
...@@ -78,7 +82,7 @@ ...@@ -78,7 +82,7 @@
78 $log.error('Message.data is not valid JSON', msgEvent.data, e); 82 $log.error('Message.data is not valid JSON', msgEvent.data, e);
79 return; 83 return;
80 } 84 }
81 - $log.debug(' *Rx* >> ', ev.event, ev.payload); 85 + $log.debug(' << *Rx* ', ev.event, ev.payload);
82 86
83 if (h = handlers[ev.event]) { 87 if (h = handlers[ev.event]) {
84 try { 88 try {
...@@ -129,12 +133,17 @@ ...@@ -129,12 +133,17 @@
129 return ip; 133 return ip;
130 } 134 }
131 135
136 + function informListeners(host, url) {
137 + angular.forEach(openListeners, function(lsnr) {
138 + lsnr.cb(host, url);
139 + });
140 + }
141 +
132 function _send(ev) { 142 function _send(ev) {
133 $log.debug(' *Tx* >> ', ev.event, ev.payload); 143 $log.debug(' *Tx* >> ', ev.event, ev.payload);
134 ws.send(JSON.stringify(ev)); 144 ws.send(JSON.stringify(ev));
135 } 145 }
136 146
137 -
138 // =================== 147 // ===================
139 // === API Functions 148 // === API Functions
140 149
...@@ -145,12 +154,14 @@ ...@@ -145,12 +154,14 @@
145 154
146 // Currently supported opts: 155 // Currently supported opts:
147 // wsport: web socket port (other than default 8181) 156 // wsport: web socket port (other than default 8181)
148 - // server: if defined, is the server address to use 157 + // host: if defined, is the host address to use
149 - function createWebSocket(opts, server) { 158 + function createWebSocket(opts, _host_) {
150 var wsport = (opts && opts.wsport) || null; 159 var wsport = (opts && opts.wsport) || null;
160 +
151 webSockOpts = opts; // preserved for future calls 161 webSockOpts = opts; // preserved for future calls
152 162
153 - url = ufs.wsUrl('core', wsport, server); 163 + host = _host_ || $loc.host();
164 + url = ufs.wsUrl('core', wsport, _host_);
154 165
155 $log.debug('Attempting to open websocket to: ' + url); 166 $log.debug('Attempting to open websocket to: ' + url);
156 ws = wsock.newWebSocket(url); 167 ws = wsock.newWebSocket(url);
...@@ -163,15 +174,18 @@ ...@@ -163,15 +174,18 @@
163 return url; 174 return url;
164 } 175 }
165 176
166 - // Binds the specified message handlers. 177 + // Binds the message handlers to their message type (event type) as
167 - // keys are the event IDs 178 + // specified in the given map. Note that keys are the event IDs; values
168 - // values are the API on which the handler function is a property 179 + // are either:
180 + // * the event handler function, or
181 + // * an API object which has an event handler for the key
182 + //
169 function bindHandlers(handlerMap) { 183 function bindHandlers(handlerMap) {
170 var m = d3.map(handlerMap), 184 var m = d3.map(handlerMap),
171 dups = []; 185 dups = [];
172 186
173 m.forEach(function (eventId, api) { 187 m.forEach(function (eventId, api) {
174 - var fn = fs.isF(api[eventId]); 188 + var fn = fs.isF(api) || fs.isF(api[eventId]);
175 if (!fn) { 189 if (!fn) {
176 $log.warn(eventId + ' handler not a function'); 190 $log.warn(eventId + ' handler not a function');
177 return; 191 return;
...@@ -198,6 +212,28 @@ ...@@ -198,6 +212,28 @@
198 }); 212 });
199 } 213 }
200 214
215 + function addOpenListener(callback) {
216 + var id = nextListenerId++,
217 + cb = fs.isF(callback),
218 + o = { id: id, cb: cb };
219 +
220 + if (cb) {
221 + openListeners[id] = o;
222 + } else {
223 + $log.error('WSS.addOpenListener(): callback not a function');
224 + o.error = 'No callback defined';
225 + }
226 + return o;
227 + }
228 +
229 + function removeOpenListener(lsnr) {
230 + var id = lsnr && lsnr.id,
231 + o = openListeners[id];
232 + if (o) {
233 + delete openListeners[id];
234 + }
235 + }
236 +
201 // Formulates an event message and sends it via the web-socket. 237 // Formulates an event message and sends it via the web-socket.
202 // If the websocket is not up yet, we store it in a pending list. 238 // If the websocket is not up yet, we store it in a pending list.
203 function sendEvent(evType, payload) { 239 function sendEvent(evType, payload) {
...@@ -230,17 +266,15 @@ ...@@ -230,17 +266,15 @@
230 wsock = _wsock_; 266 wsock = _wsock_;
231 vs = _vs_; 267 vs = _vs_;
232 268
233 - // TODO: Consider how to simplify handler structure 269 + bindHandlers(builtinHandlers);
234 - // Now it is an object of key -> object that has a method named 'key'.
235 - bindHandlers({
236 - bootstrap: builtinHandlers
237 - });
238 270
239 return { 271 return {
240 resetSid: resetSid, 272 resetSid: resetSid,
241 createWebSocket: createWebSocket, 273 createWebSocket: createWebSocket,
242 bindHandlers: bindHandlers, 274 bindHandlers: bindHandlers,
243 unbindHandlers: unbindHandlers, 275 unbindHandlers: unbindHandlers,
276 + addOpenListener: addOpenListener,
277 + removeOpenListener: removeOpenListener,
244 sendEvent: sendEvent 278 sendEvent: sendEvent
245 }; 279 };
246 } 280 }
......
...@@ -30,7 +30,8 @@ ...@@ -30,7 +30,8 @@
30 var $log, wss, tps, tis, tfs, tss, tts; 30 var $log, wss, tps, tis, tfs, tss, tts;
31 31
32 // internal state 32 // internal state
33 - var handlerMap; 33 + var handlerMap,
34 + openListener;
34 35
35 // ========================== 36 // ==========================
36 37
...@@ -58,6 +59,14 @@ ...@@ -58,6 +59,14 @@
58 }; 59 };
59 } 60 }
60 61
62 + function wsOpen(host, url) {
63 + $log.debug('TOPO: web socket open - cluster node:', host, 'URL:', url);
64 +
65 + // TODO: request "instanceUpdate" events for all instances
66 + // this should give us the updated uiAttached icon placement
67 +
68 + }
69 +
61 angular.module('ovTopo') 70 angular.module('ovTopo')
62 .factory('TopoEventService', 71 .factory('TopoEventService',
63 ['$log', '$location', 'WebSocketService', 72 ['$log', '$location', 'WebSocketService',
...@@ -76,6 +85,7 @@ ...@@ -76,6 +85,7 @@
76 createHandlerMap(); 85 createHandlerMap();
77 86
78 function start() { 87 function start() {
88 + openListener = wss.addOpenListener(wsOpen);
79 wss.bindHandlers(handlerMap); 89 wss.bindHandlers(handlerMap);
80 wss.sendEvent('topoStart'); 90 wss.sendEvent('topoStart');
81 wss.sendEvent('requestSummary'); 91 wss.sendEvent('requestSummary');
...@@ -85,6 +95,8 @@ ...@@ -85,6 +95,8 @@
85 function stop() { 95 function stop() {
86 wss.sendEvent('topoStop'); 96 wss.sendEvent('topoStop');
87 wss.unbindHandlers(handlerMap); 97 wss.unbindHandlers(handlerMap);
98 + wss.removeOpenListener(openListener);
99 + openListener = null;
88 $log.debug('topo comms stopped'); 100 $log.debug('topo comms stopped');
89 } 101 }
90 102
......
...@@ -46,7 +46,7 @@ describe('factory: fw/remote/websocket.js', function () { ...@@ -46,7 +46,7 @@ describe('factory: fw/remote/websocket.js', function () {
46 it('should define api functions', function () { 46 it('should define api functions', function () {
47 expect(fs.areFunctions(wss, [ 47 expect(fs.areFunctions(wss, [
48 'resetSid', 'createWebSocket', 'bindHandlers', 'unbindHandlers', 48 'resetSid', 'createWebSocket', 'bindHandlers', 'unbindHandlers',
49 - 'sendEvent' 49 + 'addOpenListener', 'removeOpenListener', 'sendEvent'
50 ])).toBeTruthy(); 50 ])).toBeTruthy();
51 }); 51 });
52 52
......