fix: fallback tree live events to polling
This commit is contained in:
@@ -17,8 +17,9 @@ use serde_json::{json, Value};
|
||||
use std::convert::Infallible;
|
||||
use std::path::PathBuf;
|
||||
use std::pin::Pin;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
use tokio::sync::broadcast::error::RecvError;
|
||||
use tokio::time::{interval, MissedTickBehavior};
|
||||
|
||||
type BoxedEventStream =
|
||||
Pin<Box<dyn futures_util::Stream<Item = Result<SseEvent, Infallible>> + Send>>;
|
||||
@@ -123,11 +124,6 @@ async fn build_tree_live_stream(
|
||||
canonical_root: PathBuf,
|
||||
root_uri: String,
|
||||
) -> Result<(HeaderMap, BoxedEventStream), WebError> {
|
||||
let subscription = state
|
||||
.local_folder_watcher_registry()
|
||||
.subscribe(&canonical_root)
|
||||
.map_err(|error| WebError::internal(error).with_context(&context))?;
|
||||
|
||||
let workspace_id = local_workspace_id_from_root_uri(&root_uri)
|
||||
.map_err(|error| error.with_context(&context))?;
|
||||
|
||||
@@ -148,6 +144,27 @@ async fn build_tree_live_stream(
|
||||
&file_tree_snapshot,
|
||||
);
|
||||
|
||||
let subscription = match state
|
||||
.local_folder_watcher_registry()
|
||||
.subscribe(&canonical_root)
|
||||
{
|
||||
Ok(subscription) => subscription,
|
||||
Err(error) => {
|
||||
tracing::warn!(
|
||||
error = %error,
|
||||
root_uri = %root_uri,
|
||||
"local_folder tree live watcher unavailable; falling back to revision polling"
|
||||
);
|
||||
let stream = build_tree_live_polling_stream(
|
||||
root_uri,
|
||||
workspace_id,
|
||||
revision.revision,
|
||||
initial_payload,
|
||||
);
|
||||
return Ok((HeaderMap::new(), stream));
|
||||
}
|
||||
};
|
||||
|
||||
let stream = stream::unfold(
|
||||
(Some(initial_payload), subscription, root_uri, workspace_id),
|
||||
|(payload, mut subscription, root_uri, workspace_id)| async move {
|
||||
@@ -184,6 +201,67 @@ async fn build_tree_live_stream(
|
||||
Ok((HeaderMap::new(), stream))
|
||||
}
|
||||
|
||||
fn build_tree_live_polling_stream(
|
||||
root_uri: String,
|
||||
workspace_id: String,
|
||||
initial_revision: String,
|
||||
initial_payload: Value,
|
||||
) -> BoxedEventStream {
|
||||
let mut poll_interval = interval(Duration::from_millis(1_200));
|
||||
poll_interval.set_missed_tick_behavior(MissedTickBehavior::Skip);
|
||||
|
||||
stream::unfold(
|
||||
Some(TreeLivePollingState {
|
||||
root_uri,
|
||||
workspace_id,
|
||||
current_revision: initial_revision,
|
||||
initial_payload: Some(initial_payload),
|
||||
poll_interval,
|
||||
}),
|
||||
|state| async move {
|
||||
let mut state = state?;
|
||||
if let Some(payload) = state.initial_payload.take() {
|
||||
return Some((Ok(stream_event("snapshot", &payload)), Some(state)));
|
||||
}
|
||||
|
||||
loop {
|
||||
state.poll_interval.tick().await;
|
||||
let Some((next_revision, resync_payload)) = tree_live_polling_resync_payload(
|
||||
&state.root_uri,
|
||||
&state.workspace_id,
|
||||
&state.current_revision,
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
state.current_revision = next_revision;
|
||||
return Some((Ok(stream_event("resync", &resync_payload)), Some(state)));
|
||||
}
|
||||
},
|
||||
)
|
||||
.boxed()
|
||||
}
|
||||
|
||||
struct TreeLivePollingState {
|
||||
root_uri: String,
|
||||
workspace_id: String,
|
||||
current_revision: String,
|
||||
initial_payload: Option<Value>,
|
||||
poll_interval: tokio::time::Interval,
|
||||
}
|
||||
|
||||
fn tree_live_polling_resync_payload(
|
||||
root_uri: &str,
|
||||
workspace_id: &str,
|
||||
current_revision: &str,
|
||||
) -> Option<(String, Value)> {
|
||||
let next_revision = local_folder_watch_revision(root_uri).ok()?;
|
||||
if next_revision.revision == current_revision {
|
||||
return None;
|
||||
}
|
||||
let resync_payload = rebuild_tree_resync_payload(root_uri, workspace_id)?;
|
||||
Some((next_revision.revision, resync_payload))
|
||||
}
|
||||
|
||||
fn rebuild_tree_resync_payload(root_uri: &str, workspace_id: &str) -> Option<Value> {
|
||||
let revision = local_folder_watch_revision(root_uri).ok()?;
|
||||
let sidebar_snapshot = load_local_folder_page_tree_snapshot(root_uri).ok()?;
|
||||
|
||||
Reference in New Issue
Block a user