Sean Condon | 83fc39f | 2018-04-19 18:56:13 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2015-present Open Networking Foundation |
| 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 | import { Injectable } from '@angular/core'; |
| 17 | import { FnService } from '../util/fn.service'; |
| 18 | import { GlyphService } from '../svg/glyph.service'; |
| 19 | import { LogService } from '../../log.service'; |
| 20 | import { UrlFnService } from './urlfn.service'; |
| 21 | import { WSock } from './wsock.service'; |
| 22 | |
| 23 | /** |
| 24 | * Event Type structure for the WebSocketService |
| 25 | */ |
| 26 | interface EventType { |
| 27 | event: string; |
| 28 | payload: any; |
| 29 | } |
| 30 | |
| 31 | /** |
| 32 | * ONOS GUI -- Remote -- Web Socket Service |
| 33 | */ |
| 34 | @Injectable() |
| 35 | export class WebSocketService { |
| 36 | // internal state |
| 37 | private webSockOpts; // web socket options |
| 38 | private ws = null; // web socket reference |
| 39 | private wsUp = false; // web socket is good to go |
| 40 | private handlers = {}; // event handler bindings |
| 41 | private pendingEvents: EventType[] = []; // events TX'd while socket not up |
| 42 | private host: string; // web socket host |
| 43 | private url; // web socket URL |
| 44 | private clusterNodes = []; // ONOS instances data for failover |
| 45 | private clusterIndex = -1; // the instance to which we are connected |
| 46 | private glyphs = []; |
| 47 | private connectRetries = 0; // limit our attempts at reconnecting |
| 48 | private openListeners = {}; // registered listeners for websocket open() |
| 49 | private nextListenerId = 1; // internal ID for open listeners |
| 50 | private loggedInUser = null; // name of logged-in user |
| 51 | |
| 52 | |
| 53 | constructor( |
| 54 | private fs: FnService, |
| 55 | private gs: GlyphService, |
| 56 | private log: LogService, |
| 57 | private ufs: UrlFnService, |
| 58 | private wsock: WSock, |
| 59 | private window: Window |
| 60 | ) { |
| 61 | this.log.debug(window.location.hostname); |
| 62 | this.log.debug('WebSocketService constructed'); |
| 63 | } |
| 64 | |
| 65 | /* =================== |
| 66 | * === API Functions |
| 67 | * |
| 68 | * Required for unit tests to set to known state |
| 69 | */ |
| 70 | resetState() { |
| 71 | this.webSockOpts = undefined; |
| 72 | this.ws = null; |
| 73 | this.wsUp = false; |
| 74 | this.host = undefined; |
| 75 | this.url = undefined; |
| 76 | this.pendingEvents = []; |
| 77 | this.handlers = {}; |
| 78 | this.clusterNodes = []; |
| 79 | this.clusterIndex = -1; |
| 80 | this.glyphs = []; |
| 81 | this.connectRetries = 0; |
| 82 | this.openListeners = {}; |
| 83 | this.nextListenerId = 1; |
| 84 | |
| 85 | } |
| 86 | |
| 87 | /* Currently supported opts: |
| 88 | * wsport: web socket port (other than default 8181) |
| 89 | * host: if defined, is the host address to use |
| 90 | */ |
| 91 | createWebSocket(opts, _host_: string = '') { |
Sean Condon | 49e15be | 2018-05-16 16:58:29 +0100 | [diff] [blame] | 92 | const wsport = (opts && opts.wsport) || null; |
Sean Condon | 83fc39f | 2018-04-19 18:56:13 +0100 | [diff] [blame] | 93 | |
| 94 | this.webSockOpts = opts; // preserved for future calls |
| 95 | |
| 96 | // this.host = _host_ || this.host(); |
Sean Condon | 49e15be | 2018-05-16 16:58:29 +0100 | [diff] [blame] | 97 | const url = this.ufs.wsUrl('core', wsport, _host_); |
Sean Condon | 83fc39f | 2018-04-19 18:56:13 +0100 | [diff] [blame] | 98 | |
| 99 | this.log.debug('Attempting to open websocket to: ' + url); |
| 100 | this.ws = this.wsock.newWebSocket(url); |
| 101 | if (this.ws) { |
| 102 | this.ws.onopen = this.handleOpen(); |
| 103 | this.ws.onmessage = this.handleMessage('???'); |
| 104 | this.ws.onclose = this.handleClose(); |
| 105 | |
| 106 | // sendEvent('authentication', { token: onosAuth }); |
| 107 | this.sendEvent('authentication token', ''); |
| 108 | } |
| 109 | // Note: Wsock logs an error if the new WebSocket call fails |
| 110 | return url; |
| 111 | } |
| 112 | |
| 113 | handleOpen() { |
| 114 | this.log.debug('WebSocketService: handleOpen() not yet implemented'); |
| 115 | } |
| 116 | |
| 117 | handleMessage(msgEvent: any) { |
| 118 | this.log.debug('WebSocketService: handleMessage() not yet implemented'); |
| 119 | } |
| 120 | |
| 121 | handleClose() { |
| 122 | this.log.debug('WebSocketService: handleClose() not yet implemented'); |
| 123 | } |
| 124 | |
| 125 | /* Formulates an event message and sends it via the web-socket. |
| 126 | * If the websocket is not up yet, we store it in a pending list. |
| 127 | */ |
| 128 | sendEvent(evType, payload) { |
Sean Condon | 49e15be | 2018-05-16 16:58:29 +0100 | [diff] [blame] | 129 | const ev = <EventType> { |
Sean Condon | 83fc39f | 2018-04-19 18:56:13 +0100 | [diff] [blame] | 130 | event: evType, |
| 131 | payload: payload |
Sean Condon | 49e15be | 2018-05-16 16:58:29 +0100 | [diff] [blame] | 132 | }; |
Sean Condon | 83fc39f | 2018-04-19 18:56:13 +0100 | [diff] [blame] | 133 | |
| 134 | if (this.wsUp) { |
| 135 | this._send(ev); |
| 136 | } else { |
| 137 | this.pendingEvents.push(ev); |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | _send(ev: EventType) { |
| 142 | if (this.fs.debugOn('txrx')) { |
| 143 | this.log.debug(' *Tx* >> ', ev.event, ev.payload); |
| 144 | } |
| 145 | this.ws.send(JSON.stringify(ev)); |
| 146 | } |
| 147 | |
| 148 | } |