Skip to content

Commit 3558a4d

Browse files
authored
feat(plugin): add API version compatibility check for native plugins (#1237)
1 parent 6178de5 commit 3558a4d

File tree

4 files changed

+39
-1
lines changed

4 files changed

+39
-1
lines changed

pumpkin-api-macros/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ pub fn plugin_impl(_attr: TokenStream, item: TokenStream) -> TokenStream {
8080
description: env!("CARGO_PKG_DESCRIPTION"),
8181
};
8282

83+
#[unsafe(no_mangle)]
84+
pub static PUMPKIN_API_VERSION: u32 = pumpkin::plugin::PLUGIN_API_VERSION;
85+
8386
#input_struct
8487

8588
impl pumpkin::plugin::Plugin for #struct_ident {

pumpkin/src/plugin/loader/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,17 @@ pub enum LoaderError {
5656

5757
#[error("Invalid loader data")]
5858
InvalidLoaderData,
59+
60+
#[error(
61+
"Plugin was built for an incompatible API version. Please rebuild it against this Pumpkin build."
62+
)]
63+
ApiVersionMissing,
64+
65+
#[error(
66+
"Plugin API version mismatch (plugin {plugin_version}, server {server_version}). Please rebuild it against this Pumpkin build."
67+
)]
68+
ApiVersionMismatch {
69+
plugin_version: u32,
70+
server_version: u32,
71+
},
5972
}

pumpkin/src/plugin/loader/native.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ use std::any::Any;
22

33
use libloading::Library;
44

5-
use crate::plugin::loader::{PluginLoadFuture, PluginUnloadFuture};
5+
use crate::plugin::{
6+
PLUGIN_API_VERSION,
7+
loader::{PluginLoadFuture, PluginUnloadFuture},
8+
};
69

710
use super::{LoaderError, Path, Plugin, PluginLoader, PluginMetadata};
811

@@ -16,6 +19,21 @@ impl PluginLoader for NativePluginLoader {
1619
let library = unsafe { Library::new(&path) }
1720
.map_err(|e| LoaderError::LibraryLoad(e.to_string()))?;
1821

22+
// Ensure this plugin was built against a compatible Pumpkin plugin API version
23+
let plugin_api_version = unsafe {
24+
match library.get::<*const u32>(b"PUMPKIN_API_VERSION") {
25+
Ok(symbol) => **symbol,
26+
Err(_) => return Err(LoaderError::ApiVersionMissing),
27+
}
28+
};
29+
30+
if plugin_api_version != PLUGIN_API_VERSION {
31+
return Err(LoaderError::ApiVersionMismatch {
32+
plugin_version: plugin_api_version,
33+
server_version: PLUGIN_API_VERSION,
34+
});
35+
}
36+
1937
// 2. Extract Metadata (METADATA)
2038
let metadata = unsafe {
2139
&**library

pumpkin/src/plugin/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ pub use api::*;
1818

1919
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
2020

21+
/// Bump this whenever the public plugin API or any event layout changes in a way
22+
/// that makes old binary plugins incompatible.
23+
pub const PLUGIN_API_VERSION: u32 = 2;
24+
2125
/// A trait for handling events dynamically.
2226
///
2327
/// This trait allows for handling events of any type that implements the `Event` trait.

0 commit comments

Comments
 (0)