summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorErik Larkö <erik@mullvad.net>2017-05-18 01:02:30 +0200
committerErik Larkö <erik@mullvad.net>2017-05-19 06:05:44 +0200
commit5d81ffed027675e143488cc9757f4303378778f7 (patch)
tree81f82b3331e7412027a2a2047b1f06fddebbdcd5
parent6218d88d9cc45a49a9cd37ecdf53ddee71aaab46 (diff)
downloadmullvadvpn-5d81ffed027675e143488cc9757f4303378778f7.tar.xz
mullvadvpn-5d81ffed027675e143488cc9757f4303378778f7.zip
Use a websocket as the IPC channel
-rw-r--r--app/lib/backend-redux-actions.js3
-rw-r--r--app/lib/ipc.js93
-rw-r--r--app/lib/keyframe-animation.js2
3 files changed, 73 insertions, 25 deletions
diff --git a/app/lib/backend-redux-actions.js b/app/lib/backend-redux-actions.js
index 66688bc4d0..66300613d2 100644
--- a/app/lib/backend-redux-actions.js
+++ b/app/lib/backend-redux-actions.js
@@ -2,6 +2,7 @@ import userActions from '../actions/user';
import connectActions from '../actions/connect';
import Backend from './backend';
import { LoginState, ConnectionState } from '../enums';
+import log from 'electron-log';
/**
* Add event listeners to translate backend events to redux dispatch.
@@ -28,7 +29,7 @@ export default function mapBackendEventsToReduxActions(backend, store) {
const onConnect = (serverAddress, error) => {
if (error) {
- console.error('UNABLE TO CONNECT TO', serverAddress, error);
+ log.error('Unable to connect to', serverAddress, error);
} else {
store.dispatch(connectActions.connectionChange({ status: ConnectionState.connected }));
}
diff --git a/app/lib/ipc.js b/app/lib/ipc.js
index 570abc2cec..6b548b8414 100644
--- a/app/lib/ipc.js
+++ b/app/lib/ipc.js
@@ -5,40 +5,87 @@ import log from 'electron-log';
export default class Ipc {
constructor(connectionString) {
- this.connectionString = connectionString;
+ this._connectionString = connectionString;
+ this._onConnect = [];
+ this._unansweredRequests = {};
+
+ this._reconnect();
}
on(event/*, listener*/) {
log.info('Adding a listener to', event);
}
- send(action, data) {
- const id = uuid.v4();
- const jsonrpcMessage = jsonrpc.request(id, action, data);
+ send(action, ...data) {
+ return this._getWebSocket()
+ .then(ws => this._send(ws, action, data))
+ .catch(e => {
+ log.error('Failed sending RPC message "' + action + '":', e);
+ throw e;
+ });
+ }
- return fetch(this.connectionString, {
- method: 'POST',
- headers: new Headers({
- 'Content-Type': 'application/json',
- }),
- body: JSON.stringify(jsonrpcMessage),
- }).then((res) => {
- if (!res.ok) {
- throw {msg: 'HTTP request failed', data: res};
+ _getWebSocket() {
+ return new Promise(resolve => {
+ if (this._websocket.readyState === 1) { // Connected
+ resolve(this._websocket);
+ } else {
+ log.debug('Waiting for websocket to connect');
+ this._onConnect.push({
+ resolve: () => resolve(this._websocket),
+ });
}
+ });
+ }
+
+ _send(websocket, action, data) {
+ return new Promise((resolve, reject) => {
+ const id = uuid.v4();
+ const jsonrpcMessage = jsonrpc.request(id, action, data);
+
+ this._unansweredRequests[id] = {resolve: resolve, reject: reject};
+ log.debug('Sending message', id, action);
+ websocket.send(jsonrpcMessage);
+ });
+ }
- return res.json();
- }).then(json => {
+ _onMessage(message) {
+ const json = JSON.parse(message);
+ const c = jsonrpc.parseObject(json);
- const c = jsonrpc.parseObject(json);
- if (c.type === 'error') {
- throw c.payload.error.message;
+ const id = c.payload.id;
+ const request = this._unansweredRequests[id];
+ delete this._unansweredRequests[id];
+
+ log.debug('Got answer to', id, c.type);
+ if (c.type === 'error') {
+ request.reject(c.payload.error.message);
+ } else {
+ const reply = c.payload.result;
+ request.resolve(reply);
+ }
+ }
+
+ _reconnect() {
+ if (!this._connectionString) return;
+
+ log.info('Connecting to websocket', this._connectionString);
+ this._websocket = new WebSocket(this._connectionString);
+
+ this._websocket.onopen = () => {
+ log.debug('Websocket is connected');
+ while(this._onConnect.length > 0) {
+ this._onConnect.pop().resolve();
}
- return c.payload.result;
+ };
- }).catch(e => {
- console.error('IPC call failed', action, data, e);
- throw e;
- });
+ this._websocket.onmessage = (evt) => {
+ this._onMessage(evt.data);
+ };
+
+ this._websocket.onclose = () => {
+ log.warn('The websocket connetion closed, attempting to reconnect it');
+ this._reconnect();
+ };
}
}
diff --git a/app/lib/keyframe-animation.js b/app/lib/keyframe-animation.js
index 688d578ad4..6f253b9bfd 100644
--- a/app/lib/keyframe-animation.js
+++ b/app/lib/keyframe-animation.js
@@ -346,4 +346,4 @@ export default class KeyframeAnimation {
return cur;
}
-} \ No newline at end of file
+}