Files
nym/service-providers/common/src/lib.rs
T
Jędrzej Stuczyński 9a68702d4d Feature/config refactor (#3498)
* revamping mixnode connfig

* wip

* native client config revamping

* wip

* building socks5

* using const for mixnnode config template

* compiling updated gateway

* nym-api

* nym-sdk

* everything compiling once more

but definitely not compatible with CI and older versions (yet)

* creating full directory structure on init

* renamed paths to storage_paths and fixed mixnode template

* mixnode config migration

* gateway config migration

* nym-api config migration

* native client config migration

* socks5 client config migration

* NR config migration

* removed deprecations (that will be resolved in the following PRs) + fixed clippy

* nym-connect clippy

* nym-connect config updates

* outfox fixes

* defined socks5 lib config

* clippy

* fixed wasm client build

* removed explicit packet_type argument when starting base client

it's known implicitly from the previously passed config struct

* Empty commit

* fixed re-using gateway information when client configs are re-initialised

* fixed borrowing id value in nym-connect

* post-rebase fixes

* updated 'old_config' versions

---------

Co-authored-by: Tommy Verrall <tommy@nymtech.net>
2023-06-07 17:06:35 +01:00

187 lines
7.2 KiB
Rust

// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::interface::{
BinaryInformation, ControlRequest, ControlResponse, EmptyMessage, ProviderInterfaceVersion,
Request, RequestContent, Response, ResponseContent, ServiceProviderRequest, SupportedVersions,
};
use async_trait::async_trait;
use nym_sphinx_anonymous_replies::requests::AnonymousSenderTag;
pub mod interface;
pub const DEFAULT_SERVICE_PROVIDERS_DIR: &str = "service-providers";
// FUTURE WORK:
// for next version (v4) of the interface, refactor `reply::MixnetAddress` from the socks5 SP
// and move it here so that you could optionally attach your sender address with any request for easier responses
/// Trait that every ServiceProvider on the Nym network should implement and adhere to.
#[async_trait]
pub trait ServiceProvider<T: ServiceProviderRequest = EmptyMessage>
where
T: Send + 'static,
Self: Sync,
{
type ServiceProviderError: From<<T as ServiceProviderRequest>::Error>;
// TODO: refactor to use some version of `reply::MixnetAddress`
// in case explicit address was provided
async fn on_request(
&mut self,
sender: Option<AnonymousSenderTag>,
request: Request<T>,
) -> Result<(), Self::ServiceProviderError>;
async fn handle_request(
&mut self,
sender: Option<AnonymousSenderTag>,
request: Request<T>,
) -> Result<Option<Response<T>>, Self::ServiceProviderError> {
match request.content {
RequestContent::Control(control_request) => self
.handle_control_request(sender, control_request, request.interface_version)
.await
.map(|maybe_res| {
maybe_res.map(|control_res| Response {
interface_version: request.interface_version,
content: ResponseContent::Control(control_res),
})
}),
RequestContent::ProviderData(provider_data_request) => self
.handle_provider_data_request(
sender,
provider_data_request,
request.interface_version,
)
.await
.map(|maybe_res| {
maybe_res.map(|provider_data_res| Response {
interface_version: request.interface_version,
content: ResponseContent::ProviderData(provider_data_res),
})
}),
}
}
async fn handle_control_request(
&mut self,
_sender: Option<AnonymousSenderTag>,
request: ControlRequest,
interface_version: ProviderInterfaceVersion,
) -> Result<Option<ControlResponse>, Self::ServiceProviderError> {
if interface_version.is_legacy() {
// control requests didn't exist in the legacy version
Ok(None)
} else {
let response = match request {
// Version 3 requests:
ControlRequest::Health => {
self.handle_health_control_request().await?;
Some(ControlResponse::Health)
}
ControlRequest::BinaryInfo => {
let info = self.handle_binary_info_control_request().await?;
Some(ControlResponse::BinaryInfo(Box::new(info)))
}
ControlRequest::SupportedRequestVersions => {
let versions = self.handle_supported_request_versions_request().await?;
Some(ControlResponse::SupportedRequestVersions(versions))
} //
// TODO: if we ever add new request for interface version 4 (or higher),
// we need to include a check to make sure we return a `None` if passed `interface_version` was 3
};
Ok(response)
}
}
// I don't think you can do anything more simple than that, but allow for custom implementations
// in case, for example, you wanted to include additional statistics collection here
async fn handle_health_control_request(&self) -> Result<(), Self::ServiceProviderError> {
Ok(())
}
// well, this has to be handled manually
async fn handle_binary_info_control_request(
&self,
) -> Result<BinaryInformation, Self::ServiceProviderError>;
async fn handle_supported_request_versions_request(
&self,
) -> Result<SupportedVersions, Self::ServiceProviderError> {
Ok(SupportedVersions {
interface_version: ProviderInterfaceVersion::new_current().to_string(),
provider_version: T::max_supported_version().to_string(),
})
}
async fn handle_provider_data_request(
&mut self,
sender: Option<AnonymousSenderTag>,
request: T,
interface_version: ProviderInterfaceVersion,
) -> Result<Option<T::Response>, Self::ServiceProviderError>;
}
// #[async_trait]
// pub trait ServiceProviderClient<T: ServiceProviderRequest = EmptyMessage>
// where
// T: Send + 'static,
// Self: Sync,
// {
// type ServiceProviderClientError: From<<T as ServiceProviderRequest>::Error>;
//
// fn provider_interface_version(&self) -> ProviderInterfaceVersion;
//
// fn get_control_response(
// maybe_res: Option<Response<T>>,
// ) -> Result<Option<ControlResponse>, Self::ServiceProviderClientError> {
// let Some(res) = maybe_res else {
// return Ok(None)
// };
//
// match res.content {
// ResponseContent::Control(res) => Ok(Some(res)),
// ResponseContent::ProviderData(_) => Err(Self::ServiceProviderClientError::from(
// ServiceProviderMessagingError::UnexpectedProviderDataResponse.into(),
// )),
// }
// }
//
// fn get_provider_data_response(
// maybe_res: Option<Response<T>>,
// ) -> Result<Option<T::Response>, Self::ServiceProviderClientError> {
// let Some(res) = maybe_res else {
// return Ok(None)
// };
//
// match res.content {
// ResponseContent::ProviderData(res) => Ok(Some(res)),
// ResponseContent::Control(_) => Err(Self::ServiceProviderClientError::from(
// ServiceProviderMessagingError::UnexpectedControlResponse.into(),
// )),
// }
// }
//
// // async fn send_control_request_anonymously(
// // &mut self,
// // request: ControlRequest,
// // ) -> Result<Option<ControlResponse>, Self::ServiceProviderClientError>;
// //
// // async fn send_provider_data_request_anonymously(
// // &mut self,
// // request: T,
// // ) -> Result<Option<T::Response>, Self::ServiceProviderClientError>;
// //
// // TODO: extend the traits and messaging to allow for attaching own address
// // async fn send_control_request_with_address(
// // &mut self,
// // request: ControlRequest,
// // ) -> Result<Option<ControlResponse>, Self::ServiceProviderClientError>;
// //
// // async fn send_provider_data_request_with_address(
// // &mut self,
// // request: T,
// // ) -> Result<Option<T::Response>, Self::ServiceProviderClientError>;
// }