application.rs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. use actix::Actor;
  2. use actix_identity::{CookieIdentityPolicy, IdentityService};
  3. use actix_web::{dev::Server, middleware, web, web::Data, App, HttpServer, Scope};
  4. use sqlx::{postgres::PgPoolOptions, PgPool};
  5. use std::{net::TcpListener, time::Duration};
  6. use tokio::time::interval;
  7. use crate::{
  8. config::{
  9. env::{domain, secret, use_https},
  10. DatabaseSettings, Settings,
  11. },
  12. context::AppContext,
  13. services::{
  14. document::router as doc,
  15. folder::{app::router as app, trash::router as trash, view::router as view, workspace::router as workspace},
  16. user::router as user,
  17. web_socket::WSServer,
  18. },
  19. };
  20. pub struct Application {
  21. port: u16,
  22. server: Server,
  23. }
  24. impl Application {
  25. pub async fn build(configuration: Settings, app_ctx: AppContext) -> Result<Self, std::io::Error> {
  26. let address = format!("{}:{}", configuration.application.host, configuration.application.port);
  27. let listener = TcpListener::bind(&address)?;
  28. let port = listener.local_addr().unwrap().port();
  29. let server = run(listener, app_ctx)?;
  30. Ok(Self { port, server })
  31. }
  32. pub async fn run_until_stopped(self) -> Result<(), std::io::Error> {
  33. self.server.await
  34. }
  35. pub fn port(&self) -> u16 {
  36. self.port
  37. }
  38. }
  39. pub fn run(listener: TcpListener, app_ctx: AppContext) -> Result<Server, std::io::Error> {
  40. let domain = domain();
  41. let secret: String = secret();
  42. actix_rt::spawn(period_check(app_ctx.persistence.pg_pool()));
  43. let server = HttpServer::new(move || {
  44. App::new()
  45. .wrap(middleware::Logger::default())
  46. .wrap(identify_service(&domain, &secret))
  47. .wrap(crate::middleware::default_cors())
  48. .wrap(crate::middleware::AuthenticationService)
  49. .app_data(web::JsonConfig::default().limit(4096))
  50. .service(ws_scope())
  51. .service(user_scope())
  52. .app_data(app_ctx.ws_server.clone())
  53. .app_data(app_ctx.persistence.clone())
  54. .app_data(Data::new(app_ctx.persistence.pg_pool()))
  55. .app_data(app_ctx.ws_receivers.clone())
  56. .app_data(app_ctx.document_manager.clone())
  57. })
  58. .listen(listener)?
  59. .run();
  60. Ok(server)
  61. }
  62. #[allow(dead_code)]
  63. async fn period_check(_pool: PgPool) {
  64. let mut i = interval(Duration::from_secs(60));
  65. loop {
  66. i.tick().await;
  67. }
  68. }
  69. fn ws_scope() -> Scope {
  70. web::scope("/ws").service(crate::services::web_socket::router::establish_ws_connection)
  71. }
  72. fn user_scope() -> Scope {
  73. // https://developer.mozilla.org/en-US/docs/Web/HTTP
  74. // TODO: replace GET body with query params
  75. web::scope("/api")
  76. // authentication
  77. .service(
  78. web::resource("/auth")
  79. .route(web::post().to(user::sign_in_handler))
  80. .route(web::delete().to(user::sign_out_handler)),
  81. )
  82. .service(
  83. web::resource("/user")
  84. .route(web::patch().to(user::set_user_profile_handler))
  85. .route(web::get().to(user::get_user_profile_handler)),
  86. )
  87. .service(web::resource("/register").route(web::post().to(user::register_handler)))
  88. .service(
  89. web::resource("/workspace")
  90. .route(web::post().to(workspace::create_handler))
  91. .route(web::delete().to(workspace::delete_handler))
  92. .route(web::get().to(workspace::read_handler))
  93. .route(web::patch().to(workspace::update_handler)),
  94. )
  95. .service(web::resource("/workspace_list/{user_id}").route(web::get().to(workspace::workspace_list)))
  96. .service(
  97. web::resource("/app")
  98. .route(web::post().to(app::create_handler))
  99. .route(web::get().to(app::read_handler))
  100. .route(web::delete().to(app::delete_handler))
  101. .route(web::patch().to(app::update_handler)),
  102. )
  103. .service(
  104. web::resource("/view")
  105. .route(web::post().to(view::create_handler))
  106. .route(web::delete().to(view::delete_handler))
  107. .route(web::get().to(view::read_handler))
  108. .route(web::patch().to(view::update_handler)),
  109. )
  110. .service(
  111. web::resource("/doc")
  112. .route(web::post().to(doc::create_document_handler))
  113. .route(web::get().to(doc::read_document_handler))
  114. .route(web::patch().to(doc::reset_document_handler)),
  115. )
  116. .service(
  117. web::resource("/trash")
  118. .route(web::post().to(trash::create_handler))
  119. .route(web::delete().to(trash::delete_handler))
  120. .route(web::get().to(trash::read_handler)),
  121. )
  122. .service(web::resource("/sync").route(web::post().to(trash::create_handler)))
  123. // password
  124. .service(web::resource("/password_change").route(web::post().to(user::change_password)))
  125. }
  126. pub async fn init_app_context(configuration: &Settings) -> AppContext {
  127. let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "info".to_owned());
  128. let _ = crate::services::log::Builder::new("flowy-server")
  129. .env_filter(&level)
  130. .build();
  131. let pg_pool = get_connection_pool(&configuration.database)
  132. .await
  133. .unwrap_or_else(|_| panic!("Failed to connect to Postgres at {:?}.", configuration.database));
  134. let ws_server = WSServer::new().start();
  135. AppContext::new(ws_server, pg_pool)
  136. }
  137. pub fn identify_service(domain: &str, secret: &str) -> IdentityService<CookieIdentityPolicy> {
  138. IdentityService::new(
  139. CookieIdentityPolicy::new(secret.as_bytes())
  140. .name("auth")
  141. .path("/")
  142. .domain(domain)
  143. .max_age_secs(24 * 3600)
  144. .secure(use_https()),
  145. )
  146. }
  147. pub async fn get_connection_pool(configuration: &DatabaseSettings) -> Result<PgPool, sqlx::Error> {
  148. PgPoolOptions::new()
  149. .connect_timeout(std::time::Duration::from_secs(5))
  150. .connect_with(configuration.with_db())
  151. .await
  152. }