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,
18 pub path: String,
20 pub method: Method,
22 pub headers: HeaderMap,
24}
25
26#[async_trait]
28pub trait Plugin: Send + Sync {
29 fn id(&self) -> &'static str;
31
32 async fn init(&self, _prepared: &mut PreparedRequest) -> Result<()> {
34 Ok(())
35 }
36
37 fn hooks(&self) -> Hooks {
39 Hooks::default()
40 }
41}
42
43#[derive(Default)]
45pub struct PluginRegistry {
46 plugins: Vec<Box<dyn Plugin>>,
47}
48
49impl PluginRegistry {
50 pub fn new() -> Self {
52 Self::default()
53 }
54
55 pub fn register<P: Plugin + 'static>(mut self, plugin: P) -> Self {
57 self.plugins.push(Box::new(plugin));
58 self
59 }
60
61 pub fn push(&mut self, plugin: Box<dyn Plugin>) {
63 self.plugins.push(plugin);
64 }
65
66 pub fn plugins(&self) -> &[Box<dyn Plugin>] {
68 &self.plugins
69 }
70
71 pub(crate) async fn run_init_all(&self, prepared: &mut PreparedRequest) -> Result<()> {
72 for plugin in &self.plugins {
73 plugin.init(prepared).await?;
74 }
75 Ok(())
76 }
77
78 pub(crate) fn merged_hooks(&self) -> Hooks {
79 let mut hooks = Hooks::default();
80 for plugin in &self.plugins {
81 hooks = hooks.merge(plugin.hooks());
82 }
83 hooks
84 }
85}