Skip to content

Commit

Permalink
Create beginning of nym-ip-forwarder crate
Browse files Browse the repository at this point in the history
  • Loading branch information
octol committed Oct 26, 2023
1 parent 64f89f9 commit f83b031
Show file tree
Hide file tree
Showing 7 changed files with 287 additions and 0 deletions.
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ members = [
"sdk/lib/socks5-listener",
"sdk/rust/nym-sdk",
"service-providers/common",
"service-providers/ip-forwarder",
"service-providers/network-requester",
"service-providers/network-statistics",
"nym-api",
Expand Down
21 changes: 21 additions & 0 deletions service-providers/ip-forwarder/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "nym-ip-forwarder"
version = "0.1.0"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
documentation.workspace = true
edition.workspace = true
license.workspace = true

[dependencies]
futures = { workspace = true }
log = { workspace = true }
nym-client-core = { path = "../../common/client-core" }
nym-config = { path = "../../common/config" }
nym-sdk = { path = "../../sdk/rust/nym-sdk" }
nym-sphinx = { path = "../../common/nymsphinx" }
nym-task = { path = "../../common/task" }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
thiserror = { workspace = true }
23 changes: 23 additions & 0 deletions service-providers/ip-forwarder/src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use std::{io, path::Path};

pub use nym_client_core::config::Config as BaseClientConfig;
use serde::{Deserialize, Serialize};

use crate::config::persistence::IpForwarderPaths;

mod persistence;

#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Config {
#[serde(flatten)]
pub base: BaseClientConfig,

pub storage_paths: IpForwarderPaths,
}

impl Config {
pub fn read_from_toml_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
nym_config::read_config_from_toml_file(path)
}
}
28 changes: 28 additions & 0 deletions service-providers/ip-forwarder/src/config/persistence.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2023 - Nym Technologies SA <[email protected]>
// SPDX-License-Identifier: Apache-2.0

use nym_client_core::config::disk_persistence::CommonClientPaths;
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};

pub const DEFAULT_DESCRIPTION_FILENAME: &str = "description.toml";

#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)]
pub struct IpForwarderPaths {
#[serde(flatten)]
pub common_paths: CommonClientPaths,

/// Location of the file containing our description
pub ip_forwarder_description: PathBuf,
}

impl IpForwarderPaths {
pub fn new_base<P: AsRef<Path>>(base_data_directory: P) -> Self {
let base_dir = base_data_directory.as_ref();

Self {
common_paths: CommonClientPaths::new_base(base_dir),
ip_forwarder_description: base_dir.join(DEFAULT_DESCRIPTION_FILENAME),
}
}
}
29 changes: 29 additions & 0 deletions service-providers/ip-forwarder/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
pub use nym_client_core::error::ClientCoreError;

