-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathtide_server.rs
89 lines (72 loc) · 2.85 KB
/
tide_server.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
78
79
80
81
82
83
84
85
86
87
88
89
use sai::{Component, Injected, async_trait};
use futures::prelude::*;
use futures::channel::oneshot::{Sender, Receiver};
use super::foo_controller::FooController;
#[derive(Debug)]
enum ServerCommand {
Stop,
Stopped // Technically this is a event, but I am lazy
}
#[derive(Component)]
#[lifecycle]
pub struct TideServer {
#[injected]
foo_controller: Injected<FooController>,
stop_command_sender: Option<Sender<ServerCommand>>,
stop_ack_receiver: Option<Receiver<ServerCommand>>
}
#[async_trait]
impl sai::ComponentLifecycle for TideServer {
async fn start (&mut self) {
println!("Starting TideServer...");
let ( sender, receiver ) = futures::channel::oneshot::channel::<ServerCommand>();
let ( ack_sender, ack_receiver ) = futures::channel::oneshot::channel::<ServerCommand>();
self.stop_command_sender = Some(sender);
self.stop_ack_receiver = Some(ack_receiver);
#[derive(Clone)]
struct State {
foo_controller: Injected<FooController>
};
let state = State {
foo_controller: self.foo_controller.clone()
};
// Ensure the server runs in the background
tokio::spawn(async {
let server_handle_fut = async {
// Receiver's ownership is transfered here
receiver.await.unwrap();
};
let mut app = tide::with_state(state);
app.at("/").get(|_| async { Ok("Hello, world!") });
app.at("/foo").get(|req: tide::Request<State>| async move {
let f = &req.state().foo_controller;
return f.index();
});
let server_fut = app.listen("0.0.0.0:9003");
/*
* When shutting down server_handle_fut will return first because it's
* activated by stop_command_sender
*
* Then this `select` will drop the `server` and make it shutting down gracefully
*/
future::select(
server_fut.boxed(),
server_handle_fut.boxed()
).await;
println!("TideServer gracefully shutted down...");
// Technically, the server hasn't being shutted down 100%
// Because it's up to runtime to drop those spawned tasks
// Acknowledge that the server has shutted down
ack_sender.send(ServerCommand::Stopped).unwrap();
});
}
async fn stop (&mut self) {
println!("Shutting down TideServer...");
// It's important to `take` here
let sender = self.stop_command_sender.take().unwrap();
sender.send(ServerCommand::Stop).unwrap();
// Ensure this future returns only when the server has gracefully shutted down
let ack_receiver = self.stop_ack_receiver.take().unwrap();
ack_receiver.await.unwrap();
}
}