chore: remove realtime shared state
This commit is contained in:
parent
1fbb971b83
commit
f9397eaaf2
|
|
@ -167,9 +167,6 @@ pub trait CollabStorage: Send + Sync + 'static {
|
||||||
|
|
||||||
/// Returns list of snapshots for given object_id in descending order of creation time.
|
/// Returns list of snapshots for given object_id in descending order of creation time.
|
||||||
async fn get_collab_snapshot_list(&self, oid: &str) -> AppResult<AFSnapshotMetas>;
|
async fn get_collab_snapshot_list(&self, oid: &str) -> AppResult<AFSnapshotMetas>;
|
||||||
|
|
||||||
async fn add_connected_user(&self, uid: i64, device_id: &str);
|
|
||||||
async fn remove_connected_user(&self, uid: i64, device_id: &str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|
@ -306,14 +303,6 @@ where
|
||||||
async fn get_collab_snapshot_list(&self, oid: &str) -> AppResult<AFSnapshotMetas> {
|
async fn get_collab_snapshot_list(&self, oid: &str) -> AppResult<AFSnapshotMetas> {
|
||||||
self.as_ref().get_collab_snapshot_list(oid).await
|
self.as_ref().get_collab_snapshot_list(oid).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn add_connected_user(&self, uid: i64, device_id: &str) {
|
|
||||||
self.as_ref().add_connected_user(uid, device_id).await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn remove_connected_user(&self, uid: i64, device_id: &str) {
|
|
||||||
self.as_ref().remove_connected_user(uid, device_id).await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
|
|
||||||
|
|
@ -115,15 +115,6 @@ async fn post_realtime_message_stream_handler(
|
||||||
|
|
||||||
event!(tracing::Level::INFO, "message len: {}", bytes.len());
|
event!(tracing::Level::INFO, "message len: {}", bytes.len());
|
||||||
let device_id = device_id.to_string();
|
let device_id = device_id.to_string();
|
||||||
// Only send message to websocket server when the user is connected
|
|
||||||
if !state
|
|
||||||
.realtime_shared_state
|
|
||||||
.is_user_connected(&uid, &device_id)
|
|
||||||
.await
|
|
||||||
.unwrap_or(false)
|
|
||||||
{
|
|
||||||
return Ok(Json(AppResponse::Ok()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let message = parser_realtime_msg(bytes.freeze(), req.clone()).await?;
|
let message = parser_realtime_msg(bytes.freeze(), req.clone()).await?;
|
||||||
let stream_message = ClientStreamMessage {
|
let stream_message = ClientStreamMessage {
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ use crate::command::{CLCommandReceiver, CLCommandSender};
|
||||||
use crate::config::{Config, DatabaseSetting};
|
use crate::config::{Config, DatabaseSetting};
|
||||||
use crate::indexer::IndexerProvider;
|
use crate::indexer::IndexerProvider;
|
||||||
use crate::pg_listener::PgListeners;
|
use crate::pg_listener::PgListeners;
|
||||||
use crate::shared_state::RealtimeSharedState;
|
|
||||||
use crate::snapshot::SnapshotControl;
|
use crate::snapshot::SnapshotControl;
|
||||||
use crate::state::{AppMetrics, AppState, UserCache};
|
use crate::state::{AppMetrics, AppState, UserCache};
|
||||||
use crate::CollaborationServer;
|
use crate::CollaborationServer;
|
||||||
|
|
@ -108,10 +107,6 @@ pub async fn init_state(config: &Config, rt_cmd_tx: CLCommandSender) -> Result<A
|
||||||
|
|
||||||
info!("Connecting to Redis...");
|
info!("Connecting to Redis...");
|
||||||
let redis_conn_manager = get_redis_client(config.redis_uri.expose_secret()).await?;
|
let redis_conn_manager = get_redis_client(config.redis_uri.expose_secret()).await?;
|
||||||
let realtime_shared_state = RealtimeSharedState::new(redis_conn_manager.clone());
|
|
||||||
if let Err(err) = realtime_shared_state.remove_all_connected_users().await {
|
|
||||||
warn!("Failed to remove all connected users: {:?}", err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pg listeners
|
// Pg listeners
|
||||||
info!("Setting up Pg listeners...");
|
info!("Setting up Pg listeners...");
|
||||||
|
|
@ -158,7 +153,6 @@ pub async fn init_state(config: &Config, rt_cmd_tx: CLCommandSender) -> Result<A
|
||||||
access_control,
|
access_control,
|
||||||
collab_access_control_storage: collab_storage,
|
collab_access_control_storage: collab_storage,
|
||||||
metrics,
|
metrics,
|
||||||
realtime_shared_state,
|
|
||||||
indexer_provider,
|
indexer_provider,
|
||||||
};
|
};
|
||||||
Ok(app_state)
|
Ok(app_state)
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ use tracing::{error, instrument, trace};
|
||||||
use validator::Validate;
|
use validator::Validate;
|
||||||
|
|
||||||
use crate::command::{CLCommandSender, CollaborationCommand};
|
use crate::command::{CLCommandSender, CollaborationCommand};
|
||||||
use crate::shared_state::RealtimeSharedState;
|
|
||||||
use app_error::AppError;
|
use app_error::AppError;
|
||||||
use database::collab::{
|
use database::collab::{
|
||||||
insert_into_af_collab_bulk_for_user, AppResult, CollabMetadata, CollabStorage,
|
insert_into_af_collab_bulk_for_user, AppResult, CollabMetadata, CollabStorage,
|
||||||
|
|
@ -47,7 +46,6 @@ pub struct CollabStorageImpl<AC> {
|
||||||
snapshot_control: SnapshotControl,
|
snapshot_control: SnapshotControl,
|
||||||
rt_cmd_sender: CLCommandSender,
|
rt_cmd_sender: CLCommandSender,
|
||||||
queue: Arc<StorageQueue>,
|
queue: Arc<StorageQueue>,
|
||||||
shared_state: RealtimeSharedState,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<AC> CollabStorageImpl<AC>
|
impl<AC> CollabStorageImpl<AC>
|
||||||
|
|
@ -62,7 +60,6 @@ where
|
||||||
redis_conn_manager: RedisConnectionManager,
|
redis_conn_manager: RedisConnectionManager,
|
||||||
metrics: Arc<CollabMetrics>,
|
metrics: Arc<CollabMetrics>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let shared_state = RealtimeSharedState::new(redis_conn_manager.clone());
|
|
||||||
let queue = Arc::new(StorageQueue::new_with_metrics(
|
let queue = Arc::new(StorageQueue::new_with_metrics(
|
||||||
cache.clone(),
|
cache.clone(),
|
||||||
redis_conn_manager,
|
redis_conn_manager,
|
||||||
|
|
@ -75,7 +72,6 @@ where
|
||||||
snapshot_control,
|
snapshot_control,
|
||||||
rt_cmd_sender,
|
rt_cmd_sender,
|
||||||
queue,
|
queue,
|
||||||
shared_state,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -488,22 +484,6 @@ where
|
||||||
self.snapshot_control.get_collab_snapshot_list(oid).await
|
self.snapshot_control.get_collab_snapshot_list(oid).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn add_connected_user(&self, uid: i64, device_id: &str) {
|
|
||||||
if let Err(err) = self.shared_state.add_connected_user(uid, device_id).await {
|
|
||||||
error!("Failed to add connected user: {}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn remove_connected_user(&self, uid: i64, device_id: &str) {
|
|
||||||
if let Err(err) = self
|
|
||||||
.shared_state
|
|
||||||
.remove_connected_user(uid, device_id)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
error!("Failed to remove connected user: {}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn broadcast_encode_collab(
|
async fn broadcast_encode_collab(
|
||||||
&self,
|
&self,
|
||||||
object_id: String,
|
object_id: String,
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ pub mod metrics;
|
||||||
mod permission;
|
mod permission;
|
||||||
mod pg_listener;
|
mod pg_listener;
|
||||||
mod rt_server;
|
mod rt_server;
|
||||||
pub mod shared_state;
|
|
||||||
pub mod snapshot;
|
pub mod snapshot;
|
||||||
mod state;
|
mod state;
|
||||||
pub mod telemetry;
|
pub mod telemetry;
|
||||||
|
|
|
||||||
|
|
@ -126,10 +126,6 @@ where
|
||||||
let storage = self.storage.clone();
|
let storage = self.storage.clone();
|
||||||
|
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
storage
|
|
||||||
.add_connected_user(connected_user.uid, &connected_user.device_id)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
if let Some(old_user) = connect_state.handle_user_connect(connected_user, new_client_router) {
|
if let Some(old_user) = connect_state.handle_user_connect(connected_user, new_client_router) {
|
||||||
// Remove the old user from all collaboration groups.
|
// Remove the old user from all collaboration groups.
|
||||||
group_manager.remove_user(&old_user).await;
|
group_manager.remove_user(&old_user).await;
|
||||||
|
|
@ -161,10 +157,6 @@ where
|
||||||
trace!("[realtime]: disconnect => {}", disconnect_user);
|
trace!("[realtime]: disconnect => {}", disconnect_user);
|
||||||
let was_removed = connect_state.handle_user_disconnect(&disconnect_user);
|
let was_removed = connect_state.handle_user_disconnect(&disconnect_user);
|
||||||
if was_removed.is_some() {
|
if was_removed.is_some() {
|
||||||
storage
|
|
||||||
.remove_connected_user(disconnect_user.uid, &disconnect_user.device_id)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
metrics_calculate
|
metrics_calculate
|
||||||
.connected_users
|
.connected_users
|
||||||
.set(connect_state.number_of_connected_users() as i64);
|
.set(connect_state.number_of_connected_users() as i64);
|
||||||
|
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
use crate::error::RealtimeError;
|
|
||||||
use futures_util::StreamExt;
|
|
||||||
use redis::{pipe, AsyncCommands, AsyncIter};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct RealtimeSharedState {
|
|
||||||
redis_conn_manager: redis::aio::ConnectionManager,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RealtimeSharedState {
|
|
||||||
pub fn new(redis_conn_manager: redis::aio::ConnectionManager) -> Self {
|
|
||||||
Self { redis_conn_manager }
|
|
||||||
}
|
|
||||||
pub async fn add_connected_user(&self, uid: i64, device_id: &str) -> Result<(), RealtimeError> {
|
|
||||||
let mut conn = self.redis_conn_manager.clone();
|
|
||||||
let key = realtime_shared_state_cache_key(&uid, device_id);
|
|
||||||
conn
|
|
||||||
.set_ex(key, "1", 60 * 60 * 3)
|
|
||||||
.await
|
|
||||||
.map_err(|err| RealtimeError::Internal(err.into()))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn remove_connected_user(
|
|
||||||
&self,
|
|
||||||
uid: i64,
|
|
||||||
device_id: &str,
|
|
||||||
) -> Result<(), RealtimeError> {
|
|
||||||
let mut conn = self.redis_conn_manager.clone();
|
|
||||||
let key = realtime_shared_state_cache_key(&uid, device_id);
|
|
||||||
conn
|
|
||||||
.del(key)
|
|
||||||
.await
|
|
||||||
.map_err(|err| RealtimeError::Internal(err.into()))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn is_user_connected(&self, uid: &i64, device_id: &str) -> Result<bool, RealtimeError> {
|
|
||||||
let mut conn = self.redis_conn_manager.clone();
|
|
||||||
let key = realtime_shared_state_cache_key(uid, device_id);
|
|
||||||
let result: Option<String> = conn
|
|
||||||
.get(key)
|
|
||||||
.await
|
|
||||||
.map_err(|err| RealtimeError::Internal(err.into()))?;
|
|
||||||
Ok(result.is_some())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn remove_all_connected_users(&self) -> Result<(), RealtimeError> {
|
|
||||||
let mut conn = self.redis_conn_manager.clone();
|
|
||||||
let iter: AsyncIter<String> = conn
|
|
||||||
.scan_match(format!("{}:*", REALTIME_SHARE_STATE_PREFIX))
|
|
||||||
.await
|
|
||||||
.map_err(|err| RealtimeError::Internal(err.into()))?;
|
|
||||||
let keys_to_delete: Vec<_> = iter.collect().await;
|
|
||||||
if !keys_to_delete.is_empty() {
|
|
||||||
let mut pipeline = pipe();
|
|
||||||
for key in keys_to_delete.iter() {
|
|
||||||
pipeline.del(key);
|
|
||||||
}
|
|
||||||
pipeline
|
|
||||||
.query_async(&mut conn)
|
|
||||||
.await
|
|
||||||
.map_err(|err| RealtimeError::Internal(err.into()))?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) const REALTIME_SHARE_STATE_PREFIX: &str = "realtime_shared_state_v0";
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn realtime_shared_state_cache_key(uid: &i64, device_id: &str) -> String {
|
|
||||||
format!("{}:{}:{}", REALTIME_SHARE_STATE_PREFIX, uid, device_id)
|
|
||||||
}
|
|
||||||
|
|
@ -15,7 +15,6 @@ use crate::config::Config;
|
||||||
use crate::indexer::IndexerProvider;
|
use crate::indexer::IndexerProvider;
|
||||||
use crate::metrics::CollabMetrics;
|
use crate::metrics::CollabMetrics;
|
||||||
use crate::pg_listener::PgListeners;
|
use crate::pg_listener::PgListeners;
|
||||||
use crate::shared_state::RealtimeSharedState;
|
|
||||||
use crate::CollabRealtimeMetrics;
|
use crate::CollabRealtimeMetrics;
|
||||||
|
|
||||||
pub type RedisConnectionManager = redis::aio::ConnectionManager;
|
pub type RedisConnectionManager = redis::aio::ConnectionManager;
|
||||||
|
|
@ -29,7 +28,6 @@ pub struct AppState {
|
||||||
pub access_control: AccessControl,
|
pub access_control: AccessControl,
|
||||||
pub collab_access_control_storage: Arc<CollabAccessControlStorage>,
|
pub collab_access_control_storage: Arc<CollabAccessControlStorage>,
|
||||||
pub metrics: AppMetrics,
|
pub metrics: AppMetrics,
|
||||||
pub realtime_shared_state: RealtimeSharedState,
|
|
||||||
pub indexer_provider: Arc<IndexerProvider>,
|
pub indexer_provider: Arc<IndexerProvider>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1517,15 +1517,6 @@ async fn post_realtime_message_stream_handler(
|
||||||
|
|
||||||
event!(tracing::Level::INFO, "message len: {}", bytes.len());
|
event!(tracing::Level::INFO, "message len: {}", bytes.len());
|
||||||
let device_id = device_id.to_string();
|
let device_id = device_id.to_string();
|
||||||
// Only send message to websocket server when the user is connected
|
|
||||||
if !state
|
|
||||||
.realtime_shared_state
|
|
||||||
.is_user_connected(&uid, &device_id)
|
|
||||||
.await
|
|
||||||
.unwrap_or(false)
|
|
||||||
{
|
|
||||||
return Ok(Json(AppResponse::Ok()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let message = parser_realtime_msg(bytes.freeze(), req.clone()).await?;
|
let message = parser_realtime_msg(bytes.freeze(), req.clone()).await?;
|
||||||
let stream_message = ClientStreamMessage {
|
let stream_message = ClientStreamMessage {
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,6 @@ use appflowy_collaborate::actix_ws::server::RealtimeServerActor;
|
||||||
use appflowy_collaborate::collab::storage::CollabStorageImpl;
|
use appflowy_collaborate::collab::storage::CollabStorageImpl;
|
||||||
use appflowy_collaborate::command::{CLCommandReceiver, CLCommandSender};
|
use appflowy_collaborate::command::{CLCommandReceiver, CLCommandSender};
|
||||||
use appflowy_collaborate::indexer::IndexerProvider;
|
use appflowy_collaborate::indexer::IndexerProvider;
|
||||||
use appflowy_collaborate::shared_state::RealtimeSharedState;
|
|
||||||
use appflowy_collaborate::snapshot::SnapshotControl;
|
use appflowy_collaborate::snapshot::SnapshotControl;
|
||||||
use appflowy_collaborate::CollaborationServer;
|
use appflowy_collaborate::CollaborationServer;
|
||||||
use database::file::s3_client_impl::{AwsS3BucketClientImpl, S3BucketStorage};
|
use database::file::s3_client_impl::{AwsS3BucketClientImpl, S3BucketStorage};
|
||||||
|
|
@ -316,10 +315,6 @@ pub async fn init_state(config: &Config, rt_cmd_tx: CLCommandSender) -> Result<A
|
||||||
|
|
||||||
let grpc_history_client = Arc::new(Mutex::new(HistoryClient::new(channel)));
|
let grpc_history_client = Arc::new(Mutex::new(HistoryClient::new(channel)));
|
||||||
let mailer = get_mailer(config).await?;
|
let mailer = get_mailer(config).await?;
|
||||||
let realtime_shared_state = RealtimeSharedState::new(redis_conn_manager.clone());
|
|
||||||
if let Err(err) = realtime_shared_state.remove_all_connected_users().await {
|
|
||||||
warn!("Failed to remove all connected users: {:?}", err);
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("Application state initialized");
|
info!("Application state initialized");
|
||||||
Ok(AppState {
|
Ok(AppState {
|
||||||
|
|
@ -343,7 +338,6 @@ pub async fn init_state(config: &Config, rt_cmd_tx: CLCommandSender) -> Result<A
|
||||||
mailer,
|
mailer,
|
||||||
ai_client: appflowy_ai_client,
|
ai_client: appflowy_ai_client,
|
||||||
grpc_history_client,
|
grpc_history_client,
|
||||||
realtime_shared_state,
|
|
||||||
indexer_provider,
|
indexer_provider,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ use appflowy_ai_client::client::AppFlowyAIClient;
|
||||||
use appflowy_collaborate::collab::storage::CollabAccessControlStorage;
|
use appflowy_collaborate::collab::storage::CollabAccessControlStorage;
|
||||||
use appflowy_collaborate::indexer::IndexerProvider;
|
use appflowy_collaborate::indexer::IndexerProvider;
|
||||||
use appflowy_collaborate::metrics::CollabMetrics;
|
use appflowy_collaborate::metrics::CollabMetrics;
|
||||||
use appflowy_collaborate::shared_state::RealtimeSharedState;
|
|
||||||
use appflowy_collaborate::CollabRealtimeMetrics;
|
use appflowy_collaborate::CollabRealtimeMetrics;
|
||||||
use database::file::s3_client_impl::{AwsS3BucketClientImpl, S3BucketStorage};
|
use database::file::s3_client_impl::{AwsS3BucketClientImpl, S3BucketStorage};
|
||||||
use database::user::{select_all_uid_uuid, select_uid_from_uuid};
|
use database::user::{select_all_uid_uuid, select_uid_from_uuid};
|
||||||
|
|
@ -54,7 +53,6 @@ pub struct AppState {
|
||||||
pub gotrue_admin: GoTrueAdmin,
|
pub gotrue_admin: GoTrueAdmin,
|
||||||
pub mailer: AFCloudMailer,
|
pub mailer: AFCloudMailer,
|
||||||
pub ai_client: AppFlowyAIClient,
|
pub ai_client: AppFlowyAIClient,
|
||||||
pub realtime_shared_state: RealtimeSharedState,
|
|
||||||
pub grpc_history_client: Arc<Mutex<HistoryClient<tonic::transport::Channel>>>,
|
pub grpc_history_client: Arc<Mutex<HistoryClient<tonic::transport::Channel>>>,
|
||||||
pub indexer_provider: Arc<IndexerProvider>,
|
pub indexer_provider: Arc<IndexerProvider>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue