use serde::{Deserialize, Serialize};
use std::os::raw::c_char;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PluginMetadata {
pub id: String,
pub disabled: bool,
pub name: String,
pub description: String,
pub version: String,
pub author: Option<String>,
pub library_path: Option<String>, pub config_path: String, pub instance_id: Option<String>, }
#[repr(C)]
#[derive(Copy, Clone)]
pub struct PluginMetadataFFI {
pub id: *const c_char,
pub disabled: bool,
pub name: *const c_char,
pub description: *const c_char,
pub version: *const c_char,
pub author: *const c_char, pub library_path: *const c_char, pub config_path: *const c_char,
pub instance_id: *const c_char, }
impl PluginMetadata {
pub fn to_ffi(&self) -> PluginMetadataFFI {
use std::ffi::CString;
let id = CString::new(self.id.clone()).unwrap().into_raw();
let name = CString::new(self.name.clone()).unwrap().into_raw();
let description = CString::new(self.description.clone()).unwrap().into_raw();
let version = CString::new(self.version.clone()).unwrap().into_raw();
let config_path = CString::new(self.config_path.clone()).unwrap().into_raw();
let instance_id = if let Some(ref id) = self.instance_id {
CString::new(id.clone()).unwrap().into_raw()
} else {
std::ptr::null()
};
let author = if let Some(ref author) = self.author {
CString::new(author.clone()).unwrap().into_raw()
} else {
std::ptr::null()
};
let library_path = if let Some(ref path) = self.library_path {
CString::new(path.clone()).unwrap().into_raw()
} else {
std::ptr::null()
};
PluginMetadataFFI {
id,
disabled: self.disabled,
name,
description,
version,
author,
library_path,
config_path,
instance_id,
}
}
}
pub unsafe fn free_plugin_metadata_ffi(metadata: PluginMetadataFFI) {
use std::ffi::CString;
if !metadata.id.is_null() {
let _ = CString::from_raw(metadata.id as *mut c_char);
}
if !metadata.name.is_null() {
let _ = CString::from_raw(metadata.name as *mut c_char);
}
if !metadata.description.is_null() {
let _ = CString::from_raw(metadata.description as *mut c_char);
}
if !metadata.version.is_null() {
let _ = CString::from_raw(metadata.version as *mut c_char);
}
if !metadata.config_path.is_null() {
let _ = CString::from_raw(metadata.config_path as *mut c_char);
}
if !metadata.author.is_null() {
let _ = CString::from_raw(metadata.author as *mut c_char);
}
if !metadata.library_path.is_null() {
let _ = CString::from_raw(metadata.library_path as *mut c_char);
}
}
#[derive(Debug, Clone)]
pub struct PluginInstanceContext {
pub instance_id: String,
pub metadata: PluginMetadata,
pub callbacks: Option<crate::callbacks::HostCallbacks>,
}
impl PluginInstanceContext {
pub fn new(instance_id: String, metadata: PluginMetadata) -> Self {
Self {
instance_id,
metadata,
callbacks: None,
}
}
pub fn set_callbacks(&mut self, callbacks: crate::callbacks::HostCallbacks) {
self.callbacks = Some(callbacks);
}
pub fn get_instance_id(&self) -> &str {
&self.instance_id
}
pub fn get_metadata(&self) -> &PluginMetadata {
&self.metadata
}
pub fn get_callbacks(&self) -> Option<&crate::callbacks::HostCallbacks> {
self.callbacks.as_ref()
}
pub fn send_to_frontend(&self, event: &str, payload: &str) -> bool {
if let Some(callbacks) = &self.callbacks {
use std::ffi::CString;
if let (Ok(event_str), Ok(payload_str)) = (CString::new(event), CString::new(payload)) {
return (callbacks.send_to_frontend)(event_str.as_ptr(), payload_str.as_ptr());
}
}
false
}
pub fn get_app_config(&self, key: &str) -> Option<String> {
if let Some(callbacks) = &self.callbacks {
use std::ffi::CString;
if let Ok(key_str) = CString::new(key) {
let result_ptr = (callbacks.get_app_config)(key_str.as_ptr());
if !result_ptr.is_null() {
unsafe {
let c_str = std::ffi::CStr::from_ptr(result_ptr);
return c_str.to_str().ok().map(|s| s.to_string());
}
}
}
}
None
}
pub fn call_other_plugin(&self, plugin_id: &str, message: &str) -> Option<String> {
if let Some(callbacks) = &self.callbacks {
use std::ffi::CString;
if let (Ok(id_str), Ok(msg_str)) = (CString::new(plugin_id), CString::new(message)) {
let result_ptr = (callbacks.call_other_plugin)(id_str.as_ptr(), msg_str.as_ptr());
if !result_ptr.is_null() {
unsafe {
let c_str = std::ffi::CStr::from_ptr(result_ptr);
return c_str.to_str().ok().map(|s| s.to_string());
}
}
}
}
None
}
}
pub unsafe fn convert_ffi_to_metadata(metadata_ffi: PluginMetadataFFI) -> PluginMetadata {
use std::ffi::CStr;
let id = if !metadata_ffi.id.is_null() {
CStr::from_ptr(metadata_ffi.id)
.to_string_lossy()
.to_string()
} else {
String::new()
};
let name = if !metadata_ffi.name.is_null() {
CStr::from_ptr(metadata_ffi.name)
.to_string_lossy()
.to_string()
} else {
String::new()
};
let description = if !metadata_ffi.description.is_null() {
CStr::from_ptr(metadata_ffi.description)
.to_string_lossy()
.to_string()
} else {
String::new()
};
let version = if !metadata_ffi.version.is_null() {
CStr::from_ptr(metadata_ffi.version)
.to_string_lossy()
.to_string()
} else {
String::new()
};
let author = if !metadata_ffi.author.is_null() {
Some(
CStr::from_ptr(metadata_ffi.author)
.to_string_lossy()
.to_string(),
)
} else {
None
};
let library_path = if !metadata_ffi.library_path.is_null() {
Some(
CStr::from_ptr(metadata_ffi.library_path)
.to_string_lossy()
.to_string(),
)
} else {
None
};
let config_path = if !metadata_ffi.config_path.is_null() {
CStr::from_ptr(metadata_ffi.config_path)
.to_string_lossy()
.to_string()
} else {
String::new()
};
let instance_id = if !metadata_ffi.instance_id.is_null() {
Some(
CStr::from_ptr(metadata_ffi.instance_id)
.to_string_lossy()
.to_string(),
)
} else {
None
};
PluginMetadata {
id,
disabled: metadata_ffi.disabled,
name,
description,
version,
author,
library_path,
config_path,
instance_id,
}
}