sz_rust_sdk/core/
config.rs

1//! Core implementation of SzConfig trait
2
3use crate::{error::SzResult, ffi_call_config, traits::SzConfig, types::JsonString};
4use libc;
5
6/// Core implementation of the SzConfig trait
7pub struct SzConfigCore {
8    handle: *mut libc::c_char,
9}
10
11// SAFETY: SzConfigCore is safe to send between threads as the handle is managed by Senzing
12unsafe impl Send for SzConfigCore {}
13unsafe impl Sync for SzConfigCore {}
14
15impl SzConfigCore {
16    pub fn new_with_params(
17        module_name: &str,
18        ini_params: &str,
19        verbose_logging: bool,
20    ) -> SzResult<Self> {
21        // Initialize the config module with parameters
22        let module_name_c = crate::ffi::helpers::str_to_c_string(module_name)?;
23        let ini_params_c = crate::ffi::helpers::str_to_c_string(ini_params)?;
24        let verbose = if verbose_logging { 1 } else { 0 };
25
26        ffi_call_config!(crate::ffi::bindings::SzConfig_init(
27            module_name_c.as_ptr(),
28            ini_params_c.as_ptr(),
29            verbose
30        ));
31
32        let result = unsafe { crate::ffi::bindings::SzConfig_create_helper() };
33        if result.return_code != 0 {
34            crate::ffi::helpers::check_config_return_code(result.return_code)?;
35        }
36        let handle = result.response;
37
38        Ok(Self { handle })
39    }
40
41    pub fn new_with_definition(config_definition: &str) -> SzResult<Self> {
42        // Get environment parameters for proper initialization
43        match super::environment::SzEnvironmentCore::get_existing_instance() {
44            Ok(existing_env) => {
45                // Initialize the config module with parameters
46                let module_name_c = crate::ffi::helpers::str_to_c_string("SzRustSDK-Config")?;
47                let ini_params_c =
48                    crate::ffi::helpers::str_to_c_string(existing_env.get_ini_params())?;
49                let verbose = if existing_env.get_verbose_logging() {
50                    1
51                } else {
52                    0
53                };
54
55                ffi_call_config!(crate::ffi::bindings::SzConfig_init(
56                    module_name_c.as_ptr(),
57                    ini_params_c.as_ptr(),
58                    verbose
59                ));
60
61                // Load the config definition directly - this returns the handle
62                let config_def_c = crate::ffi::helpers::str_to_c_string(config_definition)?;
63                let result =
64                    unsafe { crate::ffi::bindings::SzConfig_load_helper(config_def_c.as_ptr()) };
65                if result.return_code != 0 {
66                    crate::ffi::helpers::check_config_return_code(result.return_code)?;
67                }
68                let handle = result.response;
69
70                Ok(Self { handle })
71            }
72            Err(e) => {
73                // Error if no environment exists - don't create fake objects
74                Err(crate::error::SzError::configuration(format!(
75                    "Cannot create config with definition without initialized environment: {}",
76                    e
77                )))
78            }
79        }
80    }
81}
82
83impl SzConfig for SzConfigCore {
84    fn export(&self) -> SzResult<JsonString> {
85        let result = unsafe { crate::ffi::bindings::SzConfig_export_helper(self.handle) };
86
87        unsafe { crate::ffi::helpers::process_config_pointer_result(result) }
88    }
89
90    fn get_data_source_registry(&self) -> SzResult<JsonString> {
91        // Use the native SzConfig_getDataSourceRegistry function instead of export
92        let result =
93            unsafe { crate::ffi::bindings::SzConfig_getDataSourceRegistry_helper(self.handle) };
94        unsafe { crate::ffi::helpers::process_config_pointer_result(result) }
95    }
96
97    fn register_data_source(&self, data_source_code: &str) -> SzResult<JsonString> {
98        // Create JSON input as expected by native function (matching C# SDK behavior)
99        let json_input = format!(r#"{{"DSRC_CODE": "{}"}}"#, data_source_code);
100        let data_source_c = crate::ffi::helpers::str_to_c_string(&json_input)?;
101
102        let result = unsafe {
103            crate::ffi::bindings::SzConfig_registerDataSource_helper(
104                self.handle,
105                data_source_c.as_ptr(),
106            )
107        };
108
109        unsafe { crate::ffi::helpers::process_config_pointer_result(result) }
110    }
111
112    fn unregister_data_source(&self, data_source_code: &str) -> SzResult<()> {
113        let data_source_c = crate::ffi::helpers::str_to_c_string(data_source_code)?;
114
115        ffi_call_config!(crate::ffi::bindings::SzConfig_unregisterDataSource_helper(
116            self.handle,
117            data_source_c.as_ptr()
118        ));
119
120        Ok(())
121    }
122}
123
124impl Drop for SzConfigCore {
125    fn drop(&mut self) {
126        if !self.handle.is_null() {
127            unsafe {
128                let _ = crate::ffi::bindings::SzConfig_close_helper(self.handle);
129            }
130        }
131        // NOTE: SzConfig_destroy() should only be called when the entire process is shutting down
132        // or when we're certain no other SzConfig instances will be needed.
133        // For now, we only clean up the handle and clear exceptions.
134        // Module destruction should be handled by a singleton manager or at process exit.
135        unsafe {
136            crate::ffi::bindings::SzConfig_clearLastException();
137        }
138    }
139}