plugin_interfaces/
metadata.rs1use serde::{Deserialize, Serialize};
2use std::os::raw::c_char;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct PluginMetadata {
7 pub id: String,
8 pub disabled: bool,
9 pub name: String,
10 pub description: String,
11 pub version: String,
12 pub author: Option<String>,
13 pub library_path: Option<String>, pub config_path: String, pub instance_id: Option<String>, }
17
18#[repr(C)]
21#[derive(Copy, Clone)]
22pub struct PluginMetadataFFI {
23 pub id: *const c_char,
24 pub disabled: bool,
25 pub name: *const c_char,
26 pub description: *const c_char,
27 pub version: *const c_char,
28 pub author: *const c_char, pub library_path: *const c_char, pub config_path: *const c_char,
31 pub instance_id: *const c_char, }
33
34impl PluginMetadata {
35 pub fn to_ffi(&self) -> PluginMetadataFFI {
38 use std::ffi::CString;
39
40 let id = CString::new(self.id.clone()).unwrap().into_raw();
41 let name = CString::new(self.name.clone()).unwrap().into_raw();
42 let description = CString::new(self.description.clone()).unwrap().into_raw();
43 let version = CString::new(self.version.clone()).unwrap().into_raw();
44 let config_path = CString::new(self.config_path.clone()).unwrap().into_raw();
45 let instance_id = if let Some(ref id) = self.instance_id {
46 CString::new(id.clone()).unwrap().into_raw()
47 } else {
48 std::ptr::null()
49 };
50
51 let author = if let Some(ref author) = self.author {
52 CString::new(author.clone()).unwrap().into_raw()
53 } else {
54 std::ptr::null()
55 };
56
57 let library_path = if let Some(ref path) = self.library_path {
58 CString::new(path.clone()).unwrap().into_raw()
59 } else {
60 std::ptr::null()
61 };
62
63 PluginMetadataFFI {
64 id,
65 disabled: self.disabled,
66 name,
67 description,
68 version,
69 author,
70 library_path,
71 config_path,
72 instance_id,
73 }
74 }
75}
76
77pub unsafe fn free_plugin_metadata_ffi(metadata: PluginMetadataFFI) {
80 use std::ffi::CString;
81
82 if !metadata.id.is_null() {
83 let _ = CString::from_raw(metadata.id as *mut c_char);
84 }
85 if !metadata.name.is_null() {
86 let _ = CString::from_raw(metadata.name as *mut c_char);
87 }
88 if !metadata.description.is_null() {
89 let _ = CString::from_raw(metadata.description as *mut c_char);
90 }
91 if !metadata.version.is_null() {
92 let _ = CString::from_raw(metadata.version as *mut c_char);
93 }
94 if !metadata.config_path.is_null() {
95 let _ = CString::from_raw(metadata.config_path as *mut c_char);
96 }
97 if !metadata.author.is_null() {
98 let _ = CString::from_raw(metadata.author as *mut c_char);
99 }
100 if !metadata.library_path.is_null() {
101 let _ = CString::from_raw(metadata.library_path as *mut c_char);
102 }
103}
104
105#[derive(Debug, Clone)]
108pub struct PluginInstanceContext {
109 pub instance_id: String,
110 pub metadata: PluginMetadata,
111 pub callbacks: Option<crate::callbacks::HostCallbacks>,
112}
113
114impl PluginInstanceContext {
115 pub fn new(instance_id: String, metadata: PluginMetadata) -> Self {
117 Self {
118 instance_id,
119 metadata,
120 callbacks: None,
121 }
122 }
123
124 pub fn set_callbacks(&mut self, callbacks: crate::callbacks::HostCallbacks) {
126 self.callbacks = Some(callbacks);
127 }
128
129 pub fn get_instance_id(&self) -> &str {
131 &self.instance_id
132 }
133
134 pub fn get_metadata(&self) -> &PluginMetadata {
136 &self.metadata
137 }
138
139 pub fn get_callbacks(&self) -> Option<&crate::callbacks::HostCallbacks> {
141 self.callbacks.as_ref()
142 }
143
144 pub fn send_to_frontend(&self, event: &str, payload: &str) -> bool {
146 if let Some(callbacks) = &self.callbacks {
147 use std::ffi::CString;
148 if let (Ok(event_str), Ok(payload_str)) = (CString::new(event), CString::new(payload)) {
149 return (callbacks.send_to_frontend)(event_str.as_ptr(), payload_str.as_ptr());
150 }
151 }
152 false
153 }
154
155 pub fn get_app_config(&self, key: &str) -> Option<String> {
157 if let Some(callbacks) = &self.callbacks {
158 use std::ffi::CString;
159 if let Ok(key_str) = CString::new(key) {
160 let result_ptr = (callbacks.get_app_config)(key_str.as_ptr());
161 if !result_ptr.is_null() {
162 unsafe {
163 let c_str = std::ffi::CStr::from_ptr(result_ptr);
164 return c_str.to_str().ok().map(|s| s.to_string());
165 }
166 }
167 }
168 }
169 None
170 }
171
172 pub fn call_other_plugin(&self, plugin_id: &str, message: &str) -> Option<String> {
174 if let Some(callbacks) = &self.callbacks {
175 use std::ffi::CString;
176 if let (Ok(id_str), Ok(msg_str)) = (CString::new(plugin_id), CString::new(message)) {
177 let result_ptr = (callbacks.call_other_plugin)(id_str.as_ptr(), msg_str.as_ptr());
178 if !result_ptr.is_null() {
179 unsafe {
180 let c_str = std::ffi::CStr::from_ptr(result_ptr);
181 return c_str.to_str().ok().map(|s| s.to_string());
182 }
183 }
184 }
185 }
186 None
187 }
188}
189
190pub unsafe fn convert_ffi_to_metadata(metadata_ffi: PluginMetadataFFI) -> PluginMetadata {
192 use std::ffi::CStr;
193
194 let id = if !metadata_ffi.id.is_null() {
195 CStr::from_ptr(metadata_ffi.id)
196 .to_string_lossy()
197 .to_string()
198 } else {
199 String::new()
200 };
201
202 let name = if !metadata_ffi.name.is_null() {
203 CStr::from_ptr(metadata_ffi.name)
204 .to_string_lossy()
205 .to_string()
206 } else {
207 String::new()
208 };
209
210 let description = if !metadata_ffi.description.is_null() {
211 CStr::from_ptr(metadata_ffi.description)
212 .to_string_lossy()
213 .to_string()
214 } else {
215 String::new()
216 };
217
218 let version = if !metadata_ffi.version.is_null() {
219 CStr::from_ptr(metadata_ffi.version)
220 .to_string_lossy()
221 .to_string()
222 } else {
223 String::new()
224 };
225
226 let author = if !metadata_ffi.author.is_null() {
227 Some(
228 CStr::from_ptr(metadata_ffi.author)
229 .to_string_lossy()
230 .to_string(),
231 )
232 } else {
233 None
234 };
235
236 let library_path = if !metadata_ffi.library_path.is_null() {
237 Some(
238 CStr::from_ptr(metadata_ffi.library_path)
239 .to_string_lossy()
240 .to_string(),
241 )
242 } else {
243 None
244 };
245
246 let config_path = if !metadata_ffi.config_path.is_null() {
247 CStr::from_ptr(metadata_ffi.config_path)
248 .to_string_lossy()
249 .to_string()
250 } else {
251 String::new()
252 };
253
254 let instance_id = if !metadata_ffi.instance_id.is_null() {
255 Some(
256 CStr::from_ptr(metadata_ffi.instance_id)
257 .to_string_lossy()
258 .to_string(),
259 )
260 } else {
261 None
262 };
263
264 PluginMetadata {
265 id,
266 disabled: metadata_ffi.disabled,
267 name,
268 description,
269 version,
270 author,
271 library_path,
272 config_path,
273 instance_id,
274 }
275}