Files
nym/sdk/ffi/shared/src/lib.rs
T
mfahampshire 9b6b2117dd Max/general abstraction updates (#5560)
- new instance of echo server with lib / cli split 
- echo server docs update 
- tcpproxy and echosever now listen for kill signal 
- ffi bindings of tcpproxy functions updated
2025-05-14 15:51:18 +00:00

275 lines
8.8 KiB
Rust

// Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use anyhow::{anyhow, bail, Error, Result};
use lazy_static::lazy_static;
use nym_sdk::mixnet::{
MixnetClient, MixnetClientBuilder, MixnetMessageSender, Recipient, ReconstructedMessage,
StoragePaths,
};
use nym_crypto::asymmetric::ed25519;
use nym_sdk::tcp_proxy::{NymProxyClient, NymProxyServer};
use nym_sphinx_anonymous_replies::requests::AnonymousSenderTag;
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use tokio::runtime::Runtime;
// NYM_CLIENT/PROXIES: Static thread-safe reference (init once) to Option<Client>s.
// RUNTIME: Tokio runtime: no need to pass across FFI boundary and deal with raw pointers.
lazy_static! {
static ref NYM_PROXY_CLIENT: Arc<Mutex<Option<NymProxyClient>>> = Arc::new(Mutex::new(None));
static ref NYM_PROXY_SERVER: Arc<Mutex<Option<NymProxyServer>>> = Arc::new(Mutex::new(None));
static ref NYM_CLIENT: Arc<Mutex<Option<MixnetClient>>> = Arc::new(Mutex::new(None));
static ref RUNTIME: Runtime = Runtime::new().unwrap();
}
pub fn init_ephemeral_internal() -> Result<(), Error> {
if NYM_CLIENT.lock().unwrap().as_ref().is_some() {
bail!("client already exists");
} else {
RUNTIME.block_on(async move {
let init_client = MixnetClient::connect_new().await?;
let mut client = NYM_CLIENT.try_lock();
if let Ok(ref mut client) = client {
**client = Some(init_client);
} else {
return Err(anyhow!("couldnt lock ephemeral NYM_CLIENT"));
}
Ok::<(), Error>(())
})?;
}
Ok(())
}
pub fn init_default_storage_internal(config_dir: PathBuf) -> Result<(), Error> {
if NYM_CLIENT.lock().unwrap().as_ref().is_some() {
bail!("client already exists");
} else {
RUNTIME.block_on(async move {
let storage_paths = StoragePaths::new_from_dir(&config_dir).unwrap();
let init_client = MixnetClientBuilder::new_with_default_storage(storage_paths)
.await?
.build()?
.connect_to_mixnet()
.await?;
let mut client = NYM_CLIENT.try_lock();
if let Ok(ref mut client) = client {
**client = Some(init_client);
} else {
return Err(anyhow!("couldnt lock NYM_CLIENT"));
}
Ok::<(), Error>(())
})?;
}
Ok(())
}
pub fn get_self_address_internal() -> Result<String, Error> {
let client = NYM_CLIENT.lock().expect("could not lock NYM_CLIENT");
if client.is_none() {
bail!("Client is not yet initialised");
}
let nym_client = client
.as_ref()
.ok_or_else(|| anyhow!("could not get client as_ref()"))?;
Ok(nym_client.nym_address().to_string())
}
// TODO split sender
pub fn send_message_internal(
recipient: Recipient,
message: &str,
// TODO add Option<surb_amount>, if Some(surb_amount) call send_message() instead with specified #, else send_plain_message as this uses the default
) -> Result<(), Error> {
let client = NYM_CLIENT.lock().expect("could not lock NYM_CLIENT");
if client.is_none() {
bail!("Client is not yet initialised");
}
let nym_client = client
.as_ref()
.ok_or_else(|| anyhow!("could not get client as_ref()"))?;
RUNTIME.block_on(async move {
nym_client.send_plain_message(recipient, message).await?;
Ok::<(), Error>(())
})?;
Ok(())
}
// TODO send_raw_message_internal
pub fn reply_internal(recipient: AnonymousSenderTag, message: &str) -> Result<(), Error> {
let client = NYM_CLIENT.lock().expect("could not lock NYM_CLIENT");
if client.is_none() {
bail!("Client is not yet initialised");
}
let nym_client = client
.as_ref()
.ok_or_else(|| anyhow!("could not get client as_ref()"))?;
RUNTIME.block_on(async move {
nym_client.send_reply(recipient, message).await?;
Ok::<(), Error>(())
})?;
Ok(())
}
pub fn listen_for_incoming_internal() -> Result<ReconstructedMessage, Error> {
let mut binding = NYM_CLIENT.lock().expect("could not lock NYM_CLIENT");
if binding.is_none() {
bail!("recipient is null");
}
let client = binding
.as_mut()
.ok_or_else(|| anyhow!("could not get client as_ref()"))?;
let message = RUNTIME.block_on(async move {
let received = wait_for_non_empty_message(client).await?;
Ok::<ReconstructedMessage, Error>(ReconstructedMessage {
message: received.message,
sender_tag: received.sender_tag,
})
})?;
Ok(message)
}
pub async fn wait_for_non_empty_message(client: &mut MixnetClient) -> Result<ReconstructedMessage> {
while let Some(mut new_message) = client.wait_for_messages().await {
if !new_message.is_empty() {
return new_message
.pop()
.ok_or_else(|| anyhow!("could not get non empty message"));
}
}
bail!("(Rust) did not receive any non-empty message")
}
pub fn proxy_client_new_internal(
server_address: Recipient,
listen_address: &str,
listen_port: &str,
close_timeout: u64,
env: Option<String>,
pool_size: usize,
) -> Result<(), Error> {
if NYM_PROXY_CLIENT.lock().unwrap().as_ref().is_some() {
bail!("proxy client already exists");
} else {
RUNTIME.block_on(async move {
let init_proxy_client = NymProxyClient::new(
server_address,
listen_address,
listen_port,
close_timeout,
env,
pool_size,
)
.await?;
let mut client = NYM_PROXY_CLIENT.try_lock();
if let Ok(ref mut client) = client {
**client = Some(init_proxy_client);
} else {
return Err(anyhow!("couldnt lock NYM_PROXY_CLIENT"));
}
Ok::<(), Error>(())
})?;
}
Ok(())
}
pub fn proxy_client_new_defaults_internal(
server_address: Recipient,
env: Option<String>,
) -> Result<(), Error> {
if NYM_PROXY_CLIENT.lock().unwrap().as_ref().is_some() {
bail!("proxy client already exists");
} else {
RUNTIME.block_on(async move {
let init_proxy_client = NymProxyClient::new_with_defaults(server_address, env).await?;
let mut client = NYM_PROXY_CLIENT.try_lock();
if let Ok(ref mut client) = client {
**client = Some(init_proxy_client);
} else {
return Err(anyhow!("couldn't lock PROXY_CLIENT"));
}
Ok::<(), Error>(())
})?;
}
Ok(())
}
pub fn proxy_client_run_internal() -> Result<(), Error> {
let proxy_client = NYM_PROXY_CLIENT
.lock()
.expect("could not lock NYM_PROXY_CLIENT");
if proxy_client.is_none() {
bail!("Client is not yet initialised");
}
let proxy = proxy_client
.as_ref()
.ok_or_else(|| anyhow!("could not get proxy_client as_ref()"))?;
RUNTIME.block_on(async move {
proxy.run().await?;
Ok::<(), Error>(())
})?;
Ok(())
}
pub fn proxy_server_new_internal(
upstream_address: &str,
config_dir: &str,
env: Option<String>,
gateway: Option<ed25519::PublicKey>,
) -> Result<(), Error> {
if NYM_PROXY_SERVER.lock().unwrap().as_ref().is_some() {
bail!("proxy client already exists");
} else {
RUNTIME.block_on(async move {
let init_proxy_server =
NymProxyServer::new(upstream_address, config_dir, env, gateway).await?;
let mut client = NYM_PROXY_SERVER.try_lock();
if let Ok(ref mut client) = client {
**client = Some(init_proxy_server);
} else {
return Err(anyhow!("couldn't lock PROXY_SERVER"));
}
Ok::<(), Error>(())
})?;
}
Ok(())
}
pub fn proxy_server_run_internal() -> Result<(), Error> {
let mut proxy_server = NYM_PROXY_SERVER
.lock()
.expect("could not lock NYM_PROXY_CLIENT");
if proxy_server.is_none() {
bail!("Server is not yet initialised");
}
let proxy = proxy_server
.as_mut()
.ok_or_else(|| anyhow!("could not get proxy_client as_ref()"))?;
RUNTIME.block_on(async move {
proxy.run_with_shutdown().await?;
Ok::<(), Error>(())
})?;
Ok(())
}
pub fn proxy_server_address_internal() -> Result<Recipient, Error> {
let mut proxy_server = NYM_PROXY_SERVER
.lock()
.expect("could not lock NYM_PROXY_CLIENT");
if proxy_server.is_none() {
bail!("Server is not yet initialised");
}
let proxy = proxy_server
.as_mut()
.ok_or_else(|| anyhow!("could not get proxy_client as_ref()"))?;
Ok(proxy.nym_address().to_owned())
}