#[derive(thiserror::Error, Debug)]
pub enum IpForwarderError {
#[error("I/O error: {0}")]
IoError(#[from] std::io::Error),

#[error("client-core error: {0}")]
ClientCoreError(#[from] ClientCoreError),

#[error("failed to load configuration file: {0}")]
FailedToLoadConfig(String),

// TODO: add more details here
#[error("Failed to validate the loaded config")]
ConfigValidationFailure,

#[error("failed local version check, client and config mismatch")]
FailedLocalVersionCheck,

#[error("failed to setup mixnet client: {source}")]
FailedToSetupMixnetClient { source: nym_sdk::Error },

#[error("failed to connect to mixnet: {source}")]
FailedToConnectToMixnet { source: nym_sdk::Error },

#[error("the entity wrapping the network requester has disconnected")]
DisconnectedParent,
}
169 changes: 169 additions & 0 deletions service-providers/ip-forwarder/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
use std::path::Path;

use error::IpForwarderError;
use futures::channel::oneshot;
use nym_client_core::{
client::mix_traffic::transceiver::GatewayTransceiver,
config::disk_persistence::CommonClientPaths, HardcodedTopologyProvider, TopologyProvider,
};
use nym_sdk::{mixnet::Recipient, NymNetworkDetails};
use nym_task::{TaskClient, TaskHandle};

use crate::config::BaseClientConfig;

pub use crate::config::Config;

pub mod config;
pub mod error;

pub struct OnStartData {
// to add more fields as required
pub address: Recipient,
}

impl OnStartData {
pub fn new(address: Recipient) -> Self {
Self { address }
}
}

pub struct IpForwarderBuilder {
config: Config,
wait_for_gateway: bool,
custom_topology_provider: Option<Box<dyn TopologyProvider + Send + Sync>>,
custom_gateway_transceiver: Option<Box<dyn GatewayTransceiver + Send + Sync>>,
shutdown: Option<TaskClient>,
on_start: Option<oneshot::Sender<OnStartData>>,
}

impl IpForwarderBuilder {
pub fn new(config: Config) -> Self {
Self {
config,
wait_for_gateway: false,
custom_topology_provider: None,
custom_gateway_transceiver: None,
shutdown: None,
on_start: None,
}
}

#[must_use]
pub fn with_shutdown(mut self, shutdown: TaskClient) -> Self {
self.shutdown = Some(shutdown);
self
}

#[must_use]
pub fn with_custom_gateway_transceiver(
mut self,
gateway_transceiver: Box<dyn GatewayTransceiver + Send + Sync>,
) -> Self {
self.custom_gateway_transceiver = Some(gateway_transceiver);
self
}

#[must_use]
pub fn with_wait_for_gateway(mut self, wait_for_gateway: bool) -> Self {
self.wait_for_gateway = wait_for_gateway;
self
}

#[must_use]
pub fn with_on_start(mut self, on_start: oneshot::Sender<OnStartData>) -> Self {
self.on_start = Some(on_start);
self
}

#[must_use]
pub fn with_custom_topology_provider(
mut self,
topology_provider: Box<dyn TopologyProvider + Send + Sync>,
) -> Self {
self.custom_topology_provider = Some(topology_provider);
self
}

pub fn with_stored_topology<P: AsRef<Path>>(
mut self,
file: P,
) -> Result<Self, IpForwarderError> {
self.custom_topology_provider =
Some(Box::new(HardcodedTopologyProvider::new_from_file(file)?));
Ok(self)
}

pub async fn run_service_provider(self) -> Result<(), IpForwarderError> {
// Used to notify tasks to shutdown. Not all tasks fully supports this (yet).
let shutdown: TaskHandle = self.shutdown.map(Into::into).unwrap_or_default();

// Connect to the mixnet
let mixnet_client = create_mixnet_client(
&self.config.base,
shutdown.get_handle().named("nym_sdk::MixnetClient"),
self.custom_gateway_transceiver,
self.custom_topology_provider,
self.wait_for_gateway,
&self.config.storage_paths.common_paths,
)
.await?;

let self_address = *mixnet_client.nym_address();

log::info!("The address of this client is: {self_address}");
log::info!("All systems go. Press CTRL-C to stop the server.");

if let Some(on_start) = self.on_start {
if on_start.send(OnStartData::new(self_address)).is_err() {
// the parent has dropped the channel before receiving the response
return Err(IpForwarderError::DisconnectedParent);
}
}

todo!();
}
}

// Helper function to create the mixnet client.
// This is NOT in the SDK since we don't want to expose any of the client-core config types.
// We could however consider moving it to a crate in common in the future.
// TODO: refactor this function and its arguments
async fn create_mixnet_client(
config: &BaseClientConfig,
shutdown: TaskClient,
custom_transceiver: Option<Box<dyn GatewayTransceiver + Send + Sync>>,
custom_topology_provider: Option<Box<dyn TopologyProvider + Send + Sync>>,
wait_for_gateway: bool,
paths: &CommonClientPaths,
) -> Result<nym_sdk::mixnet::MixnetClient, IpForwarderError> {
let debug_config = config.debug;

let storage_paths = nym_sdk::mixnet::StoragePaths::from(paths.clone());

let mut client_builder =
nym_sdk::mixnet::MixnetClientBuilder::new_with_default_storage(storage_paths)
.await
.map_err(|err| IpForwarderError::FailedToSetupMixnetClient { source: err })?
.network_details(NymNetworkDetails::new_from_env())
.debug_config(debug_config)
.custom_shutdown(shutdown)
.with_wait_for_gateway(wait_for_gateway);
if !config.get_disabled_credentials_mode() {
client_builder = client_builder.enable_credentials_mode();
}
if let Some(gateway_transceiver) = custom_transceiver {
client_builder = client_builder.custom_gateway_transceiver(gateway_transceiver);
}
if let Some(topology_provider) = custom_topology_provider {
client_builder = client_builder.custom_topology_provider(topology_provider);
}

let mixnet_client = client_builder
.build()
.map_err(|err| IpForwarderError::FailedToSetupMixnetClient { source: err })?;

mixnet_client
.connect_to_mixnet()
.await
.map_err(|err| IpForwarderError::FailedToConnectToMixnet { source: err })
}

0 comments on commit f83b031

Please sign in to comment.