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