use std::collections::HashMap;
use std::ffi::CString;
use std::sync::{Mutex, OnceLock};
use libc::c_char;
use pact_plugin_driver::plugin_log_sink::{PluginLogEntry, PluginLogSink};
pub type PluginLogCallback = unsafe extern "C" fn(
plugin_instance_id: *const c_char,
test_run_id: *const c_char,
level: *const c_char,
target: *const c_char,
message: *const c_char,
);
static LOG_CALLBACK: OnceLock<Mutex<Option<PluginLogCallback>>> = OnceLock::new();
static LOG_BUFFER: OnceLock<Mutex<HashMap<String, Vec<PluginLogEntry>>>> = OnceLock::new();
fn callback_cell() -> &'static Mutex<Option<PluginLogCallback>> {
LOG_CALLBACK.get_or_init(|| Mutex::new(None))
}
pub(crate) fn buffer_cell() -> &'static Mutex<HashMap<String, Vec<PluginLogEntry>>> {
LOG_BUFFER.get_or_init(|| Mutex::new(HashMap::new()))
}
pub(crate) fn register_callback(cb: PluginLogCallback) {
*callback_cell().lock().unwrap() = Some(cb);
}
pub(crate) fn get_logs(instance_id: &str) -> Vec<PluginLogEntry> {
buffer_cell()
.lock()
.unwrap()
.get(instance_id)
.cloned()
.unwrap_or_default()
}
pub(crate) struct FfiPluginLogSink;
impl PluginLogSink for FfiPluginLogSink {
fn log(&self, entry: &PluginLogEntry) {
buffer_cell()
.lock()
.unwrap()
.entry(entry.plugin_instance_id.clone())
.or_default()
.push(entry.clone());
if let Some(cb) = *callback_cell().lock().unwrap() {
let to_c = |s: &str| CString::new(s).unwrap_or_default();
let instance_id = to_c(&entry.plugin_instance_id);
let test_run_id = to_c(entry.test_run_id.as_deref().unwrap_or(""));
let level = to_c(&entry.level);
let target = to_c(entry.target.as_deref().unwrap_or(""));
let message = to_c(&entry.message);
unsafe {
cb(
instance_id.as_ptr(),
test_run_id.as_ptr(),
level.as_ptr(),
target.as_ptr(),
message.as_ptr(),
);
}
}
}
}