2023-07-05 20:57:09 +08:00
|
|
|
use std::ops::Deref;
|
|
|
|
use std::sync::atomic::{AtomicU32, Ordering};
|
|
|
|
use std::sync::{Arc, Weak};
|
|
|
|
use std::time::Duration;
|
2023-05-21 18:53:59 +08:00
|
|
|
|
2023-07-05 20:57:09 +08:00
|
|
|
use appflowy_integrate::RemoteCollabStorage;
|
2023-07-14 13:37:13 +08:00
|
|
|
use parking_lot::RwLock;
|
2023-07-05 20:57:09 +08:00
|
|
|
use tokio::spawn;
|
|
|
|
use tokio::sync::{watch, Mutex};
|
|
|
|
use tokio::time::interval;
|
2023-05-21 18:53:59 +08:00
|
|
|
|
2023-07-05 20:57:09 +08:00
|
|
|
use flowy_database2::deps::DatabaseCloudService;
|
|
|
|
use flowy_document2::deps::DocumentCloudService;
|
2023-07-14 13:37:13 +08:00
|
|
|
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
2023-05-23 23:55:21 +08:00
|
|
|
use flowy_folder2::deps::FolderCloudService;
|
2023-07-14 13:37:13 +08:00
|
|
|
use flowy_server_config::supabase_config::{PostgresConfiguration, SupabaseConfiguration};
|
2023-05-21 18:53:59 +08:00
|
|
|
use flowy_user::event_map::UserAuthService;
|
2023-07-05 20:57:09 +08:00
|
|
|
use lib_infra::async_trait::async_trait;
|
2023-05-21 18:53:59 +08:00
|
|
|
|
2023-07-05 20:57:09 +08:00
|
|
|
use crate::supabase::impls::{
|
|
|
|
PgCollabStorageImpl, SupabaseDatabaseCloudServiceImpl, SupabaseDocumentCloudServiceImpl,
|
|
|
|
SupabaseFolderCloudServiceImpl, SupabaseUserAuthServiceImpl,
|
|
|
|
};
|
2023-07-14 13:37:13 +08:00
|
|
|
use crate::supabase::postgres_db::{PgClientReceiver, PostgresDB, PostgresEvent};
|
2023-07-05 20:57:09 +08:00
|
|
|
use crate::supabase::queue::{
|
|
|
|
PendingRequest, RequestHandler, RequestQueue, RequestRunner, RequestState,
|
|
|
|
};
|
2023-05-21 18:53:59 +08:00
|
|
|
use crate::AppFlowyServer;
|
|
|
|
|
2023-07-05 20:57:09 +08:00
|
|
|
/// Supabase server is used to provide the implementation of the [AppFlowyServer] trait.
|
|
|
|
/// It contains the configuration of the supabase server and the postgres server.
|
|
|
|
pub struct SupabaseServer {
|
|
|
|
#[allow(dead_code)]
|
|
|
|
config: SupabaseConfiguration,
|
2023-07-14 13:37:13 +08:00
|
|
|
postgres: Arc<RwLock<Option<Arc<PostgresServer>>>>,
|
2023-07-05 20:57:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl SupabaseServer {
|
|
|
|
pub fn new(config: SupabaseConfiguration) -> Self {
|
2023-07-14 13:37:13 +08:00
|
|
|
let postgres = if config.enable_sync {
|
|
|
|
Some(Arc::new(PostgresServer::new(
|
|
|
|
config.postgres_config.clone(),
|
|
|
|
)))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2023-07-05 20:57:09 +08:00
|
|
|
Self {
|
|
|
|
config,
|
2023-07-14 13:37:13 +08:00
|
|
|
postgres: Arc::new(RwLock::new(postgres)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_enable_sync(&self, enable: bool) {
|
|
|
|
if enable {
|
|
|
|
if self.postgres.read().is_some() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
*self.postgres.write() = Some(Arc::new(PostgresServer::new(
|
|
|
|
self.config.postgres_config.clone(),
|
|
|
|
)));
|
|
|
|
} else {
|
|
|
|
*self.postgres.write() = None;
|
2023-07-05 20:57:09 +08:00
|
|
|
}
|
|
|
|
}
|
2023-05-21 18:53:59 +08:00
|
|
|
}
|
|
|
|
|
2023-07-05 20:57:09 +08:00
|
|
|
impl AppFlowyServer for SupabaseServer {
|
2023-07-14 13:37:13 +08:00
|
|
|
fn enable_sync(&self, enable: bool) {
|
|
|
|
tracing::info!("supabase sync: {}", enable);
|
|
|
|
self.set_enable_sync(enable);
|
|
|
|
}
|
|
|
|
|
2023-07-05 20:57:09 +08:00
|
|
|
fn user_service(&self) -> Arc<dyn UserAuthService> {
|
2023-07-14 13:37:13 +08:00
|
|
|
Arc::new(SupabaseUserAuthServiceImpl::new(SupabaseServerServiceImpl(
|
|
|
|
self.postgres.clone(),
|
|
|
|
)))
|
2023-07-05 20:57:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn folder_service(&self) -> Arc<dyn FolderCloudService> {
|
2023-07-14 13:37:13 +08:00
|
|
|
Arc::new(SupabaseFolderCloudServiceImpl::new(
|
|
|
|
SupabaseServerServiceImpl(self.postgres.clone()),
|
|
|
|
))
|
2023-07-05 20:57:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn database_service(&self) -> Arc<dyn DatabaseCloudService> {
|
2023-07-14 13:37:13 +08:00
|
|
|
Arc::new(SupabaseDatabaseCloudServiceImpl::new(
|
|
|
|
SupabaseServerServiceImpl(self.postgres.clone()),
|
|
|
|
))
|
2023-07-05 20:57:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn document_service(&self) -> Arc<dyn DocumentCloudService> {
|
2023-07-14 13:37:13 +08:00
|
|
|
Arc::new(SupabaseDocumentCloudServiceImpl::new(
|
|
|
|
SupabaseServerServiceImpl(self.postgres.clone()),
|
|
|
|
))
|
2023-05-21 18:53:59 +08:00
|
|
|
}
|
2023-05-23 23:55:21 +08:00
|
|
|
|
2023-07-05 20:57:09 +08:00
|
|
|
fn collab_storage(&self) -> Option<Arc<dyn RemoteCollabStorage>> {
|
2023-07-14 13:37:13 +08:00
|
|
|
Some(Arc::new(PgCollabStorageImpl::new(
|
|
|
|
SupabaseServerServiceImpl(self.postgres.clone()),
|
|
|
|
)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// [SupabaseServerService] is used to provide supabase services. The caller can using this trait
|
|
|
|
/// to get the services and it might need to handle the situation when the services is unavailable.
|
|
|
|
/// For example, when user stop syncing, the services will be unavailable or when the user is logged
|
|
|
|
/// out.
|
|
|
|
pub trait SupabaseServerService: Send + Sync + 'static {
|
|
|
|
fn get_pg_server(&self) -> Option<Weak<PostgresServer>>;
|
|
|
|
|
|
|
|
fn try_get_pg_server(&self) -> FlowyResult<Weak<PostgresServer>>;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct SupabaseServerServiceImpl(pub Arc<RwLock<Option<Arc<PostgresServer>>>>);
|
|
|
|
impl SupabaseServerService for SupabaseServerServiceImpl {
|
|
|
|
/// Get the postgres server, if the postgres server is not available, return None.
|
|
|
|
fn get_pg_server(&self) -> Option<Weak<PostgresServer>> {
|
|
|
|
self.0.read().as_ref().map(Arc::downgrade)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Try to get the postgres server, if the postgres server is not available, return an error.
|
|
|
|
fn try_get_pg_server(&self) -> FlowyResult<Weak<PostgresServer>> {
|
|
|
|
self.0.read().as_ref().map(Arc::downgrade).ok_or_else(|| {
|
|
|
|
FlowyError::new(
|
|
|
|
ErrorCode::SupabaseSyncRequired,
|
|
|
|
"Supabase sync is disabled, please enable it first",
|
|
|
|
)
|
|
|
|
})
|
2023-05-23 23:55:21 +08:00
|
|
|
}
|
2023-05-21 18:53:59 +08:00
|
|
|
}
|
|
|
|
|
2023-07-05 20:57:09 +08:00
|
|
|
pub struct PostgresServer {
|
2023-07-14 13:37:13 +08:00
|
|
|
request_handler: Arc<PostgresRequestHandler>,
|
2023-05-21 18:53:59 +08:00
|
|
|
}
|
|
|
|
|
2023-07-05 20:57:09 +08:00
|
|
|
impl Deref for PostgresServer {
|
2023-07-14 13:37:13 +08:00
|
|
|
type Target = Arc<PostgresRequestHandler>;
|
2023-07-05 20:57:09 +08:00
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
2023-07-14 13:37:13 +08:00
|
|
|
&self.request_handler
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PostgresServer {
|
|
|
|
pub fn new(config: PostgresConfiguration) -> Self {
|
|
|
|
let (runner_notifier_tx, runner_notifier) = watch::channel(false);
|
|
|
|
let request_handler = Arc::new(PostgresRequestHandler::new(runner_notifier_tx, config));
|
|
|
|
|
|
|
|
// Initialize the connection to the database
|
|
|
|
let conn = PendingRequest::new(PostgresEvent::ConnectDB);
|
|
|
|
request_handler.queue.lock().push(conn);
|
|
|
|
let handler = Arc::downgrade(&request_handler) as Weak<dyn RequestHandler<PostgresEvent>>;
|
|
|
|
spawn(RequestRunner::run(runner_notifier, handler));
|
|
|
|
|
|
|
|
Self { request_handler }
|
2023-05-21 18:53:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-14 13:37:13 +08:00
|
|
|
pub struct PostgresRequestHandler {
|
2023-07-05 20:57:09 +08:00
|
|
|
config: PostgresConfiguration,
|
|
|
|
db: Arc<Mutex<Option<Arc<PostgresDB>>>>,
|
|
|
|
queue: parking_lot::Mutex<RequestQueue<PostgresEvent>>,
|
2023-07-14 13:37:13 +08:00
|
|
|
runner_notifier: Arc<watch::Sender<bool>>,
|
2023-07-05 20:57:09 +08:00
|
|
|
sequence: AtomicU32,
|
|
|
|
}
|
|
|
|
|
2023-07-14 13:37:13 +08:00
|
|
|
impl PostgresRequestHandler {
|
|
|
|
pub fn new(runner_notifier: watch::Sender<bool>, config: PostgresConfiguration) -> Self {
|
2023-07-05 20:57:09 +08:00
|
|
|
let db = Arc::new(Default::default());
|
|
|
|
let queue = parking_lot::Mutex::new(RequestQueue::new());
|
2023-07-14 13:37:13 +08:00
|
|
|
let runner_notifier = Arc::new(runner_notifier);
|
2023-07-05 20:57:09 +08:00
|
|
|
Self {
|
|
|
|
db,
|
|
|
|
queue,
|
2023-07-14 13:37:13 +08:00
|
|
|
runner_notifier,
|
2023-07-05 20:57:09 +08:00
|
|
|
config,
|
|
|
|
sequence: Default::default(),
|
|
|
|
}
|
2023-05-21 18:53:59 +08:00
|
|
|
}
|
2023-05-23 23:55:21 +08:00
|
|
|
|
2023-07-05 20:57:09 +08:00
|
|
|
pub async fn get_pg_client(&self) -> PgClientReceiver {
|
|
|
|
let (tx, rx) = tokio::sync::mpsc::channel(1);
|
|
|
|
let mut queue = self.queue.lock();
|
|
|
|
|
|
|
|
let event = PostgresEvent::GetPgClient {
|
|
|
|
id: self.sequence.fetch_add(1, Ordering::SeqCst),
|
|
|
|
sender: tx,
|
|
|
|
};
|
|
|
|
let request = PendingRequest::new(event);
|
|
|
|
queue.push(request);
|
|
|
|
self.notify();
|
|
|
|
PgClientReceiver(rx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_trait]
|
2023-07-14 13:37:13 +08:00
|
|
|
impl RequestHandler<PostgresEvent> for PostgresRequestHandler {
|
2023-07-05 20:57:09 +08:00
|
|
|
async fn prepare_request(&self) -> Option<PendingRequest<PostgresEvent>> {
|
|
|
|
match self.queue.try_lock() {
|
|
|
|
None => {
|
|
|
|
// If acquire the lock failed, try after 300ms
|
2023-07-14 13:37:13 +08:00
|
|
|
let weak_notifier = Arc::downgrade(&self.runner_notifier);
|
2023-07-05 20:57:09 +08:00
|
|
|
spawn(async move {
|
|
|
|
interval(Duration::from_millis(300)).tick().await;
|
|
|
|
if let Some(notifier) = weak_notifier.upgrade() {
|
|
|
|
let _ = notifier.send(false);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
None
|
|
|
|
},
|
|
|
|
Some(queue) => queue.peek().cloned(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn handle_request(&self, request: PendingRequest<PostgresEvent>) -> Option<()> {
|
|
|
|
debug_assert!(Some(&request) == self.queue.lock().peek());
|
|
|
|
|
|
|
|
match request.payload {
|
|
|
|
PostgresEvent::ConnectDB => {
|
|
|
|
let is_connected = self.db.lock().await.is_some();
|
|
|
|
if is_connected {
|
|
|
|
tracing::warn!("Already connect to postgres db");
|
|
|
|
} else {
|
|
|
|
tracing::info!("Start connecting to postgres db");
|
|
|
|
match PostgresDB::new(self.config.clone()).await {
|
|
|
|
Ok(db) => {
|
|
|
|
*self.db.lock().await = Some(Arc::new(db));
|
|
|
|
if let Some(mut request) = self.queue.lock().pop() {
|
|
|
|
request.set_state(RequestState::Done);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Err(e) => tracing::error!("Error connecting to the postgres db: {}", e),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
PostgresEvent::GetPgClient { id: _, sender } => {
|
|
|
|
match self.db.lock().await.as_ref().map(|db| db.client.clone()) {
|
|
|
|
None => tracing::error!("Can't get the postgres client"),
|
|
|
|
Some(pool) => {
|
|
|
|
match pool.get().await {
|
|
|
|
Ok(object) => {
|
|
|
|
if let Err(e) = sender.send(object).await {
|
|
|
|
tracing::error!("Error sending the postgres client: {}", e);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Err(e) => tracing::error!("Get postgres client failed: {}", e),
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(mut request) = self.queue.lock().pop() {
|
|
|
|
request.set_state(RequestState::Done);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
fn notify(&self) {
|
2023-07-14 13:37:13 +08:00
|
|
|
let _ = self.runner_notifier.send(false);
|
2023-05-23 23:55:21 +08:00
|
|
|
}
|
2023-05-21 18:53:59 +08:00
|
|
|
}
|