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
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! Where you have services, you need managers

use crate::service::Service;
use crate::utils;

/// Manages an internal collection of Services
///
/// This implements a simple [Composite Pattern](https://en.wikipedia.org/wiki/Composite_pattern)
/// that allows to manages a group of Service in a coordinated fashion.
///
/// Services are `start()`ed in the order they are registered, and `stop()`ped in the reverse
/// order. Also, a `ServiceManager` is also a `Service`, so further composition is possible.
///
/// The design implies that in your application, you would hand over all the instances of `Service`
/// to a `ServiceManager`, that will then orchestrate their starting and stopping.
///
/// Thanks to the use of Composite Pattern, it can contain further instances of `ServiceManager`,
/// allowing for the creation of complex
/// [DAG diagrams](https://en.wikipedia.org/wiki/Directed_acyclic_graph) of services,
/// with expressive relationship between them.
pub struct ServiceManager {
  services: Vec<Box<Service>>
}

impl ServiceManager {

  /// Constructor
  pub fn new() -> Self {
    ServiceManager {
      services: Vec::new(),
    }
  }

  /// Register an instance of `Service`.
  ///
  /// The order of registration is important: `Service`s are started in order, and stopped
  /// in reverse order.
  ///
  /// # Parameters
  ///
  /// * `service_box`: a `Box` containing an instance of implementation of the `Service` trait
  pub fn register(&mut self, service_box: Box<Service>) {
    self.services.push(service_box);
  }

  /// Wait for the Process to receive a termination signal, then stop this `ServiceManager`.
  ///
  /// It's strongly advised to use this method only onces, for the _root_ `ServiceManager`,
  /// at the end of the `main()` thread.
  pub fn wait_termination_signal_then_stop(&mut self) {
    // Block until the process is terminated by a signal...
    utils::wait_for_process_termination_signal();

    // ... then gracefully shut every service down
    self.stop_and_await();
  }

  /// Apply the same closure to all contained `Service`s, in order
  fn apply_ordered<F>(&mut self, closure: F) where F: Fn(&mut Box<Service>) -> () {
    self.services
      .iter_mut()
      .for_each(closure);
  }

  /// Apply the same closure to all contained `Service`s, in reverse order
  fn apply_reversed<F>(&mut self, closure: F) where F: FnMut(&mut Box<Service>) -> () {
    self.services
      .iter_mut()
      .rev()
      .for_each(closure);
  }

}

impl Service for ServiceManager {

  /// Start all registered `Service`s, in order of registration
  fn start(&mut self) {
    self.apply_ordered(|s: &mut Box<Service>| s.start());
  }

  /// Wait for all registered `Service`s to be started, in order of registration
  fn await_started(&mut self) {
    self.apply_ordered(|s: &mut Box<Service>| s.await_started());
  }

  /// Start and then wait for all registered `Service`, in order of registration
  ///
  /// This is different then calling `start()` and then `await_started()`, because this method
  /// will wait for a `Service` to be started, before moving to the next one.
  ///
  /// This can be used to implement a _gracefull start_.
  fn start_and_await(&mut self) {
    self.apply_ordered(|s: &mut Box<Service>| s.start_and_await());
  }


  /// Stop all registered `Service`s, in reverse order of registration
  fn stop(&mut self) {
    self.apply_reversed(|s: &mut Box<Service>| s.stop());
  }

  /// Wait for all registered `Service`s to be stopped, in reverse order of registration
  fn await_stopped(&mut self) {
    self.apply_reversed(|s: &mut Box<Service>| s.await_stopped());
  }

  /// Stop and then wait for all registered `Service`, in reverse order of registration
  ///
  /// This is different then calling `stop()` and then `await_stopped()`, because this method
  /// will wait for a `Service` to be stopped, before moving to the next one.
  ///
  /// This can be used to implement a _gracefull stop_.
  fn stop_and_await(&mut self) {
    self.apply_reversed(|s: &mut Box<Service>| s.stop_and_await());
  }

}