Change tar.xz deompression to take place in memory only
Signed-off-by: trivernis <trivernis@protonmail.com>main
parent
7d80d886ac
commit
69bd274c39
@ -1,59 +0,0 @@
|
||||
use std::io::{ErrorKind, Write};
|
||||
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
|
||||
use std::{io, mem};
|
||||
|
||||
pub struct ChannelSink {
|
||||
buffer: Vec<u8>,
|
||||
block_size: usize,
|
||||
tx: SyncSender<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl ChannelSink {
|
||||
/// Creates a new sink with a channel to send the data to
|
||||
pub fn new(block_size: usize) -> (Self, Receiver<Vec<u8>>) {
|
||||
let (tx, rx) = sync_channel(1);
|
||||
(
|
||||
Self {
|
||||
buffer: Vec::new(),
|
||||
block_size,
|
||||
tx,
|
||||
},
|
||||
rx,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for ChannelSink {
|
||||
#[tracing::instrument(skip_all, level = "trace")]
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
self.buffer.append(&mut buf.to_vec());
|
||||
if self.buffer.len() >= self.block_size {
|
||||
tracing::trace!("Block size reached. Sending buffer...");
|
||||
self.tx
|
||||
.send(mem::take(&mut self.buffer))
|
||||
.map_err(|e| io::Error::new(ErrorKind::BrokenPipe, e))?;
|
||||
}
|
||||
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, level = "trace")]
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
if !self.buffer.is_empty() {
|
||||
self.tx
|
||||
.send(mem::take(&mut self.buffer))
|
||||
.map_err(|e| io::Error::new(ErrorKind::BrokenPipe, e))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ChannelSink {
|
||||
#[tracing::instrument(skip_all, level = "trace")]
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self.flush() {
|
||||
tracing::debug!("Error while trying to flush buffer during drop {e}")
|
||||
}
|
||||
}
|
||||
}
|
@ -1,2 +1 @@
|
||||
pub mod xz_decoder;
|
||||
pub mod channel_sink;
|
||||
|
||||
|
@ -1,52 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue