application.rs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. use crate::{
  2. config::{
  3. env::{domain, secret, use_https},
  4. get_configuration,
  5. DatabaseSettings,
  6. Settings,
  7. },
  8. context::AppContext,
  9. routers::*,
  10. user_service::router as user,
  11. workspace_service::{app::router as app, view::router as view, workspace::router as workspace},
  12. ws_service,
  13. ws_service::WSServer,
  14. };
  15. use actix::Actor;
  16. use actix_identity::{CookieIdentityPolicy, IdentityService};
  17. use actix_web::{dev::Server, middleware, web, web::Data, App, HttpServer, Scope};
  18. use sqlx::{postgres::PgPoolOptions, PgPool};
  19. use std::{net::TcpListener, sync::Arc};
  20. pub struct Application {
  21. port: u16,
  22. server: Server,
  23. }
  24. impl Application {
  25. pub async fn build(configuration: Settings) -> Result<Self, std::io::Error> {
  26. let address = format!(
  27. "{}:{}",
  28. configuration.application.host, configuration.application.port
  29. );
  30. let listener = TcpListener::bind(&address)?;
  31. let port = listener.local_addr().unwrap().port();
  32. let app_ctx = init_app_context(&configuration).await;
  33. let server = run(listener, app_ctx)?;
  34. Ok(Self { port, server })
  35. }
  36. pub async fn run_until_stopped(self) -> Result<(), std::io::Error> { self.server.await }
  37. pub fn port(&self) -> u16 { self.port }
  38. }
  39. pub fn run(listener: TcpListener, app_ctx: AppContext) -> Result<Server, std::io::Error> {
  40. let AppContext { ws_server, pg_pool } = app_ctx;
  41. let ws_server = Data::new(ws_server);
  42. let pg_pool = Data::new(pg_pool);
  43. let domain = domain();
  44. let secret: String = secret();
  45. let server = HttpServer::new(move || {
  46. App::new()
  47. .wrap(middleware::Logger::default())
  48. .wrap(identify_service(&domain, &secret))
  49. .app_data(web::JsonConfig::default().limit(4096))
  50. .service(ws_scope())
  51. .service(user_scope())
  52. .app_data(ws_server.clone())
  53. .app_data(pg_pool.clone())
  54. })
  55. .listen(listener)?
  56. .run();
  57. Ok(server)
  58. }
  59. fn ws_scope() -> Scope { web::scope("/ws").service(ws_service::router::start_connection) }
  60. fn user_scope() -> Scope {
  61. web::scope("/api")
  62. // authentication
  63. .service(web::resource("/auth")
  64. .route(web::post().to(user::sign_in_handler))
  65. .route(web::delete().to(user::sign_out_handler))
  66. .route(web::get().to(user::user_profile))
  67. )
  68. .service(web::resource("/workspace")
  69. .route(web::post().to(workspace::create_handler))
  70. .route(web::delete().to(workspace::delete_handler))
  71. .route(web::get().to(workspace::read_handler))
  72. .route(web::patch().to(workspace::update_handler))
  73. )
  74. .service(web::resource("/app")
  75. .route(web::post().to(app::create_handler))
  76. .route(web::delete().to(app::delete_handler))
  77. .route(web::get().to(app::read_handler))
  78. .route(web::patch().to(app::update_handler))
  79. )
  80. .service(web::resource("/view")
  81. .route(web::post().to(view::create_view))
  82. .route(web::delete().to(view::delete_view))
  83. .route(web::get().to(view::read_view))
  84. .route(web::patch().to(view::update_view))
  85. )
  86. // password
  87. .service(web::resource("/password_change")
  88. .route(web::post().to(user::change_password))
  89. )
  90. // register
  91. .service(web::resource("/register")
  92. .route(web::post().to(user::register_user_handler))
  93. )
  94. }
  95. async fn init_app_context(configuration: &Settings) -> AppContext {
  96. let _ = flowy_log::Builder::new("flowy").env_filter("Debug").build();
  97. let pg_pool = get_connection_pool(&configuration.database)
  98. .await
  99. .expect(&format!(
  100. "Failed to connect to Postgres at {:?}.",
  101. configuration.database
  102. ));
  103. let ws_server = WSServer::new().start();
  104. AppContext::new(ws_server, pg_pool)
  105. }
  106. pub fn identify_service(domain: &str, secret: &str) -> IdentityService<CookieIdentityPolicy> {
  107. IdentityService::new(
  108. CookieIdentityPolicy::new(secret.as_bytes())
  109. .name("auth")
  110. .path("/")
  111. .domain(domain)
  112. .max_age_secs(24 * 3600)
  113. .secure(use_https()),
  114. )
  115. }
  116. pub async fn get_connection_pool(configuration: &DatabaseSettings) -> Result<PgPool, sqlx::Error> {
  117. PgPoolOptions::new()
  118. .connect_timeout(std::time::Duration::from_secs(5))
  119. .connect_with(configuration.with_db())
  120. .await
  121. }