ae6c80f0cd
* fixed rebase conflict with cargo.lock * shared cleanup * moved returncode to shared * first pass at Go binding structure * minor cleanup * working on custom type udl * trying to get LDFLAG script working * commit before changing alias -> proper types * converted CCallbacks from aliases to Struct * cleanup comments * temp * push to share * cleanup * trait Lift not implemented for *const i8 issue * test of refactor: * move c-specific var casting out of shared/ into cpp/ * error returning in go/ over ffi boundary with uniffi * _internal functions ffi wrapper agnostic * moved lang-specific type conversions to cpp / go bindings and out of shared * got send_message working in c/c++ & go * split out c/c++-specific types to mod * cont. with making _internal fns lang agnostic * working on final fn for C and shared (listening for incoming messages) * fixed return err on listen_for_incoming * got full example run running again after shared/ refactor * removed unused struct * code comments * got first runthrough of go example code * script cleanup * clean up readme instructions * clippy * removed unused imports * rustfmt * Update sdk/ffi/go/README.md with link to example file Co-authored-by: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com> * updated readme with extra build and usage info * renamed binding outer directory for nicer path * moved example file from ffi/main.go -> ./example.go * updated README with new example file name --------- Co-authored-by: mfahampshire <mfahampshire@pm.me> Co-authored-by: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com>
121 lines
3.9 KiB
Rust
121 lines
3.9 KiB
Rust
// Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
use anyhow::{anyhow, bail};
|
|
use lazy_static::lazy_static;
|
|
use nym_sdk::mixnet::{MixnetClient, MixnetMessageSender, ReconstructedMessage, Recipient};
|
|
use nym_sphinx_anonymous_replies::requests::AnonymousSenderTag;
|
|
|
|
|
|
use std::sync::{Arc, Mutex};
|
|
use tokio::runtime::Runtime;
|
|
|
|
// NYM_CLIENT: Static reference (only init-ed once) to:
|
|
// - Arc: share ownership
|
|
// - Mutex: thread-safe way to share data between threads
|
|
// - Option: init-ed or not
|
|
// RUNTIME: Tokio runtime: no need to pass back to C and deal with raw pointers as it was previously
|
|
lazy_static! {
|
|
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() -> anyhow::Result<(), anyhow::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 {
|
|
anyhow!("couldnt lock NYM_CLIENT");
|
|
}
|
|
Ok::<(), anyhow::Error>(())
|
|
})?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub fn get_self_address_internal() -> anyhow::Result<String, anyhow::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())
|
|
}
|
|
|
|
pub fn send_message_internal(
|
|
recipient: Recipient,
|
|
message: &str,
|
|
) -> anyhow::Result<(), anyhow::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()"))?;
|
|
|
|
// send message
|
|
RUNTIME.block_on(async move {
|
|
nym_client.send_plain_message(recipient, message).await?;
|
|
Ok::<(), anyhow::Error>(())
|
|
})?;
|
|
Ok(())
|
|
}
|
|
|
|
pub fn reply_internal(
|
|
recipient: AnonymousSenderTag,
|
|
message: &str,
|
|
) -> anyhow::Result<(), anyhow::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::<(), anyhow::Error>(())
|
|
})?;
|
|
Ok(())
|
|
}
|
|
|
|
pub fn listen_for_incoming_internal() -> anyhow::Result<ReconstructedMessage, anyhow::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, anyhow::Error>(ReconstructedMessage {message: received.message, sender_tag: received.sender_tag})
|
|
})?;
|
|
|
|
Ok(message)
|
|
}
|
|
|
|
pub async fn wait_for_non_empty_message(
|
|
client: &mut MixnetClient,
|
|
) -> anyhow::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")
|
|
}
|