Skip to content

Commit

Permalink
refactor(vpnapp): node location logic (#4223)
Browse files Browse the repository at this point in the history
* refactor node location logic

fontend:
remove app local data from state
remove node config from state
use only country location state

backend:
add node location in state
add set_node_location command

* call backend to update node location

* clean code
  • Loading branch information
doums authored Dec 6, 2023
1 parent 7448100 commit 26a8dec
Show file tree
Hide file tree
Showing 21 changed files with 136 additions and 118 deletions.
2 changes: 1 addition & 1 deletion nym-vpn/ui/index.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!doctype html>
<html lang="en" class="text-[14px]">
<html lang="en" class="text-[12px]">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
Expand Down
6 changes: 3 additions & 3 deletions nym-vpn/ui/src-tauri/src/commands/app_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub fn get_node_countries() -> Result<Vec<Country>, CmdError> {
Ok(countries)
}

#[instrument]
#[instrument(skip(state))]
#[tauri::command]
pub async fn set_app_data(
state: State<'_, SharedAppData>,
Expand All @@ -56,7 +56,7 @@ pub async fn set_app_data(
Ok(())
}

#[instrument]
#[instrument(skip_all)]
#[tauri::command]
pub async fn get_app_data(
state: State<'_, SharedAppData>,
Expand All @@ -75,7 +75,7 @@ pub async fn get_app_data(
Ok(data)
}

#[instrument(skip_all)]
#[instrument(skip(data_state))]
#[tauri::command]
pub async fn set_ui_theme(
data_state: State<'_, SharedAppData>,
Expand Down
2 changes: 1 addition & 1 deletion nym-vpn/ui/src-tauri/src/commands/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ pub async fn get_connection_start_time(
Ok(app_state.connection_start_time.map(|t| t.unix_timestamp()))
}

#[instrument(skip_all)]
#[instrument(skip(app_state, data_state))]
#[tauri::command]
pub async fn set_vpn_mode(
app_state: State<'_, SharedAppState>,
Expand Down
1 change: 1 addition & 0 deletions nym-vpn/ui/src-tauri/src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod app_data;
pub mod connection;
pub mod node_location;
59 changes: 59 additions & 0 deletions nym-vpn/ui/src-tauri/src/commands/node_location.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use serde::{Deserialize, Serialize};
use tauri::State;
use tracing::{debug, instrument};
use ts_rs::TS;

use crate::{
error::{CmdError, CmdErrorSource},
states::{app::Country, SharedAppData, SharedAppState},
};

#[derive(Debug, Serialize, Deserialize, TS, Clone)]
pub enum NodeType {
Entry,
Exit,
}

#[instrument(skip(app_state, data_state))]
#[tauri::command]
pub async fn set_node_location(
app_state: State<'_, SharedAppState>,
data_state: State<'_, SharedAppData>,
node_type: NodeType,
country: Country,
) -> Result<(), CmdError> {
debug!("set_node_location");
let mut state = app_state.lock().await;
match node_type {
NodeType::Entry => {
state.entry_node_location = Some(country.clone());
}
NodeType::Exit => {
state.exit_node_location = Some(country.clone());
}
}
// TODO pick a node according to the selected country

// save the location on disk
let mut app_data_store = data_state.lock().await;
let mut app_data = app_data_store
.read()
.await
.map_err(|e| CmdError::new(CmdErrorSource::InternalError, e.to_string()))?;

match node_type {
NodeType::Entry => {
app_data.entry_node_location = Some(country);
}
NodeType::Exit => {
app_data.exit_node_location = Some(country);
}
}
app_data_store.data = app_data;
app_data_store
.write()
.await
.map_err(|e| CmdError::new(CmdErrorSource::InternalError, e.to_string()))?;

Ok(())
}
4 changes: 3 additions & 1 deletion nym-vpn/ui/src-tauri/src/fs/data.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize};
use ts_rs::TS;

use crate::states::app::{NodeConfig, VpnMode};
use crate::states::app::{Country, NodeConfig, VpnMode};

#[derive(Default, Serialize, Deserialize, Debug, Clone, TS)]
#[ts(export)]
Expand All @@ -21,4 +21,6 @@ pub struct AppData {
pub vpn_mode: Option<VpnMode>,
pub entry_node: Option<NodeConfig>,
pub exit_node: Option<NodeConfig>,
pub entry_node_location: Option<Country>,
pub exit_node_location: Option<Country>,
}
1 change: 1 addition & 0 deletions nym-vpn/ui/src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ fn main() -> Result<()> {
app_data::set_app_data,
app_data::set_ui_theme,
app_data::get_node_countries,
node_location::set_node_location,
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
Expand Down
4 changes: 3 additions & 1 deletion nym-vpn/ui/src-tauri/src/states/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use ts_rs::TS;
#[ts(export)]
pub struct NodeConfig {
pub id: String,
pub country: String,
pub country: Country,
}

#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, TS)]
Expand Down Expand Up @@ -42,6 +42,8 @@ pub struct AppState {
pub vpn_mode: VpnMode,
pub entry_node: Option<NodeConfig>,
pub exit_node: Option<NodeConfig>,
pub entry_node_location: Option<Country>,
pub exit_node_location: Option<Country>,
pub tunnel: Option<TunnelConfig>,
pub connection_start_time: Option<OffsetDateTime>,
}
Expand Down
6 changes: 4 additions & 2 deletions nym-vpn/ui/src/dev/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,15 @@ export function mockTauriIPC() {
ui_theme: 'Dark',
vpn_mode: 'TwoHop',
entry_node: {
country: QuickConnectCountry.name,
country: QuickConnectCountry,
id: QuickConnectCountry.code,
},
exit_node: {
country: QuickConnectCountry.name,
country: QuickConnectCountry,
id: QuickConnectCountry.code,
},
entry_node_location: null,
exit_node_location: null,
}),
);
}
Expand Down
9 changes: 2 additions & 7 deletions nym-vpn/ui/src/pages/home/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,9 @@ function Home() {
<NetworkModeSelect />
<div className="py-2"></div>
<HopSelect
country={
state.localAppData.exitNode ?? {
country: QuickConnectCountry.name,
id: QuickConnectCountry.code,
}
}
country={state.exitNodeLocation ?? QuickConnectCountry}
onClick={() => navigate(routes.exitNodeLocation)}
nodeHop={{ type: 'exit' }}
nodeHop="exit"
/>
</div>
<Button
Expand Down
13 changes: 6 additions & 7 deletions nym-vpn/ui/src/pages/home/HopSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { useTranslation } from 'react-i18next';
import { NodeConfig } from '../../types';
import { NodeHop } from '../../types/general';
import { Country, NodeHop } from '../../types';

interface HopSelectProps {
country: NodeConfig;
country: Country;
onClick: () => void;
nodeHop: NodeHop;
}
Expand All @@ -27,13 +26,13 @@ export default function HopSelect({
readOnly={true}
type="text"
id="floating_outlined"
value={country.country}
value={country.name}
className="dark:bg-baltic-sea cursor-pointer pl-11 dark:placeholder-white border border-gun-powder block px-2.5 pb-4 pt-4 w-full text-sm text-gray-900 bg-transparent rounded-lg border-1 border-gray-300 appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-500 focus:outline-none focus:ring-0 focus:border-blue-600 peer"
/>
<img
src={`./flags/${country.id.toLowerCase()}.svg`}
src={`./flags/${country.code.toLowerCase()}.svg`}
className="h-8 scale-75 pointer-events-none absolute fill-current top-1/2 transform -translate-y-1/2 left-2"
alt={country.id}
alt={country.code}
/>
<span className="font-icon scale-125 pointer-events-none absolute fill-current top-1/4 transform -translate-x-1/2 right-2">
arrow_right
Expand All @@ -42,7 +41,7 @@ export default function HopSelect({
htmlFor="floating_outlined"
className="dark:text-white bg-blanc-nacre dark:bg-baltic-sea absolute text-sm text-gray-500 dark:text-gray-400 ml-4 duration-300 transform -translate-y-4 scale-75 top-2 z-10 origin-[0] dark:bg-gray-900 px-2 peer-placeholder-shown:px-2 peer-placeholder-shown:text-blue-600 peer-placeholder-shown:dark:text-blue-500 peer-placeholder-shown:top-2 peer-placeholder-shown:scale-75 peer-placeholder-shown:-translate-y-4 rtl:peer-placeholder-shown:translate-x-1/4 rtl:peer-placeholder-shown:left-auto start-1"
>
{nodeHop.type === 'entry' ? t('first-hop') : t('last-hop')}
{nodeHop === 'entry' ? t('first-hop') : t('last-hop')}
</label>
</div>
</>
Expand Down
2 changes: 1 addition & 1 deletion nym-vpn/ui/src/pages/location/CountryList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default function CountryList({
<ul className="flex flex-col w-full items-stretch p-1">
{countries && countries.length > 0 ? (
countries.map((country) => (
<li key={t(country.name)} className="list-none w-full">
<li key={country.code} className="list-none w-full">
<div
role="presentation"
onKeyDown={() => onClick(country.name, country.code)}
Expand Down
37 changes: 19 additions & 18 deletions nym-vpn/ui/src/pages/location/NodeLocation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,20 @@ import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { invoke } from '@tauri-apps/api';
import { useMainDispatch, useMainState } from '../../contexts';
import { InputEvent, NodeHop } from '../../types/general';
import { Country, StateDispatch } from '../../types';
import { Country, InputEvent, NodeHop, StateDispatch } from '../../types';
import { routes } from '../../constants';
import SearchBox from './SearchBox';
import CountryList from './CountryList';
import QuickConnect from './QuickConnect';

function NodeLocation({ type }: NodeHop) {
const isEntryNodeSelectionScreen = type === 'entry';
function NodeLocation({ node }: { node: NodeHop }) {
const { t } = useTranslation('nodeLocation');
const [countries, setCountries] = useState<Country[]>([]);
const [search, setSearch] = useState('');
const [loading, setLoading] = useState(false);
const [foundCountries, setFoundCountries] = useState<Country[]>([]);

const {
localAppData: { entryNode, exitNode },
} = useMainState();
const { entryNodeLocation, exitNodeLocation } = useMainState();
const dispatch = useMainDispatch() as StateDispatch;

const navigate = useNavigate();
Expand Down Expand Up @@ -54,19 +50,24 @@ function NodeLocation({ type }: NodeHop) {
};

const isCountrySelected = (code: string): boolean => {
return isEntryNodeSelectionScreen
? entryNode?.id === code
: exitNode?.id === code;
return node === 'entry'
? entryNodeLocation?.code === code
: exitNodeLocation?.code === code;
};

const setNodeSelection = (name: string, code: string) => {
const nodeType = isEntryNodeSelectionScreen
? 'set-entry-node'
: 'set-exit-node';
dispatch({ type: nodeType, data: { country: name, id: code } });
};
const handleCountrySelection = (name: string, code: string) => {
setNodeSelection(name, code);
const handleCountrySelection = async (name: string, code: string) => {
try {
await invoke<void>('set_node_location', {
nodeType: node === 'entry' ? 'Entry' : 'Exit',
country: { name, code },
});
dispatch({
type: 'set-node-location',
payload: { hop: node, country: { name, code } },
});
} catch (e) {
console.log(e);
}
navigate(routes.root);
};

Expand Down
4 changes: 3 additions & 1 deletion nym-vpn/ui/src/pages/location/SearchBox.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { InputEvent } from '../../types/general';
import { InputEvent } from '../../types';

interface SearchProps {
value: string;
onChange: (e: InputEvent) => void;
placeholder: string;
}

export default function SearchBox({
value,
onChange,
Expand Down
4 changes: 2 additions & 2 deletions nym-vpn/ui/src/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ const router = createBrowserRouter([
{
path: routes.entryNodeLocation,
// eslint-disable-next-line react/jsx-no-undef
element: <NodeLocation type="entry" />,
element: <NodeLocation node="entry" />,
errorElement: <Error />,
},
{
path: routes.exitNodeLocation,
element: <NodeLocation type="exit" />,
element: <NodeLocation node="exit" />,
errorElement: <Error />,
},
],
Expand Down
Loading

0 comments on commit 26a8dec

Please sign in to comment.