Skip to main content

astro_runner/
plugin.rs

1use astro_run::{Context, HookNoopResult, Result};
2use std::sync::Arc;
3
4#[astro_run::async_trait]
5pub trait Plugin: Send + Sync {
6  fn name(&self) -> &'static str;
7  async fn on_before_run(&self, ctx: Context) -> Result<Context> {
8    Ok(ctx)
9  }
10  async fn on_after_run(&self, _ctx: Context) -> HookNoopResult {
11    Ok(())
12  }
13}
14
15pub type SharedPluginDriver = Arc<PluginDriver>;
16
17pub struct PluginDriver {
18  pub(crate) plugins: Vec<Box<dyn Plugin>>,
19}
20
21impl PluginDriver {
22  pub fn new(plugins: Vec<Box<dyn Plugin>>) -> Self {
23    PluginDriver { plugins }
24  }
25
26  pub async fn on_before_run(&self, ctx: Context) -> Context
27  where
28    Self: Send + Sync,
29  {
30    let mut ctx = ctx;
31
32    for plugin in &self.plugins {
33      if let Ok(updated_ctx) = plugin.on_before_run(ctx.clone()).await {
34        ctx = updated_ctx;
35      } else {
36        log::error!("Plugin {} on_before_run error", plugin.name());
37      }
38    }
39
40    ctx
41  }
42
43  pub async fn on_after_run(&self, ctx: Context) {
44    for plugin in &self.plugins {
45      if let Err(err) = plugin.on_after_run(ctx.clone()).await {
46        log::error!("Plugin {} on_after_run error: {}", plugin.name(), err);
47      }
48    }
49  }
50}
51
52#[cfg(test)]
53mod tests {
54  use astro_run::StepId;
55
56  use super::*;
57
58  #[astro_run_test::test]
59  async fn test_plugin_driver() {
60    struct TestPlugin;
61
62    #[astro_run::async_trait]
63    impl Plugin for TestPlugin {
64      fn name(&self) -> &'static str {
65        "test"
66      }
67
68      async fn on_before_run(&self, ctx: Context) -> Result<Context> {
69        let mut ctx = ctx;
70
71        ctx.id = StepId::try_from("abc/1/1").unwrap();
72
73        Ok(ctx)
74      }
75
76      async fn on_after_run(&self, _ctx: Context) -> HookNoopResult {
77        Ok(())
78      }
79    }
80
81    struct ErrorBeforeRunPlugin;
82
83    #[astro_run::async_trait]
84    impl Plugin for ErrorBeforeRunPlugin {
85      fn name(&self) -> &'static str {
86        "error-before-run"
87      }
88
89      async fn on_before_run(&self, _ctx: Context) -> Result<Context> {
90        Err(astro_run::Error::error("Error"))
91      }
92    }
93
94    struct ErrorAfterRunPlugin;
95
96    #[astro_run::async_trait]
97    impl Plugin for ErrorAfterRunPlugin {
98      fn name(&self) -> &'static str {
99        "error-before-run"
100      }
101
102      async fn on_after_run(&self, _ctx: Context) -> HookNoopResult {
103        Err(astro_run::Error::error("Error"))
104      }
105    }
106
107    let driver = PluginDriver::new(vec![
108      Box::new(TestPlugin),
109      Box::new(ErrorBeforeRunPlugin),
110      Box::new(ErrorAfterRunPlugin),
111    ]);
112
113    let ctx = astro_run::Context {
114      id: StepId::try_from("aaa/1/1").unwrap(),
115      command: Default::default(),
116      event: None,
117      signal: astro_run::AstroRunSignal::new(),
118      payload: None,
119    };
120
121    let ctx = driver.on_before_run(ctx).await;
122
123    assert_eq!(ctx.id, StepId::try_from("abc/1/1").unwrap());
124
125    driver.on_after_run(ctx).await;
126  }
127}