Skip to content

Commit

Permalink
feat(core): redesign the nurse command
Browse files Browse the repository at this point in the history
This commit introduce a basic architecture to run the nurse command
by using two design pattern, that are the chain of responsability
for choosing what kind of strategy apply, and a strategy pattern
to abstract the algorithm under a basic view.

Signed-off-by: Vincenzo Palazzo <[email protected]>

feat(core): add nurse chain of responsability to select the recovery algorithm

Signed-off-by: Vincenzo Palazzo <[email protected]>
  • Loading branch information
vincenzopalazzo committed Jul 29, 2023
1 parent 5224e63 commit bad8427
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 1 deletion.
6 changes: 5 additions & 1 deletion coffee_core/src/coffee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use coffee_storage::storage::StorageManager;

use super::config;
use crate::config::CoffeeConf;
use crate::nurse::chain::RecoveryChainOfResponsibility;
use crate::CoffeeArgs;

pub type RepoName = String;
Expand Down Expand Up @@ -70,6 +71,8 @@ pub struct CoffeeManager {
storage: NoSQlStorage,
/// core lightning rpc connection
rpc: Option<Client>,
/// Recovery Strategies for the nurse command.
recovety_strategies: RecoveryChainOfResponsibility,
}

impl CoffeeManager {
Expand All @@ -82,6 +85,7 @@ impl CoffeeManager {
storage: NoSQlStorage::new(&conf.root_path).await?,
cln_config: None,
rpc: None,
recovety_strategies: RecoveryChainOfResponsibility::new().await?,
};
coffee.inventory().await?;
Ok(coffee)
Expand Down Expand Up @@ -380,7 +384,7 @@ impl PluginManager for CoffeeManager {
}

async fn nurse(&mut self) -> Result<(), CoffeeError> {
unimplemented!("nurse command is not implemented")
self.recovety_strategies.scan().await
}
}

Expand Down
2 changes: 2 additions & 0 deletions coffee_core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
pub mod coffee;
pub mod config;

mod nurse;

pub use coffee_lib as lib;

#[derive(Clone, Debug)]
Expand Down
2 changes: 2 additions & 0 deletions coffee_core/src/nurse.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod chain;
pub mod strategy;
63 changes: 63 additions & 0 deletions coffee_core/src/nurse/chain.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//! Nurse Chain of Responsibility rust implementation
//!
//! If you do not know what Chain Of Responsibility patter
//! 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 strategy 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 super::strategy::RecoveryStrategy;

#[async_trait]
pub trait Handler: Send + Sync {
async fn can_be_apply(
self: Arc<Self>,
) -> Result<Option<Arc<dyn RecoveryStrategy>>, CoffeeError>;
}

pub struct RecoveryChainOfResponsibility {
pub handlers: Vec<Arc<dyn Handler>>,
}

impl RecoveryChainOfResponsibility {
pub async fn new() -> Result<Self, CoffeeError> {
Ok(Self {
handlers: Vec::new(),
})
}

pub async fn scan(&self) -> Result<(), CoffeeError> {
for handler in self.handlers.iter() {
if let Some(strategy) = handler.clone().can_be_apply().await? {
strategy.patch().await?;
}
}
Ok(())
}
}
53 changes: 53 additions & 0 deletions coffee_core/src/nurse/strategy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//! Nurse Strategy patter implementation for recovery methods.
//!
//! If you do not know what Strategy patter is here is a small
//! description.
//!
//! >The basic idea behind the Strategy pattern is that, given an
//! > algorithm solving a particular problem, we define only
//! > the skeleton of the algorithm at an abstract level, and we
//! > separate the specific algorithm’s implementation into
//! > different parts.
//! >
//! > In this way, a client using the algorithm may choose
//! > a specific implementation, while the general algorithm
//! > workflow remains the same. In other words, the abstract
//! > specification of the class does not depend on the specific
//! > implementation of the derived class, but specific implementation
//! > must adhere to the abstract specification.
//!
//! So in this specific case the nurse command may need
//! different kind of recovery algorithm, so we should
//! be able to choose the algorithm at runtime.
//!
//! Author: Vincenzo Palazzo <[email protected]>
use std::sync::Arc;

use async_trait::async_trait;

use coffee_lib::errors::CoffeeError;

use crate::nurse::chain::Handler;

#[async_trait]
pub trait RecoveryStrategy: Send + Sync {
async fn patch(&self) -> Result<(), CoffeeError>;
}

pub struct GitRepositoryMissedStrategy;

#[async_trait]
impl RecoveryStrategy for GitRepositoryMissedStrategy {
async fn patch(&self) -> Result<(), CoffeeError> {
unimplemented!()
}
}

#[async_trait]
impl Handler for GitRepositoryMissedStrategy {
async fn can_be_apply(
self: Arc<Self>,
) -> Result<Option<std::sync::Arc<dyn RecoveryStrategy>>, CoffeeError> {
Ok(Some(self))
}
}

0 comments on commit bad8427

Please sign in to comment.