AppFlowy/backend/src/application.rs

162 lines
5.8 KiB
Rust
Raw Normal View History

2021-09-10 16:22:38 +08:00
use actix::Actor;
use actix_identity::{CookieIdentityPolicy, IdentityService};
use actix_web::{dev::Server, middleware, web, web::Data, App, HttpServer, Scope};
2021-09-10 16:22:38 +08:00
use sqlx::{postgres::PgPoolOptions, PgPool};
2021-12-06 21:47:21 +08:00
use std::{net::TcpListener, time::Duration};
2021-09-10 16:22:38 +08:00
use tokio::time::interval;
2021-08-21 22:02:05 +08:00
use crate::{
2021-08-23 18:39:10 +08:00
config::{
env::{domain, secret, use_https},
DatabaseSettings,
Settings,
},
2021-08-21 22:02:05 +08:00
context::AppContext,
2021-12-06 21:47:21 +08:00
services::{
2021-12-21 11:13:38 +08:00
document::router as doc,
2022-01-14 20:52:03 +08:00
folder::{app::router as app, trash::router as trash, view::router as view, workspace::router as workspace},
2021-09-23 16:10:24 +08:00
user::router as user,
2021-12-21 11:13:38 +08:00
web_socket::WSServer,
2021-09-10 16:22:38 +08:00
},
2021-08-21 22:02:05 +08:00
};
pub struct Application {
port: u16,
server: Server,
}
impl Application {
pub async fn build(configuration: Settings, app_ctx: AppContext) -> Result<Self, std::io::Error> {
let address = format!("{}:{}", configuration.application.host, configuration.application.port);
2021-08-21 22:02:05 +08:00
let listener = TcpListener::bind(&address)?;
let port = listener.local_addr().unwrap().port();
2021-08-22 22:16:03 +08:00
let server = run(listener, app_ctx)?;
Ok(Self { port, server })
2021-08-21 22:02:05 +08:00
}
pub async fn run_until_stopped(self) -> Result<(), std::io::Error> { self.server.await }
pub fn port(&self) -> u16 { self.port }
2021-08-21 22:02:05 +08:00
}
2021-08-22 22:16:03 +08:00
pub fn run(listener: TcpListener, app_ctx: AppContext) -> Result<Server, std::io::Error> {
2021-08-23 18:39:10 +08:00
let domain = domain();
let secret: String = secret();
2021-12-22 18:53:52 +08:00
actix_rt::spawn(period_check(app_ctx.persistence.pg_pool()));
2021-08-31 17:25:08 +08:00
2021-08-21 22:02:05 +08:00
let server = HttpServer::new(move || {
App::new()
.wrap(middleware::Logger::default())
2021-08-23 18:39:10 +08:00
.wrap(identify_service(&domain, &secret))
2021-09-04 16:32:34 +08:00
.wrap(crate::middleware::default_cors())
2021-09-02 17:19:23 +08:00
.wrap(crate::middleware::AuthenticationService)
2021-08-21 22:02:05 +08:00
.app_data(web::JsonConfig::default().limit(4096))
.service(ws_scope())
.service(user_scope())
.app_data(app_ctx.ws_server.clone())
2021-12-22 18:53:52 +08:00
.app_data(app_ctx.persistence.clone())
.app_data(Data::new(app_ctx.persistence.pg_pool()))
2021-12-21 11:13:38 +08:00
.app_data(app_ctx.ws_receivers.clone())
2022-01-02 22:23:33 +08:00
.app_data(app_ctx.document_manager.clone())
2021-08-21 22:02:05 +08:00
})
.listen(listener)?
.run();
Ok(server)
}
2021-12-22 18:53:52 +08:00
#[allow(dead_code)]
async fn period_check(_pool: PgPool) {
2021-08-31 17:25:08 +08:00
let mut i = interval(Duration::from_secs(60));
loop {
i.tick().await;
}
}
2021-12-21 11:13:38 +08:00
fn ws_scope() -> Scope { web::scope("/ws").service(crate::services::web_socket::router::establish_ws_connection) }
2021-08-21 22:02:05 +08:00
fn user_scope() -> Scope {
2021-08-27 23:53:53 +08:00
// https://developer.mozilla.org/en-US/docs/Web/HTTP
// TODO: replace GET body with query params
2021-08-23 18:39:10 +08:00
web::scope("/api")
// authentication
.service(web::resource("/auth")
2021-08-24 13:10:53 +08:00
.route(web::post().to(user::sign_in_handler))
.route(web::delete().to(user::sign_out_handler))
2021-09-01 16:08:32 +08:00
)
.service(web::resource("/user")
2021-09-04 16:53:58 +08:00
.route(web::patch().to(user::set_user_profile_handler))
.route(web::get().to(user::get_user_profile_handler))
2021-08-24 13:10:53 +08:00
)
2021-08-31 23:01:46 +08:00
.service(web::resource("/register")
.route(web::post().to(user::register_handler))
)
2021-08-24 13:10:53 +08:00
.service(web::resource("/workspace")
2021-08-24 21:38:53 +08:00
.route(web::post().to(workspace::create_handler))
.route(web::delete().to(workspace::delete_handler))
.route(web::get().to(workspace::read_handler))
.route(web::patch().to(workspace::update_handler))
2021-08-24 13:10:53 +08:00
)
2021-08-26 17:58:59 +08:00
.service(web::resource("/workspace_list/{user_id}")
.route(web::get().to(workspace::workspace_list))
)
2021-08-24 13:10:53 +08:00
.service(web::resource("/app")
2021-08-25 17:34:20 +08:00
.route(web::post().to(app::create_handler))
.route(web::get().to(app::read_handler))
2021-11-08 10:57:33 +08:00
.route(web::delete().to(app::delete_handler))
2021-08-25 17:34:20 +08:00
.route(web::patch().to(app::update_handler))
2021-08-24 13:10:53 +08:00
)
.service(web::resource("/view")
2021-08-25 21:33:29 +08:00
.route(web::post().to(view::create_handler))
.route(web::delete().to(view::delete_handler))
.route(web::get().to(view::read_handler))
.route(web::patch().to(view::update_handler))
2021-08-23 18:39:10 +08:00
)
.service(web::resource("/doc")
.route(web::post().to(doc::create_document_handler))
.route(web::get().to(doc::read_document_handler))
.route(web::patch().to(doc::reset_document_handler))
2021-09-10 15:53:24 +08:00
)
.service(web::resource("/trash")
.route(web::post().to(trash::create_handler))
.route(web::delete().to(trash::delete_handler))
.route(web::get().to(trash::read_handler))
)
2021-12-06 21:47:21 +08:00
.service(web::resource("/sync")
.route(web::post().to(trash::create_handler))
)
2021-08-23 18:39:10 +08:00
// password
.service(web::resource("/password_change")
2021-08-24 13:10:53 +08:00
.route(web::post().to(user::change_password))
2021-08-23 18:39:10 +08:00
)
2021-08-21 22:02:05 +08:00
}
pub async fn init_app_context(configuration: &Settings) -> AppContext {
2022-01-14 20:52:03 +08:00
let _ = crate::services::log::Builder::new("flowy-server")
.env_filter("Trace")
.build();
2021-12-02 21:54:21 +08:00
let pg_pool = get_connection_pool(&configuration.database)
.await
.unwrap_or_else(|_| panic!("Failed to connect to Postgres at {:?}.", configuration.database));
2021-08-21 22:02:05 +08:00
2021-12-21 11:13:38 +08:00
let ws_server = WSServer::new().start();
2021-08-22 22:16:03 +08:00
AppContext::new(ws_server, pg_pool)
2021-08-21 22:02:05 +08:00
}
2021-08-23 18:39:10 +08:00
pub fn identify_service(domain: &str, secret: &str) -> IdentityService<CookieIdentityPolicy> {
IdentityService::new(
CookieIdentityPolicy::new(secret.as_bytes())
.name("auth")
.path("/")
.domain(domain)
.max_age_secs(24 * 3600)
.secure(use_https()),
)
}
2021-08-21 22:02:05 +08:00
pub async fn get_connection_pool(configuration: &DatabaseSettings) -> Result<PgPool, sqlx::Error> {
PgPoolOptions::new()
.connect_timeout(std::time::Duration::from_secs(5))
2021-08-21 22:02:05 +08:00
.connect_with(configuration.with_db())
.await
}