summaryrefslogtreecommitdiffhomepage
path: root/app/lib
diff options
context:
space:
mode:
authorErik Larkö <erik@mullvad.net>2017-05-19 07:10:07 +0200
committerErik Larkö <erik@mullvad.net>2017-05-19 07:10:07 +0200
commit9e2e6c728f6b1bcdfc171772300ff3b787db2aed (patch)
tree3965d54e89441768c4deb87f059e7d8e462f1343 /app/lib
parent6218d88d9cc45a49a9cd37ecdf53ddee71aaab46 (diff)
parent57e718385501b4a42a29633889ba6740b5ce5064 (diff)
downloadmullvadvpn-9e2e6c728f6b1bcdfc171772300ff3b787db2aed.tar.xz
mullvadvpn-9e2e6c728f6b1bcdfc171772300ff3b787db2aed.zip
Merge branch 'new-backend-api'
Diffstat (limited to 'app/lib')
-rw-r--r--app/lib/backend-redux-actions.js3
-rw-r--r--app/lib/backend.js75
-rw-r--r--app/lib/ipc.js93
-rw-r--r--app/lib/keyframe-animation.js2
4 files changed, 103 insertions, 70 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/backend.js b/app/lib/backend.js
index 38adc6cf14..cfd6596bdb 100644
--- a/app/lib/backend.js
+++ b/app/lib/backend.js
@@ -1,4 +1,3 @@
-import moment from 'moment';
import log from 'electron-log';
import Enum from './enum';
import { EventEmitter } from 'events';
@@ -180,26 +179,13 @@ export default class Backend extends EventEmitter {
this._registerIpcListeners();
}
- /**
- * Tells whether account has credits
- *
- * @type {bool}
- * @readonly
- *
- * @memberOf Backend
- */
- get hasCredits() {
- return this._paidUntil !== null &&
- moment(this._paidUntil).isAfter(moment());
- }
-
sync() {
log.info('Syncing with the backend...');
- this._ipc.send('get_connection')
- .then( connectionInfo => {
- log.info('Got connection info', connectionInfo);
- this.emit(Backend.EventType.updatedIp, connectionInfo.ip);
+ this._ipc.send('get_ip')
+ .then( ip => {
+ log.info('Got ip', ip);
+ this.emit(Backend.EventType.updatedIp, ip);
})
.catch(e => {
log.info('Failed syncing with the backend', e);
@@ -282,22 +268,30 @@ export default class Backend extends EventEmitter {
*/
login(account) {
log.info('Attempting to login with account number', account);
- this._paidUntil = null;
// emit: logging in
this.emit(Backend.EventType.logging, { account }, null);
- this._ipc.send('login', {
- accountNumber: account,
- }).then(response => {
- log.info('Successfully logged in', response);
- this._paidUntil = response.paidUntil;
- this.emit(Backend.EventType.login, response, undefined);
- }).catch(e => {
- console.warn('Failed to log in', e);
- const err = new BackendError(Backend.ErrorType.invalidAccount);
- this.emit(Backend.EventType.login, {}, err);
- });
+
+
+ this._ipc.send('get_account_data', account)
+ .then(response => {
+ log.info('Account exists', response);
+
+ return this._ipc.send('set_account', account)
+ .then(() => response );
+ }).then( accountData => {
+ log.info('Log in complete');
+
+ this.emit(Backend.EventType.login, {
+ paidUntil: accountData.paid_until,
+ }, undefined);
+
+ }).catch(e => {
+ log.error('Failed to log in', e);
+ const err = new BackendError(Backend.ErrorType.invalidAccount);
+ this.emit(Backend.EventType.login, {}, err);
+ });
}
/**
@@ -308,15 +302,13 @@ export default class Backend extends EventEmitter {
*/
logout() {
// @TODO: What does it mean for a logout to be successful or failed?
- this._ipc.send('logout')
+ this._ipc.send('set_account', '')
.then(() => {
- this._paidUntil = null;
-
// emit event
this.emit(Backend.EventType.logout);
// disconnect user during logout
- this.disconnect();
+ return this.disconnect();
})
.catch(e => {
log.info('Failed to logout', e);
@@ -333,15 +325,14 @@ export default class Backend extends EventEmitter {
* @memberOf Backend
*/
connect(addr) {
- // do not attempt to connect when no credits available
- if(!this.hasCredits) {
- return;
- }
// emit: connecting
this.emit(Backend.EventType.connecting, addr);
- this._ipc.send('connect', { address: addr })
+ this._ipc.send('set_country', addr)
+ .then( () => {
+ return this._ipc.send('connect');
+ })
.then(() => {
this.emit(Backend.EventType.connect, addr);
this.sync(); // TODO: This is a pooooooor way of updating the location and the IP and stuff
@@ -360,12 +351,6 @@ export default class Backend extends EventEmitter {
*/
disconnect() {
// @TODO: Failure modes
- this._ipc.send('cancelConnection')
- .catch(e => {
- log.info('Failed cancelling connection', e);
- });
-
- // @TODO: Failure modes
this._ipc.send('disconnect')
.then(() => {
// emit: disconnect
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
+}