-
Notifications
You must be signed in to change notification settings - Fork 234
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create beginning of nym-ip-forwarder crate
- Loading branch information
Showing
7 changed files
with
287 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 }) | ||
} |