diff --git a/examples/c/main.c b/examples/c/main.c index b8b0b78..8ed17df 100644 --- a/examples/c/main.c +++ b/examples/c/main.c @@ -5,8 +5,10 @@ int main(int argc, char **argv) { + tribufu_api_initialize(); char *version = tribufu_api_get_user_agent(); printf("%s\n", version); tribufu_free_string(version); + tribufu_api_shutdown(); return 0; } diff --git a/examples/cpp/main.cpp b/examples/cpp/main.cpp index 08cc4e3..4fabc92 100644 --- a/examples/cpp/main.cpp +++ b/examples/cpp/main.cpp @@ -5,8 +5,10 @@ int main(int argc, char **argv) { + tribufu_api_initialize(); const char *version = tribufu_api_get_user_agent(); std::cout << version << std::endl; tribufu_free_string((char *)version); + tribufu_api_shutdown(); return 0; } diff --git a/include/tribufu/native.h b/include/tribufu/native.h index d86d202..cd63a1c 100644 --- a/include/tribufu/native.h +++ b/include/tribufu/native.h @@ -5,18 +5,34 @@ #include <tribufu/prelude.h> -TRIBUFU_API void tribufu_api_default(void); +typedef void TribufuApiGetUserInfoCallbackData; -TRIBUFU_API void tribufu_api_from_env(void); - -TRIBUFU_API void tribufu_api_from_env_or_default(void); +typedef void (*TribufuApiGetUserInfoCallback)(void*, const TribufuApiGetUserInfoCallbackData*); +/** + * Gets the user agent string for the Tribufu API. + */ TRIBUFU_API const char *tribufu_api_get_user_agent(void); +TRIBUFU_API void tribufu_api_get_user_info(void *context, TribufuApiGetUserInfoCallback callback); + +/** + * Gets the version of the Tribufu API. + */ TRIBUFU_API const char *tribufu_api_get_version(void); -TRIBUFU_API void tribufu_api_new(void); +/** + * Initialize the Tribufu API instance. + * + * This must be called before any other API functions. + */ +TRIBUFU_API bool tribufu_api_initialize(void); -TRIBUFU_API void tribufu_api_with_api_key(void); +/** + * Shutdown the Tribufu API instance. + * + * This must be called when the API is no longer needed. + */ +TRIBUFU_API void tribufu_api_shutdown(void); TRIBUFU_API void tribufu_free_string(char *ptr); diff --git a/src/native/Cargo.toml b/src/native/Cargo.toml index d9bd5ba..2a2ac70 100644 --- a/src/native/Cargo.toml +++ b/src/native/Cargo.toml @@ -15,4 +15,7 @@ path = "lib.rs" [dependencies] tribufu = { path = "../../" } +futures = "0.3.31" libc = "0.2.172" +once_cell = "1.19.0" +tokio = { version = "1.45.1", features = ["full"] } diff --git a/src/native/api.rs b/src/native/api.rs index 1ee234a..7f55162 100644 --- a/src/native/api.rs +++ b/src/native/api.rs @@ -1,33 +1,88 @@ // Copyright (c) Tribufu. All Rights Reserved. // SPDX-License-Identifier: UNLICENSED +use crate::models::{TribufuApiCallbackContext, TribufuApiGetUserInfoCallback}; +use futures::lock::Mutex; +use libc::{c_char, c_void}; +use once_cell::sync::Lazy; use std::ffi::CString; -use std::os::raw::c_char; +use std::ptr; +use tokio::runtime::Runtime; +use tribufu::apis::tribufu_generated_api::TribufuGeneratedApiClient; use tribufu::TribufuApi; -#[no_mangle] -pub extern "C" fn tribufu_api_new() {} - -#[no_mangle] -pub extern "C" fn tribufu_api_default() {} - -#[no_mangle] -pub extern "C" fn tribufu_api_with_api_key() {} - -#[no_mangle] -pub extern "C" fn tribufu_api_from_env() {} - -#[no_mangle] -pub extern "C" fn tribufu_api_from_env_or_default() {} +static INSTANCE: Lazy<Mutex<Option<TribufuGeneratedApiClient>>> = Lazy::new(|| Mutex::new(None)); +static RUNTIME: Lazy<Runtime> = Lazy::new(|| Runtime::new().unwrap()); +/// Gets the version of the Tribufu API. #[no_mangle] pub extern "C" fn tribufu_api_get_version() -> *const c_char { CString::new(TribufuApi::get_version()).unwrap().into_raw() } +/// Gets the user agent string for the Tribufu API. #[no_mangle] pub extern "C" fn tribufu_api_get_user_agent() -> *const c_char { CString::new(TribufuApi::get_user_agent()) .unwrap() .into_raw() } + +/// Initialize the Tribufu API instance. +/// +/// This must be called before any other API functions. +#[no_mangle] +pub extern "C" fn tribufu_api_initialize() -> bool { + let api = TribufuApi::from_env_or_default(None); + + if INSTANCE.try_lock().is_none() { + return false; + } + + let mut instance = INSTANCE.try_lock().unwrap(); + *instance = Some(api); + + true +} + +/// Shutdown the Tribufu API instance. +/// +/// This must be called when the API is no longer needed. +#[no_mangle] +pub extern "C" fn tribufu_api_shutdown() { + if INSTANCE.try_lock().is_none() { + return; + } + + let mut instance = INSTANCE.try_lock().unwrap(); + *instance = None; +} + +#[no_mangle] +#[allow(unused_variables)] +pub extern "C" fn tribufu_api_get_user_info( + context: *mut c_void, + callback: TribufuApiGetUserInfoCallback, +) { + let context = TribufuApiCallbackContext(context); + + RUNTIME.spawn(async move { + let mut instance = INSTANCE.lock().await; + if instance.is_none() { + callback(context.as_ptr(), ptr::null()); + return; + } + + let api = instance.as_mut(); + if api.is_none() { + callback(context.as_ptr(), ptr::null()); + return; + } + + let api = api.unwrap(); + + // TODO: Implement logic here + + callback(context.as_ptr(), ptr::null()); + }); +} diff --git a/src/native/lib.rs b/src/native/lib.rs index 751dce9..aa68739 100644 --- a/src/native/lib.rs +++ b/src/native/lib.rs @@ -1,5 +1,8 @@ // Copyright (c) Tribufu. All Rights Reserved. // SPDX-License-Identifier: UNLICENSED +#![allow(dead_code)] + pub mod api; pub mod mem; +pub mod models; diff --git a/src/native/models.rs b/src/native/models.rs new file mode 100644 index 0000000..b1076c2 --- /dev/null +++ b/src/native/models.rs @@ -0,0 +1,19 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +use libc::c_void; + +pub struct TribufuApiCallbackContext(pub(crate) *mut c_void); + +impl TribufuApiCallbackContext { + pub(crate) fn as_ptr(&self) -> *mut c_void { + self.0 + } +} + +unsafe impl Send for TribufuApiCallbackContext {} +unsafe impl Sync for TribufuApiCallbackContext {} + +pub type TribufuApiGetUserInfoCallbackData = c_void; +pub type TribufuApiGetUserInfoCallback = + extern "C" fn(*mut c_void, *const TribufuApiGetUserInfoCallbackData);