aboutsummaryrefslogtreecommitdiffstats
path: root/teleterm/src/web.rs
blob: 07ece1256d323067a61303cdfe07aa8304d1c0e2 (plain) (blame)
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
119
120
121
122
123
124
125
126
mod disk_session;
mod list;
mod login;
mod view;
mod watch;
mod ws;

use crate::prelude::*;

use gotham::router::builder::{DefineSingleRoute as _, DrawRoutes as _};
use gotham::state::FromState as _;

#[derive(Clone, serde::Serialize, gotham_derive::StateData)]
struct Config {
    title: String,
    server_address: (String, std::net::SocketAddr),
    public_address: String,
}

#[derive(Default, serde::Deserialize, serde::Serialize)]
struct SessionData {
    username: Option<String>,
}

pub struct Server {
    server: Box<dyn futures::Future<Item = (), Error = ()> + Send>,
}

impl Server {
    pub fn new(
        listen_address: std::net::SocketAddr,
        public_address: String,
        server_address: (String, std::net::SocketAddr),
    ) -> Self {
        let data = Config {
            title: "teleterm".to_string(),
            server_address,
            public_address,
        };
        Self {
            server: Box::new(gotham::init_server(
                listen_address,
                router(&data),
            )),
        }
    }
}

impl futures::Future for Server {
    type Item = ();
    type Error = Error;

    fn poll(&mut self) -> futures::Poll<Self::Item, Self::Error> {
        self.server.poll().map_err(|_| unreachable!())
    }
}

fn router(data: &Config) -> impl gotham::handler::NewHandler {
    let (chain, pipeline) = gotham::pipeline::single::single_pipeline(
        gotham::pipeline::new_pipeline()
            .add(gotham::middleware::state::StateMiddleware::new(
                data.clone(),
            ))
            .add(
                gotham::middleware::session::NewSessionMiddleware::new(
                    disk_session::DiskSession,
                )
                .insecure()
                .with_cookie_name("teleterm")
                .with_session_type::<SessionData>(),
            )
            .build(),
    );
    gotham::router::builder::build_router(chain, pipeline, |route| {
        route
            .get("/")
            .to(serve_template("text/html", view::INDEX_HTML_TMPL_NAME));
        route.get("/teleterm_web.js").to(serve_static(
            "application/javascript",
            &view::TELETERM_WEB_JS,
        ));
        route
            .get("/teleterm_web_bg.wasm")
            .to(serve_static("application/wasm", &view::TELETERM_WEB_WASM));
        route
            .get("/teleterm.css")
            .to(serve_static("text/css", &view::TELETERM_CSS));
        route.get("/list").to(list::run);
        route
            .get("/watch")
            .with_query_string_extractor::<watch::QueryParams>()
            .to(watch::run);
        route
            .get("/login")
            .with_query_string_extractor::<login::QueryParams>()
            .to(login::run);
    })
}

fn serve_static(
    content_type: &'static str,
    s: &'static [u8],
) -> impl gotham::handler::Handler + Copy {
    move |state| {
        let response = hyper::Response::builder()
            .header("Content-Type", content_type)
            .body(hyper::Body::from(s))
            .unwrap();
        (state, response)
    }
}

fn serve_template(
    content_type: &'static str,
    name: &'static str,
) -> impl gotham::handler::Handler + Copy {
    move |state| {
        let config = Config::borrow_from(&state);
        let rendered = view::HANDLEBARS.render(name, &config).unwrap();
        let response = hyper::Response::builder()
            .header("Content-Type", content_type)
            .body(hyper::Body::from(rendered))
            .unwrap();
        (state, response)
    }
}