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
mod app;
mod archive;
pub mod auth;
mod bff;
mod clock;
mod config;
mod dev;
mod extract;
mod forum;
mod oauth_clients;
#[cfg(test)]
pub(crate) mod test;
mod users;

pub use crate::dev::DevApi;
pub use crate::extract::InternalAuthKey;
use axum::body::Body;
use axum::extract::Extension;
use axum::http::Request;
use axum::middleware::Next;
use axum::response::Response;
use axum::Router;
use etwin_core::clock::Clock;
use etwin_core::types::AnyError;
use etwin_services::auth::DynAuthService;
use etwin_services::dinoparc::DynDinoparcService;
use etwin_services::forum::DynForumService;
use etwin_services::hammerfest::DynHammerfestService;
use etwin_services::oauth::DynOauthService;
use etwin_services::twinoid::DynTwinoidService;
use etwin_services::user::DynUserService;
pub use serde::Serialize;
use std::sync::Arc;

#[derive(Debug)]
struct ServerError(AnyError);

#[derive(Clone)]
pub struct RouterApi {
  pub dev: DevApi,
  pub auth: Arc<DynAuthService>,
  pub clock: Arc<dyn Clock>,
  pub dinoparc: Arc<DynDinoparcService>,
  pub forum: Arc<DynForumService>,
  pub hammerfest: Arc<DynHammerfestService>,
  pub oauth: Arc<DynOauthService>,
  pub twinoid: Arc<DynTwinoidService>,
  pub user: Arc<DynUserService>,
}

pub fn router() -> Router<(), Body> {
  Router::new()
    .nest("/app", app::router())
    .nest("/archive", archive::router())
    .nest("/auth", auth::router())
    .nest("/clock", clock::router())
    .nest("/config", config::router())
    .nest("/forum", forum::router())
    .nest("/hammerfest_client", dev::hammerfest_client::router())
    .nest("/oauth_clients", oauth_clients::router())
    .nest("/users", users::router())
}

pub fn app(api: RouterApi) -> Router<(), Body> {
  Router::new()
    .nest("/api/v1", router())
    .nest("/oauth", bff::oauth::router())
    .nest("/actions", bff::actions::router())
    .layer(Extension(api.dev.clone()))
    .layer(Extension(api))
    .layer(axum::middleware::from_fn(on_request))
}

async fn on_request<B>(request: Request<B>, next: Next<B>) -> Response {
  let method = request.method();
  let path = request.uri().path();
  eprintln!("--> {} {}", method, path);
  let method = method.clone();
  let path = path.to_string();
  let start_time = std::time::Instant::now();
  let response = next.run(request).await;
  let duration = start_time.elapsed();
  eprintln!(
    "<-- {} {} {}ms {}",
    method,
    path,
    duration.as_millis(),
    response.status()
  );
  response
}