You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
53 lines
1.5 KiB
Rust
53 lines
1.5 KiB
Rust
use crate::utils::channel_sink::ChannelSink;
|
|
use lzma_rs::xz_decompress;
|
|
use std::cmp::min;
|
|
use std::io;
|
|
use std::io::{BufRead, Read, Write};
|
|
use std::sync::mpsc::Receiver;
|
|
|
|
pub struct XzDecoder {
|
|
buffer: Vec<u8>,
|
|
rx: Receiver<Vec<u8>>,
|
|
}
|
|
|
|
impl XzDecoder {
|
|
pub fn new<R: BufRead + Send + 'static>(mut reader: R) -> Self {
|
|
let (mut sink, rx) = ChannelSink::new(1024);
|
|
std::thread::spawn(move || {
|
|
tracing::debug!("Async decompression thread running");
|
|
if let Err(e) = xz_decompress(&mut reader, &mut sink) {
|
|
tracing::error!("Async decompressing finished with error {e}");
|
|
} else {
|
|
tracing::debug!("async decompressing succeeded");
|
|
}
|
|
});
|
|
Self {
|
|
rx,
|
|
buffer: Vec::new(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Read for XzDecoder {
|
|
#[tracing::instrument(skip_all, level = "trace")]
|
|
fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
|
|
self.buffer.reverse();
|
|
if self.buffer.is_empty() {
|
|
tracing::trace!("Receiving chunk from channel");
|
|
if let Ok(chunk) = self.rx.recv() {
|
|
self.buffer = chunk;
|
|
} else {
|
|
tracing::debug!("Receiving timed out");
|
|
}
|
|
}
|
|
|
|
let max_write = min(self.buffer.len(), buf.len());
|
|
tracing::trace!("Wrote {max_write} bytes");
|
|
buf.write_all(&self.buffer[0..max_write])?;
|
|
self.buffer.reverse();
|
|
self.buffer.truncate(self.buffer.len() - max_write);
|
|
|
|
Ok(max_write)
|
|
}
|
|
}
|