blob: 6445d366b0891b28e2e09c58ce66ef8a3a326c78 [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);
54 $log.debug(' *Rx* >> ', ev.event, ev.payload);
55
56 if (h = handlers[ev.event]) {
57 h(ev.payload);
58 } else {
59 $log.warn('Unhandled event:', ev);
60 }
61
62 } catch (e) {
63 $log.error('Message.data is (probably) not valid JSON', msgEvent);
64 }
65 }
66
67 function handleClose() {
68 $log.info('Web socket closed');
69 wsUp = false;
70
71 // FIXME: implement controller failover logic
72
73 // If no controllers left to contact, show the Veil...
74 vs.show([
75 'Oops!',
76 'Web-socket connection to server closed...',
77 'Try refreshing the page.'
78 ]);
79 }
80
81
82 // ==============================
83 // === Private Helper Functions
84
85 function _send(ev) {
86 $log.debug(' *Tx* >> ', ev.event, ev.payload);
87 ws.send(JSON.stringify(ev));
88 }
89
90
91 // ===================
92 // === API Functions
93
94 // Required for unit tests to set to known state
Thomas Vachuska329af532015-03-10 02:08:33 -070095 function resetSid() {
96 sid = 0;
Simon Hunt970e7fd2015-01-22 17:46:28 -080097 }
98
Simon Hunt20207df2015-03-10 18:30:14 -070099 // Currently supported opts:
100 // wsport: web socket port (other than default 8181)
101 function createWebSocket(opts) {
102 var wsport = (opts && opts.wsport) || null;
103
104 url = ufs.wsUrl('core', wsport);
105
106 $log.debug('Attempting to open websocket to: ' + url);
107 ws = wsock.newWebSocket(url);
108 if (ws) {
109 ws.onopen = handleOpen;
110 ws.onmessage = handleMessage;
111 ws.onclose = handleClose;
112 }
113 // Note: Wsock logs an error if the new WebSocket call fails
114 }
115
Thomas Vachuska329af532015-03-10 02:08:33 -0700116 // Binds the specified message handlers.
Simon Hunt20207df2015-03-10 18:30:14 -0700117 // keys are the event IDs
118 // values are the API on which the handler function is a property
Thomas Vachuska329af532015-03-10 02:08:33 -0700119 function bindHandlers(handlerMap) {
120 var m = d3.map(handlerMap),
121 dups = [];
Simon Hunt970e7fd2015-01-22 17:46:28 -0800122
Simon Hunt20207df2015-03-10 18:30:14 -0700123 m.forEach(function (eventId, api) {
124 var fn = fs.isF(api[eventId]);
Thomas Vachuska329af532015-03-10 02:08:33 -0700125 if (!fn) {
Simon Hunt20207df2015-03-10 18:30:14 -0700126 $log.warn(eventId + ' handler not a function');
Thomas Vachuska329af532015-03-10 02:08:33 -0700127 return;
Simon Hunt970e7fd2015-01-22 17:46:28 -0800128 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700129
Simon Hunt20207df2015-03-10 18:30:14 -0700130 if (handlers[eventId]) {
131 dups.push(eventId);
Thomas Vachuska329af532015-03-10 02:08:33 -0700132 } else {
Simon Hunt20207df2015-03-10 18:30:14 -0700133 handlers[eventId] = fn;
Thomas Vachuska329af532015-03-10 02:08:33 -0700134 }
135 });
136 if (dups.length) {
137 $log.warn('duplicate bindings ignored:', dups);
138 }
Simon Hunt970e7fd2015-01-22 17:46:28 -0800139 }
140
Thomas Vachuska329af532015-03-10 02:08:33 -0700141 // Unbinds the specified message handlers.
Simon Hunt20207df2015-03-10 18:30:14 -0700142 // Expected that the same map will be used, but we only care about keys
Thomas Vachuska329af532015-03-10 02:08:33 -0700143 function unbindHandlers(handlerMap) {
144 var m = d3.map(handlerMap);
Simon Hunt20207df2015-03-10 18:30:14 -0700145
146 m.forEach(function (eventId) {
147 delete handlers[eventId];
Thomas Vachuska329af532015-03-10 02:08:33 -0700148 });
149 }
Simon Huntacf410b2015-01-23 10:05:48 -0800150
Simon Hunt20207df2015-03-10 18:30:14 -0700151 // Formulates an event message and sends it via the web-socket.
152 // If the websocket is not up yet, we store it in a pending list.
Thomas Vachuska329af532015-03-10 02:08:33 -0700153 function sendEvent(evType, payload) {
Simon Hunt20207df2015-03-10 18:30:14 -0700154 var ev = {
Thomas Vachuska329af532015-03-10 02:08:33 -0700155 event: evType,
156 sid: ++sid,
Simon Hunt20207df2015-03-10 18:30:14 -0700157 payload: payload || {}
158 };
159
160 if (wsUp) {
161 _send(ev);
Thomas Vachuska329af532015-03-10 02:08:33 -0700162 } else {
Simon Hunt20207df2015-03-10 18:30:14 -0700163 pendingEvents.push(ev);
Thomas Vachuska329af532015-03-10 02:08:33 -0700164 }
165 }
166
167
Simon Hunt20207df2015-03-10 18:30:14 -0700168 // ============================
169 // ===== Definition of module
Simon Hunt584122a2015-01-21 15:32:40 -0800170 angular.module('onosRemote')
Simon Huntbb920fd2015-01-22 17:06:32 -0800171 .factory('WebSocketService',
Simon Hunt20207df2015-03-10 18:30:14 -0700172 ['$log', '$location', 'FnService', 'UrlFnService', 'WSock',
173 'VeilService',
Simon Huntbb920fd2015-01-22 17:06:32 -0800174
Simon Hunt20207df2015-03-10 18:30:14 -0700175 function (_$log_, _$loc_, _fs_, _ufs_, _wsock_, _vs_) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700176 $log = _$log_;
Simon Hunt20207df2015-03-10 18:30:14 -0700177 $loc = _$loc_;
178 fs = _fs_;
179 ufs = _ufs_;
180 wsock = _wsock_;
181 vs = _vs_;
Simon Hunt1e4a0012015-01-21 11:36:08 -0800182
183 return {
Thomas Vachuska329af532015-03-10 02:08:33 -0700184 resetSid: resetSid,
185 createWebSocket: createWebSocket,
186 bindHandlers: bindHandlers,
187 unbindHandlers: unbindHandlers,
188 sendEvent: sendEvent
Simon Hunt1e4a0012015-01-21 11:36:08 -0800189 };
Simon Hunt20207df2015-03-10 18:30:14 -0700190 }
191 ]);
Simon Hunt1e4a0012015-01-21 11:36:08 -0800192
193}());