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
//! The module contains an inplementation of the `Supervisor`.

mod app;
mod engine;
mod forwarder;
mod root;
mod server;

use anyhow::Error;
use async_trait::async_trait;
use derive_more::{Deref, DerefMut, From, Into};
use meio::all::{Actor, Address, Context, InterruptedBy, StartedBy};
use meio::system::{Standalone, System};
use meio_connect::server::HttpServerLink;
use way_basis::RootLayout;

/// The link to control the `Way` actor.
///
/// This link produced automatically when the [`Way`] actor is
/// spawned in the `System`, but it also can be produced from
/// any `Address` of the [`Way`] actor.
#[derive(Debug, From, Into, Deref, DerefMut)]
pub struct WayLink {
    address: Address<Way>,
}

/// The main actor. Spawn it to launch the web UI.
///
/// This actor starts the server and routing. To control it
/// use [`WayLink`] that returned when the actor spawned in the `System`.
pub struct Way {
    log_target: String,
    server: Option<HttpServerLink>,
    root: Option<RootLayout>,
}

impl Way {
    /// Creates a new instance of a supervisor with the RillRate Engine.
    pub fn new() -> Self {
        Self {
            log_target: "RillRate".into(),
            server: None,
            root: None,
        }
    }
}

impl Standalone for Way {
    type Link = WayLink;
}

impl Actor for Way {
    type GroupBy = Group;

    fn log_target(&self) -> &str {
        &self.log_target
    }
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Group {
    Engine,
    Assets,
    Forwarder,
    AppServer,
}

#[async_trait]
impl StartedBy<System> for Way {
    async fn handle(&mut self, ctx: &mut Context<Self>) -> Result<(), Error> {
        let app_addr = crate::extras::get_addr("RR_ADDR", "127.0.0.1:6361")?;
        let app_server = self.spawn_server(app_addr, Group::AppServer, ctx);
        self.spawn_engine(app_server.clone(), ctx).await?;
        // TODO: User has to do it manually.
        self.install_root()?;
        self.spawn_forwarder(app_server.clone(), ctx)?;
        self.server = Some(app_server);
        Ok(())
    }
}

#[async_trait]
impl InterruptedBy<System> for Way {
    async fn handle(&mut self, ctx: &mut Context<Self>) -> Result<(), Error> {
        self.root.take();
        self.server.take();
        ctx.shutdown();
        Ok(())
    }
}