Files
MetaCrate/crates/libremetaverse/src/transfers.rs
Chili Palmer 52f62d8c39
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
Implement native asset pipeline and cache (#64)
2026-08-10 07:51:17 +00:00

227 lines
5.6 KiB
Rust

//! Asset transfer state shared by HTTP and LLUDP pipelines.
#![allow(clippy::missing_errors_doc, clippy::must_use_candidate)]
use crate::{
ChannelType, Error, ImageCodec, ImageType, Simulator, SourceType, StatusCode, TargetType,
TransferError,
};
use libremetaverse_types::compat::SortedList;
use libremetaverse_types::{AssetType, UUID};
use std::collections::HashMap;
use std::sync::RwLock;
use std::time::Instant;
#[derive(Clone, Debug)]
pub struct Transfer {
pub asset_data: Vec<u8>,
pub asset_type: AssetType,
pub id: UUID,
pub size: i32,
pub success: bool,
pub transferred: i32,
pub(crate) last_packet: Instant,
}
impl Transfer {
pub fn new() -> Result<Self, Error> {
Ok(Self {
asset_data: Vec::new(),
asset_type: AssetType::Unknown,
id: UUID::zero(),
size: 0,
success: false,
transferred: 0,
last_packet: Instant::now(),
})
}
pub fn time_since_last_packet(&self) -> i32 {
i32::try_from(self.last_packet.elapsed().as_millis()).unwrap_or(i32::MAX)
}
pub fn set_time_since_last_packet(&mut self, value: i32) {
self.last_packet = Instant::now()
.checked_sub(std::time::Duration::from_millis(
u64::try_from(value.max(0)).unwrap_or(0),
))
.unwrap_or_else(Instant::now);
}
}
#[derive(Debug)]
pub struct AssetDownload {
pub asset_id: UUID,
pub channel: ChannelType,
pub priority: f32,
pub simulator: Option<Simulator>,
pub source: SourceType,
pub status: StatusCode,
pub target: TargetType,
pub next_packet: i32,
pub out_of_order_packets: RwLock<HashMap<i32, Vec<u8>>>,
pub base: Transfer,
}
impl AssetDownload {
pub fn new() -> Result<Self, Error> {
Ok(Self {
asset_id: UUID::zero(),
channel: ChannelType::Asset,
priority: 0.0,
simulator: None,
source: SourceType::Asset,
status: StatusCode::Unknown,
target: TargetType::Unknown,
next_packet: 0,
out_of_order_packets: RwLock::new(HashMap::new()),
base: Transfer::new()?,
})
}
}
#[derive(Debug)]
pub struct ImageDownload {
pub codec: ImageCodec,
pub discard_level: i32,
pub image_type: ImageType,
pub packet_count: u16,
pub packets_seen: SortedList<u16, u16>,
pub priority: f32,
pub simulator: Option<Simulator>,
pub base: Transfer,
}
impl ImageDownload {
pub fn new() -> Result<Self, Error> {
Ok(Self {
codec: ImageCodec::Invalid,
discard_level: 0,
image_type: ImageType::Normal,
packet_count: 0,
packets_seen: SortedList(std::collections::BTreeMap::new()),
priority: 0.0,
simulator: None,
base: Transfer::new()?,
})
}
}
#[derive(Clone, Debug)]
pub struct AssetUpload {
pub asset_id: UUID,
pub packet_num: u32,
pub type_: AssetType,
pub xfer_id: u64,
pub base: Transfer,
}
impl AssetUpload {
pub fn new() -> Result<Self, Error> {
Ok(Self {
asset_id: UUID::zero(),
packet_num: 0,
type_: AssetType::Unknown,
xfer_id: 0,
base: Transfer::new()?,
})
}
}
#[derive(Clone, Debug)]
pub struct AssetUploadEventArgs {
upload: AssetUpload,
}
impl AssetUploadEventArgs {
pub fn new(upload: AssetUpload) -> Result<Self, Error> {
Ok(Self { upload })
}
pub fn upload(&self) -> AssetUpload {
self.upload.clone()
}
}
#[derive(Clone, Debug)]
pub struct ImageReceiveProgressEventArgs {
image_id: UUID,
received: i32,
total: i32,
}
impl ImageReceiveProgressEventArgs {
pub fn new(image_id: UUID, received: i32, total: i32) -> Result<Self, Error> {
if received < 0 || total < 0 || received > total {
return Err(Error::Argument);
}
Ok(Self {
image_id,
received,
total,
})
}
pub const fn image_id(&self) -> UUID {
self.image_id
}
pub const fn received(&self) -> i32 {
self.received
}
pub const fn total(&self) -> i32 {
self.total
}
}
#[derive(Clone, Debug)]
pub struct InitiateDownloadEventArgs {
sim_filename: String,
viewer_filename: String,
}
impl InitiateDownloadEventArgs {
pub fn new(sim_filename: String, viewer_filename: String) -> Result<Self, Error> {
if sim_filename.as_bytes().contains(&0) || viewer_filename.as_bytes().contains(&0) {
return Err(Error::Argument);
}
Ok(Self {
sim_filename,
viewer_filename,
})
}
pub fn sim_file_name(&self) -> String {
self.sim_filename.clone()
}
pub fn viewer_file_name(&self) -> String {
self.viewer_filename.clone()
}
}
#[derive(Clone, Debug)]
pub struct XferDownload {
pub error: TransferError,
pub filename: String,
pub packet_num: u32,
pub v_file_id: UUID,
pub xfer_id: u64,
pub base: Transfer,
}
impl XferDownload {
pub fn new() -> Result<Self, Error> {
Ok(Self {
error: TransferError::None,
filename: String::new(),
packet_num: 0,
v_file_id: UUID::zero(),
xfer_id: 0,
base: Transfer::new()?,
})
}
}
#[derive(Clone, Debug)]
pub struct XferReceivedEventArgs {
xfer: XferDownload,
}
impl XferReceivedEventArgs {
pub fn new(xfer: XferDownload) -> Result<Self, Error> {
Ok(Self { xfer })
}
pub fn xfer(&self) -> XferDownload {
self.xfer.clone()
}
}