feat: prefetch visible observation frontier

This commit is contained in:
2026-09-30 19:26:50 +09:00
parent ea7b0f00ea
commit 06edf62d4e
9 changed files with 440 additions and 68 deletions
+4 -3
View File
@@ -299,7 +299,9 @@ impl App {
#[must_use]
pub fn new(endpoint: impl Into<String>) -> Self {
let mut entries = BTreeMap::new();
entries.insert("/".into(), EntryView::placeholder("/"));
let mut root = EntryView::placeholder("/");
root.expanded = true;
entries.insert("/".into(), root);
Self {
endpoint: endpoint.into(),
connection: ConnectionState::Disconnected,
@@ -556,7 +558,6 @@ impl App {
let entry = self.ensure_entry(&observation.path);
entry.children = children.clone();
entry.tree_state = ViewState::from(&observation.state);
entry.expanded = true;
for path in children {
self.ensure_entry(&path);
}
@@ -876,6 +877,6 @@ mod tests {
wip_client::SecurityContext::new("test"),
)
.unwrap();
client.prepare_observe(&session, "/", 0).unwrap().id
client.refresh_object(&session, "/").unwrap().id
}
}
+30
View File
@@ -608,6 +608,36 @@ mod tests {
.join("\n")
}
#[test]
fn observed_empty_visible_entry_is_labeled_without_expansion() {
let mut app = App::new("https://example.test/wip/");
{
let root = app.entries.get_mut("/").unwrap();
root.children = vec!["/empty".into()];
root.tree_state = ViewState::Fresh;
}
app.entries.insert(
"/empty".into(),
EntryView {
path: "/empty".into(),
object: Some(Object {
name: "empty".into(),
description: None,
interfaces: vec![],
r#ref: None,
validator: None,
}),
state: ViewState::Fresh,
children: vec![],
tree_state: ViewState::Fresh,
expanded: false,
},
);
let snapshot = rendered(&app, 80, 20);
assert!(snapshot.contains("empty [empty]"));
}
#[test]
fn snapshot_contains_non_color_state_markers_and_hides_validators() {
let mut app = App::new("https://example.test/wip/");
+29 -9
View File
@@ -304,7 +304,7 @@ impl<T: Transport> Runtime<T> {
/// Starts or restarts observation at Worldspace `/`.
pub fn connect(&mut self) {
self.app.connection = ConnectionState::Connecting;
match self.client.prepare_observe(&self.session, "/", 1) {
match self.client.refresh_children(&self.session, "/") {
Ok(request) => self.dispatch(request, InFlightKind::Tree("/".into()), false),
Err(error) => self.local_error("connect", error),
}
@@ -317,6 +317,9 @@ impl<T: Transport> Runtime<T> {
for action in actions {
quit |= self.perform(action);
}
if !quit {
self.reconcile_visible_lookahead();
}
quit
}
@@ -347,16 +350,14 @@ impl<T: Transport> Runtime<T> {
fn perform(&mut self, action: Action) -> bool {
match action {
Action::Expand { path } => match self.client.prepare_observe(&self.session, &path, 1) {
Action::Expand { path } => match self.client.refresh_children(&self.session, &path) {
Ok(request) => self.dispatch(request, InFlightKind::Tree(path), false),
Err(error) => self.local_error("tree expansion", error),
},
Action::Refresh { path } => {
match self.client.prepare_observe(&self.session, &path, 1) {
Ok(request) => self.dispatch(request, InFlightKind::Tree(path), false),
Err(error) => self.local_error("subtree refresh", error),
}
}
Action::Refresh { path } => match self.client.refresh_children(&self.session, &path) {
Ok(request) => self.dispatch(request, InFlightKind::Tree(path), false),
Err(error) => self.local_error("subtree refresh", error),
},
Action::FetchInterface(reference) => {
match self.client.prepare_interface(&self.session, &reference) {
Ok(request) => {
@@ -393,7 +394,7 @@ impl<T: Transport> Runtime<T> {
Action::Reconnect => self.connect(),
Action::NavigateEntry(path) => {
self.app.navigate_entry(path.clone());
match self.client.prepare_observe(&self.session, &path, 0) {
match self.client.refresh_object(&self.session, &path) {
Ok(request) => self.dispatch(request, InFlightKind::Object(path), false),
Err(error) => self.local_error("Entry navigation", error),
}
@@ -403,6 +404,24 @@ impl<T: Transport> Runtime<T> {
false
}
fn reconcile_visible_lookahead(&mut self) {
if self.app.connection != ConnectionState::Connected {
return;
}
for path in self.app.visible_paths() {
match self.client.ensure_children_observed(&self.session, &path) {
Ok(Some(request)) => {
self.dispatch(request, InFlightKind::Tree(path), false);
}
Ok(None) => {}
Err(error) => {
self.local_error("observation lookahead", error);
break;
}
}
}
}
fn dispatch(&mut self, request: PreparedRequest, kind: InFlightKind, operation: bool) {
let id = request.id;
self.app.request_started(id.get(), kind.clone());
@@ -567,6 +586,7 @@ impl<T: Transport> Runtime<T> {
}
}
self.reconcile_authoritative();
self.reconcile_visible_lookahead();
}
fn apply_completion(&mut self, completion: Completion, kind: Option<&InFlightKind>) {