diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2018-08-08 16:53:23 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2018-08-08 16:53:23 +0200 |
| commit | ac98e48c68eadfdd7250eccd38aa492e6f830744 (patch) | |
| tree | 05bfd7a9f05456220f11f40329093b127a5b20a2 /app/lib | |
| parent | d53fda746465c0bb6525371b9d780cbfac90f942 (diff) | |
| parent | a8f2831cd50e98b1d126b8c3169adcf1ef75b8a2 (diff) | |
| download | mullvadvpn-ac98e48c68eadfdd7250eccd38aa492e6f830744.tar.xz mullvadvpn-ac98e48c68eadfdd7250eccd38aa492e6f830744.zip | |
Merge branch 'remove-auto-login'
Diffstat (limited to 'app/lib')
| -rw-r--r-- | app/lib/daemon-rpc.js | 2 | ||||
| -rw-r--r-- | app/lib/jsonrpc-transport.js | 117 | ||||
| -rw-r--r-- | app/lib/reconnection-backoff.js | 8 | ||||
| -rw-r--r-- | app/lib/window-state-observer.js | 64 |
4 files changed, 124 insertions, 67 deletions
diff --git a/app/lib/daemon-rpc.js b/app/lib/daemon-rpc.js index fb3915e068..163ea170d0 100644 --- a/app/lib/daemon-rpc.js +++ b/app/lib/daemon-rpc.js @@ -327,7 +327,7 @@ export class DaemonRpc implements DaemonRpcProtocol { const validatedObject = validate(RelaySettingsSchema, response); /* $FlowFixMe: - There is no way to express the constraints with string literals, i.e: + There is no way to express constraints with string literals, i.e: RelaySettingsSchema constraint: oneOf(string, object) diff --git a/app/lib/jsonrpc-transport.js b/app/lib/jsonrpc-transport.js index 2fa98df988..cbf1e7dce8 100644 --- a/app/lib/jsonrpc-transport.js +++ b/app/lib/jsonrpc-transport.js @@ -123,7 +123,7 @@ const DEFAULT_TIMEOUT_MILLIS = 5000; export default class JsonRpcTransport extends EventEmitter { _unansweredRequests: Map<string, UnansweredRequest> = new Map(); _subscriptions: Map<string | number, (mixed) => void> = new Map(); - _websocket: ?WebSocket; + _webSocket: ?WebSocket; _websocketFactory: (string) => WebSocket; constructor(websocketFactory: ?(string) => WebSocket) { @@ -133,46 +133,60 @@ export default class JsonRpcTransport extends EventEmitter { } /// Connect websocket - connect(connectionString: string) { - this.disconnect(); + connect(connectionString: string): Promise<void> { + return new Promise((resolve, reject) => { + this.disconnect(); - log.info('Connecting to websocket', connectionString); + log.info('Connecting to websocket', connectionString); - const websocket = this._websocketFactory(connectionString); + const webSocket = this._websocketFactory(connectionString); - websocket.onopen = () => { - log.info('Websocket is connected'); - this.emit('open'); - }; + // A flag used to determine if Promise was resolved. + let isPromiseResolved = false; - websocket.onmessage = (event) => { - const data = event.data; - if (typeof data === 'string') { - this._onMessage(data); - } else { - log.error('Got invalid reply from the server', event); - } - }; + webSocket.onopen = () => { + log.info('Websocket is connected'); + this.emit('open'); + + // Resolve the Promise + resolve(); + isPromiseResolved = true; + }; + + webSocket.onmessage = (event) => { + const data = event.data; + if (typeof data === 'string') { + this._onMessage(data); + } else { + log.error('Got invalid reply from the server', event); + } + }; - websocket.onclose = (event) => { - log.info(`The websocket connection closed with code: ${event.code}`); + webSocket.onclose = (event) => { + log.info(`The websocket connection closed with code: ${event.code}`); - // Remove all subscriptions since they are connection based - this._subscriptions.clear(); + // Remove all subscriptions since they are connection based + this._subscriptions.clear(); - // 1000 is a code used for normal connection closure. - const connectionError = event.code === 1000 ? null : new ConnectionError(event.code); + // 1000 is a code used for normal connection closure. + const connectionError = event.code === 1000 ? null : new ConnectionError(event.code); - this.emit('close', connectionError); - }; + this.emit('close', connectionError); - this._websocket = websocket; + // Prevent rejecting a previously resolved Promise. + if (!isPromiseResolved) { + reject(connectionError); + } + }; + + this._webSocket = webSocket; + }); } disconnect() { - if (this._websocket) { - this._websocket.close(); - this._websocket = null; + if (this._webSocket) { + this._webSocket.close(); + this._webSocket = null; } } @@ -195,19 +209,14 @@ export default class JsonRpcTransport extends EventEmitter { } } - async send( - action: string, - data: mixed, - timeout: number = DEFAULT_TIMEOUT_MILLIS, - ): Promise<mixed> { - let socket: WebSocket; - try { - socket = await this._getWebSocket(); - } catch (error) { - throw error; - } - + send(action: string, data: mixed, timeout: number = DEFAULT_TIMEOUT_MILLIS): Promise<mixed> { return new Promise((resolve, reject) => { + const webSocket = this._webSocket; + if (!webSocket) { + reject(new Error('Websocket is not connected.')); + return; + } + const id = uuid.v4(); const payload = this._prepareParams(data); const timerId = setTimeout(() => this._onTimeout(id), timeout); @@ -221,9 +230,14 @@ export default class JsonRpcTransport extends EventEmitter { try { log.silly('Sending message', id, action); - socket.send(JSON.stringify(message)); + webSocket.send(JSON.stringify(message)); } catch (error) { log.error(`Failed sending RPC message "${action}": ${error.message}`); + + // clean up on error + this._unansweredRequests.delete(id); + clearTimeout(timerId); + throw error; } }); @@ -245,25 +259,6 @@ export default class JsonRpcTransport extends EventEmitter { } } - _getWebSocket(): Promise<WebSocket> { - if (this._websocket && this._websocket.readyState === 1) { - return Promise.resolve(this._websocket); - } else { - return new Promise((resolve, reject) => { - log.debug('Waiting for websocket to connect'); - - this.once('open', () => { - const ws = this._websocket; - if (ws) { - resolve(ws); - } else { - reject(new Error('Internal error')); - } - }); - }); - } - } - _onTimeout(requestId) { const request = this._unansweredRequests.get(requestId); diff --git a/app/lib/reconnection-backoff.js b/app/lib/reconnection-backoff.js index 1cd8203dac..d777e86e57 100644 --- a/app/lib/reconnection-backoff.js +++ b/app/lib/reconnection-backoff.js @@ -1,13 +1,11 @@ +// @flow + /* * Used to calculate the time to wait before reconnecting to the daemon. * It uses a linear backoff function that goes from 500ms to 3000ms. */ export default class ReconnectionBackoff { - _attempt: number; - - constructor() { - this._attempt = 0; - } + _attempt = 0; attempt(handler: () => void) { setTimeout(handler, this._getIncreasedBackoff()); diff --git a/app/lib/window-state-observer.js b/app/lib/window-state-observer.js new file mode 100644 index 0000000000..67252d8f6a --- /dev/null +++ b/app/lib/window-state-observer.js @@ -0,0 +1,64 @@ +// @flow + +import { remote } from 'electron'; + +type EventListener = () => void; + +// Tiny helper for detecting the window state. +export default class WindowStateObserver { + _onShow: ?EventListener; + _onHide: ?EventListener; + + get onShow() { + return this._onShow; + } + + set onShow(listener: ?EventListener) { + const currentWindow = remote.getCurrentWindow(); + const oldListener = this._onShow; + if (oldListener) { + currentWindow.removeListener('show', oldListener); + } + + if (listener) { + currentWindow.addListener('show', listener); + } + + this._onShow = listener; + } + + get onHide() { + return this._onHide; + } + + set onHide(listener: ?EventListener) { + const currentWindow = remote.getCurrentWindow(); + const oldListener = this._onHide; + if (oldListener) { + currentWindow.removeListener('hide', oldListener); + } + + if (listener) { + currentWindow.addListener('hide', listener); + } + + this._onHide = listener; + } + + constructor() { + // Because BrowserWindow persists between page reloads, + // it's important to release event handlers when that happens. + window.addEventListener('beforeunload', this._onBeforeUnload); + } + + _onBeforeUnload = () => { + this.dispose(); + }; + + dispose() { + this.onShow = null; + this.onHide = null; + + window.removeEventListener('beforeunload', this._onBeforeUnload); + } +} |
