crawlkit_plugin_sdk/export.rs
1//! WASM export macros for plugins.
2
3/// Export an analyzer as a WASM plugin.
4///
5/// This macro generates the required WASM export functions:
6/// - `crawlkit_plugin_init`
7/// - `crawlkit_plugin_analyze`
8/// - `crawlkit_plugin_free_string`
9///
10/// # Example
11///
12/// ```rust,no_run
13/// use crawlkit_plugin_sdk::{Analyzer, Finding, Severity, AnalysisContext};
14///
15/// pub struct MyAnalyzer;
16/// impl MyAnalyzer { pub fn new() -> Self { Self } }
17/// impl Default for MyAnalyzer { fn default() -> Self { Self::new() } }
18///
19/// impl Analyzer for MyAnalyzer {
20/// fn name(&self) -> &str { "my-analyzer" }
21/// fn analyze(&self, _ctx: &AnalysisContext) -> Vec<Finding> { vec![] }
22/// }
23///
24/// crawlkit_plugin_sdk::export_analyzer!(MyAnalyzer);
25/// ```
26#[macro_export]
27macro_rules! export_analyzer {
28 ($analyzer_type:ty) => {
29 static mut ANALYZER: Option<$analyzer_type> = None;
30
31 #[no_mangle]
32 pub extern "C" fn crawlkit_plugin_init() -> i32 {
33 unsafe {
34 ANALYZER = Some(<$analyzer_type>::new());
35 }
36 0
37 }
38
39 /// # Safety
40 ///
41 /// This function reads from raw pointers provided by the host.
42 /// The host must ensure the pointers are valid and point to valid UTF-8 data.
43 #[no_mangle]
44 pub unsafe extern "C" fn crawlkit_plugin_analyze(
45 html_ptr: *const u8,
46 html_len: usize,
47 url_ptr: *const u8,
48 url_len: usize,
49 ) -> *mut u8 {
50 let html = String::from_utf8_unchecked(
51 std::slice::from_raw_parts(html_ptr, html_len).to_vec(),
52 );
53 let url =
54 String::from_utf8_unchecked(std::slice::from_raw_parts(url_ptr, url_len).to_vec());
55
56 let ctx = $crate::AnalysisContext {
57 url,
58 html,
59 status_code: None,
60 headers: Vec::new(),
61 response_time_ms: None,
62 };
63
64 let analyzer = ANALYZER.as_ref().expect("Analyzer not initialized");
65 let findings = analyzer.analyze(&ctx);
66
67 let json = serde_json::to_string(&findings).unwrap();
68 let bytes = json.into_bytes();
69 let ptr = bytes.as_ptr();
70 std::mem::forget(bytes);
71 ptr as *mut u8
72 }
73
74 /// # Safety
75 ///
76 /// This function frees memory allocated by the plugin.
77 /// The pointer must have been returned by `crawlkit_plugin_analyze`.
78 #[no_mangle]
79 pub unsafe extern "C" fn crawlkit_plugin_free_string(ptr: *mut u8) {
80 if !ptr.is_null() {
81 let _ = Box::from_raw(ptr);
82 }
83 }
84
85 #[no_mangle]
86 pub extern "C" fn crawlkit_plugin_api_version() -> *mut u8 {
87 let version = "1.0";
88 let bytes = version.as_bytes().to_vec();
89 let ptr = bytes.as_ptr();
90 std::mem::forget(bytes);
91 ptr as *mut u8
92 }
93 };
94}