blob: 861bb4037f5206e2c37d73c7838b19bd6ebddd16 [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
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -070032 url, // web socket URL
33 instances = [];
Simon Huntacf410b2015-01-23 10:05:48 -080034
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -070035 var builtinHandlers = {
36 onosInstances: function (data) {
37 instances = data.instances;
38 }
39 }
Simon Hunt20207df2015-03-10 18:30:14 -070040
41 // ==========================
42 // === Web socket callbacks
43
44 function handleOpen() {
45 $log.info('Web socket open');
46 $log.debug('Sending ' + pendingEvents.length + ' pending event(s)...');
47 pendingEvents.forEach(function (ev) {
48 _send(ev);
49 });
50 pendingEvents = [];
51 wsUp = true;
52 }
53
54 // Handles the specified (incoming) message using handler bindings.
55 function handleMessage(msgEvent) {
56 var ev, h;
57
58 try {
59 ev = JSON.parse(msgEvent.data);
Simon Hunt20207df2015-03-10 18:30:14 -070060 } catch (e) {
Simon Hunt2d16fc82015-03-10 20:19:52 -070061 $log.error('Message.data is not valid JSON', msgEvent.data, e);
62 return;
Simon Hunt20207df2015-03-10 18:30:14 -070063 }
Simon Hunt2d16fc82015-03-10 20:19:52 -070064 $log.debug(' *Rx* >> ', ev.event, ev.payload);
65
66 if (h = handlers[ev.event]) {
67 try {
68 h(ev.payload);
69 } catch (e) {
70 $log.error('Problem handling event:', ev, e);
71 }
72 } else {
73 $log.warn('Unhandled event:', ev);
74 }
75
Simon Hunt20207df2015-03-10 18:30:14 -070076 }
77
78 function handleClose() {
79 $log.info('Web socket closed');
80 wsUp = false;
81
82 // FIXME: implement controller failover logic
83
84 // If no controllers left to contact, show the Veil...
85 vs.show([
86 'Oops!',
87 'Web-socket connection to server closed...',
88 'Try refreshing the page.'
89 ]);
90 }
91
92
93 // ==============================
94 // === Private Helper Functions
95
96 function _send(ev) {
97 $log.debug(' *Tx* >> ', ev.event, ev.payload);
98 ws.send(JSON.stringify(ev));
99 }
100
101
102 // ===================
103 // === API Functions
104
105 // Required for unit tests to set to known state
Thomas Vachuska329af532015-03-10 02:08:33 -0700106 function resetSid() {
107 sid = 0;
Simon Hunt970e7fd2015-01-22 17:46:28 -0800108 }
109
Simon Hunt20207df2015-03-10 18:30:14 -0700110 // Currently supported opts:
111 // wsport: web socket port (other than default 8181)
112 function createWebSocket(opts) {
113 var wsport = (opts && opts.wsport) || null;
114
115 url = ufs.wsUrl('core', wsport);
116
117 $log.debug('Attempting to open websocket to: ' + url);
118 ws = wsock.newWebSocket(url);
119 if (ws) {
120 ws.onopen = handleOpen;
121 ws.onmessage = handleMessage;
122 ws.onclose = handleClose;
123 }
124 // Note: Wsock logs an error if the new WebSocket call fails
Simon Hunt2d16fc82015-03-10 20:19:52 -0700125 return url;
Simon Hunt20207df2015-03-10 18:30:14 -0700126 }
127
Thomas Vachuska329af532015-03-10 02:08:33 -0700128 // Binds the specified message handlers.
Simon Hunt20207df2015-03-10 18:30:14 -0700129 // keys are the event IDs
130 // values are the API on which the handler function is a property
Thomas Vachuska329af532015-03-10 02:08:33 -0700131 function bindHandlers(handlerMap) {
132 var m = d3.map(handlerMap),
133 dups = [];
Simon Hunt970e7fd2015-01-22 17:46:28 -0800134
Simon Hunt20207df2015-03-10 18:30:14 -0700135 m.forEach(function (eventId, api) {
136 var fn = fs.isF(api[eventId]);
Thomas Vachuska329af532015-03-10 02:08:33 -0700137 if (!fn) {
Simon Hunt20207df2015-03-10 18:30:14 -0700138 $log.warn(eventId + ' handler not a function');
Thomas Vachuska329af532015-03-10 02:08:33 -0700139 return;
Simon Hunt970e7fd2015-01-22 17:46:28 -0800140 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700141
Simon Hunt20207df2015-03-10 18:30:14 -0700142 if (handlers[eventId]) {
143 dups.push(eventId);
Thomas Vachuska329af532015-03-10 02:08:33 -0700144 } else {
Simon Hunt20207df2015-03-10 18:30:14 -0700145 handlers[eventId] = fn;
Thomas Vachuska329af532015-03-10 02:08:33 -0700146 }
147 });
148 if (dups.length) {
149 $log.warn('duplicate bindings ignored:', dups);
150 }
Simon Hunt970e7fd2015-01-22 17:46:28 -0800151 }
152
Thomas Vachuska329af532015-03-10 02:08:33 -0700153 // Unbinds the specified message handlers.
Simon Hunt20207df2015-03-10 18:30:14 -0700154 // Expected that the same map will be used, but we only care about keys
Thomas Vachuska329af532015-03-10 02:08:33 -0700155 function unbindHandlers(handlerMap) {
156 var m = d3.map(handlerMap);
Simon Hunt20207df2015-03-10 18:30:14 -0700157
158 m.forEach(function (eventId) {
159 delete handlers[eventId];
Thomas Vachuska329af532015-03-10 02:08:33 -0700160 });
161 }
Simon Huntacf410b2015-01-23 10:05:48 -0800162
Simon Hunt20207df2015-03-10 18:30:14 -0700163 // Formulates an event message and sends it via the web-socket.
164 // If the websocket is not up yet, we store it in a pending list.
Thomas Vachuska329af532015-03-10 02:08:33 -0700165 function sendEvent(evType, payload) {
Simon Hunt20207df2015-03-10 18:30:14 -0700166 var ev = {
Thomas Vachuska329af532015-03-10 02:08:33 -0700167 event: evType,
168 sid: ++sid,
Simon Hunt20207df2015-03-10 18:30:14 -0700169 payload: payload || {}
170 };
171
172 if (wsUp) {
173 _send(ev);
Thomas Vachuska329af532015-03-10 02:08:33 -0700174 } else {
Simon Hunt20207df2015-03-10 18:30:14 -0700175 pendingEvents.push(ev);
Thomas Vachuska329af532015-03-10 02:08:33 -0700176 }
177 }
178
179
Simon Hunt20207df2015-03-10 18:30:14 -0700180 // ============================
181 // ===== Definition of module
Simon Hunt584122a2015-01-21 15:32:40 -0800182 angular.module('onosRemote')
Simon Huntbb920fd2015-01-22 17:06:32 -0800183 .factory('WebSocketService',
Simon Hunt20207df2015-03-10 18:30:14 -0700184 ['$log', '$location', 'FnService', 'UrlFnService', 'WSock',
185 'VeilService',
Simon Huntbb920fd2015-01-22 17:06:32 -0800186
Simon Hunt20207df2015-03-10 18:30:14 -0700187 function (_$log_, _$loc_, _fs_, _ufs_, _wsock_, _vs_) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700188 $log = _$log_;
Simon Hunt20207df2015-03-10 18:30:14 -0700189 $loc = _$loc_;
190 fs = _fs_;
191 ufs = _ufs_;
192 wsock = _wsock_;
193 vs = _vs_;
Simon Hunt1e4a0012015-01-21 11:36:08 -0800194
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700195 // Bind instance handlers
196 bindHandlers({
197 onosInstances: builtinHandlers
198 });
199
Simon Hunt1e4a0012015-01-21 11:36:08 -0800200 return {
Thomas Vachuska329af532015-03-10 02:08:33 -0700201 resetSid: resetSid,
202 createWebSocket: createWebSocket,
203 bindHandlers: bindHandlers,
204 unbindHandlers: unbindHandlers,
205 sendEvent: sendEvent
Simon Hunt1e4a0012015-01-21 11:36:08 -0800206 };
Simon Hunt20207df2015-03-10 18:30:14 -0700207 }
208 ]);
Simon Hunt1e4a0012015-01-21 11:36:08 -0800209
210}());