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
// Copyright 2020-2021 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

//! A module that deals with asynchronous workers in general.

use std::any::{Any, TypeId};

use async_trait::async_trait;

use crate::node::Node;

/// Errors that might occur during the lifetime of asynchronous workers.
#[derive(Debug)]
pub struct Error(pub Box<dyn std::error::Error + Send>);

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "worker error: {:?}.", self.0)
    }
}

impl std::error::Error for Error {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        self.0.source()
    }
}

/// A trait representing a node worker.
///
/// Node workers are conceptually similar to actors in the actor programming model, but differ slightly in a number of
/// crucial ways.
///
/// - Workers may register and access shared state, known as 'resources'.
/// - Workers have a topological ordering that determine when they should be started and stopped.
#[async_trait]
pub trait Worker<N: Node>: Any + Send + Sync + Sized {
    /// The configuration state required to start this worker.
    type Config;
    /// An error that may be emitted during node startup and shutdown.
    type Error: std::error::Error;

    /// Generate a list of `TypeId`s representing the topological worker dependencies of this worker.
    ///
    /// Workers listed will be started before this worker and shut down after this worker.
    // TODO Replace with associated constant when stabilized.
    fn dependencies() -> &'static [TypeId] {
        &[]
    }

    /// Attempt to instantiate this worker with the given node and worker configuration.
    async fn start(node: &mut N, config: Self::Config) -> Result<Self, Self::Error>;

    /// Attempt to stop an instance of this worker.
    async fn stop(self, _node: &mut N) -> Result<(), Self::Error> {
        Ok(())
    }
}