Skip to main content

Mountain/IPC/WindServiceHandlers/TreeView/
GetChildren.rs

1//! Wire method: `tree:getChildren`.
2//! Renderer-side tree-view child lookup. Mirrors the Cocoon→Mountain
3//! `GetTreeChildren` gRPC path but is invoked directly by the Wind/Sky
4//! tree-view bridge so the UI can request children without waiting for
5//! Cocoon to ask first.
6//!
7//! Waits up to 5 s for the Cocoon gRPC connection (boot-race guard) then
8//! dispatches `$provideTreeChildren` with a 5 s timeout. On timeout or
9//! extension rejection the workbench receives `{ items: [] }` and schedules
10//! its own retry when the view scrolls back into view.
11
12use std::sync::Arc;
13
14use serde_json::{Value, json};
15use tauri::AppHandle;
16
17use crate::RunTime::ApplicationRunTime::ApplicationRunTime;
18
19pub async fn Fn(
20	ApplicationHandle:AppHandle,
21
22	RunTime:Arc<ApplicationRunTime>,
23
24	Arguments:Vec<Value>,
25) -> Result<Value, String> {
26	let ViewId = Arguments
27		.first()
28		.and_then(|V| V.get("viewId").or_else(|| V.get(0)))
29		.and_then(Value::as_str)
30		.unwrap_or("")
31		.to_string();
32
33	let ItemHandle = Arguments
34		.first()
35		.and_then(|V| V.get("treeItemHandle").or_else(|| V.get(1)))
36		.and_then(Value::as_str)
37		.unwrap_or("")
38		.to_string();
39
40	crate::dev_log!(
41		"tree-view",
42		"[TreeView] invoke:getChildren view={} parent={}",
43		ViewId,
44		ItemHandle
45	);
46
47	if ViewId.is_empty() {
48		return Err("tree:getChildren requires viewId".to_string());
49	}
50
51	let Parameters = json!({
52		"viewId": ViewId,
53		"treeItemHandle": ItemHandle,
54	});
55
56	// Boot-race: the workbench's Explorer view fires `tree:getChildren` ~700
57	// log lines before Cocoon's gRPC client finishes handshaking. Without
58	// this wait the first call returns `ClientNotConnected`, the workbench
59	// caches an empty list, and the Explorer never recovers without a manual
60	// refresh. 5000 ms chosen from boot-trace observation.
61	let _ = ::Vine::Client::WaitForClientConnection::Fn("cocoon-main", 5000).await;
62
63	match ::Vine::Client::SendRequest::Fn(
64		"cocoon-main",
65		"$provideTreeChildren".to_string(),
66		Parameters,
67		// 15000 ms: warm tree calls take 1-50 ms but cold scans can
68		// blow well past 5 s on first activation (`npm` walks every
69		// `package.json` in the workspace; `vscode.git` enumerates
70		// every nested submodule). 5 s repeatedly tripped on multi-
71		// repo workspaces like Land itself, so the panel rendered
72		// empty until the user manually refreshed. Bumping to 15 s
73		// keeps the upper bound bounded (renderer still receives
74		// `{items:[]}` on real hang) while letting genuine cold
75		// scans complete.
76		15000,
77	)
78	.await
79	{
80		Ok(Value_) => {
81			match &Value_ {
82				Value::Object(_) | Value::Array(_) => Ok(Value_),
83
84				// Non-conforming shape: force to {items:[]} so the renderer
85				// always has iterable data and avoids TypeError crashes.
86				_ => Ok(json!({ "items": [] })),
87			}
88		},
89
90		Err(Error) => {
91			// Log first failure per view; silence repeats so the dev log
92			// doesn't fill with identical lines while the user browses
93			// nodes from a misbehaving extension.
94			crate::IPC::DevLog::DebugOnce::Fn(
95				"tree-view",
96				&format!("get-children-error:{}", ViewId),
97				&format!(
98					"[TreeView] invoke:getChildren error view={} err={:?} (further occurrences silenced)",
99					ViewId, Error
100				),
101			);
102
103			Ok(json!({ "items": [] }))
104		},
105	}
106}