1use std::ffi::{CStr, CString};
8 use std::os::raw::c_char;
9 use libloading::{Library, Symbol};
10 use std::ptr;
11 use std::fs::File;
12 use std::io::{self, Read};
13 use sha2::{Sha256, Digest};
14 use std::collections::HashMap;
15
16 pub mod models;
17 use crate::models::*;
18
19 fn compute_sha256_hash(file_path: &str) -> Result<String, io::Error> {
21 let mut file = File::open(file_path)?;
22 let mut hasher = Sha256::new();
23 let mut buffer = [0; 4096];
24
25 loop {
26 let bytes_read = file.read(&mut buffer)?;
27 if bytes_read == 0 {
28 break;
29 }
30 hasher.update(&buffer[..bytes_read]);
31 }
32
33 let hash = hasher.finalize();
34 Ok(format!("{:x}", hash))
35 }
36
37 fn validate_hash(file_path: &str, expected_hash: &str) -> Result<(), String> {
39 let computed_hash = compute_sha256_hash(file_path).map_err(|e| format!("Error computing hash: {}", e))?;
40
41 if computed_hash == expected_hash {
42 Ok(())
43 } else {
44 Err(format!("Hash mismatch! Expected: {}, Got: {}", expected_hash, computed_hash))
45 }
46 }
47
48 pub trait ITargetProvider: Send + Sync {
50 fn init(&self, config: ProviderConfig) -> Result<(), String>;
51 fn get_validation_rule(&self) -> Result<ValidationRule, String>; fn get(&self, deployment: DeploymentSpec, references: Vec<ComponentStep>) -> Result<Vec<ComponentSpec>, String>; fn apply(&self, deployment: DeploymentSpec, step: DeploymentStep, is_dry_run: bool) -> Result<HashMap<String, ComponentResultSpec>, String>;
54 }
55
56 #[repr(C)]
58 pub struct ProviderHandle {
59 provider: Box<dyn ITargetProvider>,
60 lib: Library, }
62
63 pub struct ProviderWrapper {
64 pub inner: Box<dyn ITargetProvider>,
65 }
66
67 #[no_mangle]
69 pub extern "C" fn create_provider_instance(
70 provider_path: *const c_char,
71 expected_hash: *const c_char
72 ) -> *mut ProviderHandle {
73 let provider_path = unsafe { CStr::from_ptr(provider_path) }
74 .to_str()
75 .expect("Invalid provider path");
76
77 let expected_hash = unsafe { CStr::from_ptr(expected_hash) }
78 .to_str()
79 .expect("Invalid hash value");
80
81 if let Err(err) = validate_hash(provider_path, expected_hash) {
83 eprintln!("Hash validation failed: {}", err);
84 return ptr::null_mut();
85 }
86
87 let lib = unsafe { Library::new(provider_path).expect("Failed to load provider library") };
88
89 type CreateProviderFn = unsafe fn() -> *mut ProviderWrapper;
90 let create_provider: Symbol<CreateProviderFn> = unsafe {
91 lib.get(b"create_provider\0").expect("Failed to load create_provider function")
92 };
93
94 let wrapper = unsafe { create_provider() };
95
96 if wrapper.is_null() {
97 eprintln!("Error: create_provider returned null pointer");
98 return ptr::null_mut();
99 }
100
101 let provider_box = unsafe { Box::from_raw(wrapper).inner };
103
104 let handle = Box::new(ProviderHandle {
105 provider: provider_box, lib: lib,
107 });
108
109 Box::into_raw(handle)
110 }
111
112 #[no_mangle]
114 pub extern "C" fn destroy_provider_instance(handle: *mut ProviderHandle) {
115 if !handle.is_null() {
116 unsafe {
117 drop(Box::from_raw(handle));
118 }
119 }
120 }
121
122 #[no_mangle]
124 pub extern "C" fn init_provider(handle: *mut ProviderHandle, config_json: *const c_char) -> i32 {
125 if handle.is_null() {
126 eprintln!("Error: handle pointer is null");
127 return -1;
128 }
129
130 if config_json.is_null() {
131 eprintln!("Error: config_json pointer is null");
132 return -1;
133 }
134
135 let config_str = match unsafe { CStr::from_ptr(config_json).to_str() } {
136 Ok(str) => str,
137 Err(err) => {
138 eprintln!("Error converting config_json to string: {:?}", err);
139 return -1;
140 },
141 };
142 let config: ProviderConfig = match serde_json::from_str(config_str) {
143 Ok(cfg) => cfg,
144 Err(err) => {
145 eprintln!("Error deserializing config_json: {:?}", err);
146 return -1;
147 },
148 };
149 let handle_ref = unsafe { &*handle };
150 match handle_ref.provider.init(config) {
151 Ok(_) => {
152 return 0;
153 }
154 Err(err) => {
155 eprintln!("Error during provider initialization: {:?}", err);
156 return -1;
157 },
158 }
159 }
160
161 #[no_mangle]
163 pub extern "C" fn get_validation_rule(handle: *mut ProviderHandle) -> *mut c_char {
164 let handle = unsafe { &*handle };
165 match handle.provider.get_validation_rule() {
166 Ok(validation_rule) => {
167 match CString::new(serde_json::to_string(&validation_rule).unwrap()) {
168 Ok(cstr) => cstr.into_raw(),
169 Err(_) => ptr::null_mut(),
170 }
171 }
172 Err(_) => ptr::null_mut(),
173 }
174 }
175
176 #[no_mangle]
178 pub extern "C" fn get(
179 handle: *mut ProviderHandle,
180 deployment_json: *const c_char,
181 references_json: *const c_char,
182 ) -> *mut c_char {
183 let handle = unsafe { &*handle };
184 let deployment_str = unsafe { CStr::from_ptr(deployment_json).to_str().unwrap() };
185 let references_str = unsafe { CStr::from_ptr(references_json).to_str().unwrap() };
186 let deployment: DeploymentSpec = serde_json::from_str(deployment_str).unwrap();
187 let references: Vec<ComponentStep> = serde_json::from_str(references_str).unwrap();
188 match handle.provider.get(deployment, references) {
189 Ok(components) => {
190 let json = serde_json::to_string(&components).unwrap();
191 CString::new(json).unwrap().into_raw()
192 }
193 Err(_) => {
194 println!("Error getting components");
195 ptr::null_mut()
196 }
197 }
198 }
199
200 #[no_mangle]
202 pub extern "C" fn apply(
203 handle: *mut ProviderHandle,
204 deployment_json: *const c_char,
205 step_json: *const c_char,
206 is_dry_run: i32,
207 ) -> *mut c_char {
208 let handle = unsafe { &*handle };
209 let deployment_str = unsafe { CStr::from_ptr(deployment_json).to_str().unwrap() };
210 let step_str = unsafe { CStr::from_ptr(step_json).to_str().unwrap() };
211 let deployment: DeploymentSpec = serde_json::from_str(deployment_str).unwrap();
212 let step: DeploymentStep = serde_json::from_str(step_str).unwrap();
213 let is_dry_run = is_dry_run != 0;
214
215 match handle.provider.apply(deployment, step, is_dry_run) {
216 Ok(result_map) => {
217 let json = serde_json::to_string(&result_map).unwrap();
218 CString::new(json).unwrap().into_raw()
219 }
220 Err(_) => ptr::null_mut(),
221 }
222 }