Thomas Vachuska

Deprecating old web-socket stuff and adding ability for client-side message hand…

…ler registration. Failover still to be done and same for the async hooks.

Change-Id: I6029c91eb1a04e01401e495b9673ddaea728e215
...@@ -31,6 +31,7 @@ import java.util.TimerTask; ...@@ -31,6 +31,7 @@ import java.util.TimerTask;
31 /** 31 /**
32 * Web socket servlet capable of creating various sockets for the user interface. 32 * Web socket servlet capable of creating various sockets for the user interface.
33 */ 33 */
34 +@Deprecated
34 public class GuiWebSocketServlet extends WebSocketServlet { 35 public class GuiWebSocketServlet extends WebSocketServlet {
35 36
36 private static final long PING_DELAY_MS = 5000; 37 private static final long PING_DELAY_MS = 5000;
......
...@@ -98,6 +98,7 @@ import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED; ...@@ -98,6 +98,7 @@ import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED;
98 /** 98 /**
99 * Facility for creating messages bound for the topology viewer. 99 * Facility for creating messages bound for the topology viewer.
100 */ 100 */
101 +@Deprecated
101 public abstract class TopologyViewMessages { 102 public abstract class TopologyViewMessages {
102 103
103 protected static final Logger log = LoggerFactory.getLogger(TopologyViewMessages.class); 104 protected static final Logger log = LoggerFactory.getLogger(TopologyViewMessages.class);
......
...@@ -77,6 +77,7 @@ import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED; ...@@ -77,6 +77,7 @@ import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
77 /** 77 /**
78 * Web socket capable of interacting with the GUI topology view. 78 * Web socket capable of interacting with the GUI topology view.
79 */ 79 */
80 +@Deprecated
80 public class TopologyViewWebSocket 81 public class TopologyViewWebSocket
81 extends TopologyViewMessages 82 extends TopologyViewMessages
82 implements WebSocket.OnTextMessage, WebSocket.OnControl { 83 implements WebSocket.OnTextMessage, WebSocket.OnControl {
......
...@@ -59,7 +59,7 @@ public class UiExtensionManager implements UiExtensionService { ...@@ -59,7 +59,7 @@ public class UiExtensionManager implements UiExtensionService {
59 List<UiView> coreViews = of(new UiView("sample", "Sample"), 59 List<UiView> coreViews = of(new UiView("sample", "Sample"),
60 new UiView("topo", "Topology View"), 60 new UiView("topo", "Topology View"),
61 new UiView("device", "Devices")); 61 new UiView("device", "Devices"));
62 - UiMessageHandlerFactory messageHandlerFactory = null; 62 + UiMessageHandlerFactory messageHandlerFactory = () -> ImmutableList.of(new TopologyViewMessageHandler());
63 return new UiExtension(coreViews, messageHandlerFactory, "core", 63 return new UiExtension(coreViews, messageHandlerFactory, "core",
64 UiExtensionManager.class.getClassLoader()); 64 UiExtensionManager.class.getClassLoader());
65 } 65 }
......
...@@ -22,6 +22,7 @@ import org.onlab.osgi.ServiceDirectory; ...@@ -22,6 +22,7 @@ import org.onlab.osgi.ServiceDirectory;
22 import org.onosproject.ui.UiConnection; 22 import org.onosproject.ui.UiConnection;
23 import org.onosproject.ui.UiExtensionService; 23 import org.onosproject.ui.UiExtensionService;
24 import org.onosproject.ui.UiMessageHandler; 24 import org.onosproject.ui.UiMessageHandler;
25 +import org.onosproject.ui.UiMessageHandlerFactory;
25 import org.slf4j.Logger; 26 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory; 27 import org.slf4j.LoggerFactory;
27 28
...@@ -117,7 +118,7 @@ public class UiWebSocket ...@@ -117,7 +118,7 @@ public class UiWebSocket
117 lastActive = System.currentTimeMillis(); 118 lastActive = System.currentTimeMillis();
118 try { 119 try {
119 ObjectNode message = (ObjectNode) mapper.reader().readTree(data); 120 ObjectNode message = (ObjectNode) mapper.reader().readTree(data);
120 - String type = message.path("type").asText("unknown"); 121 + String type = message.path("event").asText("unknown");
121 UiMessageHandler handler = handlers.get(type); 122 UiMessageHandler handler = handlers.get(type);
122 if (handler != null) { 123 if (handler != null) {
123 handler.process(message); 124 handler.process(message);
...@@ -146,10 +147,15 @@ public class UiWebSocket ...@@ -146,10 +147,15 @@ public class UiWebSocket
146 private void createHandlers() { 147 private void createHandlers() {
147 handlers = new HashMap<>(); 148 handlers = new HashMap<>();
148 UiExtensionService service = directory.get(UiExtensionService.class); 149 UiExtensionService service = directory.get(UiExtensionService.class);
149 - service.getExtensions().forEach(ext -> ext.messageHandlerFactory().newHandlers().forEach(handler -> { 150 + service.getExtensions().forEach(ext -> {
150 - handler.init(this, directory); 151 + UiMessageHandlerFactory factory = ext.messageHandlerFactory();
151 - handler.messageTypes().forEach(type -> handlers.put(type, handler)); 152 + if (factory != null) {
152 - })); 153 + factory.newHandlers().forEach(handler -> {
154 + handler.init(this, directory);
155 + handler.messageTypes().forEach(type -> handlers.put(type, handler));
156 + });
157 + }
158 + });
153 } 159 }
154 160
155 // Destroys message handlers. 161 // Destroys message handlers.
......
...@@ -151,12 +151,24 @@ ...@@ -151,12 +151,24 @@
151 151
152 <servlet> 152 <servlet>
153 <servlet-name>Web Socket Service</servlet-name> 153 <servlet-name>Web Socket Service</servlet-name>
154 - <servlet-class>org.onosproject.ui.impl.GuiWebSocketServlet</servlet-class> 154 + <servlet-class>org.onosproject.ui.impl.UiWebSocketServlet</servlet-class>
155 <load-on-startup>2</load-on-startup> 155 <load-on-startup>2</load-on-startup>
156 </servlet> 156 </servlet>
157 157
158 <servlet-mapping> 158 <servlet-mapping>
159 <servlet-name>Web Socket Service</servlet-name> 159 <servlet-name>Web Socket Service</servlet-name>
160 + <url-pattern>/websock/*</url-pattern>
161 + </servlet-mapping>
162 +
163 +
164 + <servlet>
165 + <servlet-name>Legacy Web Socket Service</servlet-name>
166 + <servlet-class>org.onosproject.ui.impl.GuiWebSocketServlet</servlet-class>
167 + <load-on-startup>2</load-on-startup>
168 + </servlet>
169 +
170 + <servlet-mapping>
171 + <servlet-name>Legacy Web Socket Service</servlet-name>
160 <url-pattern>/ws/*</url-pattern> 172 <url-pattern>/ws/*</url-pattern>
161 </servlet-mapping> 173 </servlet-mapping>
162 174
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
22 22
23 var uiContext = '/onos/ui/', 23 var uiContext = '/onos/ui/',
24 rsSuffix = uiContext + 'rs/', 24 rsSuffix = uiContext + 'rs/',
25 - wsSuffix = uiContext + 'ws/'; 25 + wsSuffix = uiContext + 'websock/';
26 26
27 angular.module('onosRemote') 27 angular.module('onosRemote')
28 .factory('UrlFnService', ['$location', function ($loc) { 28 .factory('UrlFnService', ['$location', function ($loc) {
......
...@@ -20,62 +20,105 @@ ...@@ -20,62 +20,105 @@
20 (function () { 20 (function () {
21 'use strict'; 21 'use strict';
22 22
23 - var fs; 23 + // injected refs
24 + var fs, $log;
24 25
25 - function fnOpen(f) { 26 + // internal state
26 - // wrap the onOpen function; we will handle any housekeeping here... 27 + var ws, sws, sid = 0,
27 - if (!fs.isF(f)) { 28 + handlers = {};
28 - return null; 29 +
30 + function resetSid() {
31 + sid = 0;
32 + }
33 +
34 + // Binds the specified message handlers.
35 + function bindHandlers(handlerMap) {
36 + var m = d3.map(handlerMap),
37 + dups = [];
38 +
39 + m.forEach(function (key, value) {
40 + var fn = fs.isF(value[key]);
41 + if (!fn) {
42 + $log.warn(key + ' binding not a function on ' + value);
43 + return;
44 + }
45 +
46 + if (handlers[key]) {
47 + dups.push(key);
48 + } else {
49 + handlers[key] = fn;
50 + }
51 + });
52 + if (dups.length) {
53 + $log.warn('duplicate bindings ignored:', dups);
29 } 54 }
55 + }
30 56
31 - return function (openEvent) { 57 + // Unbinds the specified message handlers.
32 - // NOTE: nothing worth passing to the caller? 58 + function unbindHandlers(handlerMap) {
33 - f(); 59 + var m = d3.map(handlerMap);
34 - }; 60 + m.forEach(function (key) {
61 + delete handlers[key];
62 + });
35 } 63 }
36 64
37 - function fnMessage(f) { 65 + // Formulates an event message and sends it via the shared web-socket.
38 - // wrap the onMessage function; we will attempt to decode the 66 + function sendEvent(evType, payload) {
39 - // message event payload as JSON and pass that in... 67 + var p = payload || {};
40 - if (!fs.isF(f)) { 68 + if (sws) {
41 - return null; 69 + $log.debug(' *Tx* >> ', evType, payload);
70 + sws.send({
71 + event: evType,
72 + sid: ++sid,
73 + payload: p
74 + });
75 + } else {
76 + $log.warn('sendEvent: no websocket open:', evType, payload);
42 } 77 }
78 + }
43 79
44 - return function (msgEvent) { 80 +
45 - var ev; 81 + // Handles the specified message using handler bindings.
46 - try { 82 + function handleMessage(msgEvent) {
47 - ev = JSON.parse(msgEvent.data); 83 + var ev;
48 - } catch (e) { 84 + try {
49 - ev = { 85 + ev = JSON.parse(msgEvent.data);
50 - error: 'Failed to parse JSON', 86 + $log.debug(' *Rx* >> ', ev.event, ev.payload);
51 - e: e 87 + dispatchToHandler(ev);
52 - }; 88 + } catch (e) {
53 - } 89 + $log.error('message is not valid JSON', msgEvent);
54 - f(ev); 90 + }
55 - };
56 } 91 }
57 92
58 - function fnClose(f) { 93 + // Dispatches the message to the appropriate handler.
59 - // wrap the onClose function; we will handle any parameters to the 94 + function dispatchToHandler(event) {
60 - // close event here... 95 + var handler = handlers[event.event];
61 - if (!fs.isF(f)) { 96 + if (handler) {
62 - return null; 97 + handler(event.payload);
98 + } else {
99 + $log.warn('unhandled event:', event);
63 } 100 }
101 + }
102 +
103 + function handleOpen() {
104 + $log.info('web socket open');
105 + // FIXME: implement calling external hooks
106 + }
64 107
65 - return function (closeEvent) { 108 + function handleClose() {
66 - // NOTE: only seen {reason == ""} so far, nevertheless... 109 + $log.info('web socket closed');
67 - f(closeEvent.reason); 110 + // FIXME: implement reconnect logic
68 - };
69 } 111 }
70 112
71 angular.module('onosRemote') 113 angular.module('onosRemote')
72 .factory('WebSocketService', 114 .factory('WebSocketService',
73 ['$log', '$location', 'UrlFnService', 'FnService', 115 ['$log', '$location', 'UrlFnService', 'FnService',
74 116
75 - function ($log, $loc, ufs, _fs_) { 117 + function (_$log_, $loc, ufs, _fs_) {
76 fs = _fs_; 118 fs = _fs_;
119 + $log = _$log_;
77 120
78 - // creates a web socket for the given path, returning a "handle". 121 + // Creates a web socket for the given path, returning a "handle".
79 // opts contains the event handler callbacks, etc. 122 // opts contains the event handler callbacks, etc.
80 function createWebSocket(path, opts) { 123 function createWebSocket(path, opts) {
81 var o = opts || {}, 124 var o = opts || {},
...@@ -85,8 +128,7 @@ ...@@ -85,8 +128,7 @@
85 meta: { path: fullUrl, ws: null }, 128 meta: { path: fullUrl, ws: null },
86 send: send, 129 send: send,
87 close: close 130 close: close
88 - }, 131 + };
89 - ws;
90 132
91 try { 133 try {
92 ws = new WebSocket(fullUrl); 134 ws = new WebSocket(fullUrl);
...@@ -97,23 +139,21 @@ ...@@ -97,23 +139,21 @@
97 $log.debug('Attempting to open websocket to: ' + fullUrl); 139 $log.debug('Attempting to open websocket to: ' + fullUrl);
98 140
99 if (ws) { 141 if (ws) {
100 - ws.onopen = fnOpen(o.onOpen); 142 + ws.onopen = handleOpen;
101 - ws.onmessage = fnMessage(o.onMessage); 143 + ws.onmessage = handleMessage;
102 - ws.onclose = fnClose(o.onClose); 144 + ws.onclose = handleClose;
103 } 145 }
104 146
105 - // messages are expected to be event objects.. 147 + // Sends a formulated event message via the backing web-socket.
106 function send(ev) { 148 function send(ev) {
107 - if (ev) { 149 + if (ev && ws) {
108 - if (ws) { 150 + ws.send(JSON.stringify(ev));
109 - ws.send(JSON.stringify(ev)); 151 + } else if (!ws) {
110 - } else { 152 + $log.warn('ws.send() no web socket open!', fullUrl, ev);
111 - $log.warn('ws.send() no web socket open!',
112 - fullUrl, ev);
113 - }
114 } 153 }
115 } 154 }
116 155
156 + // Closes the backing web-socket.
117 function close() { 157 function close() {
118 if (ws) { 158 if (ws) {
119 ws.close(); 159 ws.close();
...@@ -122,11 +162,16 @@ ...@@ -122,11 +162,16 @@
122 } 162 }
123 } 163 }
124 164
165 + sws = api; // Make the shared web-socket accessible
125 return api; 166 return api;
126 } 167 }
127 168
128 return { 169 return {
129 - createWebSocket: createWebSocket 170 + resetSid: resetSid,
171 + createWebSocket: createWebSocket,
172 + bindHandlers: bindHandlers,
173 + unbindHandlers: unbindHandlers,
174 + sendEvent: sendEvent
130 }; 175 };
131 }]); 176 }]);
132 177
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
15 */ 15 */
16 16
17 /* 17 /*
18 + DEPRECATED: to be deleted
18 ONOS GUI -- Remote -- Web Socket Event Service 19 ONOS GUI -- Remote -- Web Socket Event Service
19 */ 20 */
20 (function () { 21 (function () {
......
...@@ -263,7 +263,7 @@ ...@@ -263,7 +263,7 @@
263 // Cleanup on destroyed scope.. 263 // Cleanup on destroyed scope..
264 $scope.$on('$destroy', function () { 264 $scope.$on('$destroy', function () {
265 $log.log('OvTopoCtrl is saying Buh-Bye!'); 265 $log.log('OvTopoCtrl is saying Buh-Bye!');
266 - tes.closeSock(); 266 + tes.stop();
267 tps.destroyPanels(); 267 tps.destroyPanels();
268 tis.destroyInst(); 268 tis.destroyInst();
269 tfs.destroyForce(); 269 tfs.destroyForce();
...@@ -291,7 +291,7 @@ ...@@ -291,7 +291,7 @@
291 tfs.initForce(svg, forceG, uplink, dim); 291 tfs.initForce(svg, forceG, uplink, dim);
292 tis.initInst({ showMastership: tfs.showMastership }); 292 tis.initInst({ showMastership: tfs.showMastership });
293 tps.initPanels({ sendEvent: tes.sendEvent }); 293 tps.initPanels({ sendEvent: tes.sendEvent });
294 - tes.openSock(); 294 + tes.start();
295 295
296 $log.log('OvTopoCtrl has been created'); 296 $log.log('OvTopoCtrl has been created');
297 }]); 297 }]);
......
...@@ -27,15 +27,15 @@ ...@@ -27,15 +27,15 @@
27 'use strict'; 27 'use strict';
28 28
29 // injected refs 29 // injected refs
30 - var $log, wss, wes, vs, tps, tis, tfs, tss, tts; 30 + var $log, vs, wss, tps, tis, tfs, tss, tts;
31 31
32 // internal state 32 // internal state
33 - var wsock, evApis; 33 + var handlers;
34 34
35 // ========================== 35 // ==========================
36 36
37 - function bindApis() { 37 + function createHandlers() {
38 - evApis = { 38 + handlers = {
39 showSummary: tps, 39 showSummary: tps,
40 40
41 showDetails: tss, 41 showDetails: tss,
...@@ -58,103 +58,43 @@ ...@@ -58,103 +58,43 @@
58 }; 58 };
59 } 59 }
60 60
61 - var nilApi = {}, 61 + var nilApi = {};
62 - dispatcher = {
63 - handleEvent: function (ev) {
64 - var eid = ev.event,
65 - api = evApis[eid] || nilApi,
66 - eh = api[eid];
67 -
68 - if (eh) {
69 - $log.debug(' << *Rx* ', eid, ev.payload);
70 - eh(ev.payload);
71 - } else {
72 - $log.warn('Unknown event (ignored):', ev);
73 - }
74 - },
75 -
76 - sendEvent: function (evType, payload) {
77 - if (wsock) {
78 - $log.debug(' *Tx* >> ', evType, payload);
79 - wes.sendEvent(wsock, evType, payload);
80 - } else {
81 - $log.warn('sendEvent: no websocket open:', evType, payload);
82 - }
83 - }
84 - };
85 -
86 - // === Web Socket functions ===
87 -
88 - function onWsOpen() {
89 - $log.debug('web socket opened...');
90 - // start by requesting periodic summary data...
91 - dispatcher.sendEvent('requestSummary');
92 - vs.hide();
93 - }
94 -
95 - function onWsMessage(ev) {
96 - dispatcher.handleEvent(ev);
97 - }
98 -
99 - function onWsClose(reason) {
100 - $log.log('web socket closed; reason=', reason);
101 - wsock = null;
102 - vs.lostServer('OvTopoCtrl', [
103 - 'Oops!',
104 - 'Web-socket connection to server closed...',
105 - 'Try refreshing the page.'
106 - ]);
107 - }
108 -
109 - // ==========================
110 62
111 angular.module('ovTopo') 63 angular.module('ovTopo')
112 .factory('TopoEventService', 64 .factory('TopoEventService',
113 - ['$log', '$location', 'WebSocketService', 'WsEventService', 'VeilService', 65 + ['$log', '$location', 'VeilService', 'WebSocketService',
114 'TopoPanelService', 'TopoInstService', 'TopoForceService', 66 'TopoPanelService', 'TopoInstService', 'TopoForceService',
115 'TopoSelectService', 'TopoTrafficService', 67 'TopoSelectService', 'TopoTrafficService',
116 68
117 - function (_$log_, $loc, _wss_, _wes_, _vs_, 69 + function (_$log_, $loc, _vs_, _wss_, _tps_, _tis_, _tfs_, _tss_, _tts_) {
118 - _tps_, _tis_, _tfs_, _tss_, _tts_) {
119 $log = _$log_; 70 $log = _$log_;
120 - wss = _wss_;
121 - wes = _wes_;
122 vs = _vs_; 71 vs = _vs_;
72 + wss = _wss_;
123 tps = _tps_; 73 tps = _tps_;
124 tis = _tis_; 74 tis = _tis_;
125 tfs = _tfs_; 75 tfs = _tfs_;
126 tss = _tss_; 76 tss = _tss_;
127 tts = _tts_; 77 tts = _tts_;
128 78
129 - bindApis(); 79 + createHandlers();
130 -
131 - // TODO: handle "guiSuccessor" functionality (replace host)
132 - // TODO: implement retry on close functionality
133 80
134 - function openSock() { 81 + // FIXME: need to handle async socket open to avoid race
135 - wsock = wss.createWebSocket('topology', { 82 + function start() {
136 - onOpen: onWsOpen, 83 + wss.bindHandlers(handlers);
137 - onMessage: onWsMessage, 84 + wss.sendEvent('topoStart');
138 - onClose: onWsClose, 85 + $log.debug('topo comms started');
139 - wsport: $loc.search().wsport
140 - });
141 - $log.debug('web socket opened:', wsock);
142 } 86 }
143 87
144 - function closeSock() { 88 + function stop() {
145 - var path; 89 + wss.unbindHandlers();
146 - if (wsock) { 90 + wss.sendEvent('topoStop');
147 - path = wsock.meta.path; 91 + $log.debug('topo comms stopped');
148 - wsock.close();
149 - wsock = null;
150 - $log.debug('web socket closed. path:', path);
151 - }
152 } 92 }
153 93
154 return { 94 return {
155 - openSock: openSock, 95 + start: start,
156 - closeSock: closeSock, 96 + stop: stop,
157 - sendEvent: dispatcher.sendEvent 97 + sendEvent: wss.sendEvent
158 }; 98 };
159 }]); 99 }]);
160 }()); 100 }());
......
...@@ -64,10 +64,10 @@ ...@@ -64,10 +64,10 @@
64 .controller('OnosCtrl', [ 64 .controller('OnosCtrl', [
65 '$log', '$route', '$routeParams', '$location', 65 '$log', '$route', '$routeParams', '$location',
66 'KeyService', 'ThemeService', 'GlyphService', 'PanelService', 66 'KeyService', 'ThemeService', 'GlyphService', 'PanelService',
67 - 'FlashService', 'QuickHelpService', 67 + 'FlashService', 'QuickHelpService', 'WebSocketService',
68 68
69 function ($log, $route, $routeParams, $location, 69 function ($log, $route, $routeParams, $location,
70 - ks, ts, gs, ps, flash, qhs) { 70 + ks, ts, gs, ps, flash, qhs, wss) {
71 var self = this; 71 var self = this;
72 72
73 self.$route = $route; 73 self.$route = $route;
...@@ -84,6 +84,13 @@ ...@@ -84,6 +84,13 @@
84 flash.initFlash(); 84 flash.initFlash();
85 qhs.initQuickHelp(); 85 qhs.initQuickHelp();
86 86
87 + // TODO: register handlers for initial messages: instances, settings, etc.
88 +
89 + // TODO: opts?
90 + wss.createWebSocket('core', {
91 + wsport: $location.search().wsport
92 + });
93 +
87 $log.log('OnosCtrl has been created'); 94 $log.log('OnosCtrl has been created');
88 95
89 $log.debug('route: ', self.$route); 96 $log.debug('route: ', self.$route);
......