Skip to content

Commit

Permalink
refactor: use callbacks to interact with go-waku bindings and remove …
Browse files Browse the repository at this point in the history
…JsonResponse (#74)
  • Loading branch information
richard-ramos committed Nov 2, 2023
1 parent 3acddc9 commit dc64164
Show file tree
Hide file tree
Showing 16 changed files with 469 additions and 194 deletions.
3 changes: 2 additions & 1 deletion 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 waku-bindings/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ sscanf = "0.4"
smart-default = "0.6"
url = "2.3"
waku-sys = { version = "0.4.0", path = "../waku-sys" }
libc = "0.2"

[dev-dependencies]
futures = "0.3.25"
Expand Down
41 changes: 32 additions & 9 deletions waku-bindings/src/decrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
use std::ffi::CString;
// crates
use aes_gcm::{Aes256Gcm, Key};
use libc::*;
use secp256k1::SecretKey;
// internal
use crate::general::{DecodedPayload, Result, WakuMessage};
use crate::utils::decode_and_free_response;
use crate::utils::{get_trampoline, handle_json_response};

/// Decrypt a message using a symmetric key
///
Expand All @@ -28,14 +29,25 @@ pub fn waku_decode_symmetric(
.expect("CString should build properly from hex encoded symmetric key")
.into_raw();

let result_ptr = unsafe {
let res = waku_sys::waku_decode_symmetric(message_ptr, symk_ptr);
let mut result: String = Default::default();
let result_cb = |v: &str| result = v.to_string();
let code = unsafe {
let mut closure = result_cb;
let cb = get_trampoline(&closure);
let out = waku_sys::waku_decode_symmetric(
message_ptr,
symk_ptr,
cb,
&mut closure as *mut _ as *mut c_void,
);

drop(CString::from_raw(message_ptr));
drop(CString::from_raw(symk_ptr));
res

out
};

decode_and_free_response(result_ptr)
handle_json_response(code, &result)
}

/// Decrypt a message using a symmetric key
Expand All @@ -57,12 +69,23 @@ pub fn waku_decode_asymmetric(
.expect("CString should build properly from hex encoded symmetric key")
.into_raw();

let result_ptr = unsafe {
let res = waku_sys::waku_decode_asymmetric(message_ptr, sk_ptr);
let mut result: String = Default::default();
let result_cb = |v: &str| result = v.to_string();
let code = unsafe {
let mut closure = result_cb;
let cb = get_trampoline(&closure);
let out = waku_sys::waku_decode_asymmetric(
message_ptr,
sk_ptr,
cb,
&mut closure as *mut _ as *mut c_void,
);

drop(CString::from_raw(message_ptr));
drop(CString::from_raw(sk_ptr));
res

out
};

decode_and_free_response(result_ptr)
handle_json_response(code, &result)
}
47 changes: 36 additions & 11 deletions waku-bindings/src/encrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
use std::ffi::CString;
// crates
use aes_gcm::{Aes256Gcm, Key};
use libc::*;
use secp256k1::{PublicKey, SecretKey};
// internal
use crate::general::{Result, WakuMessage};
use crate::utils::decode_and_free_response;
use crate::utils::{get_trampoline, handle_json_response};

/// Optionally sign and encrypt a message using asymmetric encryption
pub fn waku_encode_asymmetric(
Expand All @@ -16,7 +17,7 @@ pub fn waku_encode_asymmetric(
let pk = hex::encode(public_key.serialize_uncompressed());
let sk = signing_key
.map(|signing_key| hex::encode(signing_key.secret_bytes()))
.unwrap_or_else(String::new);
.unwrap_or_default();
let message_ptr = CString::new(
serde_json::to_string(&message)
.expect("WakuMessages should always be able to success serializing"),
Expand All @@ -30,15 +31,27 @@ pub fn waku_encode_asymmetric(
.expect("CString should build properly from hex encoded signing key")
.into_raw();

let result_ptr = unsafe {
let res = waku_sys::waku_encode_asymmetric(message_ptr, pk_ptr, sk_ptr);
let mut result: String = Default::default();
let result_cb = |v: &str| result = v.to_string();
let code = unsafe {
let mut closure = result_cb;
let cb = get_trampoline(&closure);
let out = waku_sys::waku_encode_asymmetric(
message_ptr,
pk_ptr,
sk_ptr,
cb,
&mut closure as *mut _ as *mut c_void,
);

drop(CString::from_raw(message_ptr));
drop(CString::from_raw(pk_ptr));
drop(CString::from_raw(sk_ptr));
res

out
};

decode_and_free_response(result_ptr)
handle_json_response(code, &result)
}

/// Optionally sign and encrypt a message using symmetric encryption
Expand All @@ -50,7 +63,7 @@ pub fn waku_encode_symmetric(
let symk = hex::encode(symmetric_key.as_slice());
let sk = signing_key
.map(|signing_key| hex::encode(signing_key.secret_bytes()))
.unwrap_or_else(String::new);
.unwrap_or_default();
let message_ptr = CString::new(
serde_json::to_string(&message)
.expect("WakuMessages should always be able to success serializing"),
Expand All @@ -64,13 +77,25 @@ pub fn waku_encode_symmetric(
.expect("CString should build properly from hex encoded signing key")
.into_raw();

let result_ptr = unsafe {
let res = waku_sys::waku_encode_symmetric(message_ptr, symk_ptr, sk_ptr);
let mut result: String = Default::default();
let result_cb = |v: &str| result = v.to_string();
let code = unsafe {
let mut closure = result_cb;
let cb = get_trampoline(&closure);
let out = waku_sys::waku_encode_symmetric(
message_ptr,
symk_ptr,
sk_ptr,
cb,
&mut closure as *mut _ as *mut c_void,
);

drop(CString::from_raw(message_ptr));
drop(CString::from_raw(symk_ptr));
drop(CString::from_raw(sk_ptr));
res

out
};

decode_and_free_response(result_ptr)
handle_json_response(code, &result)
}
6 changes: 3 additions & 3 deletions waku-bindings/src/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! When an event is emitted, this callback will be triggered receiving a [`Signal`]

// std
use std::ffi::{c_char, CStr};
use std::ffi::{c_char, c_void, CStr};
use std::ops::Deref;
use std::sync::Mutex;
// crates
Expand Down Expand Up @@ -79,7 +79,7 @@ fn set_callback<F: FnMut(Signal) + Send + Sync + 'static>(f: F) {

/// Wrapper callback, it transformst the `*const c_char` into a [`Signal`]
/// and executes the [`CALLBACK`] funtion with it
extern "C" fn callback(data: *const c_char) {
extern "C" fn callback(data: *const c_char, _user_data: *mut c_void) {
let raw_response = unsafe { CStr::from_ptr(data) }
.to_str()
.expect("Not null ptr");
Expand All @@ -95,7 +95,7 @@ extern "C" fn callback(data: *const c_char) {
/// which are used to react to asynchronous events in Waku
pub fn waku_set_event_callback<F: FnMut(Signal) + Send + Sync + 'static>(f: F) {
set_callback(f);
unsafe { waku_sys::waku_set_event_callback(callback as *mut std::ffi::c_void) };
unsafe { waku_sys::waku_set_event_callback(Some(callback)) };
}

#[cfg(test)]
Expand Down
20 changes: 0 additions & 20 deletions waku-bindings/src/general/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,29 +51,9 @@ impl Display for ProtocolId {
}
}

/// JsonResponse wrapper.
/// `go-waku` ffi returns this type as a `char *` as per the [specification](https://rfc.vac.dev/spec/36/#jsonresponse-type)
/// This is internal, as it is better to use rust plain `Result` type.
#[derive(Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
pub(crate) enum JsonResponse<T> {
Result(T),
Error(String),
}

/// Waku response, just a `Result` with an `String` error.
pub type Result<T> = std::result::Result<T, String>;

/// Convenient we can transform a [`JsonResponse`] into a [`std::result::Result`]
impl<T> From<JsonResponse<T>> for Result<T> {
fn from(response: JsonResponse<T>) -> Self {
match response {
JsonResponse::Result(t) => Ok(t),
JsonResponse::Error(e) => Err(e),
}
}
}

// TODO: Properly type and deserialize payload form base64 encoded string
/// Waku message in JSON format.
/// as per the [specification](https://rfc.vac.dev/spec/36/#jsonmessage-type)
Expand Down
49 changes: 32 additions & 17 deletions waku-bindings/src/node/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ use std::ffi::CString;
use std::time::Duration;
// crates
use enr::Enr;
use libc::*;
use multiaddr::Multiaddr;
use serde::Deserialize;
use url::{Host, Url};
// internal
use crate::utils::decode_and_free_response;
use crate::utils::{get_trampoline, handle_json_response, handle_no_response};
use crate::{PeerId, Result};

#[derive(Deserialize, Debug)]
Expand All @@ -30,15 +31,16 @@ pub fn waku_dns_discovery(
let url = CString::new(url.to_string())
.expect("CString should build properly from a valid Url")
.into_raw();
let server = CString::new(
server
.map(|host| host.to_string())
.unwrap_or_else(|| "".to_string()),
)
.expect("CString should build properly from a String nameserver")
.into_raw();
let result_ptr = unsafe {
let res = waku_sys::waku_dns_discovery(
let server = CString::new(server.map(|host| host.to_string()).unwrap_or_default())
.expect("CString should build properly from a String nameserver")
.into_raw();

let mut result: String = Default::default();
let result_cb = |v: &str| result = v.to_string();
let code = unsafe {
let mut closure = result_cb;
let cb = get_trampoline(&closure);
let out = waku_sys::waku_dns_discovery(
url,
server,
timeout
Expand All @@ -49,14 +51,17 @@ pub fn waku_dns_discovery(
.expect("Duration as milliseconds should fit in a i32")
})
.unwrap_or(0),
cb,
&mut closure as *mut _ as *mut c_void,
);
// Recover strings and drop them

drop(CString::from_raw(url));
drop(CString::from_raw(server));
res

out
};

decode_and_free_response(result_ptr)
handle_json_response(code, &result)
}

/// Update the bootnodes used by DiscoveryV5 by passing a list of ENRs
Expand All @@ -68,13 +73,23 @@ pub fn waku_discv5_update_bootnodes(bootnodes: Vec<String>) -> Result<()> {
.expect("CString should build properly from the string vector")
.into_raw();

let result_ptr = unsafe {
let res = waku_sys::waku_discv5_update_bootnodes(bootnodes_ptr);
let mut error: String = Default::default();
let error_cb = |v: &str| error = v.to_string();
let code = unsafe {
let mut closure = error_cb;
let cb = get_trampoline(&closure);
let out = waku_sys::waku_discv5_update_bootnodes(
bootnodes_ptr,
cb,
&mut closure as *mut _ as *mut c_void,
);

drop(CString::from_raw(bootnodes_ptr));
res

out
};

decode_and_free_response::<bool>(result_ptr).map(|_| ())
handle_no_response(code, &error)
}

#[cfg(test)]
Expand Down

0 comments on commit dc64164

Please sign in to comment.