blob: 16c1a2b8ca1b16b1a826da3c25d669c65290f366 [file] [log] [blame]
Simon Hunt1e4a0012015-01-21 11:36:08 -08001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 ONOS GUI -- Remote -- Web Socket Service
19 */
20(function () {
21 'use strict';
22
Thomas Vachuska329af532015-03-10 02:08:33 -070023 // injected refs
Simon Hunt20207df2015-03-10 18:30:14 -070024 var $log, $loc, fs, ufs, wsock, vs;
Simon Hunt1e4a0012015-01-21 11:36:08 -080025
Thomas Vachuska329af532015-03-10 02:08:33 -070026 // internal state
Simon Hunt20207df2015-03-10 18:30:14 -070027 var ws = null, // web socket reference
28 wsUp = false, // web socket is good to go
29 sid = 0, // event sequence identifier
30 handlers = {}, // event handler bindings
31 pendingEvents = [], // events TX'd while socket not up
32 url; // web socket URL
Simon Huntacf410b2015-01-23 10:05:48 -080033
Simon Hunt20207df2015-03-10 18:30:14 -070034
35 // ==========================
36 // === Web socket callbacks
37
38 function handleOpen() {
39 $log.info('Web socket open');
40 $log.debug('Sending ' + pendingEvents.length + ' pending event(s)...');
41 pendingEvents.forEach(function (ev) {
42 _send(ev);
43 });
44 pendingEvents = [];
45 wsUp = true;
46 }
47
48 // Handles the specified (incoming) message using handler bindings.
49 function handleMessage(msgEvent) {
50 var ev, h;
51
52 try {
53 ev = JSON.parse(msgEvent.data);
Simon Hunt20207df2015-03-10 18:30:14 -070054 } catch (e) {
Simon Hunt2d16fc82015-03-10 20:19:52 -070055 $log.error('Message.data is not valid JSON', msgEvent.data, e);
56 return;
Simon Hunt20207df2015-03-10 18:30:14 -070057 }
Simon Hunt2d16fc82015-03-10 20:19:52 -070058 $log.debug(' *Rx* >> ', ev.event, ev.payload);
59
60 if (h = handlers[ev.event]) {
61 try {
62 h(ev.payload);
63 } catch (e) {
64 $log.error('Problem handling event:', ev, e);
65 }
66 } else {
67 $log.warn('Unhandled event:', ev);
68 }
69
Simon Hunt20207df2015-03-10 18:30:14 -070070 }
71
72 function handleClose() {
73 $log.info('Web socket closed');
74 wsUp = false;
75
76 // FIXME: implement controller failover logic
77
78 // If no controllers left to contact, show the Veil...
79 vs.show([
80 'Oops!',
81 'Web-socket connection to server closed...',
82 'Try refreshing the page.'
83 ]);
84 }
85
86
87 // ==============================
88 // === Private Helper Functions
89
90 function _send(ev) {
91 $log.debug(' *Tx* >> ', ev.event, ev.payload);
92 ws.send(JSON.stringify(ev));
93 }
94
95
96 // ===================
97 // === API Functions
98
99 // Required for unit tests to set to known state
Thomas Vachuska329af532015-03-10 02:08:33 -0700100 function resetSid() {
101 sid = 0;
Simon Hunt970e7fd2015-01-22 17:46:28 -0800102 }
103
Simon Hunt20207df2015-03-10 18:30:14 -0700104 // Currently supported opts:
105 // wsport: web socket port (other than default 8181)
106 function createWebSocket(opts) {
107 var wsport = (opts && opts.wsport) || null;
108
109 url = ufs.wsUrl('core', wsport);
110
111 $log.debug('Attempting to open websocket to: ' + url);
112 ws = wsock.newWebSocket(url);
113 if (ws) {
114 ws.onopen = handleOpen;
115 ws.onmessage = handleMessage;
116 ws.onclose = handleClose;
117 }
118 // Note: Wsock logs an error if the new WebSocket call fails
Simon Hunt2d16fc82015-03-10 20:19:52 -0700119 return url;
Simon Hunt20207df2015-03-10 18:30:14 -0700120 }
121
Thomas Vachuska329af532015-03-10 02:08:33 -0700122 // Binds the specified message handlers.
Simon Hunt20207df2015-03-10 18:30:14 -0700123 // keys are the event IDs
124 // values are the API on which the handler function is a property
Thomas Vachuska329af532015-03-10 02:08:33 -0700125 function bindHandlers(handlerMap) {
126 var m = d3.map(handlerMap),
127 dups = [];
Simon Hunt970e7fd2015-01-22 17:46:28 -0800128
Simon Hunt20207df2015-03-10 18:30:14 -0700129 m.forEach(function (eventId, api) {
130 var fn = fs.isF(api[eventId]);
Thomas Vachuska329af532015-03-10 02:08:33 -0700131 if (!fn) {
Simon Hunt20207df2015-03-10 18:30:14 -0700132 $log.warn(eventId + ' handler not a function');
Thomas Vachuska329af532015-03-10 02:08:33 -0700133 return;
Simon Hunt970e7fd2015-01-22 17:46:28 -0800134 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700135
Simon Hunt20207df2015-03-10 18:30:14 -0700136 if (handlers[eventId]) {
137 dups.push(eventId);
Thomas Vachuska329af532015-03-10 02:08:33 -0700138 } else {
Simon Hunt20207df2015-03-10 18:30:14 -0700139 handlers[eventId] = fn;
Thomas Vachuska329af532015-03-10 02:08:33 -0700140 }
141 });
142 if (dups.length) {
143 $log.warn('duplicate bindings ignored:', dups);
144 }
Simon Hunt970e7fd2015-01-22 17:46:28 -0800145 }
146
Thomas Vachuska329af532015-03-10 02:08:33 -0700147 // Unbinds the specified message handlers.
Simon Hunt20207df2015-03-10 18:30:14 -0700148 // Expected that the same map will be used, but we only care about keys
Thomas Vachuska329af532015-03-10 02:08:33 -0700149 function unbindHandlers(handlerMap) {
150 var m = d3.map(handlerMap);
Simon Hunt20207df2015-03-10 18:30:14 -0700151
152 m.forEach(function (eventId) {
153 delete handlers[eventId];
Thomas Vachuska329af532015-03-10 02:08:33 -0700154 });
155 }
Simon Huntacf410b2015-01-23 10:05:48 -0800156
Simon Hunt20207df2015-03-10 18:30:14 -0700157 // Formulates an event message and sends it via the web-socket.
158 // If the websocket is not up yet, we store it in a pending list.
Thomas Vachuska329af532015-03-10 02:08:33 -0700159 function sendEvent(evType, payload) {
Simon Hunt20207df2015-03-10 18:30:14 -0700160 var ev = {
Thomas Vachuska329af532015-03-10 02:08:33 -0700161 event: evType,
162 sid: ++sid,
Simon Hunt20207df2015-03-10 18:30:14 -0700163 payload: payload || {}
164 };
165
166 if (wsUp) {
167 _send(ev);
Thomas Vachuska329af532015-03-10 02:08:33 -0700168 } else {
Simon Hunt20207df2015-03-10 18:30:14 -0700169 pendingEvents.push(ev);
Thomas Vachuska329af532015-03-10 02:08:33 -0700170 }
171 }
172
173
Simon Hunt20207df2015-03-10 18:30:14 -0700174 // ============================
175 // ===== Definition of module
Simon Hunt584122a2015-01-21 15:32:40 -0800176 angular.module('onosRemote')
Simon Huntbb920fd2015-01-22 17:06:32 -0800177 .factory('WebSocketService',
Simon Hunt20207df2015-03-10 18:30:14 -0700178 ['$log', '$location', 'FnService', 'UrlFnService', 'WSock',
179 'VeilService',
Simon Huntbb920fd2015-01-22 17:06:32 -0800180
Simon Hunt20207df2015-03-10 18:30:14 -0700181 function (_$log_, _$loc_, _fs_, _ufs_, _wsock_, _vs_) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700182 $log = _$log_;
Simon Hunt20207df2015-03-10 18:30:14 -0700183 $loc = _$loc_;
184 fs = _fs_;
185 ufs = _ufs_;
186 wsock = _wsock_;
187 vs = _vs_;
Simon Hunt1e4a0012015-01-21 11:36:08 -0800188
189 return {
Thomas Vachuska329af532015-03-10 02:08:33 -0700190 resetSid: resetSid,
191 createWebSocket: createWebSocket,
192 bindHandlers: bindHandlers,
193 unbindHandlers: unbindHandlers,
194 sendEvent: sendEvent
Simon Hunt1e4a0012015-01-21 11:36:08 -0800195 };
Simon Hunt20207df2015-03-10 18:30:14 -0700196 }
197 ]);
Simon Hunt1e4a0012015-01-21 11:36:08 -0800198
199}());