1use async_trait::async_trait;
7use http::{HeaderMap, Method};
8use url::Url;
9
10use crate::hooks::Hooks;
11use crate::Result;
12
13#[derive(Debug, Clone)]
15pub struct PreparedRequest {
16 pub url: Url,
17 pub path: String,
18 pub method: Method,
19 pub headers: HeaderMap,
20}
21
22#[async_trait]
24pub trait Plugin: Send + Sync {
25 fn id(&self) -> &'static str;
26
27 async fn init(&self, _prepared: &mut PreparedRequest) -> Result<()> {
28 Ok(())
29 }
30
31 fn hooks(&self) -> Hooks {
32 Hooks::default()
33 }
34}
35
36#[derive(Default)]
38pub struct PluginRegistry {
39 plugins: Vec<Box<dyn Plugin>>,
40}
41
42impl PluginRegistry {
43 pub fn new() -> Self {
44 Self::default()
45 }
46
47 pub fn register<P: Plugin + 'static>(mut self, plugin: P) -> Self {
48 self.plugins.push(Box::new(plugin));
49 self
50 }
51
52 pub fn push(&mut self, plugin: Box<dyn Plugin>) {
53 self.plugins.push(plugin);
54 }
55
56 pub fn plugins(&self) -> &[Box<dyn Plugin>] {
57 &self.plugins
58 }
59
60 pub(crate) async fn run_init_all(&self, prepared: &mut PreparedRequest) -> Result<()> {
61 for plugin in &self.plugins {
62 plugin.init(prepared).await?;
63 }
64 Ok(())
65 }
66
67 pub(crate) fn merged_hooks(&self) -> Hooks {
68 let mut hooks = Hooks::default();
69 for plugin in &self.plugins {
70 hooks = hooks.merge(plugin.hooks());
71 }
72 hooks
73 }
74}