AppFlowy/rust-lib/flowy-user/src/services/user/user_session.rs

262 lines
8.1 KiB
Rust
Raw Normal View History

use crate::{
2021-08-29 14:00:42 +00:00
entities::{SignInParams, SignUpParams, UpdateUserParams, UserDetail},
2021-08-30 14:44:17 +00:00
errors::{ErrorBuilder, ErrorCode, UserError},
2021-09-01 08:37:46 +00:00
services::user::{construct_user_server, database::UserDB},
sql_tables::{UserTable, UserTableChangeset},
};
2021-08-29 14:00:42 +00:00
use flowy_database::{
query_dsl::*,
schema::{user_table, user_table::dsl},
DBConnection,
ExpressionMethods,
2021-07-13 15:08:20 +00:00
UserDatabaseConnection,
};
2021-08-29 14:00:42 +00:00
2021-09-01 08:37:46 +00:00
use crate::services::server::Server;
2021-09-03 04:44:48 +00:00
use flowy_infra::kv::KV;
2021-08-31 15:01:46 +00:00
use flowy_sqlite::ConnectionPool;
use parking_lot::RwLock;
use serde::{Deserialize, Serialize};
2021-09-01 08:37:46 +00:00
use std::sync::Arc;
pub struct UserSessionConfig {
root_dir: String,
}
impl UserSessionConfig {
pub fn new(root_dir: &str) -> Self {
Self {
root_dir: root_dir.to_owned(),
}
}
}
pub struct UserSession {
database: UserDB,
config: UserSessionConfig,
#[allow(dead_code)]
2021-09-01 08:08:32 +00:00
server: Server,
session: RwLock<Option<Session>>,
}
impl UserSession {
2021-08-31 15:01:46 +00:00
pub fn new(config: UserSessionConfig) -> Self {
let db = UserDB::new(&config.root_dir);
2021-08-31 15:01:46 +00:00
let server = construct_user_server();
Self {
database: db,
config,
2021-07-14 15:00:58 +00:00
server,
session: RwLock::new(None),
}
}
2021-07-16 15:18:12 +00:00
pub fn get_db_connection(&self) -> Result<DBConnection, UserError> {
let user_id = self.get_session()?.user_id;
2021-07-16 15:18:12 +00:00
self.database.get_connection(&user_id)
}
// The caller will be not 'Sync' before of the return value,
// PooledConnection<ConnectionManager> is not sync. You can use
// db_connection_pool function to require the ConnectionPool that is 'Sync'.
//
// let pool = self.db_connection_pool()?;
// let conn: PooledConnection<ConnectionManager> = pool.get()?;
2021-08-31 15:01:46 +00:00
pub fn db_connection_pool(&self) -> Result<Arc<ConnectionPool>, UserError> {
let user_id = self.get_session()?.user_id;
2021-08-31 15:01:46 +00:00
self.database.get_pool(&user_id)
}
pub async fn sign_in(&self, params: SignInParams) -> Result<UserDetail, UserError> {
if self.is_login(&params.email) {
self.user_detail().await
} else {
let resp = self.server.sign_in(params).await?;
let session = Session::new(&resp.uid, &resp.token, &resp.email);
let _ = self.set_session(Some(session))?;
let user_table = self.save_user(resp.into()).await?;
let user_detail = UserDetail::from(user_table);
Ok(user_detail)
}
}
pub async fn sign_up(&self, params: SignUpParams) -> Result<UserDetail, UserError> {
2021-09-04 01:00:15 +00:00
if self.is_login(&params.email) {
self.user_detail().await
} else {
let resp = self.server.sign_up(params).await?;
let session = Session::new(&resp.user_id, &resp.token, &resp.email);
let _ = self.set_session(Some(session))?;
let user_table = self.save_user(resp.into()).await?;
let user_detail = UserDetail::from(user_table);
Ok(user_detail)
}
}
2021-08-31 09:25:08 +00:00
pub async fn sign_out(&self) -> Result<(), UserError> {
2021-09-01 08:08:32 +00:00
let session = self.get_session()?;
match self.server.sign_out(&session.token).await {
2021-08-31 09:25:08 +00:00
Ok(_) => {},
Err(e) => log::error!("Sign out failed: {:?}", e),
}
2021-07-11 09:38:03 +00:00
let conn = self.get_db_connection()?;
let _ = diesel::delete(dsl::user_table.filter(dsl::id.eq(&session.user_id))).execute(&*conn)?;
2021-09-01 08:08:32 +00:00
let _ = self.server.sign_out(&session.token);
let _ = self.database.close_user_db(&session.user_id)?;
let _ = self.set_session(None)?;
2021-07-11 09:38:03 +00:00
Ok(())
}
2021-08-31 15:01:46 +00:00
pub async fn update_user(&self, params: UpdateUserParams) -> Result<(), UserError> {
2021-09-01 09:57:06 +00:00
let session = self.get_session()?;
match self.server.update_user(&session.token, params.clone()).await {
2021-09-01 09:57:06 +00:00
Ok(_) => {},
Err(e) => {
// TODO: retry?
log::error!("update user profile failed: {:?}", e);
},
}
let changeset = UserTableChangeset::new(params);
let conn = self.get_db_connection()?;
diesel_update_table!(user_table, changeset, conn);
2021-08-31 15:01:46 +00:00
Ok(())
}
2021-08-31 15:01:46 +00:00
pub async fn user_detail(&self) -> Result<UserDetail, UserError> {
2021-09-01 08:37:46 +00:00
let session = self.get_session()?;
let token = session.token;
2021-08-31 15:01:46 +00:00
let server = self.server.clone();
tokio::spawn(async move {
match server.get_user_detail(&token).await {
Ok(user_detail) => {
//
log::info!("{:?}", user_detail);
},
Err(e) => {
//
log::info!("{:?}", e);
},
}
})
.await;
2021-07-11 09:38:03 +00:00
2021-09-01 08:37:46 +00:00
let user = dsl::user_table
.filter(user_table::id.eq(&session.user_id))
.first::<UserTable>(&*(self.get_db_connection()?))?;
Ok(UserDetail::from(user))
}
2021-08-29 14:00:42 +00:00
pub fn user_dir(&self) -> Result<String, UserError> {
let session = self.get_session()?;
Ok(format!("{}/{}", self.config.root_dir, session.user_id))
2021-07-23 09:30:33 +00:00
}
2021-09-01 08:08:32 +00:00
pub fn user_id(&self) -> Result<String, UserError> { Ok(self.get_session()?.user_id) }
2021-09-01 14:50:22 +00:00
pub fn token(&self) -> Result<String, UserError> { Ok(self.get_session()?.token) }
2021-09-01 08:08:32 +00:00
}
impl UserSession {
async fn save_user(&self, user: UserTable) -> Result<UserTable, UserError> {
let conn = self.get_db_connection()?;
let _ = diesel::insert_into(user_table::table).values(user.clone()).execute(&*conn)?;
2021-09-01 08:08:32 +00:00
Ok(user)
}
fn set_session(&self, session: Option<Session>) -> Result<(), UserError> {
2021-09-04 07:12:53 +00:00
log::debug!("Update user session: {:?}", session);
match &session {
2021-09-03 04:44:48 +00:00
None => KV::remove(SESSION_CACHE_KEY).map_err(|e| UserError::new(ErrorCode::SqlInternalError, &e))?,
Some(session) => KV::set_str(SESSION_CACHE_KEY, session.clone().into()),
}
2021-09-03 04:44:48 +00:00
*self.session.write() = session;
Ok(())
}
fn get_session(&self) -> Result<Session, UserError> {
2021-09-03 04:44:48 +00:00
let mut session = { (*self.session.read()).clone() };
if session.is_none() {
2021-09-03 04:44:48 +00:00
match KV::get_str(SESSION_CACHE_KEY) {
None => {},
Some(s) => {
session = Some(Session::from(s));
let _ = self.set_session(session.clone())?;
},
}
}
match session {
2021-08-30 14:44:17 +00:00
None => Err(ErrorBuilder::new(ErrorCode::UserNotLoginYet).build()),
Some(session) => Ok(session),
}
}
fn is_login(&self, email: &str) -> bool {
match self.get_session() {
Ok(session) => session.email == email,
Err(_) => false,
}
}
2021-08-31 15:01:46 +00:00
}
pub async fn update_user(_server: Server, pool: Arc<ConnectionPool>, params: UpdateUserParams) -> Result<(), UserError> {
2021-08-31 15:01:46 +00:00
let changeset = UserTableChangeset::new(params);
let conn = pool.get()?;
diesel_update_table!(user_table, changeset, conn);
Ok(())
2021-07-16 15:18:12 +00:00
}
2021-07-11 09:38:03 +00:00
2021-07-13 15:08:20 +00:00
impl UserDatabaseConnection for UserSession {
fn get_connection(&self) -> Result<DBConnection, String> { self.get_db_connection().map_err(|e| format!("{:?}", e)) }
2021-07-13 15:08:20 +00:00
}
const SESSION_CACHE_KEY: &str = "session_cache_key";
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
struct Session {
user_id: String,
token: String,
email: String,
}
impl Session {
pub fn new(user_id: &str, token: &str, email: &str) -> Self {
Self {
user_id: user_id.to_owned(),
token: token.to_owned(),
email: email.to_owned(),
}
}
}
impl std::convert::From<String> for Session {
fn from(s: String) -> Self {
match serde_json::from_str(&s) {
Ok(s) => s,
Err(e) => {
2021-09-01 08:08:32 +00:00
log::error!("Deserialize string to Session failed: {:?}", e);
Session::default()
},
}
}
}
impl std::convert::Into<String> for Session {
fn into(self) -> String {
match serde_json::to_string(&self) {
Ok(s) => s,
Err(e) => {
2021-09-01 08:08:32 +00:00
log::error!("Serialize session to string failed: {:?}", e);
"".to_string()
},
}
}
}