Implement grid and directory discovery (#71)
All checks were successful
Native code generation / deterministic (push) Successful in 15m16s
Imaging and meshing gate / native (push) Successful in 5m9s
JPEG 2000 feature / linux (push) Successful in 2m47s
Native Rust workspace compile / compile (push) Successful in 5m14s
Skia feature / linux (push) Successful in 31m28s

This commit is contained in:
2026-08-10 17:45:08 +00:00
parent d537a37172
commit 66fbb87b3f
14 changed files with 3949 additions and 1541 deletions

View File

@@ -375,7 +375,10 @@ async fn run_seed_requests(weak: Weak<CapsInner>, cancellation: CancellationToke
.await;
match response {
Ok((response, data)) if response.is_success_status_code() => {
if install_seed_response(&inner, &simulator, data).is_ok() {
if install_seed_response(&inner, &simulator, data, cancellation.clone())
.await
.is_ok()
{
return;
}
}
@@ -392,10 +395,11 @@ async fn run_seed_requests(weak: Weak<CapsInner>, cancellation: CancellationToke
}
}
fn install_seed_response(
async fn install_seed_response(
inner: &Arc<CapsInner>,
simulator: &Simulator,
data: Vec<u8>,
cancellation: CancellationToken,
) -> Result<(), Error> {
let OSD::Map(map) = OSDParser::deserialize_with_bytes(data)? else {
return Err(Error::Parse {
@@ -439,6 +443,24 @@ fn install_seed_response(
queue.start()?;
*mutex(&inner.event_queue) = Some(queue);
}
// SimulatorFeatures is a GET capability, not merely an event-queue
// message. Load its initial snapshot before announcing that capability
// discovery is complete, while still allowing grids that omit or reject
// the optional endpoint to finish seed discovery normally.
let simulator_features_uri = read(&inner.caps).get("SimulatorFeatures").cloned();
if let Some(uri) = simulator_features_uri
&& let Ok((response, bytes)) = simulator
.client
.native_http_caps_client()
.get(uri, cancellation.clone(), None)
.await
&& response.is_success_status_code()
&& bytes.len() <= 8 * 1024 * 1024
{
let _ = simulator.features.set_features(None, Some(bytes), None);
}
cancellation.throw_if_cancellation_requested()?;
inner.emit_capabilities_received(simulator.clone());
Ok(())
}
@@ -635,6 +657,10 @@ mod tests {
"GetTexture".to_owned(),
OSD::Uri(Uri("https://asset.example.test/texture".to_owned())),
),
(
"SimulatorFeatures".to_owned(),
OSD::Uri(Uri("https://caps.example.test/features".to_owned())),
),
(
"InvalidScheme".to_owned(),
OSD::Uri(Uri("file:///private/capability".to_owned())),
@@ -654,12 +680,22 @@ mod tests {
let release = Arc::clone(&release);
async move {
let is_seed = request.uri.0.contains("/seed");
let is_features = request.uri.0.contains("/features");
lock(&recorded).push(request);
if is_seed {
while !release.load(Ordering::Acquire) {
tokio::time::sleep(Duration::from_millis(1)).await;
}
response(200, seed_body())
} else if is_features {
response(
200,
OSDParser::serialize_llsd_xml_bytes(OSD::Map(HashMap::from([(
"MeshRezEnabled".to_owned(),
OSD::Boolean(true),
)])))
.unwrap(),
)
} else {
response(404, Vec::new())
}
@@ -708,6 +744,10 @@ mod tests {
None
);
assert!(caps.event_queue().is_some());
assert_eq!(
simulator.features.get("MeshRezEnabled".to_owned()).unwrap(),
Some(OSD::Boolean(true))
);
let deadline = Instant::now() + Duration::from_secs(2);
while lock(&requests).len() < 2 && Instant::now() < deadline {