1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
use std::collections::HashMap;
use std::fmt;
use std::sync::Arc;
use crate::errors::Error;
/// Represents the rustc compiler version and the plugin interface version.
/// When a plugin is loaded, the `VersionInfo` of the server is
/// cross-referenced against the `VersionInfo` exported by the plugin. If they
/// don't match, the plugin fails.
///
/// The rustc version must match exactly because rust doesn't expose a stable
/// ABI, and there is a risk of it changing in any version. The plugin
/// interface version is also exposed to allow for changes to the interface in
/// the future. If the interface is changed, this value should be incremented.
#[derive(Debug, Eq, PartialEq)]
pub struct VersionInfo {
/// The version of rustc used to compile. This must match because rust
/// doesn't expose a stable ABI, and there is a risk of it changing in any
/// version.
pub rustc: String,
/// The plugin interface version is also exposed to allow for changes to
/// the interface in the future.
pub plugin_interface: u8,
}
impl Default for VersionInfo {
fn default() -> Self {
Self {
rustc: env!("RUSTC_VERSION").to_string(),
// If the interface is changed, this value should be incremented.
plugin_interface: 0,
}
}
}
impl fmt::Display for VersionInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "rustc={}, plugin_interface={}", self.rustc, self.plugin_interface)
}
}
/// Plugins should implement this trait.
pub trait Plugin: Send + Sync + 'static {
/// Executes the plugin. Returns JSON that will be sent back to the
/// calling client.
///
/// # Arguments
/// * `datastore`: The datastore.
/// * `arg`: The argument from the calling client.
fn call(
&self,
datastore: Arc<dyn indradb::Datastore + Send + Sync + 'static>,
arg: serde_json::Value,
) -> Result<serde_json::Value, Error>;
}
/// A declaration of a plugin.
pub struct PluginDeclaration {
pub version_info: VersionInfo,
pub entries: HashMap<String, Box<dyn Plugin>>,
}
/// Libraries use this macro to register their plugins.
#[macro_export]
macro_rules! register_plugins {
( $indradb_interface_version:expr, $( $name:expr, $t:expr ),* ) => {
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn register() -> $crate::PluginDeclaration {
use std::collections::HashMap;
let mut entries = HashMap::new();
$(
{
let t: Box<dyn $crate::Plugin> = $t;
entries.insert($name.to_string(), t);
}
)*
$crate::PluginDeclaration {
version_info: $crate::VersionInfo::default(),
entries,
}
}
};
}