unicom/real/
manager.rs

1use super::{Backend, BoxedBackend, BoxedConnector};
2use crate::{Error, Result, ToUrl};
3use log::{error, info};
4use std::sync::{Arc, RwLock};
5
6/// The list of backends
7type Backends = Arc<RwLock<Vec<BoxedBackend>>>;
8
9/// Backends manager
10///
11/// Manager holds registered backends and helps create client instances.
12#[derive(Clone)]
13pub struct Manager {
14    backends: Backends,
15}
16
17impl Default for Manager {
18    /// Create new backends manager
19    fn default() -> Self {
20        Self {
21            backends: Arc::new(RwLock::new(Vec::default())),
22        }
23    }
24}
25
26impl Manager {
27    /// Register backend
28    pub fn register(&self, backend: impl Backend + 'static) -> Result<()> {
29        self.with_mut(|backends| {
30            let name = backend.name();
31            if backends.iter().any(|backend| backend.name() == name) {
32                error!("Attempt to register backend \"{}\" twice", name);
33                return Err(Error::AlreadyRegistered(name.into()));
34            }
35            info!("Registering backend \"{}\"", name);
36            backends.push(Box::new(backend));
37            Ok(())
38        })
39    }
40
41    /// Create the backend using URL by probing registered backend types
42    pub fn create(&self, url: impl ToUrl) -> Result<BoxedConnector> {
43        let url = url.to_url()?;
44        self.with(|backends| {
45            backends
46                .iter()
47                .filter_map(|backend| backend.connector(&url))
48                .next()
49                .ok_or_else(|| {
50                    error!("No backends which can handle URL {}", url);
51                    url.into()
52                })
53        })
54    }
55
56    fn with_raw<R>(&self, func: impl FnOnce(Backends) -> R) -> R {
57        func(self.backends.clone())
58    }
59
60    fn with<R>(&self, func: impl FnOnce(&[BoxedBackend]) -> R) -> R {
61        self.with_raw(|backends: Backends| {
62            let backends = backends.read().unwrap();
63            func(&backends)
64        })
65    }
66
67    fn with_mut<R>(&self, func: impl FnOnce(&mut Vec<BoxedBackend>) -> R) -> R {
68        self.with_raw(|backends: Backends| {
69            let mut backends = backends.write().unwrap();
70            func(&mut backends)
71        })
72    }
73}