13 changed files with 1904 additions and 1740 deletions
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,3 @@
|
||||
[workspace] |
||||
|
||||
members = ["zeroidc"] |
||||
members = ["smeeclient", "zeroidc"] |
||||
|
||||
@ -0,0 +1,15 @@
|
||||
#unstable_features = true |
||||
max_width = 120 |
||||
#use_small_heuristics = "Max" |
||||
edition = "2021" |
||||
#empty_item_single_line = true |
||||
newline_style = "Unix" |
||||
struct_lit_width = 60 |
||||
tab_spaces = 4 |
||||
use_small_heuristics = "Default" |
||||
#fn_single_line = true |
||||
#hex_literal_case = "Lower" |
||||
#merge_imports = true |
||||
#group_imports = "StdExternalCrate" |
||||
single_line_if_else_max_width = 0 |
||||
use_try_shorthand = true |
||||
@ -0,0 +1,21 @@
|
||||
[package] |
||||
name = "smeeclient" |
||||
version = "0.1.0" |
||||
edition = "2021" |
||||
|
||||
[lib] |
||||
crate-type = ["staticlib", "rlib"] |
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
||||
|
||||
[dependencies] |
||||
serde = { version = "1", features = ["derive"] } |
||||
temporal-sdk = { git = "https://github.com/temporalio/sdk-core" } |
||||
temporal-client = { git = "https://github.com/temporalio/sdk-core" } |
||||
temporal-sdk-core-protos = { git = "https://github.com/temporalio/sdk-core" } |
||||
tokio = { version = "1.29", features = ["full"] } |
||||
url = { version = "2" } |
||||
uuid = { version = "1.4", features = ["v4"] } |
||||
|
||||
[build-dependencies] |
||||
cbindgen = "0.20" |
||||
@ -0,0 +1,36 @@
|
||||
extern crate cbindgen; |
||||
|
||||
use cbindgen::{Config, Language}; |
||||
use std::env; |
||||
use std::path::PathBuf; |
||||
|
||||
fn main() { |
||||
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); |
||||
|
||||
let package_name = env::var("CARGO_PKG_NAME").unwrap(); |
||||
let output_file = target_dir().join(format!("{}.h", package_name)).display().to_string(); |
||||
|
||||
let config = Config { |
||||
language: Language::C, |
||||
cpp_compat: true, |
||||
namespace: Some(String::from("smeeclient")), |
||||
..Default::default() |
||||
}; |
||||
|
||||
cbindgen::generate_with_config(&crate_dir, config) |
||||
.unwrap() |
||||
.write_to_file(&output_file); |
||||
} |
||||
|
||||
/// Find the location of the `target/` directory. Note that this may be
|
||||
/// overridden by `cmake`, so we also need to check the `CARGO_TARGET_DIR`
|
||||
/// variable.
|
||||
fn target_dir() -> PathBuf { |
||||
if let Ok(target) = env::var("CARGO_TARGET_DIR") { |
||||
PathBuf::from(target) |
||||
} else { |
||||
PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) |
||||
.join("..") |
||||
.join("target") |
||||
} |
||||
} |
||||
@ -0,0 +1,104 @@
|
||||
/* |
||||
* Copyright (c)2021 ZeroTier, Inc. |
||||
* |
||||
* Use of this software is governed by the Business Source License included |
||||
* in the LICENSE.TXT file in the project's root directory. |
||||
* |
||||
* Change Date: 2025-01-01 |
||||
* |
||||
* On the date above, in accordance with the Business Source License, use |
||||
* of this software will be governed by version 2.0 of the Apache License. |
||||
*/ |
||||
|
||||
use std::ffi::CStr; |
||||
use std::os::raw::c_char; |
||||
|
||||
use crate::NetworkJoinedParams; |
||||
use crate::SmeeClient; |
||||
|
||||
#[no_mangle] |
||||
pub extern "C" fn smee_client_new( |
||||
temporal_url: *const c_char, |
||||
namespace: *const c_char, |
||||
task_queue: *const c_char, |
||||
) -> *mut SmeeClient { |
||||
let url = unsafe { |
||||
assert!(!temporal_url.is_null()); |
||||
CStr::from_ptr(temporal_url).to_str().unwrap() |
||||
}; |
||||
|
||||
let ns = unsafe { |
||||
assert!(!namespace.is_null()); |
||||
CStr::from_ptr(namespace).to_str().unwrap() |
||||
}; |
||||
|
||||
let tq = unsafe { |
||||
assert!(!task_queue.is_null()); |
||||
CStr::from_ptr(task_queue).to_str().unwrap() |
||||
}; |
||||
|
||||
match SmeeClient::new(url, ns, tq) { |
||||
Ok(c) => Box::into_raw(Box::new(c)), |
||||
Err(e) => { |
||||
println!("error creating smee client instance: {}", e); |
||||
std::ptr::null_mut() |
||||
} |
||||
} |
||||
} |
||||
|
||||
#[no_mangle] |
||||
pub extern "C" fn smee_client_delete(ptr: *mut SmeeClient) { |
||||
if ptr.is_null() { |
||||
return; |
||||
} |
||||
let smee = unsafe { |
||||
assert!(!ptr.is_null()); |
||||
Box::from_raw(&mut *ptr) |
||||
}; |
||||
|
||||
smee.shutdown(); |
||||
} |
||||
|
||||
#[no_mangle] |
||||
pub extern "C" fn smee_client_notify_netowrk_joined( |
||||
smee_instance: *mut SmeeClient, |
||||
network_id: *const c_char, |
||||
member_id: *const c_char, |
||||
hook_url: *const c_char, |
||||
src_ip: *const c_char, |
||||
) -> bool { |
||||
let nwid = unsafe { |
||||
assert!(!network_id.is_null()); |
||||
CStr::from_ptr(network_id).to_str().unwrap() |
||||
}; |
||||
|
||||
let mem_id = unsafe { |
||||
assert!(!member_id.is_null()); |
||||
CStr::from_ptr(member_id).to_str().unwrap() |
||||
}; |
||||
|
||||
let url = unsafe { |
||||
assert!(!hook_url.is_null()); |
||||
CStr::from_ptr(hook_url).to_str().unwrap() |
||||
}; |
||||
|
||||
let src = unsafe { |
||||
if src_ip.is_null() { |
||||
None |
||||
} else { |
||||
Some(CStr::from_ptr(src_ip).to_str().unwrap()) |
||||
} |
||||
}; |
||||
|
||||
let smee = unsafe { |
||||
assert!(!smee_instance.is_null()); |
||||
&mut *smee_instance |
||||
}; |
||||
|
||||
let params = NetworkJoinedParams::new(nwid, mem_id, url, src); |
||||
|
||||
match smee.notify_network_joined(params) { |
||||
Ok(()) => true, |
||||
Err(_) => false, |
||||
} |
||||
} |
||||
@ -0,0 +1,115 @@
|
||||
/* |
||||
* Copyright (c)2023 ZeroTier, Inc. |
||||
* |
||||
* Use of this software is governed by the Business Source License included |
||||
* in the LICENSE.TXT file in the project's root directory. |
||||
* |
||||
* Change Date: 2025-01-01 |
||||
* |
||||
* On the date above, in accordance with the Business Source License, use |
||||
* of this software will be governed by version 2.0 of the Apache License. |
||||
*/ |
||||
|
||||
pub mod ext; |
||||
|
||||
use serde::{Deserialize, Serialize}; |
||||
use std::str::FromStr; |
||||
use std::time::Duration; |
||||
use temporal_client::{Client, ClientOptionsBuilder, RetryClient, WorkflowClientTrait, WorkflowOptions}; |
||||
use temporal_sdk_core_protos::{coresdk::AsJsonPayloadExt, temporal::api::enums::v1::WorkflowIdReusePolicy}; |
||||
use url::Url; |
||||
use uuid::Uuid; |
||||
|
||||
const CLIENT_NAME: &str = "SmeeClient-Rust"; |
||||
const CLIENT_VERSION: &str = "0.1"; |
||||
const NETWORK_JOINED_WORKFLOW: &str = "NetworkJoinedWorkflow"; |
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] |
||||
pub struct NetworkJoinedParams { |
||||
#[serde(rename = "NetworkID")] |
||||
pub network_id: String, |
||||
|
||||
#[serde(rename = "MemberID")] |
||||
pub member_id: String, |
||||
|
||||
#[serde(rename = "HookURL")] |
||||
pub hook_url: String, |
||||
|
||||
#[serde(rename = "SrcIP")] |
||||
pub src_ip: Option<String>, |
||||
} |
||||
|
||||
impl NetworkJoinedParams { |
||||
fn new(network_id: &str, member_id: &str, hook_url: &str, src_ip: Option<&str>) -> Self { |
||||
Self { |
||||
network_id: network_id.to_string(), |
||||
member_id: member_id.to_string(), |
||||
hook_url: hook_url.to_string(), |
||||
src_ip: match src_ip { |
||||
Some(x) => Some(x.to_string()), |
||||
None => None, |
||||
}, |
||||
} |
||||
} |
||||
} |
||||
|
||||
pub struct SmeeClient { |
||||
tokio_rt: tokio::runtime::Runtime, |
||||
client: RetryClient<Client>, |
||||
task_queue: String, |
||||
} |
||||
|
||||
impl SmeeClient { |
||||
pub fn new(temporal_url: &str, namespace: &str, task_queue: &str) -> Result<Self, Box<dyn std::error::Error>> { |
||||
// start tokio runtime. Required by temporal
|
||||
let rt = tokio::runtime::Runtime::new()?; |
||||
|
||||
let c = ClientOptionsBuilder::default() |
||||
.target_url(Url::from_str(temporal_url).unwrap()) |
||||
.client_name(CLIENT_NAME) |
||||
.client_version(CLIENT_VERSION) |
||||
.build()?; |
||||
|
||||
let con = rt.block_on(async { c.connect(namespace.to_string(), None, None).await })?; |
||||
|
||||
Ok(Self { |
||||
tokio_rt: rt, |
||||
client: con, |
||||
task_queue: task_queue.to_string(), |
||||
}) |
||||
} |
||||
|
||||
pub fn notify_network_joined(&self, params: NetworkJoinedParams) -> Result<(), Box<dyn std::error::Error>> { |
||||
let options = WorkflowOptions { |
||||
id_reuse_policy: WorkflowIdReusePolicy::RejectDuplicate, |
||||
execution_timeout: None, |
||||
run_timeout: None, |
||||
task_timeout: None, |
||||
cron_schedule: None, |
||||
search_attributes: None, |
||||
}; |
||||
|
||||
let payload = vec![params.as_json_payload()?]; |
||||
|
||||
let workflow_id = Uuid::new_v4(); |
||||
|
||||
self.tokio_rt.block_on(async { |
||||
self.client |
||||
.start_workflow( |
||||
payload, |
||||
self.task_queue.clone(), |
||||
workflow_id.hyphenated().to_string(), |
||||
String::from(NETWORK_JOINED_WORKFLOW), |
||||
None, |
||||
options, |
||||
) |
||||
.await |
||||
})?; |
||||
|
||||
Ok(()) |
||||
} |
||||
|
||||
pub fn shutdown(self) { |
||||
self.tokio_rt.shutdown_timeout(Duration::from_secs(5)) |
||||
} |
||||
} |
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue