summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--app/app.js14
-rw-r--r--app/lib/backend-redux-actions.js83
-rw-r--r--app/lib/backend-routing.js30
-rw-r--r--app/lib/backend.js44
-rw-r--r--app/lib/ipc-facade.js9
-rw-r--r--test/mocks/ipc.js2
-rw-r--r--test/routing.spec.js37
7 files changed, 18 insertions, 201 deletions
diff --git a/app/app.js b/app/app.js
index 07c3126fa1..1e56830880 100644
--- a/app/app.js
+++ b/app/app.js
@@ -13,8 +13,6 @@ import configureStore from './redux/store';
import accountActions from './redux/account/actions';
import connectionActions from './redux/connection/actions';
import { Backend } from './lib/backend';
-import mapBackendEventsToReduxActions from './lib/backend-redux-actions';
-import mapBackendEventsToRouter from './lib/backend-routing';
import type { LoginState } from './redux/account/reducers';
import type { ConnectionState } from './redux/connection/reducers';
@@ -57,23 +55,15 @@ const getIconType = (s: ConnectionState): TrayIconType => {
*/
const updateTrayIcon = () => {
const { connection } = store.getState();
+ // TODO: Only update the tray icon if the connection status changed
ipcRenderer.send('changeTrayIcon', getIconType(connection.status));
};
-
-// Setup primary event handlers to translate backend events into redux dispatch
-mapBackendEventsToReduxActions(backend, store);
-
-// Setup routing based on backend events
-mapBackendEventsToRouter(backend, store);
+store.subscribe(updateTrayIcon);
ipcRenderer.on('backend-info', (_event, args) => {
backend.setLocation(args.addr);
backend.sync();
});
-// Setup events to update tray icon
-backend.on('connect', updateTrayIcon);
-backend.on('connecting', updateTrayIcon);
-backend.on('disconnect', updateTrayIcon);
// force update tray
updateTrayIcon();
diff --git a/app/lib/backend-redux-actions.js b/app/lib/backend-redux-actions.js
deleted file mode 100644
index bf5f2cc59d..0000000000
--- a/app/lib/backend-redux-actions.js
+++ /dev/null
@@ -1,83 +0,0 @@
-// @flow
-
-import log from 'electron-log';
-import accountActions from '../redux/account/actions.js';
-import connectionActions from '../redux/connection/actions.js';
-import { Backend } from './backend.js';
-import type { ReduxStore } from '../redux/store.js';
-
-/**
- * Add event listeners to translate backend events to redux dispatch.
- *
- * @export
- * @param {Backend} backend
- * @param {Redux.Store} store
- */
-export default function mapBackendEventsToReduxActions(backend: Backend, store: ReduxStore) {
-
- const onUpdateIp = (clientIp) => {
- store.dispatch(connectionActions.connectionChange({ clientIp }));
- };
-
- const onUpdateLocation = (data) => {
- store.dispatch(accountActions.loginChange(data));
- };
-
- const onConnecting = (serverAddress) => {
- store.dispatch(connectionActions.connectionChange({
- status: 'connecting',
- serverAddress
- }));
- };
-
- const onConnect = (serverAddress, error) => {
- if (error) {
- log.error('Unable to connect to', serverAddress, error);
- } else {
- store.dispatch(connectionActions.connectionChange({ status: 'connected' }));
- }
- };
-
- const onDisconnect = () => {
- store.dispatch(connectionActions.connectionChange({
- status: 'disconnected',
- serverAddress: null
- }));
- };
-
- const onLoggingIn = (info) => {
- store.dispatch(accountActions.loginChange(Object.assign({
- status: 'connecting',
- error: null
- }, info)));
- };
-
- const onLogin = (info, error) => {
- const status = error ? 'failed' : 'ok';
- const paidUntil = info.paidUntil ? info.paidUntil : null;
- store.dispatch(accountActions.loginChange({ paidUntil, status, error }));
- };
-
- const onLogout = () => {
- store.dispatch(accountActions.loginChange({
- status: 'none',
- accountNumber: '',
- paidUntil: null,
- error: null
- }));
- };
-
- const onReachability = (isOnline) => {
- store.dispatch(connectionActions.connectionChange({ isOnline }));
- };
-
- 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
deleted file mode 100644
index 2a49a8a3e9..0000000000
--- a/app/lib/backend-routing.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import { replace } from 'react-router-redux';
-
-/**
- * Add listeners to translate backend events to react router actions
- *
- * @export
- * @param {Backend} backend
- * @param {Redux.Store} store
- */
-export default function mapBackendEventsToRouter(backend, store) {
- // redirect user to main screen after login
- backend.on('login', (_account, error) => {
- if(error) { return; } // no-op on error
-
- setTimeout(() => {
- const { settings } = store.getState();
-
- // auto-connect only if autoSecure is on
- if(settings.autoSecure) {
- const server = backend.serverInfo(settings.preferredServer);
- backend.connect(server.address);
- }
-
- store.dispatch(replace('/connect'));
- }, 1000);
- });
-
- // redirect user to login page on logout
- backend.on('logout', () => store.dispatch(replace('/')));
-}
diff --git a/app/lib/backend.js b/app/lib/backend.js
index da2bc60613..9c5b2ed064 100644
--- a/app/lib/backend.js
+++ b/app/lib/backend.js
@@ -94,7 +94,7 @@ export class Backend {
this._ipc.getIp()
.then( ip => {
log.info('Got ip', ip);
- this._emit('updatedIp', ip);
+ this._store.dispatch(connectionActions.connectionChange({ clientIp: ip }));
})
.catch(e => {
log.info('Failed syncing with the backend', e);
@@ -108,7 +108,7 @@ export class Backend {
country: location.country,
city: location.city
};
- this._emit('updatedLocation', newLocation, null);
+ this._store.dispatch(accountActions.loginChange(newLocation));
})
.catch(e => {
log.info('Failed getting new location', e);
@@ -147,9 +147,6 @@ export class Backend {
login(accountNumber: string) {
log.info('Attempting to login with account number', accountNumber);
- // emit: logging in
- this._emit('logging', { accountNumber: accountNumber }, null);
-
this._store.dispatch(accountActions.loginChange({
accountNumber: accountNumber,
status: 'connecting',
@@ -166,10 +163,6 @@ export class Backend {
}).then( accountData => {
log.info('Log in complete');
- this._emit('login', {
- paidUntil: accountData.paid_until,
- }, undefined);
-
this._store.dispatch(accountActions.loginChange({
status: 'ok',
paidUntil: accountData.paid_until,
@@ -190,8 +183,6 @@ export class Backend {
status: 'failed',
error: err,
}));
-
- this._emit('login', {}, err);
});
}
@@ -200,8 +191,6 @@ export class Backend {
// @TODO: What does it mean for a logout to be successful or failed?
this._ipc.setAccount('')
.then(() => {
- // emit event
- this._emit('logout');
this._store.dispatch(accountActions.loginChange({
status: 'none',
@@ -222,8 +211,6 @@ export class Backend {
connect(addr: string) {
- // emit: connecting
- this._emit('connecting', addr);
this._store.dispatch(connectionActions.connectionChange({
status: 'connecting',
serverAddress: addr,
@@ -236,7 +223,6 @@ export class Backend {
})
.catch(e => {
log.info('Failed connecting to', addr, e);
- this._emit('connect', undefined, e);
this._store.dispatch(connectionActions.connectionChange({
status: 'disconnected',
}));
@@ -257,15 +243,19 @@ export class Backend {
* with proper backend integration.
*/
_startReachability() {
- window.addEventListener('online', () => this._emit('updatedReachability', true));
+ window.addEventListener('online', () => {
+ this._store.dispatch(connectionActions.connectionChange({ isOnline: true }));
+ });
window.addEventListener('offline', () => {
// force disconnect since there is no real connection anyway.
this.disconnect();
- this._emit('updatedReachability', false);
+ this._store.dispatch(connectionActions.connectionChange({ isOnline: false }));
});
// update online status in background
- setTimeout(() => this._emit('updatedReachability', navigator.onLine), 0);
+ setTimeout(() => {
+ this._store.dispatch(connectionActions.connectionChange({ isOnline: navigator.onLine }));
+ }, 0);
}
_registerIpcListeners() {
@@ -292,20 +282,4 @@ export class Backend {
throw new Error('Unknown backend state: ' + backendState);
}
}
-
- 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/app/lib/ipc-facade.js b/app/lib/ipc-facade.js
index 19daf71b97..ff2b7050ed 100644
--- a/app/lib/ipc-facade.js
+++ b/app/lib/ipc-facade.js
@@ -1,14 +1,16 @@
// @flow
import JsonRpcWs, { InvalidReply } from './jsonrpc-ws-ipc';
-import { object, string, number, arrayOf } from 'validated/schema';
+import { object, string, arrayOf, number } from 'validated/schema';
import { validate } from 'validated/object';
+import type { Coordinate2d } from '../types';
+
export type AccountData = {paid_until: string};
export type AccountNumber = string;
export type Ip = string;
export type Location = {
- latlong: Array<number>,
+ latlong: Coordinate2d,
country: string,
city: string,
};
@@ -90,7 +92,8 @@ export class RealIpc implements IpcFacade {
return this._ipc.send('get_location')
.then(raw => {
try {
- return validate(LocationSchema, raw);
+ const validated: any = validate(LocationSchema, raw);
+ return (validated: Location);
} catch (e) {
throw new InvalidReply(raw, e);
}
diff --git a/test/mocks/ipc.js b/test/mocks/ipc.js
index 3225fe9ed9..a172bef8e5 100644
--- a/test/mocks/ipc.js
+++ b/test/mocks/ipc.js
@@ -37,7 +37,7 @@ export function newMockIpc() {
return new Promise(r => r({
city: '',
country: '',
- latlong: [],
+ latlong: [0, 0],
}));
},
getState: () => {
diff --git a/test/routing.spec.js b/test/routing.spec.js
deleted file mode 100644
index ccb702de8b..0000000000
--- a/test/routing.spec.js
+++ /dev/null
@@ -1,37 +0,0 @@
-// @flow
-
-import { expect } from 'chai';
-
-import { filterMinorActions, mockState, mockStore } from './mocks/redux';
-import accountActions from '../app/redux/account/actions';
-import mapBackendEventsToRouter from '../app/lib/backend-routing';
-import { Backend } from '../app/lib/backend';
-import { newMockIpc } from './mocks/ipc';
-
-describe('routing', function() {
- this.timeout(10000);
-
- it('should redirect to login screen on logout', () => {
- const expectedActions = [
- { type: '@@router/CALL_HISTORY_METHOD', payload: { method: 'replace', args: [ '/' ] } }
- ];
-
- let state = Object.assign(mockState(), {
- account: {
- account: '1111234567890',
- status: 'ok'
- }
- });
-
- const store = mockStore(state);
- const backend = new Backend(store, newMockIpc());
- mapBackendEventsToRouter(backend, store);
-
- store.dispatch(accountActions.logout(backend));
-
- setTimeout(() => {
- const storeActions = filterMinorActions(store.getActions());
- expect(storeActions).deep.equal(expectedActions);
- }, 0);
- });
-});