diff options
| author | Andrej Mihajlov <and@codeispoetry.ru> | 2017-06-19 19:11:49 +0300 |
|---|---|---|
| committer | Andrej Mihajlov <and@codeispoetry.ru> | 2017-06-21 16:13:32 +0300 |
| commit | 1137b82c76214f37e7d88ff2e6068705da52e7dc (patch) | |
| tree | 9fe97235c2d92c429a31a79181c94b902393b7e5 | |
| parent | 5ae8eda0075ec72424c478fdf1ff731db43b0ff5 (diff) | |
| download | mullvadvpn-1137b82c76214f37e7d88ff2e6068705da52e7dc.tar.xz mullvadvpn-1137b82c76214f37e7d88ff2e6068705da52e7dc.zip | |
- Migrate Backend.EventType and Backend.ErrorType to Flow
- Export Backend and BackendError separately
| -rw-r--r-- | app/app.js | 8 | ||||
| -rw-r--r-- | app/components/Connect.js | 8 | ||||
| -rw-r--r-- | app/lib/backend-redux-actions.js | 21 | ||||
| -rw-r--r-- | app/lib/backend-routing.js | 5 | ||||
| -rw-r--r-- | app/lib/backend.js | 271 | ||||
| -rw-r--r-- | test/actions.spec.js | 17 | ||||
| -rw-r--r-- | test/routing.spec.js | 8 |
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); |
