Implement native asset pipeline and cache (#64)
Some checks failed
Native code generation / deterministic (push) Failing after 2m18s
Imaging and meshing gate / native (push) Failing after 1m30s
JPEG 2000 feature / linux (push) Successful in 2m40s
Native Rust workspace compile / compile (push) Failing after 57s
Skia feature / linux (push) Successful in 31m8s

This commit is contained in:
2026-08-10 07:51:17 +00:00
parent d5c318d280
commit 52f62d8c39
23 changed files with 4511 additions and 1620 deletions

View File

@@ -4396,6 +4396,117 @@ fn parse_task_inventory_values(
Ok(result)
}
impl InventoryManager {
pub(crate) async fn native_update_material_inventory(
&self,
material: crate::assets::AssetMaterial,
material_item_id: UUID,
task_id: Option<UUID>,
cancellation_token: Option<CancellationToken>,
progress: Option<
Box<dyn libremetaverse_types::compat::IProgress<crate::HttpCapsClientProgressReport>>,
>,
) -> Result<(bool, String, UUID, UUID), Error> {
let client = self.client()?;
let simulator = client
.native_network()?
.current_sim()
.ok_or(Error::InvalidOperation)?;
let caps = simulator.native_caps().ok_or(Error::InvalidOperation)?;
let name = if task_id.is_some() {
"UpdateMaterialTaskInventory"
} else {
"UpdateMaterialAgentInventory"
};
let deadline = Instant::now() + Duration::from_secs(2);
let uri = loop {
if let Some(uri) = caps.capability_uri(name.to_owned())? {
break uri;
}
if caps.seed_request_finished() || Instant::now() >= deadline {
return Err(Error::InvalidOperation);
}
std::thread::sleep(Duration::from_millis(1));
};
let mut query = HashMap::from([("item_id".to_owned(), OSD::UUID(material_item_id))]);
if let Some(task_id) = task_id {
query.insert("task_id".to_owned(), OSD::UUID(task_id));
}
let payload = OSDParser::serialize_llsd_xml_bytes(OSD::Map(query))?;
let token = cancellation_token.unwrap_or_default();
let (response, metadata) = client
.native_http_caps_client()
.post_with_uri_string_bytes_cancellation_token_i_progress(
uri,
"application/llsd+xml".into(),
payload,
token.clone(),
None,
)
.await?;
if !(200..300).contains(&response.status_code) {
return Ok((
false,
format!("HTTP {}", response.status_code),
UUID::zero(),
UUID::zero(),
));
}
let meta: serde_json::Value =
serde_json::from_slice(&metadata).map_err(|_| Error::Argument)?;
let status = meta
.get("state")
.and_then(serde_json::Value::as_str)
.unwrap_or_default()
.to_owned();
let uploader = meta
.get("uploader")
.and_then(serde_json::Value::as_str)
.ok_or(Error::Argument)?
.to_owned();
let data = material.to_json()?.into_bytes();
let (upload_response, response_body) = client
.native_http_caps_client()
.post_with_uri_string_bytes_cancellation_token_i_progress(
Uri(uploader),
"application/octet-stream".into(),
data,
token,
progress,
)
.await?;
if !(200..300).contains(&upload_response.status_code) {
return Ok((
false,
format!("HTTP {}", upload_response.status_code),
material_item_id,
UUID::zero(),
));
}
let result: serde_json::Value =
serde_json::from_slice(&response_body).map_err(|_| Error::Argument)?;
let final_status = result
.get("state")
.and_then(serde_json::Value::as_str)
.unwrap_or(&status)
.to_owned();
let asset_id = result
.get("new_asset")
.or_else(|| result.get("new_asset_id"))
.and_then(serde_json::Value::as_str)
.map(|id| UUID::new_with_string(id.to_owned()))
.transpose()?
.unwrap_or_else(UUID::zero);
let item_id = result
.get("item_id")
.and_then(serde_json::Value::as_str)
.map(|id| UUID::new_with_string(id.to_owned()))
.transpose()?
.unwrap_or(material_item_id);
Ok((final_status == "complete", final_status, asset_id, item_id))
}
}
#[cfg(test)]
mod tests {
use super::*;