-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathchain.rs
77 lines (70 loc) · 2.62 KB
/
chain.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
//! Nurse Chain of Responsibility rust implementation
//!
//! If you do not know what Chain Of Responsibility pattern
//! is, here is a small description:
//!
//! > Chain of Responsibility is behavioral design pattern
//! > that allows passing request along the chain of potential
//! > handlers until one of them handles request.
//! >
//! > The pattern allows multiple objects to handle the
//! > request without coupling sender class to the concrete
//! > classes of the receivers. The chain can be composed
//! > dynamically at runtime with any handler that follows
//! > a standard handler interface.
//!
//! In our case we do not need to handle a request, but we should
//! handler through the various recovery strategies to see what can
//! be applied.
//!
//! So in our case the handler is a specific recovery strategy
//! that tell the chain of responsibility if can be applied or not.
//!
//! If can be applied, the chain of responsibility will apply it.
//!
//! P.S: I do not know if my Advanced System programming teacher will be
//! proud of me for the following design, or simply mad with me!
//!
//! Author: Vincenzo Palazzo <[email protected]>
use std::sync::Arc;
use async_trait::async_trait;
use coffee_lib::errors::CoffeeError;
use coffee_lib::types::response::{ChainOfResponsibilityStatus, Defect};
use super::strategy::{CoffeeRepositoryDirCleanUpStrategy, GitRepositoryLocallyAbsentStrategy};
use crate::coffee::CoffeeManager;
#[async_trait]
pub trait Handler: Send + Sync {
async fn can_be_applied(
self: Arc<Self>,
coffee: &CoffeeManager,
) -> Result<Option<Defect>, CoffeeError>;
}
pub struct RecoveryChainOfResponsibility {
pub handlers: Vec<Arc<dyn Handler>>,
}
impl RecoveryChainOfResponsibility {
/// Create a new instance of the chain of responsibility
pub async fn new() -> Result<Self, CoffeeError> {
Ok(Self {
handlers: vec![
Arc::new(CoffeeRepositoryDirCleanUpStrategy),
Arc::new(GitRepositoryLocallyAbsentStrategy),
],
})
}
/// Scan the chain of responsibility to see what can be applied
/// and return the status of the chain of responsibility
/// with the list of defects
pub async fn scan(
&self,
coffee: &CoffeeManager,
) -> Result<ChainOfResponsibilityStatus, CoffeeError> {
let mut defects: Vec<Defect> = vec![];
for handler in self.handlers.iter() {
if let Some(defect) = handler.clone().can_be_applied(coffee).await? {
defects.push(defect);
}
}
Ok(ChainOfResponsibilityStatus { defects })
}
}