2021-07-11 13:54:55 +00:00
|
|
|
use crate::errors::{ErrorBuilder, UserError, UserErrorCode};
|
2021-07-10 08:27:20 +00:00
|
|
|
use flowy_database::{DBConnection, Database};
|
2021-07-09 15:31:44 +00:00
|
|
|
use lazy_static::lazy_static;
|
|
|
|
use std::{
|
|
|
|
cell::RefCell,
|
|
|
|
sync::{
|
|
|
|
atomic::{AtomicBool, Ordering},
|
|
|
|
RwLock,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
lazy_static! {
|
2021-07-10 08:27:20 +00:00
|
|
|
static ref DB: RwLock<Option<Database>> = RwLock::new(None);
|
2021-07-09 15:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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> {
|
2021-07-11 07:33:19 +00:00
|
|
|
INIT_FLAG.store(true, Ordering::SeqCst);
|
2021-07-10 08:27:20 +00:00
|
|
|
let dir = format!("{}/{}", self.db_dir, user_id);
|
2021-07-11 13:54:55 +00:00
|
|
|
let db = flowy_database::init(&dir).map_err(|e| {
|
|
|
|
ErrorBuilder::new(UserErrorCode::DatabaseInitFailed)
|
|
|
|
.error(e)
|
|
|
|
.build()
|
|
|
|
})?;
|
|
|
|
|
|
|
|
let mut user_db = DB.write().map_err(|e| {
|
|
|
|
ErrorBuilder::new(UserErrorCode::DatabaseWriteLocked)
|
|
|
|
.error(e)
|
|
|
|
.build()
|
|
|
|
})?;
|
2021-07-10 08:27:20 +00:00
|
|
|
*(user_db) = Some(db);
|
|
|
|
|
2021-07-09 15:31:44 +00:00
|
|
|
set_user_id(Some(user_id.to_owned()));
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-07-11 09:38:03 +00:00
|
|
|
pub(crate) fn close_user_db(&self) -> Result<(), UserError> {
|
2021-07-11 07:33:19 +00:00
|
|
|
INIT_FLAG.store(false, Ordering::SeqCst);
|
|
|
|
|
2021-07-11 13:54:55 +00:00
|
|
|
let mut write_guard = DB.write().map_err(|e| {
|
|
|
|
ErrorBuilder::new(UserErrorCode::DatabaseWriteLocked)
|
|
|
|
.msg(format!("Close user db failed. {:?}", e))
|
|
|
|
.build()
|
|
|
|
})?;
|
|
|
|
|
2021-07-09 15:31:44 +00:00
|
|
|
*write_guard = None;
|
|
|
|
set_user_id(None);
|
2021-07-11 07:33:19 +00:00
|
|
|
|
2021-07-09 15:31:44 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn get_connection(&self, user_id: &str) -> Result<DBConnection, UserError> {
|
2021-07-11 07:33:19 +00:00
|
|
|
if !INIT_FLAG.load(Ordering::SeqCst) {
|
2021-07-09 15:31:44 +00:00
|
|
|
let _ = self.open_user_db(user_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
let thread_user_id = get_user_id();
|
2021-07-11 07:33:19 +00:00
|
|
|
if thread_user_id.is_some() {
|
|
|
|
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);
|
2021-07-11 13:54:55 +00:00
|
|
|
|
|
|
|
return Err(ErrorBuilder::new(UserErrorCode::DatabaseUserDidNotMatch)
|
|
|
|
.msg(msg)
|
|
|
|
.build());
|
2021-07-11 07:33:19 +00:00
|
|
|
}
|
2021-07-09 15:31:44 +00:00
|
|
|
}
|
|
|
|
|
2021-07-11 13:54:55 +00:00
|
|
|
let read_guard = DB.read().map_err(|e| {
|
|
|
|
ErrorBuilder::new(UserErrorCode::DatabaseReadLocked)
|
|
|
|
.error(e)
|
|
|
|
.build()
|
|
|
|
})?;
|
2021-07-09 15:31:44 +00:00
|
|
|
match read_guard.as_ref() {
|
2021-07-11 13:54:55 +00:00
|
|
|
None => Err(ErrorBuilder::new(UserErrorCode::DatabaseInitFailed)
|
|
|
|
.msg("Database is not initialization")
|
|
|
|
.build()),
|
2021-07-09 15:31:44 +00:00
|
|
|
Some(database) => Ok(database.get_connection()?),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-11 07:33:19 +00:00
|
|
|
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 INIT_FLAG: AtomicBool = AtomicBool::new(false);
|
|
|
|
|
2021-07-09 15:31:44 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2021-07-10 16:07:37 +00:00
|
|
|
|
2021-07-09 15:31:44 +00:00
|
|
|
#[test]
|
|
|
|
fn init_db_test() {
|
|
|
|
// init_user_db(".").unwrap();
|
|
|
|
}
|
|
|
|
}
|