diff --git a/resources/ne_s3.h b/resources/ne_s3.h new file mode 100644 index 0000000..f4b4c33 --- /dev/null +++ b/resources/ne_s3.h @@ -0,0 +1,76 @@ +extern "C" { +#ifdef _WIN32 +#define NE_S3_IMPORT __declspec(dllimport) +#else +#define NE_S3_IMPORT +#endif +/// The callback function when upload/download finished +/// # Arguments +/// - `success` - Whether upload/download success +/// - `message` - The message of upload/download +/// - `user_data` - The user data passed to upload/download function +typedef void (*result_callback)(bool success, + const char* message, + const char* user_data); + +/// The callback function when upload/download progress changed +/// # Arguments +/// - `progress` - The progress of upload/download +/// - `user_data` - The user data passed to upload/download function +typedef void (*progress_callback)(float progress, const char* user_data); + +/// init sdk +/// run this function before any other functions +/// # Arguments +/// - `params` - The params of init, in json format +/// - `log_path` - The log path, use stdout if not given +NE_S3_IMPORT void __cdecl ne_s3_init(const char* params); + +/// uninit sdk +/// run this function to shutdown +NE_S3_IMPORT void __cdecl ne_s3_uninit(); + +/// Upload file to s3 +/// # Arguments +/// - `params` - The params of upload, json format +/// - `bucket` - The bucket name +/// - `object` - The object key +/// - `access_key_id` - The access key id +/// - `secret_access_key` - The secret access key +/// - `session_token` - The session token +/// - `security_token` - The security token +/// - `file_path` - The file path +/// - `region` - The region +/// - `tries` - The max retry times +/// - `endpoint` - The endpoint, use default if not set +/// - `ca_cert_path` - The ca certs path, use system certs if not set +/// - `result_callback` - The callback function when upload finished +/// - `progress_callback` - The callback function when upload progress changed +/// - `user_data` - The user data, will be passed to callbacks, lifetime must be +/// longer than callbacks +NE_S3_IMPORT void __cdecl ne_s3_upload(const char* params, + result_callback result, + progress_callback progress, + const char* user_data); + +/// download file from s3 +/// # Arguments +/// - `params` - The params of download, json format +/// - `bucket` - The bucket name +/// - `object` - The object key +/// - `access_key_id` - The access key id +/// - `secret_access_key` - The secret access key +/// - `session_token` - The session token +/// - `security_token` - The security token +/// - `file_path` - The file path +/// - `region` - The region +/// - `tries` - The max retry times +/// - `endpoint` - The endpoint, use default if not set +/// - `ca_cert_path` - The ca certs path, use system certs if not set +/// - `result_callback` - The callback function when download finished +/// - `user_data` - The user data, will be passed to callbacks, lifetime must be +/// longer than callbacks +NE_S3_IMPORT void __cdecl ne_s3_download(const char* params, + result_callback result, + const char* user_data); +} \ No newline at end of file diff --git a/src/basic.rs b/src/basic.rs index cdeb3b9..2b6d1a1 100644 --- a/src/basic.rs +++ b/src/basic.rs @@ -16,8 +16,14 @@ use std::{ task::{Context, Poll}, }; +/// result callback +/// - `success` - true if success, false if failed +/// - `message` - error message if failed pub type ResultCallback = Box; -pub type ProgressCallback = Arc>; + +/// progress callback +/// - `progress` - progress of upload or download, in percentage +pub type ProgressCallback = Arc>; #[derive(Debug)] pub struct NeS3Credential { @@ -68,7 +74,7 @@ impl ProgressTracker { fn track(&mut self, len: u64) { let mut bytes_written = self.bytes_written.lock().unwrap(); *bytes_written += len; - let progress = *bytes_written as f64 / self.content_length as f64 * 100.0; + let progress = *bytes_written as f32 / self.content_length as f32 * 100.0; let progress_callback = self.progress_callback.lock().unwrap(); if std::time::Instant::now() - self.last_callback_time < std::time::Duration::from_millis(500) @@ -159,12 +165,12 @@ pub struct S3Params { pub(crate) access_key_id: String, pub(crate) secret_access_key: String, pub(crate) session_token: String, - pub(crate) file_path: String, pub(crate) security_token: String, - pub(crate) ca_certs_path: Option, + pub(crate) file_path: String, pub(crate) region: Option, pub(crate) tries: Option, pub(crate) endpoint: Option, + pub(crate) ca_cert_path: Option, } fn load_ca_cert(path: &String) -> Result> { @@ -193,12 +199,12 @@ pub fn create_s3_client(params: &S3Params) -> Result> = Mutex::new(None); -/// init tokio runtime +/// init sdk /// run this function before any other functions /// # Arguments /// - `params` - The params of init, json format /// - `log_path` - The log path, use stdout if not set -pub fn init(params_str: String) { +pub fn init(params: String) { let mut runtime = unsafe { RUNTIME.lock().unwrap() }; if !runtime.is_none() { return; } - let params = match serde_json::from_str::(¶ms_str) { - Ok(params) => params, + let parsed_params = match serde_json::from_str::(¶ms) { + Ok(result) => result, Err(err) => { panic!("parse init params failed: {}", err); } }; - let log_path = params.log_path.as_ref(); + let log_path = parsed_params.log_path.as_ref(); if log_path.is_some_and(|path| Path::new(path).exists()) { let log_path = log_path.unwrap(); let _logger = Logger::try_with_str("info") @@ -55,7 +55,7 @@ pub fn init(params_str: String) { .start() .unwrap(); } - info!("init params: {}", params_str); + info!("init params: {}", params); let mut system_info = System::new_all(); system_info.refresh_all(); let system_info_json = json!({ @@ -74,8 +74,14 @@ pub fn init(params_str: String) { .unwrap(); *runtime = Some(rt); } +#[no_mangle] +pub extern "cdecl" fn ne_s3_init(params: *const std::os::raw::c_char) { + let params = unsafe { std::ffi::CStr::from_ptr(params) }; + let params = params.to_str().unwrap(); + init(params.to_string()); +} -/// uninit tokio runtime +/// uninit sdk /// run this function to shutdown pub fn uninit() { let mut runtime = unsafe { RUNTIME.lock().unwrap() }; @@ -86,6 +92,10 @@ pub fn uninit() { rt.shutdown_background(); } } +#[no_mangle] +pub extern "cdecl" fn ne_s3_uninit() { + uninit(); +} /// Upload file to s3 /// # Arguments @@ -94,16 +104,15 @@ pub fn uninit() { /// - `object` - The object key /// - `access_key_id` - The access key id /// - `secret_access_key` - The secret access key -/// - `file_path` - The file path +/// - `session_token` - The session token /// - `security_token` - The security token +/// - `file_path` - The file path /// - `region` - The region /// - `tries` - The max retry times /// - `endpoint` - The endpoint, use default if not set +/// - `ca_cert_path` - The ca certs path, use system certs if not set /// - `result_callback` - The callback function when upload finished -/// - `success` - The upload succeeded or not -/// - `message` - The error message if upload failed /// - `progress_callback` - The callback function when upload progress changed -/// - `progress` - The progress of upload, in percentage pub fn upload( params: String, result_callback: basic::ResultCallback, @@ -147,6 +156,25 @@ pub fn upload( } }); } +#[no_mangle] +pub extern "cdecl" fn ne_s3_upload( + params: *const std::os::raw::c_char, + result_callback: extern "C" fn(success: bool, message: *const std::os::raw::c_char, user_data: *const std::os::raw::c_char), + progress_callback: extern "C" fn(progress: f32, user_data: *const std::os::raw::c_char), + user_data: *const std::os::raw::c_char, +) { + let params = unsafe { std::ffi::CStr::from_ptr(params as *mut _) }; + let params = params.to_str().unwrap().to_string(); + let user_data = unsafe { std::ffi::CStr::from_ptr(user_data) }; + let result_callback = move |success: bool, message: String| { + let message = std::ffi::CString::new(message).unwrap(); + result_callback(success, message.as_ptr(), user_data.as_ptr()); + }; + let progress_callback = move |progress: f32| { + progress_callback(progress, user_data.as_ptr()); + }; + upload(params.to_string(), Box::new(result_callback), Arc::new(Mutex::new(progress_callback))); +} /// download file from s3 /// # Arguments @@ -155,14 +183,14 @@ pub fn upload( /// - `object` - The object key /// - `access_key_id` - The access key id /// - `secret_access_key` - The secret access key -/// - `file_path` - The file path +/// - `session_token` - The session token /// - `security_token` - The security token +/// - `file_path` - The file path /// - `region` - The region /// - `tries` - The max retry times /// - `endpoint` - The endpoint, use default if not set +/// - `ca_cert_path` - The ca certs path, use system certs if not set /// - `result_callback` - The callback function when download finished -/// - `success` - The download succeeded or not -/// - `message` - The error message if download failed pub fn download(params: String, result_callback: basic::ResultCallback) { info!("download params: {}", params); let runtime = unsafe { RUNTIME.lock().unwrap() }; @@ -201,4 +229,19 @@ pub fn download(params: String, result_callback: basic::ResultCallback) { result_callback(false, error_descrption); } }); +} +#[no_mangle] +pub extern "cdecl" fn ne_s3_download( + params: *const std::os::raw::c_char, + result_callback: extern "C" fn(success: bool, message: *const std::os::raw::c_char, user_data: *const std::os::raw::c_char), + user_data: *const std::os::raw::c_char, +) { + let params = unsafe { std::ffi::CStr::from_ptr(params as *mut _) }; + let params = params.to_str().unwrap().to_string(); + let user_data = unsafe { std::ffi::CStr::from_ptr(user_data) }; + let result_callback = move |success: bool, message: String| { + let message = std::ffi::CString::new(message).unwrap(); + result_callback(success, message.as_ptr(), user_data.as_ptr()); + }; + download(params.to_string(), Box::new(result_callback)); } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 1528328..cb9e866 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,7 +24,7 @@ struct Args { #[arg(long)] security_token: String, #[arg(long, default_value_t = String::new())] - ca_certs_path: String, + ca_cert_path: String, #[arg(long, default_value_t = String::new())] region: String, #[arg(long, default_value_t = 3)] @@ -58,7 +58,7 @@ fn main() { *lock = true; ccond.notify_one(); }; - let progress_callback = |progress: f64| { + let progress_callback = |progress: f32| { info!("put object progress: {:.2}%", progress); }; upload(