main.rs

 1mod api;
 2mod auth;
 3mod db;
 4mod env;
 5mod errors;
 6mod rpc;
 7
 8use ::rpc::Peer;
 9use async_std::net::TcpListener;
10use async_trait::async_trait;
11use db::{Db, PostgresDb};
12use serde::Deserialize;
13use std::sync::Arc;
14use tide_compress::CompressMiddleware;
15
16type Request = tide::Request<Arc<AppState>>;
17
18#[derive(Default, Deserialize)]
19pub struct Config {
20    pub http_port: u16,
21    pub database_url: String,
22    pub api_token: String,
23}
24
25pub struct AppState {
26    db: Arc<dyn Db>,
27    config: Config,
28}
29
30impl AppState {
31    async fn new(config: Config) -> tide::Result<Arc<Self>> {
32        let db = PostgresDb::new(&config.database_url, 5).await?;
33
34        let this = Self {
35            db: Arc::new(db),
36            config,
37        };
38        Ok(Arc::new(this))
39    }
40}
41
42#[async_trait]
43trait RequestExt {
44    fn db(&self) -> &Arc<dyn Db>;
45}
46
47#[async_trait]
48impl RequestExt for Request {
49    fn db(&self) -> &Arc<dyn Db> {
50        &self.state().db
51    }
52}
53
54#[async_std::main]
55async fn main() -> tide::Result<()> {
56    if std::env::var("LOG_JSON").is_ok() {
57        json_env_logger::init();
58    } else {
59        tide::log::start();
60    }
61
62    if let Err(error) = env::load_dotenv() {
63        log::error!(
64            "error loading .env.toml (this is expected in production): {}",
65            error
66        );
67    }
68
69    let config = envy::from_env::<Config>().expect("error loading config");
70    let state = AppState::new(config).await?;
71    let rpc = Peer::new();
72    run_server(
73        state.clone(),
74        rpc,
75        TcpListener::bind(&format!("0.0.0.0:{}", state.config.http_port)).await?,
76    )
77    .await?;
78    Ok(())
79}
80
81pub async fn run_server(
82    state: Arc<AppState>,
83    rpc: Arc<Peer>,
84    listener: TcpListener,
85) -> tide::Result<()> {
86    let mut app = tide::with_state(state.clone());
87    rpc::add_routes(&mut app, &rpc);
88
89    let mut web = tide::with_state(state.clone());
90    web.with(CompressMiddleware::new());
91    api::add_routes(&mut web);
92
93    app.at("/").nest(web);
94
95    app.listen(listener).await?;
96
97    Ok(())
98}