diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2017-12-19 12:34:24 +0100 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2017-12-19 14:12:44 +0100 |
| commit | 557595d2c4673004bf0e1218c8bbdc748c7c63b6 (patch) | |
| tree | 5eedbc23b941f21bb189f4b3d127acaa97b0e90e | |
| parent | bbef28c9270aa199143098019546682cf6e3435d (diff) | |
| download | mullvadvpn-557595d2c4673004bf0e1218c8bbdc748c7c63b6.tar.xz mullvadvpn-557595d2c4673004bf0e1218c8bbdc748c7c63b6.zip | |
Integrate RelayList into Redux
| -rw-r--r-- | app/components/Connect.js | 2 | ||||
| -rw-r--r-- | app/components/SelectLocation.js | 38 | ||||
| -rw-r--r-- | app/lib/backend.js | 127 | ||||
| -rw-r--r-- | app/redux/settings/actions.js | 6 | ||||
| -rw-r--r-- | app/redux/settings/reducers.js | 22 | ||||
| -rw-r--r-- | test/components/Connect.spec.js | 23 | ||||
| -rw-r--r-- | test/components/SelectLocation.spec.js | 21 | ||||
| -rw-r--r-- | test/components/Settings.spec.js | 4 |
8 files changed, 137 insertions, 106 deletions
diff --git a/app/components/Connect.js b/app/components/Connect.js index dc8e06c1da..93ac19a4eb 100644 --- a/app/components/Connect.js +++ b/app/components/Connect.js @@ -95,7 +95,7 @@ export default class Connect extends Component { } _findRelayName(relay: RelayLocation): ?string { - const { countries } = this.props.settings.relayLocations; + const countries = this.props.settings.relayLocations; const countryPredicate = (countryCode) => (country) => country.code === countryCode; if(relay.country) { diff --git a/app/components/SelectLocation.js b/app/components/SelectLocation.js index ac00e305d4..7fb124bf33 100644 --- a/app/components/SelectLocation.js +++ b/app/components/SelectLocation.js @@ -8,8 +8,8 @@ import ChevronDownSVG from '../assets/images/icon-chevron-down.svg'; import ChevronUpSVG from '../assets/images/icon-chevron-up.svg'; import TickSVG from '../assets/images/icon-tick.svg'; -import type { SettingsReduxState } from '../redux/settings/reducers'; -import type { RelayLocation, RelayListCity, RelayListCountry } from '../lib/ipc-facade'; +import type { SettingsReduxState, RelayLocationRedux, RelayLocationCityRedux } from '../redux/settings/reducers'; +import type { RelayLocation } from '../lib/ipc-facade'; export type SelectLocationProps = { settings: SettingsReduxState, @@ -73,7 +73,7 @@ export default class SelectLocation extends Component { While connected, your real location is masked with a private and secure location in the selected region </div> - { this.props.settings.relayLocations.countries.map((relayCountry) => { + { this.props.settings.relayLocations.map((relayCountry) => { return this._renderCountry(relayCountry); }) } @@ -126,17 +126,13 @@ export default class SelectLocation extends Component { return (<div className={ 'select-location-relay-status ' + statusClass }></div>); } - _renderCountry(relayCountry: RelayListCountry) { - const countryHasActiveRelays = relayCountry.cities.some((relayCity) => { - return relayCity.has_active_relays; - }); - + _renderCountry(relayCountry: RelayLocationRedux) { const isSelected = this._isSelected({ country: relayCountry.code }); // either expanded by user or when the city selected within the country const isExpanded = this.state.expanded.includes(relayCountry.code); - const handleSelect = (countryHasActiveRelays && !isSelected) ? () => { + const handleSelect = (relayCountry.hasActiveRelays && !isSelected) ? () => { this.props.onSelect({ country: relayCountry.code }); } : undefined; @@ -147,7 +143,7 @@ export default class SelectLocation extends Component { const countryClass = 'select-location__cell' + (isSelected ? ' select-location__cell--selected' : '') + - (countryHasActiveRelays ? ' select-location__cell--selectable' : ''); + (relayCountry.hasActiveRelays ? ' select-location__cell--selectable' : ''); const onRef = isSelected ? (element) => { this._selectedCell = element; @@ -163,16 +159,16 @@ export default class SelectLocation extends Component { <div className="select-location__cell-icon"> { isSelected ? <TickSVG /> : - this._relayStatusIndicator(countryHasActiveRelays) } + this._relayStatusIndicator(relayCountry.hasActiveRelays) } </div> <div className={ 'select-location__cell-label' + - (countryHasActiveRelays ? '' : ' select-location__cell-label--inactive') }> + (relayCountry.hasActiveRelays ? '' : ' select-location__cell-label--inactive') }> { relayCountry.name } </div> </div> - { countryHasActiveRelays && <button type="button" className="select-location__collapse-button" onClick={ handleCollapse }> + { relayCountry.hasActiveRelays && <button type="button" className="select-location__collapse-button" onClick={ handleCollapse }> { isExpanded ? <ChevronUpSVG className="select-location__collapse-icon" /> : <ChevronDownSVG className="select-location__collapse-icon" /> } @@ -180,7 +176,7 @@ export default class SelectLocation extends Component { </div> - { countryHasActiveRelays && relayCountry.cities.length > 0 && + { relayCountry.hasActiveRelays && relayCountry.cities.length > 0 && (<Accordion className="select-location__cities" height={ isExpanded ? 'auto' : 0 }> { relayCountry.cities.map((relayCity) => this._renderCity(relayCountry.code, relayCity)) } </Accordion>) @@ -189,18 +185,16 @@ export default class SelectLocation extends Component { ); } - _renderCity(countryCode: string, relayCity: RelayListCity) { + _renderCity(countryCode: string, relayCity: RelayLocationCityRedux) { const relayLocation: RelayLocation = { city: [countryCode, relayCity.code] }; const isSelected = this._isSelected(relayLocation); - const cityHasActiveRelays = relayCity.has_active_relays; - const key = countryCode + '_' + relayCity.code; const cityClass = 'select-location__sub-cell' + (isSelected ? ' select-location__sub-cell--selected' : '') + - (cityHasActiveRelays ? ' select-location__sub-cell--selectable' : ''); + (relayCity.hasActiveRelays ? ' select-location__sub-cell--selectable' : ''); - const handleSelect = (cityHasActiveRelays && !isSelected) ? () => { + const handleSelect = (relayCity.hasActiveRelays && !isSelected) ? () => { this.props.onSelect(relayLocation); } : undefined; @@ -209,7 +203,7 @@ export default class SelectLocation extends Component { } : undefined; return ( - <div key={ key } + <div key={ `${countryCode}_${relayCity.code}` } className={ cityClass } onClick={ handleSelect } ref={ onRef }> @@ -217,11 +211,11 @@ export default class SelectLocation extends Component { <div className="select-location__cell-icon"> { isSelected ? <TickSVG /> : - this._relayStatusIndicator(cityHasActiveRelays) } + this._relayStatusIndicator(relayCity.hasActiveRelays) } </div> <div className={ 'select-location__cell-label' + - (cityHasActiveRelays ? '' : ' select-location__cell-label--inactive') }> + (relayCity.hasActiveRelays ? '' : ' select-location__cell-label--inactive') }> { relayCity.name } </div> </div> diff --git a/app/lib/backend.js b/app/lib/backend.js index 5fe9421648..f78d359926 100644 --- a/app/lib/backend.js +++ b/app/lib/backend.js @@ -121,54 +121,28 @@ export class Backend { async sync() { log.info('Syncing with the backend...'); - await this._ensureAuthenticated(); - try { - const locations = await this._ipc.getRelayLocations(); - - log.info('Got relay locations'); - - this._store.dispatch( - settingsActions.updateRelayLocations(locations) - ); - } catch (e) { - log.error('Cannot fetch relay locations', e); + await this._fetchRelayLocations(); + } catch(e) { + log.error('Failed to fetch the relay locations: ', e.message); } try { - const publicIp = await this._ipc.getPublicIp(); - - log.info('Got public IP: ', publicIp); - - this._store.dispatch( - connectionActions.newPublicIp(publicIp) - ); - } catch (e) { - log.info('Cannot fetch public IP: ', e.message); + await this._fetchPublicIP(); + } catch(e) { + log.error('Failed to fetch the public IP: ', e.message); } try { - const location = await this._ipc.getLocation(); - - log.info('Got location: ', location); - - const locationUpdate = { - country: location.country, - city: location.city, - location: location.position - }; - - this._store.dispatch( - connectionActions.newLocation(locationUpdate) - ); - } catch (e) { - log.info('Cannot fetch new location: ', e.message); + await this._fetchLocation(); + } catch(e) { + log.error('Failed to fetch the location: ', e.message); } - await this._updateAccountHistory(); + await this._fetchAccountHistory(); } - async login(accountToken: AccountToken): Promise<void> { + async login(accountToken: AccountToken) { log.debug('Attempting to login'); this._store.dispatch(accountActions.startLogin(accountToken)); @@ -197,7 +171,7 @@ export class Backend { this.connect(); }, 1000); - await this._updateAccountHistory(); + await this._fetchAccountHistory(); } catch(e) { log.error('Failed to log in,', e.message); @@ -256,7 +230,7 @@ export class Backend { } } - async connect(): Promise<void> { + async connect() { try { this._store.dispatch(connectionActions.connecting()); @@ -268,7 +242,7 @@ export class Backend { } } - async disconnect(): Promise<void> { + async disconnect() { // @TODO: Failure modes try { await this._ensureAuthenticated(); @@ -278,7 +252,7 @@ export class Backend { } } - async shutdown(): Promise<void> { + async shutdown() { try { await this._ensureAuthenticated(); await this._ipc.shutdown(); @@ -287,7 +261,7 @@ export class Backend { } } - async updateRelaySettings(relaySettings: RelaySettingsUpdate): Promise<void> { + async updateRelaySettings(relaySettings: RelaySettingsUpdate) { try { await this._ensureAuthenticated(); await this._ipc.updateRelaySettings(relaySettings); @@ -296,7 +270,7 @@ export class Backend { } } - async fetchRelaySettings(): Promise<void> { + async fetchRelaySettings() { await this._ensureAuthenticated(); const relaySettings = await this._ipc.getRelaySettings(); @@ -342,17 +316,17 @@ export class Backend { } } - async removeAccountFromHistory(accountToken: AccountToken): Promise<void> { + async removeAccountFromHistory(accountToken: AccountToken) { try { await this._ensureAuthenticated(); await this._ipc.removeAccountFromHistory(accountToken); - await this._updateAccountHistory(); + await this._fetchAccountHistory(); } catch(e) { log.error('Failed to remove account token from history', e.message); } } - async _updateAccountHistory(): Promise<void> { + async _fetchAccountHistory() { try { await this._ensureAuthenticated(); const accountHistory = await this._ipc.getAccountHistory(); @@ -361,9 +335,66 @@ export class Backend { ); } catch(e) { log.info('Failed to fetch account history,', e.message); + throw e; } } + + + async _fetchRelayLocations() { + await this._ensureAuthenticated(); + + const locations = await this._ipc.getRelayLocations(); + + log.info('Got relay locations'); + + const storedLocations = locations.countries.map((country) => ({ + name: country.name, + code: country.code, + hasActiveRelays: country.cities.some((city) => city.has_active_relays), + cities: country.cities.map((city) => ({ + name: city.name, + code: city.code, + position: city.position, + hasActiveRelays: city.has_active_relays, + })) + })); + + this._store.dispatch( + settingsActions.updateRelayLocations(storedLocations) + ); + } + + async _fetchPublicIP() { + await this._ensureAuthenticated(); + + const publicIp = await this._ipc.getPublicIp(); + + log.info('Got public IP: ', publicIp); + + this._store.dispatch( + connectionActions.newPublicIp(publicIp) + ); + } + + async _fetchLocation() { + await this._ensureAuthenticated(); + + const location = await this._ipc.getLocation(); + + log.info('Got location: ', location); + + const locationUpdate = { + country: location.country, + city: location.city, + location: location.position + }; + + this._store.dispatch( + connectionActions.newLocation(locationUpdate) + ); + } + /** * Start reachability monitoring for online/offline detection * This is currently done via HTML5 APIs but will be replaced later @@ -421,7 +452,7 @@ export class Backend { throw new Error('Unsupported state/target state combination: ' + JSON.stringify(backendState)); } - _ensureAuthenticated(): Promise<void> { + _ensureAuthenticated() { const credentials = this._credentials; if(credentials) { if(!this._authenticationPromise) { @@ -433,7 +464,7 @@ export class Backend { } } - async _authenticate(sharedSecret: string): Promise<void> { + async _authenticate(sharedSecret: string) { try { await this._ipc.authenticate(sharedSecret); log.info('Authenticated with backend'); diff --git a/app/redux/settings/actions.js b/app/redux/settings/actions.js index c4f7b20efe..783eb042d2 100644 --- a/app/redux/settings/actions.js +++ b/app/redux/settings/actions.js @@ -1,6 +1,6 @@ // @flow -import type { RelaySettingsRedux, RelayLocationsRedux } from './reducers'; +import type { RelaySettingsRedux, RelayLocationRedux } from './reducers'; export type UpdateRelayAction = { type: 'UPDATE_RELAY', @@ -9,7 +9,7 @@ export type UpdateRelayAction = { export type UpdateRelayLocationsAction = { type: 'UPDATE_RELAY_LOCATIONS', - relayLocations: RelayLocationsRedux + relayLocations: Array<RelayLocationRedux> } export type SettingsAction = UpdateRelayAction | UpdateRelayLocationsAction; @@ -21,7 +21,7 @@ function updateRelay(relay: RelaySettingsRedux): UpdateRelayAction { }; } -function updateRelayLocations(relayLocations: RelayLocationsRedux): UpdateRelayLocationsAction { +function updateRelayLocations(relayLocations: Array<RelayLocationRedux>): UpdateRelayLocationsAction { return { type: 'UPDATE_RELAY_LOCATIONS', relayLocations: relayLocations, diff --git a/app/redux/settings/reducers.js b/app/redux/settings/reducers.js index 779a6306ad..21258a80a7 100644 --- a/app/redux/settings/reducers.js +++ b/app/redux/settings/reducers.js @@ -1,7 +1,7 @@ // @flow import type { ReduxAction } from '../store'; -import type { RelayProtocol, RelayLocation, RelayList } from '../../lib/ipc-facade'; +import type { RelayProtocol, RelayLocation } from '../../lib/ipc-facade'; export type RelaySettingsRedux = {| normal: { @@ -17,11 +17,23 @@ export type RelaySettingsRedux = {| } |}; -export type RelayLocationsRedux = RelayList; +export type RelayLocationCityRedux = { + name: string, + code: string, + position: [number, number], + hasActiveRelays: boolean, +}; + +export type RelayLocationRedux = { + name: string, + code: string, + hasActiveRelays: boolean, + cities: Array<RelayLocationCityRedux>, +}; export type SettingsReduxState = { relaySettings: RelaySettingsRedux, - relayLocations: RelayLocationsRedux, + relayLocations: Array<RelayLocationRedux>, }; const initialState: SettingsReduxState = { @@ -32,9 +44,7 @@ const initialState: SettingsReduxState = { protocol: 'any', } }, - relayLocations: { - countries: [] - }, + relayLocations: [], }; export default function(state: SettingsReduxState = initialState, action: ReduxAction): SettingsReduxState { diff --git a/test/components/Connect.spec.js b/test/components/Connect.spec.js index 799692466f..4fcc3c6f60 100644 --- a/test/components/Connect.spec.js +++ b/test/components/Connect.spec.js @@ -150,18 +150,17 @@ const defaultProps: ConnectProps = { port: 'any', } }, - relayLocations: { - countries: [{ - name: 'Sweden', - code: 'se', - cities: [{ - name: 'Malmö', - code: 'mma', - has_active_relays: true, - position: [0, 0], - }] - }], - }, + relayLocations: [{ + name: 'Sweden', + code: 'se', + hasActiveRelays: true, + cities: [{ + name: 'Malmö', + code: 'mma', + hasActiveRelays: true, + position: [0, 0], + }] + }], }, connection: { status: 'disconnected', diff --git a/test/components/SelectLocation.spec.js b/test/components/SelectLocation.spec.js index a33112d43b..1abdf515d9 100644 --- a/test/components/SelectLocation.spec.js +++ b/test/components/SelectLocation.spec.js @@ -17,18 +17,17 @@ describe('components/SelectLocation', () => { port: 'any', } }, - relayLocations: { - countries: [{ - name: 'Sweden', - code: 'se', - cities: [{ - name: 'Malmö', - code: 'mma', - position: [0, 0], - has_active_relays: true, - }], + relayLocations: [{ + name: 'Sweden', + code: 'se', + hasActiveRelays: true, + cities: [{ + name: 'Malmö', + code: 'mma', + position: [0, 0], + hasActiveRelays: true, }], - }, + }], }; const makeProps = (state: SettingsReduxState, mergeProps: $Shape<SelectLocationProps>): SelectLocationProps => { diff --git a/test/components/Settings.spec.js b/test/components/Settings.spec.js index 7b4780ece2..cc38c54616 100644 --- a/test/components/Settings.spec.js +++ b/test/components/Settings.spec.js @@ -42,9 +42,7 @@ describe('components/Settings', () => { port: 1301, }, }, - relayLocations: { - countries: [], - }, + relayLocations: [], }; const makeProps = (anAccountState: AccountReduxState, aSettingsState: SettingsReduxState, mergeProps: $Shape<SettingsProps> = {}): SettingsProps => { |
