summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@codeispoetry.ru>2017-06-19 19:11:49 +0300
committerAndrej Mihajlov <and@codeispoetry.ru>2017-06-21 16:13:32 +0300
commit1137b82c76214f37e7d88ff2e6068705da52e7dc (patch)
tree9fe97235c2d92c429a31a79181c94b902393b7e5
parent5ae8eda0075ec72424c478fdf1ff731db43b0ff5 (diff)
downloadmullvadvpn-1137b82c76214f37e7d88ff2e6068705da52e7dc.tar.xz
mullvadvpn-1137b82c76214f37e7d88ff2e6068705da52e7dc.zip
- Migrate Backend.EventType and Backend.ErrorType to Flow
- Export Backend and BackendError separately
-rw-r--r--app/app.js8
-rw-r--r--app/components/Connect.js8
-rw-r--r--app/lib/backend-redux-actions.js21
-rw-r--r--app/lib/backend-routing.js5
-rw-r--r--app/lib/backend.js271
-rw-r--r--test/actions.spec.js17
-rw-r--r--test/routing.spec.js8
7 files changed, 85 insertions, 253 deletions
diff --git a/app/app.js b/app/app.js
index 86084202af..1ef9bc7e14 100644
--- a/app/app.js
+++ b/app/app.js
@@ -10,7 +10,7 @@ import makeRoutes from './routes';
import configureStore from './store';
import userActions from './actions/user';
import connectActions from './actions/connect';
-import Backend from './lib/backend';
+import { Backend } from './lib/backend';
import mapBackendEventsToReduxActions from './lib/backend-redux-actions';
import mapBackendEventsToRouter from './lib/backend-routing';
@@ -68,9 +68,9 @@ ipcRenderer.on('backend-info', (_event, args) => {
backend.sync();
});
// Setup events to update tray icon
-backend.on(Backend.EventType.connect, updateTrayIcon);
-backend.on(Backend.EventType.connecting, updateTrayIcon);
-backend.on(Backend.EventType.disconnect, updateTrayIcon);
+backend.on('connect', updateTrayIcon);
+backend.on('connecting', updateTrayIcon);
+backend.on('disconnect', updateTrayIcon);
// force update tray
updateTrayIcon();
diff --git a/app/components/Connect.js b/app/components/Connect.js
index 0a3bd761a9..9904012b85 100644
--- a/app/components/Connect.js
+++ b/app/components/Connect.js
@@ -6,7 +6,7 @@ import ReactMapboxGl, { Marker } from 'react-mapbox-gl';
import cheapRuler from 'cheap-ruler';
import { Layout, Container, Header } from './Layout';
import { mapbox as mapboxConfig } from '../config';
-import Backend from '../lib/backend';
+import { BackendError } from '../lib/backend';
import ExternalLinkSVG from '../assets/images/icon-extLink.svg';
import type HeaderBarStyle from './HeaderBar';
@@ -55,12 +55,12 @@ export default class Connect extends Component {
// this is by far the simplest implementation
// later on backend will notify us and disconnect VPN etc..
if(moment(this.props.user.paidUntil).isSameOrBefore(moment())) {
- error = new Backend.Error(Backend.ErrorType.noCredit);
+ error = new BackendError('NO_CREDIT');
}
// Offline?
if(this.props.connect.isOnline === false) {
- error = new Backend.Error(Backend.ErrorType.noInternetConnection);
+ error = new BackendError('NO_INTERNET');
}
return (
@@ -89,7 +89,7 @@ export default class Connect extends Component {
<div className="connect__error-message">
{ error.message }
</div>
- <If condition={ error.code === Backend.ErrorType.noCredit }>
+ <If condition={ error.code === 'NO_CREDIT' }>
<Then>
<div>
<button className="button button--positive" onClick={ this.onExternalLink.bind(this, 'purchase') }>
diff --git a/app/lib/backend-redux-actions.js b/app/lib/backend-redux-actions.js
index 50bfd22943..654651942f 100644
--- a/app/lib/backend-redux-actions.js
+++ b/app/lib/backend-redux-actions.js
@@ -1,7 +1,6 @@
+import log from 'electron-log';
import userActions from '../actions/user';
import connectActions from '../actions/connect';
-import Backend from './backend';
-import log from 'electron-log';
/**
* Add event listeners to translate backend events to redux dispatch.
@@ -67,13 +66,13 @@ export default function mapBackendEventsToReduxActions(backend, store) {
store.dispatch(connectActions.connectionChange({ isOnline }));
};
- backend.on(Backend.EventType.updatedIp, onUpdateIp);
- backend.on(Backend.EventType.updatedLocation, onUpdateLocation);
- backend.on(Backend.EventType.connecting, onConnecting);
- backend.on(Backend.EventType.connect, onConnect);
- backend.on(Backend.EventType.disconnect, onDisconnect);
- backend.on(Backend.EventType.logging, onLoggingIn);
- backend.on(Backend.EventType.login, onLogin);
- backend.on(Backend.EventType.logout, onLogout);
- backend.on(Backend.EventType.updatedReachability, onReachability);
+ backend.on('updatedIp', onUpdateIp);
+ backend.on('updatedLocation', onUpdateLocation);
+ backend.on('connecting', onConnecting);
+ backend.on('connect', onConnect);
+ backend.on('disconnect', onDisconnect);
+ backend.on('logging', onLoggingIn);
+ backend.on('login', onLogin);
+ backend.on('logout', onLogout);
+ backend.on('updatedReachability', onReachability);
}
diff --git a/app/lib/backend-routing.js b/app/lib/backend-routing.js
index 11c9f349eb..2a49a8a3e9 100644
--- a/app/lib/backend-routing.js
+++ b/app/lib/backend-routing.js
@@ -1,5 +1,4 @@
import { replace } from 'react-router-redux';
-import Backend from './backend';
/**
* Add listeners to translate backend events to react router actions
@@ -10,7 +9,7 @@ import Backend from './backend';
*/
export default function mapBackendEventsToRouter(backend, store) {
// redirect user to main screen after login
- backend.on(Backend.EventType.login, (_account, error) => {
+ backend.on('login', (_account, error) => {
if(error) { return; } // no-op on error
setTimeout(() => {
@@ -27,5 +26,5 @@ export default function mapBackendEventsToRouter(backend, store) {
});
// redirect user to login page on logout
- backend.on(Backend.EventType.logout, () => store.dispatch(replace('/')));
+ backend.on('logout', () => store.dispatch(replace('/')));
}
diff --git a/app/lib/backend.js b/app/lib/backend.js
index 7cf1d5b043..a3574557a4 100644
--- a/app/lib/backend.js
+++ b/app/lib/backend.js
@@ -1,114 +1,43 @@
// @flow
-
import log from 'electron-log';
-import Enum from './enum';
import EventEmitter from 'events';
import { servers } from '../config';
import { IpcFacade, RealIpc } from './ipc-facade';
-/**
- * Server info
- * @typedef {object} ServerInfo
- * @property {string} address - server address
- * @property {string} name - server name
- * @property {string} city - location city
- * @property {string} country - location country
- * @property {number[]} location - geo coordinate [latitude, longitude]
- *
- */
-
-/**
- * Connect event
- *
- * @event Backend.EventType.connect
- * @param {string} addr - server address
- * @param {error|null} error - error
- */
-
-/**
- * Connecting event
- *
- * @event Backend.EventType.connecting
- * @param {string} addr - server address
- */
-
-/**
- * Disconnect event
- *
- * @event Backend.EventType.disconnect
- * @param {string} addr - server address
- */
-
-/**
- * Login event
- *
- * @event Backend.EventType.login
- * @param {object} response
- * @param {error} error
- */
-
-/**
- * Logging event
- *
- * @event Backend.EventType.logging
- * @param {object} response
- */
+export type EventType = 'connect' | 'connecting' | 'disconnect' | 'login' | 'logging' | 'logout' | 'updatedIp' | 'updatedLocation' | 'updatedReachability';
+export type ErrorType = 'NO_CREDIT' | 'NO_INTERNET' | 'INVALID_ACCOUNT';
-/**
- * Logout event
- *
- * @event Backend.EventType.logout
- */
-
-/**
- * Updated IP event
- *
- * @event Backend.EventType.updatedIp
- * @param {string} new IP address
- */
-/**
- * Updated location event
- *
- * @event Backend.EventType.updatedLocation
- * @param {object} location data
- */
-
-/**
- * Updated reachability
- *
- * @event Backend.EventType.updatedReachability
- * @param {bool} true if online, otherwise false
- */
-
-class BackendError extends Error {
- code: number;
+export class BackendError extends Error {
+ type: ErrorType;
title: string;
message: string;
- constructor(code) {
+ constructor(type: ErrorType) {
super('');
- this.code = code;
- this.title = BackendError.localizedTitle(code);
- this.message = BackendError.localizedMessage(code);
+ this.type = type;
+ this.title = BackendError.localizedTitle(type);
+ this.message = BackendError.localizedMessage(type);
}
- static localizedTitle(code) {
- switch(code) {
- case Backend.ErrorType.noCredit:
+ static localizedTitle(type: ErrorType): string {
+ switch(type) {
+ case 'NO_CREDIT':
return 'Out of time';
- case Backend.ErrorType.noInternetConnection:
+ case 'NO_INTERNET':
return 'Offline';
default:
return 'Something went wrong';
}
}
- static localizedMessage(code) {
- switch(code) {
- case Backend.ErrorType.noCredit:
+ static localizedMessage(type: ErrorType): string {
+ switch(type) {
+ case 'NO_CREDIT':
return 'Buy more time, so you can continue using the internet securely';
- case Backend.ErrorType.noInternetConnection:
+ case 'NO_INTERNET':
return 'Your internet connection will be secured when you get back online';
+ case 'INVALID_ACCOUNT':
+ return 'Invalid account number';
default:
return '';
}
@@ -118,63 +47,15 @@ class BackendError extends Error {
/**
* Backend implementation
- *
- * @class Backend
*/
-export default class Backend extends EventEmitter {
-
- /**
- * BackendError type
- *
- * @static
- *
- * @memberOf Backend
- */
- static Error = BackendError;
-
- /**
- * Backend error enum
- *
- * @static
- *
- * @memberOf Backend
- */
- static ErrorType = new Enum({
- noCredit: 1,
- noInternetConnection: 2,
- invalidAccount: 3
- });
-
- /**
- * Event type enum
- *
- * @type {EventType}
- * @extends {Enum}
- * @property {string} connect
- * @property {string} connecting
- * @property {string} disconnect
- * @property {string} login
- * @property {string} logging
- * @property {string} logout
- * @property {string} updatedIp
- * @property {string} updatedLocation
- * @property {string} updatedReachability
- */
- static EventType = new Enum('connect', 'connecting', 'disconnect', 'login', 'logging', 'logout', 'updatedIp', 'updatedLocation', 'updatedReachability');
+export class Backend {
_ipc: IpcFacade;
+ _eventEmitter = new EventEmitter();
- /**
- * Creates an instance of Backend.
- *
- * @memberOf Backend
- */
- constructor(ipc: IpcFacade) {
- super();
+ constructor(ipc: ?IpcFacade) {
this._ipc = ipc || new RealIpc('');
this._registerIpcListeners();
-
- // check for network reachability
this._startReachability();
}
@@ -191,7 +72,7 @@ export default class Backend extends EventEmitter {
this._ipc.getIp()
.then( ip => {
log.info('Got ip', ip);
- this.emit(Backend.EventType.updatedIp, ip);
+ this._emit('updatedIp', ip);
})
.catch(e => {
log.info('Failed syncing with the backend', e);
@@ -205,22 +86,13 @@ export default class Backend extends EventEmitter {
country: location.country,
city: location.city
};
- this.emit(Backend.EventType.updatedLocation, newLocation, null);
+ this._emit('updatedLocation', newLocation, null);
})
.catch(e => {
log.info('Failed getting new location', e);
});
}
- /**
- * Get server info by key
- * 'fastest' or 'nearest' can be used as well
- *
- * @param {string} key
- * @returns {ServerInfo}
- *
- * @memberOf Backend
- */
serverInfo(key: string) {
switch(key) {
case 'fastest': return this.fastestServer();
@@ -229,13 +101,6 @@ export default class Backend extends EventEmitter {
}
}
- /**
- * Get fastest server info
- *
- * @returns {ServerInfo}
- *
- * @memberOf Backend
- */
fastestServer() {
return {
address: 'uk.mullvad.net',
@@ -246,13 +111,6 @@ export default class Backend extends EventEmitter {
};
}
- /**
- * Get nearest server info
- *
- * @returns {ServerInfo}
- *
- * @memberOf Backend
- */
nearestServer() {
return {
address: 'es.mullvad.net',
@@ -263,20 +121,11 @@ export default class Backend extends EventEmitter {
};
}
- /**
- * Log in with mullvad account
- *
- * @emits Backend.EventType.logging
- * @emits Backend.EventType.login
- * @param {string} account
- *
- * @memberOf Backend
- */
login(account: string) {
log.info('Attempting to login with account number', account);
// emit: logging in
- this.emit(Backend.EventType.logging, { account }, null);
+ this._emit('logging', { account }, null);
this._ipc.getAccountData(account)
.then( response => {
@@ -288,29 +137,23 @@ export default class Backend extends EventEmitter {
}).then( accountData => {
log.info('Log in complete');
- this.emit(Backend.EventType.login, {
+ this._emit('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);
+ const err = new BackendError('INVALID_ACCOUNT');
+ this._emit('login', {}, err);
});
}
- /**
- * Log out
- *
- * @emits Backend.EventType.logout
- * @memberOf Backend
- */
logout() {
// @TODO: What does it mean for a logout to be successful or failed?
this._ipc.setAccount('')
.then(() => {
// emit event
- this.emit(Backend.EventType.logout);
+ this._emit('logout');
// disconnect user during logout
return this.disconnect();
@@ -320,46 +163,31 @@ export default class Backend extends EventEmitter {
});
}
- /**
- * Connect to VPN server
- * @emits Backend.EventType.connecting
- * @emits Backend.EventType.connect
- *
- * @param {string} addr IP address or domain name
- *
- * @memberOf Backend
- */
connect(addr: string) {
// emit: connecting
- this.emit(Backend.EventType.connecting, addr);
+ this._emit('connecting', addr);
this._ipc.setCountry(addr)
.then( () => {
return this._ipc.connect();
})
.then(() => {
- this.emit(Backend.EventType.connect, addr);
+ this._emit('connect', addr);
this.sync(); // TODO: This is a pooooooor way of updating the location and the IP and stuff
})
.catch(e => {
log.info('Failed connecting to', addr, e);
- this.emit(Backend.EventType.connect, undefined, e);
+ this._emit('connect', undefined, e);
});
}
- /**
- * Disconnect from VPN server
- *
- * @emits Backend.EventType.disconnect
- * @memberOf Backend
- */
disconnect() {
// @TODO: Failure modes
this._ipc.disconnect()
.then(() => {
// emit: disconnect
- this.emit(Backend.EventType.disconnect);
+ this._emit('disconnect');
this.sync(); // TODO: This is a pooooooor way of updating the location and the IP and stuff
})
.catch(e => {
@@ -371,31 +199,38 @@ export default class Backend extends EventEmitter {
* Start reachability monitoring for online/offline detection
* This is currently done via HTML5 APIs but will be replaced later
* with proper backend integration.
- * @private
- * @memberOf Backend
- * @emits Backend.EventType.updatedReachability
*/
_startReachability() {
- // update online status in background
- setTimeout(() => {
- this.emit(Backend.EventType.updatedReachability, navigator.onLine);
- }, 0);
-
- window.addEventListener('online', () => {
- this.emit(Backend.EventType.updatedReachability, true);
- });
-
+ window.addEventListener('online', () => this._emit('updatedReachability', true));
window.addEventListener('offline', () => {
// force disconnect since there is no real connection anyway.
this.disconnect();
- this.emit(Backend.EventType.updatedReachability, false);
+ this._emit('updatedReachability', false);
});
- }
+ // update online status in background
+ setTimeout(() => this._emit('updatedReachability', navigator.onLine), 0);
+ }
_registerIpcListeners() {
/*this._ipc.on('connection-info', (newConnectionInfo) => {
log.info('Got new connection info from backend', newConnectionInfo);
});*/
}
+
+ on(event: EventType, listener: Function) {
+ this._eventEmitter.on(event, listener);
+ }
+
+ once(event: EventType, listener: Function) {
+ this._eventEmitter.once(event, listener);
+ }
+
+ off(event: EventType, listener: Function) {
+ this._eventEmitter.removeListener(event, listener);
+ }
+
+ _emit(event: EventType, ...args:Array<any>): boolean {
+ return this._eventEmitter.emit(event, ...args);
+ }
}
diff --git a/test/actions.spec.js b/test/actions.spec.js
index 914483161e..d1bffe2d5e 100644
--- a/test/actions.spec.js
+++ b/test/actions.spec.js
@@ -1,8 +1,7 @@
// @flow
-
import { expect } from 'chai';
import { filterMinorActions, mockState, mockStore } from './mocks/redux';
-import Backend from '../app/lib/backend';
+import { Backend } from '../app/lib/backend';
import { newMockIpc } from './mocks/ipc';
import userActions from '../app/actions/user';
import connectActions from '../app/actions/connect';
@@ -28,7 +27,7 @@ describe('actions', function() {
mapBackendEventsToReduxActions(backend, store);
- backend.once(Backend.EventType.login, () => {
+ backend.once('login', () => {
const storeActions = filterMinorActions(store.getActions());
expect(storeActions).deep.equal(expectedActions);
done();
@@ -47,7 +46,7 @@ describe('actions', function() {
const backend = new Backend(mockIpc);
mapBackendEventsToReduxActions(backend, store);
- backend.once(Backend.EventType.logout, () => {
+ backend.once('logout', () => {
const storeActions = filterMinorActions(store.getActions());
expect(storeActions).deep.equal(expectedActions);
@@ -73,7 +72,7 @@ describe('actions', function() {
};
mapBackendEventsToReduxActions(backend, store);
- backend.once(Backend.EventType.connect, () => {
+ backend.once('connect', () => {
const storeActions = filterMinorActions(store.getActions())
.filter(action => {
@@ -83,8 +82,8 @@ describe('actions', function() {
expect(storeActions).deep.equal(expectedActions);
done();
});
-
- backend.once(Backend.EventType.login, () => {
+
+ backend.once('login', () => {
store.dispatch(connectActions.connect(backend, '1.2.3.4'));
});
store.dispatch(userActions.login(backend, '1'));
@@ -111,7 +110,7 @@ describe('actions', function() {
const backend = new Backend(newMockIpc());
mapBackendEventsToReduxActions(backend, store);
- backend.once(Backend.EventType.disconnect, () => {
+ backend.once('disconnect', () => {
const storeActions = filterMinorActions(store.getActions());
expect(storeActions).deep.equal(expectedActions);
@@ -143,7 +142,7 @@ describe('actions', function() {
const backend = new Backend(newMockIpc());
mapBackendEventsToReduxActions(backend, store);
- backend.once(Backend.EventType.disconnect, () => {
+ backend.once('disconnect', () => {
const storeActions = filterMinorActions(store.getActions());
expect(storeActions).deep.equal(expectedActions);
diff --git a/test/routing.spec.js b/test/routing.spec.js
index e728ca59a6..062c1e5246 100644
--- a/test/routing.spec.js
+++ b/test/routing.spec.js
@@ -3,7 +3,7 @@ import { expect } from 'chai';
import { filterMinorActions, mockState, mockStore } from './mocks/redux';
import userActions from '../app/actions/user';
import mapBackendEventsToRouter from '../app/lib/backend-routing';
-import Backend from '../app/lib/backend';
+import { Backend } from '../app/lib/backend';
import { newMockIpc } from './mocks/ipc';
describe('routing', function() {
@@ -24,7 +24,7 @@ describe('routing', function() {
const store = mockStore(state);
const backend = new Backend(newMockIpc());
mapBackendEventsToRouter(backend, store);
-
+
store.dispatch(userActions.logout(backend));
setTimeout(() => {
@@ -37,11 +37,11 @@ describe('routing', function() {
const expectedActions = [
{ type: '@@router/CALL_HISTORY_METHOD', payload: { method: 'replace', args: [ '/connect' ] } }
];
-
+
const store = mockStore(mockState());
const backend = new Backend(newMockIpc());
mapBackendEventsToRouter(backend, store);
-
+
store.subscribe(() => {
const storeActions = filterMinorActions(store.getActions());
expect(storeActions).deep.equal(expectedActions);