mirror of
https://github.com/ZeroTier/ZeroTierOne
synced 2025-08-21 05:43:59 -07:00
plumb through callbacks
This commit is contained in:
parent
06b2ce9f30
commit
0e94891e5b
4 changed files with 114 additions and 29 deletions
|
@ -12,8 +12,11 @@
|
||||||
|
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::c_char;
|
||||||
|
#[cfg(feature = "ztcontroller")]
|
||||||
|
use std::os::raw::c_void;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
#[cfg(feature = "ztcontroller")]
|
||||||
use tokio::runtime;
|
use tokio::runtime;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -495,11 +498,18 @@ use crate::pubsub::member_listener::MemberListener;
|
||||||
#[cfg(feature = "ztcontroller")]
|
#[cfg(feature = "ztcontroller")]
|
||||||
use crate::pubsub::network_listener::NetworkListener;
|
use crate::pubsub::network_listener::NetworkListener;
|
||||||
|
|
||||||
|
#[cfg(feature = "ztcontroller")]
|
||||||
|
use crate::pubsub::member_listener::MemberListenerCallback;
|
||||||
|
#[cfg(feature = "ztcontroller")]
|
||||||
|
use crate::pubsub::network_listener::NetworkListenerCallback;
|
||||||
|
|
||||||
#[cfg(feature = "ztcontroller")]
|
#[cfg(feature = "ztcontroller")]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn init_network_listener(
|
pub unsafe extern "C" fn init_network_listener(
|
||||||
controller_id: *const c_char,
|
controller_id: *const c_char,
|
||||||
listen_timeout: u64,
|
listen_timeout: u64,
|
||||||
|
callback: NetworkListenerCallback,
|
||||||
|
user_ptr: *mut c_void,
|
||||||
) -> *const Arc<NetworkListener> {
|
) -> *const Arc<NetworkListener> {
|
||||||
if listen_timeout == 0 {
|
if listen_timeout == 0 {
|
||||||
println!("listen_timeout is zero");
|
println!("listen_timeout is zero");
|
||||||
|
@ -514,7 +524,7 @@ pub unsafe extern "C" fn init_network_listener(
|
||||||
|
|
||||||
let rt = runtime::Handle::current();
|
let rt = runtime::Handle::current();
|
||||||
rt.block_on(async {
|
rt.block_on(async {
|
||||||
match NetworkListener::new(id, Duration::from_secs(listen_timeout)).await {
|
match NetworkListener::new(id, Duration::from_secs(listen_timeout), callback, user_ptr).await {
|
||||||
Ok(listener) => Arc::into_raw(Arc::new(listener)),
|
Ok(listener) => Arc::into_raw(Arc::new(listener)),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("error creating network listener: {}", e);
|
println!("error creating network listener: {}", e);
|
||||||
|
@ -562,6 +572,8 @@ pub unsafe extern "C" fn network_listener_listen(ptr: *const Arc<NetworkListener
|
||||||
pub unsafe extern "C" fn init_member_listener(
|
pub unsafe extern "C" fn init_member_listener(
|
||||||
controller_id: *const c_char,
|
controller_id: *const c_char,
|
||||||
listen_timeout: u64,
|
listen_timeout: u64,
|
||||||
|
callback: MemberListenerCallback,
|
||||||
|
user_ptr: *mut c_void,
|
||||||
) -> *const Arc<MemberListener> {
|
) -> *const Arc<MemberListener> {
|
||||||
if listen_timeout == 0 {
|
if listen_timeout == 0 {
|
||||||
println!("listen_timeout is zero");
|
println!("listen_timeout is zero");
|
||||||
|
@ -576,7 +588,7 @@ pub unsafe extern "C" fn init_member_listener(
|
||||||
|
|
||||||
let rt = runtime::Handle::current();
|
let rt = runtime::Handle::current();
|
||||||
rt.block_on(async {
|
rt.block_on(async {
|
||||||
match MemberListener::new(id, Duration::from_secs(listen_timeout)).await {
|
match MemberListener::new(id, Duration::from_secs(listen_timeout), callback, user_ptr).await {
|
||||||
Ok(listener) => Arc::into_raw(Arc::new(listener)),
|
Ok(listener) => Arc::into_raw(Arc::new(listener)),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("error creating member listener: {}", e);
|
println!("error creating member listener: {}", e);
|
||||||
|
|
|
@ -88,33 +88,42 @@ impl ChangeListener {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
// use super::*;
|
use super::*;
|
||||||
|
|
||||||
// use testcontainers::runners::AsyncRunner;
|
use testcontainers::runners::AsyncRunner;
|
||||||
// use testcontainers_modules::google_cloud_sdk_emulators;
|
use testcontainers::ContainerAsync;
|
||||||
// use tokio;
|
use testcontainers_modules::google_cloud_sdk_emulators;
|
||||||
|
use testcontainers_modules::google_cloud_sdk_emulators::CloudSdk;
|
||||||
|
use tokio;
|
||||||
|
|
||||||
// #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
async fn setup_pubsub_emulator() -> Result<(ContainerAsync<CloudSdk>, String), Box<dyn std::error::Error>> {
|
||||||
// async fn setup_pubsub_emulator() -> Result<(), Box<dyn std::error::Error + 'static>> {
|
let container = google_cloud_sdk_emulators::CloudSdk::pubsub().start().await?;
|
||||||
// let container = google_cloud_sdk_emulators::CloudSdk::pubsub().start().await?;
|
let port = container.get_host_port_ipv4(8085).await?;
|
||||||
|
let host = format!("localhost:{}", port);
|
||||||
|
Ok((container, host))
|
||||||
|
}
|
||||||
|
|
||||||
// let port = container.get_host_port_ipv4(8085).await?;
|
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||||
// let host = format!("localhost:{}", port);
|
async fn test_can_connect_to_pubsub() -> Result<(), Box<dyn std::error::Error + 'static>> {
|
||||||
|
let (_container, host) = setup_pubsub_emulator().await?;
|
||||||
|
|
||||||
// unsafe {
|
unsafe {
|
||||||
// std::env::set_var("PUBSUB_EMULATOR_HOST", host);
|
std::env::set_var("PUBSUB_EMULATOR_HOST", host);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// let cl = ChangeListener::new(
|
let (tx, _rx) = tokio::sync::mpsc::channel(64);
|
||||||
// "test_controller",
|
|
||||||
// "test_topic",
|
|
||||||
// "test_subscription",
|
|
||||||
// Duration::from_secs(10),
|
|
||||||
// )
|
|
||||||
// .await;
|
|
||||||
|
|
||||||
// assert!(cl.is_ok(), "Failed to connect to pubsub emulator: {:?}", cl.err());
|
let cl = ChangeListener::new(
|
||||||
|
"test_controller",
|
||||||
|
"test_topic",
|
||||||
|
"test_subscription",
|
||||||
|
Duration::from_secs(10),
|
||||||
|
tx,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Ok(())
|
assert!(cl.is_ok(), "Failed to connect to pubsub emulator: {:?}", cl.err());
|
||||||
// }
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
use crate::pubsub::change_listener::ChangeListener;
|
use crate::pubsub::change_listener::ChangeListener;
|
||||||
use crate::pubsub::protobuf::pbmessages::MemberChange;
|
use crate::pubsub::protobuf::pbmessages::MemberChange;
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::os::raw::c_void;
|
||||||
|
use std::sync::atomic::AtomicPtr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::sync::mpsc::Receiver;
|
use tokio::sync::mpsc::Receiver;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub type MemberListenerCallback = extern "C" fn(*const c_void, *const u8, usize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Member Listener listens for member changes and passes them back to the controller
|
* Member Listener listens for member changes and passes them back to the controller
|
||||||
*
|
*
|
||||||
|
@ -15,10 +20,17 @@ use tokio::sync::Mutex;
|
||||||
pub struct MemberListener {
|
pub struct MemberListener {
|
||||||
change_listener: ChangeListener,
|
change_listener: ChangeListener,
|
||||||
rx_channel: Mutex<Receiver<Vec<u8>>>,
|
rx_channel: Mutex<Receiver<Vec<u8>>>,
|
||||||
|
callback: Mutex<MemberListenerCallback>,
|
||||||
|
user_ptr: AtomicPtr<c_void>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemberListener {
|
impl MemberListener {
|
||||||
pub async fn new(controller_id: &str, listen_timeout: Duration) -> Result<Arc<Self>, Box<dyn std::error::Error>> {
|
pub async fn new(
|
||||||
|
controller_id: &str,
|
||||||
|
listen_timeout: Duration,
|
||||||
|
callback: MemberListenerCallback,
|
||||||
|
user_ptr: *mut c_void,
|
||||||
|
) -> Result<Arc<Self>, Box<dyn std::error::Error>> {
|
||||||
let (tx, rx) = tokio::sync::mpsc::channel(64);
|
let (tx, rx) = tokio::sync::mpsc::channel(64);
|
||||||
|
|
||||||
let change_listener = ChangeListener::new(
|
let change_listener = ChangeListener::new(
|
||||||
|
@ -30,7 +42,12 @@ impl MemberListener {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(Arc::new(Self { change_listener, rx_channel: Mutex::new(rx) }))
|
Ok(Arc::new(Self {
|
||||||
|
change_listener,
|
||||||
|
rx_channel: Mutex::new(rx),
|
||||||
|
callback: Mutex::new(callback),
|
||||||
|
user_ptr: AtomicPtr::new(user_ptr as *mut c_void),
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn listen(&self) -> Result<(), Box<dyn std::error::Error>> {
|
pub async fn listen(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
@ -44,6 +61,21 @@ impl MemberListener {
|
||||||
while let Some(change) = rx.recv().await {
|
while let Some(change) = rx.recv().await {
|
||||||
if let Ok(m) = MemberChange::decode(change.as_slice()) {
|
if let Ok(m) = MemberChange::decode(change.as_slice()) {
|
||||||
print!("Received change: {:?}", m);
|
print!("Received change: {:?}", m);
|
||||||
|
|
||||||
|
let j = serde_json::to_string(&m).unwrap();
|
||||||
|
let mut buffer = [0; 16384];
|
||||||
|
let mut test: &mut [u8] = &mut buffer;
|
||||||
|
let mut size: usize = 0;
|
||||||
|
while let Ok(bytes) = test.write(j.as_bytes()) {
|
||||||
|
if bytes == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
size += bytes;
|
||||||
|
}
|
||||||
|
let callback = this.callback.lock().await;
|
||||||
|
let user_ptr = this.user_ptr.load(std::sync::atomic::Ordering::Relaxed);
|
||||||
|
|
||||||
|
(callback)(user_ptr, test.as_ptr(), size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,11 +2,16 @@ use crate::pubsub::change_listener::ChangeListener;
|
||||||
use crate::pubsub::protobuf::pbmessages::NetworkChange;
|
use crate::pubsub::protobuf::pbmessages::NetworkChange;
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::os::raw::c_void;
|
||||||
|
use std::sync::atomic::{AtomicPtr, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::sync::mpsc::Receiver;
|
use tokio::sync::mpsc::Receiver;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub type NetworkListenerCallback = extern "C" fn(*mut c_void, *const u8, usize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Network Listener listens for network changes and passes them back to the controller
|
* Network Listener listens for network changes and passes them back to the controller
|
||||||
*
|
*
|
||||||
|
@ -16,10 +21,17 @@ use tokio::sync::Mutex;
|
||||||
pub struct NetworkListener {
|
pub struct NetworkListener {
|
||||||
change_listener: ChangeListener,
|
change_listener: ChangeListener,
|
||||||
rx_channel: Mutex<Receiver<Vec<u8>>>,
|
rx_channel: Mutex<Receiver<Vec<u8>>>,
|
||||||
|
callback: Mutex<NetworkListenerCallback>,
|
||||||
|
user_ptr: AtomicPtr<c_void>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetworkListener {
|
impl NetworkListener {
|
||||||
pub async fn new(controller_id: &str, listen_timeout: Duration) -> Result<Arc<Self>, Box<dyn std::error::Error>> {
|
pub async fn new(
|
||||||
|
controller_id: &str,
|
||||||
|
listen_timeout: Duration,
|
||||||
|
callback: NetworkListenerCallback,
|
||||||
|
user_ptr: *mut c_void,
|
||||||
|
) -> Result<Arc<Self>, Box<dyn std::error::Error>> {
|
||||||
let (tx, rx) = tokio::sync::mpsc::channel(64);
|
let (tx, rx) = tokio::sync::mpsc::channel(64);
|
||||||
|
|
||||||
let change_listener = ChangeListener::new(
|
let change_listener = ChangeListener::new(
|
||||||
|
@ -30,7 +42,13 @@ impl NetworkListener {
|
||||||
tx,
|
tx,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(Arc::new(Self { change_listener, rx_channel: Mutex::new(rx) }))
|
|
||||||
|
Ok(Arc::new(Self {
|
||||||
|
change_listener,
|
||||||
|
rx_channel: Mutex::new(rx),
|
||||||
|
callback: Mutex::new(callback),
|
||||||
|
user_ptr: AtomicPtr::new(user_ptr as *mut c_void),
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn listen(&self) -> Result<(), Box<dyn std::error::Error>> {
|
pub async fn listen(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
@ -43,8 +61,22 @@ impl NetworkListener {
|
||||||
let mut rx = this.rx_channel.lock().await;
|
let mut rx = this.rx_channel.lock().await;
|
||||||
while let Some(change) = rx.recv().await {
|
while let Some(change) = rx.recv().await {
|
||||||
if let Ok(m) = NetworkChange::decode(change.as_slice()) {
|
if let Ok(m) = NetworkChange::decode(change.as_slice()) {
|
||||||
|
print!("Received change: {:?}", m);
|
||||||
|
|
||||||
let j = serde_json::to_string(&m).unwrap();
|
let j = serde_json::to_string(&m).unwrap();
|
||||||
print!("Received change: {:?}", j);
|
let mut buffer = [0; 16384];
|
||||||
|
let mut test: &mut [u8] = &mut buffer;
|
||||||
|
let mut size: usize = 0;
|
||||||
|
while let Ok(bytes) = test.write(j.as_bytes()) {
|
||||||
|
if bytes == 0 {
|
||||||
|
break; // No more space to write
|
||||||
|
}
|
||||||
|
size += bytes;
|
||||||
|
}
|
||||||
|
let callback = this.callback.lock().await;
|
||||||
|
let user_ptr = this.user_ptr.load(Ordering::Relaxed);
|
||||||
|
|
||||||
|
(callback)(user_ptr, test.as_ptr(), size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue