1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import BridgeSettingsBuilder from '../../shared/bridge-settings-builder';
import { LiftedConstraint, RelayLocation } from '../../shared/daemon-rpc-types';
import log from '../../shared/logging';
import RelaySettingsBuilder from '../../shared/relay-settings-builder';
import SelectLocation from '../components/SelectLocation';
import withAppContext, { IAppContext } from '../context';
import { IHistoryProps, withHistory } from '../lib/history';
import { RoutePath } from '../lib/routes';
import { IRelayLocationRedux } from '../redux/settings/reducers';
import { IReduxState, ReduxDispatch } from '../redux/store';
import userInterfaceActions from '../redux/userinterface/actions';
import { LocationScope } from '../redux/userinterface/reducers';
const mapStateToProps = (state: IReduxState) => {
let selectedExitLocation: RelayLocation | undefined;
let selectedBridgeLocation: LiftedConstraint<RelayLocation> | undefined;
if ('normal' in state.settings.relaySettings) {
const exitLocation = state.settings.relaySettings.normal.location;
if (exitLocation !== 'any') {
selectedExitLocation = exitLocation;
}
}
if ('normal' in state.settings.bridgeSettings) {
selectedBridgeLocation = state.settings.bridgeSettings.normal.location;
}
const allowBridgeSelection = state.settings.bridgeState === 'on';
const locationScope = allowBridgeSelection
? state.userInterface.locationScope
: LocationScope.relay;
const relaySettings = state.settings.relaySettings;
const providers = 'normal' in relaySettings ? relaySettings.normal.providers : [];
return {
selectedExitLocation,
selectedBridgeLocation,
relayLocations: filterLocationsByProvider(state.settings.relayLocations, providers),
bridgeLocations: filterLocationsByProvider(state.settings.bridgeLocations, providers),
locationScope,
allowBridgeSelection,
providers,
};
};
const mapDispatchToProps = (dispatch: ReduxDispatch, props: IHistoryProps & IAppContext) => {
const userInterface = bindActionCreators(userInterfaceActions, dispatch);
return {
onClose: () => props.history.dismiss(),
onViewFilterByProvider: () => props.history.push(RoutePath.filterByProvider),
onChangeLocationScope: (scope: LocationScope) => {
userInterface.setLocationScope(scope);
},
onSelectExitLocation: async (relayLocation: RelayLocation) => {
// dismiss the view first
props.history.dismiss();
try {
const relayUpdate = RelaySettingsBuilder.normal().location.fromRaw(relayLocation).build();
await props.app.updateRelaySettings(relayUpdate);
await props.app.connectTunnel();
} catch (e) {
const error = e as Error;
log.error(`Failed to select the exit location: ${error.message}`);
}
},
onSelectBridgeLocation: async (bridgeLocation: RelayLocation) => {
// dismiss the view first
props.history.dismiss();
try {
await props.app.updateBridgeSettings(
new BridgeSettingsBuilder().location.fromRaw(bridgeLocation).build(),
);
} catch (e) {
const error = e as Error;
log.error(`Failed to select the bridge location: ${error.message}`);
}
},
onSelectClosestToExit: async () => {
// dismiss the view first
props.history.dismiss();
try {
await props.app.updateBridgeSettings(new BridgeSettingsBuilder().location.any().build());
} catch (e) {
const error = e as Error;
log.error(`Failed to set the bridge location to closest to exit: ${error.message}`);
}
},
onClearProviders: async () => {
await props.app.updateRelaySettings({ normal: { providers: [] } });
},
};
};
function filterLocationsByProvider(
locations: IRelayLocationRedux[],
providers: string[],
): IRelayLocationRedux[] {
return providers.length === 0
? locations
: locations
.map((country) => ({
...country,
cities: country.cities
.map((city) => ({
...city,
relays: city.relays.filter((relay) => providers.includes(relay.provider)),
}))
.filter((city) => city.relays.length > 0),
}))
.filter((country) => country.cities.length > 0);
}
export default withAppContext(
withHistory(connect(mapStateToProps, mapDispatchToProps)(SelectLocation)),
);
|