mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
config user db and user session
This commit is contained in:
parent
13e52ae350
commit
b9d7902acb
@ -16,8 +16,8 @@
|
||||
<sourceFolder url="file://$MODULE_DIR$/scripts/flowy-tool/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-test/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-user/tests" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-db/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-infra/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-database/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-sqlite/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/build" />
|
||||
|
@ -1,5 +1,5 @@
|
||||
PODS:
|
||||
- flowy_infra (0.0.1):
|
||||
- flowy_sqlite (0.0.1):
|
||||
- FlutterMacOS
|
||||
- flowy_sdk (0.0.1):
|
||||
- FlutterMacOS
|
||||
@ -9,15 +9,15 @@ PODS:
|
||||
- FlutterMacOS
|
||||
|
||||
DEPENDENCIES:
|
||||
- flowy_infra (from `Flutter/ephemeral/.symlinks/plugins/flowy_infra/macos`)
|
||||
- flowy_sqlite (from `Flutter/ephemeral/.symlinks/plugins/flowy_sqlite/macos`)
|
||||
- flowy_sdk (from `Flutter/ephemeral/.symlinks/plugins/flowy_sdk/macos`)
|
||||
- FlutterMacOS (from `Flutter/ephemeral/.symlinks/flutter/darwin-x64`)
|
||||
- path_provider (from `Flutter/ephemeral/.symlinks/plugins/path_provider/macos`)
|
||||
- path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
flowy_infra:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/flowy_infra/macos
|
||||
flowy_sqlite:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/flowy_sqlite/macos
|
||||
flowy_sdk:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/flowy_sdk/macos
|
||||
FlutterMacOS:
|
||||
@ -28,7 +28,7 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
flowy_infra: 6638deea1ca0baeef75156d16236123d4703161d
|
||||
flowy_sqlite: 6638deea1ca0baeef75156d16236123d4703161d
|
||||
flowy_sdk: 12d2c047ed260a0aa8788a0b9616da46e2312025
|
||||
FlutterMacOS: 15bea8a44d2fa024068daa0140371c020b4b6ff9
|
||||
path_provider: e0848572d1d38b9a7dd099e79cf83f5b7e2cde9f
|
||||
|
@ -8,8 +8,8 @@ members = [
|
||||
"flowy-ast",
|
||||
"flowy-derive",
|
||||
"flowy-test",
|
||||
"flowy-infra",
|
||||
"flowy-db",
|
||||
"flowy-sqlite",
|
||||
"flowy-database",
|
||||
]
|
||||
|
||||
[profile.dev]
|
||||
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "flowy-db"
|
||||
name = "flowy-database"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
@ -9,4 +9,4 @@ edition = "2018"
|
||||
diesel = {version = "1.4.7", features = ["sqlite"]}
|
||||
diesel_derives = {version = "1.4.1", features = ["sqlite"]}
|
||||
diesel_migrations = {version = "1.4.0", features = ["sqlite"]}
|
||||
flowy-infra = {path = "../flowy-infra"}
|
||||
flowy-sqlite = {path = "../flowy-sqlite" }
|
16
rust-lib/flowy-database/src/errors.rs
Normal file
16
rust-lib/flowy-database/src/errors.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use flowy_sqlite::Error;
|
||||
use std::io;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DataBaseError {
|
||||
InitError(String),
|
||||
IOError(String),
|
||||
}
|
||||
|
||||
impl std::convert::From<flowy_sqlite::Error> for DataBaseError {
|
||||
fn from(error: flowy_sqlite::Error) -> Self { DataBaseError::InitError(format!("{:?}", error)) }
|
||||
}
|
||||
|
||||
impl std::convert::From<io::Error> for DataBaseError {
|
||||
fn from(error: io::Error) -> Self { DataBaseError::IOError(format!("{:?}", error)) }
|
||||
}
|
29
rust-lib/flowy-database/src/lib.rs
Normal file
29
rust-lib/flowy-database/src/lib.rs
Normal file
@ -0,0 +1,29 @@
|
||||
mod errors;
|
||||
mod schema;
|
||||
|
||||
#[macro_use]
|
||||
extern crate diesel;
|
||||
#[macro_use]
|
||||
extern crate diesel_derives;
|
||||
#[macro_use]
|
||||
extern crate diesel_migrations;
|
||||
|
||||
pub use errors::*;
|
||||
pub use flowy_sqlite::{DBConnection, DataBase};
|
||||
|
||||
use diesel_migrations::*;
|
||||
use flowy_sqlite::PoolConfig;
|
||||
use std::path::Path;
|
||||
|
||||
embed_migrations!("../flowy-database/migrations/");
|
||||
pub const DB_NAME: &str = "flowy-database.db";
|
||||
|
||||
pub fn init(storage_path: &str) -> Result<DataBase, DataBaseError> {
|
||||
if !Path::new(storage_path).exists() {
|
||||
std::fs::create_dir_all(storage_path)?;
|
||||
}
|
||||
|
||||
let pool_config = PoolConfig::default();
|
||||
let database = DataBase::new(storage_path, DB_NAME, pool_config)?;
|
||||
Ok(database)
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
use crate::errors::FlowyDBError;
|
||||
use diesel_migrations::*;
|
||||
use flowy_infra::sqlite::*;
|
||||
use std::path::Path;
|
||||
|
||||
embed_migrations!("../flowy-db/migrations/");
|
||||
pub const DB_NAME: &str = "flowy-database.db";
|
||||
|
||||
pub fn init(storage_path: &str) -> Result<DataBase, FlowyDBError> {
|
||||
if !Path::new(storage_path).exists() {
|
||||
std::fs::create_dir_all(storage_path)?;
|
||||
}
|
||||
|
||||
let pool_config = PoolConfig::default();
|
||||
let database = DataBase::new(storage_path, DB_NAME, pool_config)?;
|
||||
Ok(database)
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
use flowy_infra::Error;
|
||||
use std::io;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FlowyDBError {
|
||||
InitError(String),
|
||||
IOError(String),
|
||||
}
|
||||
|
||||
impl std::convert::From<flowy_infra::Error> for FlowyDBError {
|
||||
fn from(error: flowy_infra::Error) -> Self { FlowyDBError::InitError(format!("{:?}", error)) }
|
||||
}
|
||||
|
||||
impl std::convert::From<io::Error> for FlowyDBError {
|
||||
fn from(error: io::Error) -> Self { FlowyDBError::IOError(format!("{:?}", error)) }
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
mod database;
|
||||
mod errors;
|
||||
mod schema;
|
||||
|
||||
#[macro_use]
|
||||
extern crate diesel;
|
||||
#[macro_use]
|
||||
extern crate diesel_derives;
|
||||
#[macro_use]
|
||||
extern crate diesel_migrations;
|
||||
|
||||
pub use flowy_infra::sqlite::DataBase;
|
||||
|
||||
pub use database::init;
|
||||
pub use errors::*;
|
@ -1,13 +0,0 @@
|
||||
#[allow(deprecated, clippy::large_enum_variant)]
|
||||
mod errors;
|
||||
pub mod sqlite;
|
||||
|
||||
pub use errors::{Error, ErrorKind, Result};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
mod database;
|
||||
mod pool;
|
||||
|
||||
pub use database::*;
|
||||
pub use pool::*;
|
@ -3,6 +3,7 @@ pub use module::*;
|
||||
|
||||
use flowy_dispatch::prelude::*;
|
||||
use module::build_modules;
|
||||
|
||||
pub struct FlowySDK {}
|
||||
|
||||
impl FlowySDK {
|
||||
@ -10,6 +11,11 @@ impl FlowySDK {
|
||||
|
||||
pub fn init(path: &str) {
|
||||
tracing::trace!("🔥 Root path: {}", path);
|
||||
EventDispatch::construct(|| build_modules());
|
||||
|
||||
let config = ModuleConfig {
|
||||
root: path.to_string(),
|
||||
};
|
||||
|
||||
EventDispatch::construct(|| build_modules(config));
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,14 @@
|
||||
use flowy_dispatch::prelude::Module;
|
||||
use flowy_user::prelude::user_session::{UserSession, UserSessionConfig};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn build_modules() -> Vec<Module> { vec![flowy_user::module::create()] }
|
||||
pub struct ModuleConfig {
|
||||
pub root: String,
|
||||
}
|
||||
|
||||
pub fn build_modules(config: ModuleConfig) -> Vec<Module> {
|
||||
let user_config = UserSessionConfig::new(&config.root);
|
||||
let user_session = Arc::new(UserSession::new(user_config));
|
||||
|
||||
vec![flowy_user::module::create(user_session)]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "flowy-infra"
|
||||
name = "flowy-sqlite"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
errors::*,
|
||||
sqlite::pool::{ConnectionManager, ConnectionPool, PoolConfig},
|
||||
pool::{ConnectionManager, ConnectionPool, PoolConfig},
|
||||
};
|
||||
use r2d2::PooledConnection;
|
||||
|
||||
@ -9,6 +9,8 @@ pub struct DataBase {
|
||||
pool: ConnectionPool,
|
||||
}
|
||||
|
||||
pub type DBConnection = PooledConnection<ConnectionManager>;
|
||||
|
||||
impl DataBase {
|
||||
pub fn new(dir: &str, name: &str, pool_config: PoolConfig) -> Result<Self> {
|
||||
let uri = db_file_uri(dir, name);
|
||||
@ -18,7 +20,7 @@ impl DataBase {
|
||||
|
||||
pub fn get_uri(&self) -> &str { &self.uri }
|
||||
|
||||
pub fn get_conn(&self) -> Result<PooledConnection<ConnectionManager>> {
|
||||
pub fn get_connection(&self) -> Result<DBConnection> {
|
||||
let conn = self.pool.get()?;
|
||||
Ok(conn)
|
||||
}
|
9
rust-lib/flowy-sqlite/src/lib.rs
Normal file
9
rust-lib/flowy-sqlite/src/lib.rs
Normal file
@ -0,0 +1,9 @@
|
||||
mod database;
|
||||
#[allow(deprecated, clippy::large_enum_variant)]
|
||||
mod errors;
|
||||
mod pool;
|
||||
|
||||
pub use database::*;
|
||||
pub use pool::*;
|
||||
|
||||
pub use errors::{Error, ErrorKind, Result};
|
1
rust-lib/flowy-sqlite/src/mod.rs
Normal file
1
rust-lib/flowy-sqlite/src/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
|
@ -10,7 +10,8 @@ derive_more = {version = "0.99", features = ["display"]}
|
||||
flowy-dispatch = { path = "../flowy-dispatch" }
|
||||
flowy-log = { path = "../flowy-log" }
|
||||
flowy-derive = { path = "../flowy-derive" }
|
||||
flowy-db = { path = "../flowy-db" }
|
||||
flowy-database = { path = "../flowy-database" }
|
||||
flowy-sqlite = { path = "../flowy-sqlite" }
|
||||
|
||||
tracing = { version = "0.1", features = ["log"] }
|
||||
bytes = "1.0"
|
||||
|
@ -1,28 +0,0 @@
|
||||
use crate::errors::UserError;
|
||||
use flowy_db::DataBase;
|
||||
use lazy_static::lazy_static;
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
RwLock,
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
pub static ref DB: RwLock<Option<DataBase>> = RwLock::new(None);
|
||||
}
|
||||
|
||||
static DB_INIT: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
pub fn init_user_db(dir: &str) -> Result<(), UserError> {
|
||||
let database = flowy_db::init(dir)?;
|
||||
*(DB.write()?) = Some(database);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn init_db_test() {
|
||||
// init_user_db(".").unwrap();
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
pub use user::*;
|
||||
|
||||
mod database;
|
||||
pub mod user;
|
||||
pub mod user_db;
|
||||
pub mod user_session;
|
||||
|
87
rust-lib/flowy-user/src/domain/user_db.rs
Normal file
87
rust-lib/flowy-user/src/domain/user_db.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use crate::errors::UserError;
|
||||
use flowy_database::{DBConnection, DataBase};
|
||||
use lazy_static::lazy_static;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
RwLock,
|
||||
},
|
||||
};
|
||||
|
||||
thread_local! {
|
||||
static USER_ID: RefCell<Option<String>> = RefCell::new(None);
|
||||
}
|
||||
fn set_user_id(user_id: Option<String>) {
|
||||
USER_ID.with(|id| {
|
||||
*id.borrow_mut() = user_id;
|
||||
});
|
||||
}
|
||||
fn get_user_id() -> Option<String> { USER_ID.with(|id| id.borrow().clone()) }
|
||||
|
||||
static IS_USER_DB_INIT: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
lazy_static! {
|
||||
static ref USER_DB_INNER: RwLock<Option<DataBase>> = RwLock::new(None);
|
||||
}
|
||||
|
||||
pub(crate) struct UserDB {
|
||||
db_dir: String,
|
||||
}
|
||||
|
||||
impl UserDB {
|
||||
pub(crate) fn new(db_dir: &str) -> Self {
|
||||
Self {
|
||||
db_dir: db_dir.to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
fn open_user_db(&self, user_id: &str) -> Result<(), UserError> {
|
||||
let user_dir = format!("{}/{}", self.db_dir, user_id);
|
||||
let database = flowy_database::init(&user_dir)?;
|
||||
let mut write_guard = USER_DB_INNER.write()?;
|
||||
set_user_id(Some(user_id.to_owned()));
|
||||
*(write_guard) = Some(database);
|
||||
IS_USER_DB_INIT.store(true, Ordering::SeqCst);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn close_user_db(&mut self) -> Result<(), UserError> {
|
||||
let mut write_guard = USER_DB_INNER.write()?;
|
||||
*write_guard = None;
|
||||
set_user_id(None);
|
||||
IS_USER_DB_INIT.store(false, Ordering::SeqCst);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn get_connection(&self, user_id: &str) -> Result<DBConnection, UserError> {
|
||||
if !IS_USER_DB_INIT.load(Ordering::SeqCst) {
|
||||
let _ = self.open_user_db(user_id);
|
||||
}
|
||||
|
||||
let thread_user_id = get_user_id();
|
||||
if thread_user_id != Some(user_id.to_owned()) {
|
||||
let msg = format!(
|
||||
"DataBase owner does not match. origin: {:?}, current: {}",
|
||||
thread_user_id, user_id
|
||||
);
|
||||
log::error!("{}", msg);
|
||||
return Err(UserError::DBConnection(msg));
|
||||
}
|
||||
|
||||
let read_guard = USER_DB_INNER.read()?;
|
||||
match read_guard.as_ref() {
|
||||
None => Err(UserError::DBNotInit),
|
||||
Some(database) => Ok(database.get_connection()?),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn init_db_test() {
|
||||
// init_user_db(".").unwrap();
|
||||
}
|
||||
}
|
48
rust-lib/flowy-user/src/domain/user_session.rs
Normal file
48
rust-lib/flowy-user/src/domain/user_session.rs
Normal file
@ -0,0 +1,48 @@
|
||||
use crate::{domain::user_db::UserDB, errors::UserError};
|
||||
use flowy_sqlite::DBConnection;
|
||||
use lazy_static::lazy_static;
|
||||
use std::sync::RwLock;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref CURRENT_USER_ID: RwLock<Option<String>> = RwLock::new(None);
|
||||
}
|
||||
fn get_current_user_id() -> Result<Option<String>, UserError> {
|
||||
match CURRENT_USER_ID.read() {
|
||||
Ok(read_guard) => Ok((*read_guard).clone()),
|
||||
Err(e) => {
|
||||
log::error!("Get current user id failed: {:?}", e);
|
||||
Err(e.into())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
db: UserDB,
|
||||
config: UserSessionConfig,
|
||||
}
|
||||
|
||||
impl UserSession {
|
||||
pub fn new(config: UserSessionConfig) -> Self {
|
||||
let db = UserDB::new(&config.root_dir);
|
||||
Self { db, config }
|
||||
}
|
||||
|
||||
pub fn get_db_connection(&self) -> Result<DBConnection, UserError> {
|
||||
match get_current_user_id()? {
|
||||
None => Err(UserError::UserNotLogin),
|
||||
Some(user_id) => self.db.get_connection(&user_id),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +1,23 @@
|
||||
use flowy_database::DataBaseError;
|
||||
use std::sync::PoisonError;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum UserError {
|
||||
DBInitFail(String),
|
||||
DBInit(String),
|
||||
DBNotInit,
|
||||
UserNotLogin,
|
||||
DBConnection(String),
|
||||
PoisonError(String),
|
||||
}
|
||||
|
||||
impl std::convert::From<flowy_db::FlowyDBError> for UserError {
|
||||
fn from(error: flowy_db::FlowyDBError) -> Self { UserError::DBInitFail(format!("{:?}", error)) }
|
||||
impl std::convert::From<DataBaseError> for UserError {
|
||||
fn from(error: DataBaseError) -> Self { UserError::DBInit(format!("{:?}", error)) }
|
||||
}
|
||||
|
||||
impl<T> std::convert::From<PoisonError<T>> for UserError {
|
||||
fn from(error: PoisonError<T>) -> Self { UserError::PoisonError(format!("{:?}", error)) }
|
||||
}
|
||||
|
||||
impl std::convert::From<flowy_sqlite::Error> for UserError {
|
||||
fn from(e: flowy_sqlite::Error) -> Self { UserError::DBConnection(format!("{:?}", e)) }
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::domain::user::*;
|
||||
use crate::domain::{user::*, user_session::UserSession};
|
||||
use flowy_dispatch::prelude::*;
|
||||
use std::convert::TryInto;
|
||||
use std::{convert::TryInto, sync::Arc};
|
||||
|
||||
// tracing instrument 👉🏻 https://docs.rs/tracing/0.1.26/tracing/attr.instrument.html
|
||||
#[tracing::instrument(
|
||||
@ -19,12 +19,15 @@ pub async fn user_sign_in(data: Data<SignInRequest>) -> ResponseResult<SignInRes
|
||||
|
||||
#[tracing::instrument(
|
||||
name = "user_sign_up",
|
||||
skip(data),
|
||||
skip(data, session),
|
||||
fields(
|
||||
email = %data.email,
|
||||
)
|
||||
)]
|
||||
pub async fn user_sign_up(data: Data<SignUpRequest>) -> ResponseResult<SignUpResponse, String> {
|
||||
pub async fn user_sign_up(
|
||||
data: Data<SignUpRequest>,
|
||||
session: ModuleData<Arc<UserSession>>,
|
||||
) -> ResponseResult<SignUpResponse, String> {
|
||||
let _params: SignUpParams = data.into_inner().try_into()?;
|
||||
// TODO: user sign up
|
||||
|
||||
|
@ -1,10 +1,16 @@
|
||||
use flowy_dispatch::prelude::*;
|
||||
|
||||
use crate::{event::UserEvent, handlers::*};
|
||||
use crate::{
|
||||
domain::{user_db::*, user_session::UserSession},
|
||||
event::UserEvent,
|
||||
handlers::*,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn create() -> Module {
|
||||
pub fn create(user_session: Arc<UserSession>) -> Module {
|
||||
Module::new()
|
||||
.name("Flowy-User")
|
||||
.data(user_session)
|
||||
.event(UserEvent::SignIn, user_sign_in)
|
||||
.event(UserEvent::SignUp, user_sign_up)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user