use async_trait::async_trait;
use std::sync::Arc;
use crate::error::StateResult;
use crate::resource::Resource;
use super::state::{State, StateConfig};
use super::transaction::Transaction;
#[async_trait]
pub trait PluginTrait: Send + Sync + Debug {
async fn append_transaction(
&self,
_: &[Transaction],
_: &State,
_: &State,
) -> StateResult<Option<Transaction>> {
Ok(None)
}
async fn filter_transaction(
&self,
_: &Transaction,
_: &State,
) -> bool {
true
}
}
#[async_trait]
pub trait StateField: Send + Sync + Debug {
async fn init(
&self,
config: &StateConfig,
instance: &State,
) -> Arc<dyn Resource>;
async fn apply(
&self,
tr: &Transaction,
value: Arc<dyn Resource>,
old_state: &State,
new_state: &State,
) -> Arc<dyn Resource>;
fn serialize(
&self,
_value: Arc<dyn Resource>,
) -> Option<Vec<u8>> {
None
}
fn deserialize(
&self,
_value: &Vec<u8>,
) -> Option<Arc<dyn Resource>> {
None
}
}
#[derive(Clone, Debug)]
pub struct PluginSpec {
pub state_field: Option<Arc<dyn StateField>>,
pub key: PluginKey,
pub tr: Option<Arc<dyn PluginTrait>>,
pub priority: i32,
}
unsafe impl Send for PluginSpec {}
unsafe impl Sync for PluginSpec {}
impl PluginSpec {
async fn filter_transaction(
&self,
tr: &Transaction,
state: &State,
) -> bool {
match &self.tr {
Some(filter) => filter.filter_transaction(tr, state).await,
None => true,
}
}
async fn append_transaction<'a>(
&self,
trs: &'a [Transaction],
old_state: &State,
new_state: &State,
) -> StateResult<Option<Transaction>> {
match &self.tr {
Some(transaction) => {
let tr = transaction
.append_transaction(trs, old_state, new_state)
.await?;
if let Some(mut tr) = tr {
tr.commit();
Ok(Some(tr))
} else {
Ok(None)
}
},
None => Ok(None),
}
}
}
#[derive(Clone, Debug)]
pub struct Plugin {
pub spec: PluginSpec,
pub key: String,
}
unsafe impl Send for Plugin {}
unsafe impl Sync for Plugin {}
impl Plugin {
pub fn new(spec: PluginSpec) -> Self {
let key = spec.key.0.clone();
Plugin { spec, key }
}
pub fn get_state(
&self,
state: &State,
) -> Option<Arc<dyn Resource>> {
state.get_field(&self.key)
}
pub async fn apply_filter_transaction(
&self,
tr: &Transaction,
state: &State,
) -> bool {
self.spec.filter_transaction(tr, state).await
}
pub async fn apply_append_transaction(
&self,
trs: &[Transaction],
old_state: &State,
new_state: &State,
) -> StateResult<Option<Transaction>> {
self.spec.append_transaction(trs, old_state, new_state).await
}
}
use std::fmt::Debug;
pub type PluginKey = (String, String);