1use async_trait::async_trait;
2use std::sync::Arc;
3
4use crate::error::StateResult;
5use crate::plugin::{PluginConfig, PluginMetadata};
6use crate::resource::Resource;
7
8use crate::state::{State, StateConfig};
9use crate::transaction::Transaction;
10
11#[async_trait]
14pub trait PluginTrait: Send + Sync + Debug {
15 fn metadata(&self) -> PluginMetadata;
17
18 fn config(&self) -> PluginConfig {
20 PluginConfig {
21 enabled: true,
22 priority: 0,
23 settings: std::collections::HashMap::new(),
24 }
25 }
26
27 async fn append_transaction(
30 &self,
31 _: &[Arc<Transaction>],
32 _: &Arc<State>,
33 _: &Arc<State>,
34 ) -> StateResult<Option<Transaction>> {
35 Ok(None)
36 }
37 async fn filter_transaction(
40 &self,
41 _: &Transaction,
42 _: &State,
43 ) -> bool {
44 true
45 }
46}
47#[async_trait]
84pub trait StateField: Send + Sync + Debug {
85 type Value: Resource;
87
88 async fn init(
90 &self,
91 config: &StateConfig,
92 instance: &State,
93 ) -> Arc<Self::Value>;
94
95 async fn apply(
98 &self,
99 tr: &Transaction,
100 value: Arc<Self::Value>,
101 old_state: &State,
102 new_state: &State,
103 ) -> Arc<Self::Value>;
104
105 fn serialize(
107 &self,
108 _value: &Arc<Self::Value>,
109 ) -> Option<Vec<u8>> {
110 None
111 }
112
113 fn deserialize(
115 &self,
116 _data: &[u8],
117 ) -> Option<Arc<Self::Value>> {
118 None
119 }
120}
121
122#[async_trait]
125pub trait ErasedStateField: Send + Sync + Debug {
126 async fn init_erased(
128 &self,
129 config: &StateConfig,
130 instance: &State,
131 ) -> Arc<dyn Resource>;
132
133 async fn apply_erased(
135 &self,
136 tr: &Transaction,
137 value: Arc<dyn Resource>,
138 old_state: &State,
139 new_state: &State,
140 ) -> Arc<dyn Resource>;
141
142 fn serialize_erased(
144 &self,
145 value: Arc<dyn Resource>,
146 ) -> Option<Vec<u8>>;
147
148 fn deserialize_erased(
150 &self,
151 data: &[u8],
152 ) -> Option<Arc<dyn Resource>>;
153}
154
155#[async_trait]
157impl<T: StateField + 'static> ErasedStateField for T {
158 #[cfg_attr(feature = "dev-tracing", tracing::instrument(skip(self, config, instance), fields(
159 crate_name = "state",
160 state_field_type = std::any::type_name::<T>(),
161 value_type = std::any::type_name::<T::Value>()
162 )))]
163 async fn init_erased(
164 &self,
165 config: &StateConfig,
166 instance: &State,
167 ) -> Arc<dyn Resource> {
168 let value = self.init(config, instance).await;
169 value as Arc<dyn Resource>
170 }
171
172 #[cfg_attr(feature = "dev-tracing", tracing::instrument(skip(self, tr, value, old_state, new_state), fields(
173 crate_name = "state",
174 state_field_type = std::any::type_name::<T>(),
175 value_type = std::any::type_name::<T::Value>(),
176 tr_id = %tr.id
177 )))]
178 async fn apply_erased(
179 &self,
180 tr: &Transaction,
181 value: Arc<dyn Resource>,
182 old_state: &State,
183 new_state: &State,
184 ) -> Arc<dyn Resource> {
185 if let Some(typed_value) = value.downcast_arc::<T::Value>() {
187 let new_value =
188 self.apply(tr, typed_value.clone(), old_state, new_state).await;
189 new_value as Arc<dyn Resource>
190 } else {
191 tracing::warn!(
193 "StateField 类型不匹配,期望 {},跳过应用",
194 std::any::type_name::<T::Value>()
195 );
196 value
197 }
198 }
199
200 #[cfg_attr(feature = "dev-tracing", tracing::instrument(skip(self, value), fields(
201 crate_name = "state",
202 state_field_type = std::any::type_name::<T>(),
203 value_type = std::any::type_name::<T::Value>()
204 )))]
205 fn serialize_erased(
206 &self,
207 value: Arc<dyn Resource>,
208 ) -> Option<Vec<u8>> {
209 if let Some(typed_value) = value.downcast_arc::<T::Value>() {
210 let result = self.serialize(typed_value);
211 #[cfg(feature = "dev-tracing")]
212 if let Some(ref data) = result {
213 tracing::debug!(serialized_size = data.len(), "序列化成功");
214 }
215 result
216 } else {
217 None
218 }
219 }
220
221 #[cfg_attr(feature = "dev-tracing", tracing::instrument(skip(self, data), fields(
222 crate_name = "state",
223 state_field_type = std::any::type_name::<T>(),
224 value_type = std::any::type_name::<T::Value>(),
225 data_size = data.len()
226 )))]
227 fn deserialize_erased(
228 &self,
229 data: &[u8],
230 ) -> Option<Arc<dyn Resource>> {
231 let result = self.deserialize(data).map(|v| v as Arc<dyn Resource>);
232 #[cfg(feature = "dev-tracing")]
233 if result.is_some() {
234 tracing::debug!("反序列化成功");
235 }
236 result
237 }
238}
239
240#[derive(Clone, Debug)]
243pub struct PluginSpec {
244 pub state_field: Option<Arc<dyn ErasedStateField>>,
245 pub tr: Arc<dyn PluginTrait>,
246}
247
248impl PluginSpec {
251 #[cfg_attr(feature = "dev-tracing", tracing::instrument(skip(self, tr, state), fields(
253 crate_name = "state",
254 plugin_name = %self.tr.metadata().name,
255 tr_id = %tr.id
256 )))]
257 async fn filter_transaction(
258 &self,
259 tr: &Transaction,
260 state: &State,
261 ) -> bool {
262 let filter = &self.tr;
263 let result = filter.filter_transaction(tr, state).await;
264 #[cfg(feature = "dev-tracing")]
265 tracing::debug!(allowed = result, "过滤结果");
266 result
267 }
268 #[cfg_attr(feature = "dev-tracing", tracing::instrument(skip(self, trs, old_state, new_state), fields(
270 crate_name = "state",
271 plugin_name = %self.tr.metadata().name,
272 tr_count = trs.len()
273 )))]
274 async fn append_transaction(
275 &self,
276 trs: &[Arc<Transaction>],
277 old_state: &Arc<State>,
278 new_state: &Arc<State>,
279 ) -> StateResult<Option<Transaction>> {
280 let tr = self.tr.append_transaction(trs, old_state, new_state).await?;
281 if let Some(mut tr) = tr {
282 let _ = tr.commit(); #[cfg(feature = "dev-tracing")]
284 tracing::debug!(step_count = tr.steps.len(), "追加事务成功");
285 Ok(Some(tr))
286 } else {
287 #[cfg(feature = "dev-tracing")]
288 tracing::debug!("无需追加事务");
289 Ok(None)
290 }
291 }
292}
293#[derive(Clone, Debug)]
296pub struct Plugin {
297 pub spec: PluginSpec,
298 pub key: String,
299}
300
301impl Plugin {
304 pub fn new(spec: PluginSpec) -> Self {
306 let key = spec.tr.metadata().name.clone();
307
308 Plugin { spec, key }
309 }
310 pub fn get_name(&self) -> &str {
312 &self.key
313 }
314 pub fn get_metadata(&self) -> PluginMetadata {
316 self.spec.tr.metadata()
317 }
318 pub fn get_config(&self) -> PluginConfig {
320 self.spec.tr.config()
321 }
322
323 pub fn get_state(
325 &self,
326 state: &State,
327 ) -> Option<Arc<dyn Resource>> {
328 state.get_field(&self.key)
329 }
330 #[cfg_attr(feature = "dev-tracing", tracing::instrument(skip(self, tr, state), fields(
332 crate_name = "state",
333 plugin_key = %self.key,
334 tr_id = %tr.id
335 )))]
336 pub async fn apply_filter_transaction(
337 &self,
338 tr: &Transaction,
339 state: &State,
340 ) -> bool {
341 self.spec.filter_transaction(tr, state).await
342 }
343
344 #[cfg_attr(feature = "dev-tracing", tracing::instrument(skip(self, trs, old_state, new_state), fields(
346 crate_name = "state",
347 plugin_key = %self.key,
348 tr_count = trs.len()
349 )))]
350 pub async fn apply_append_transaction(
351 &self,
352 trs: &[Arc<Transaction>],
353 old_state: &Arc<State>,
354 new_state: &Arc<State>,
355 ) -> StateResult<Option<Transaction>> {
356 self.spec.append_transaction(trs, old_state, new_state).await
357 }
358}
359
360use std::fmt::Debug;