mirror of
https://github.com/markuryy/shark.git
synced 2025-12-12 19:51:01 +00:00
refactor: move download/decryption to backend to fix UI freezing
Now implements streaming download+decryption entirely in Rust: - Added reqwest/tokio/futures-util dependencies - Created StreamingDecryptor for chunk-by-chunk decryption - New download_and_decrypt_track command streams to disk directly - Frontend simplified to single invoke() call
This commit is contained in:
@@ -97,6 +97,69 @@ pub fn decrypt_track(data: &[u8], track_id: &str) -> Vec<u8> {
|
||||
result
|
||||
}
|
||||
|
||||
/// Streaming decryption state for processing data chunk-by-chunk
|
||||
pub struct StreamingDecryptor {
|
||||
blowfish_key: Vec<u8>,
|
||||
buffer: Vec<u8>,
|
||||
}
|
||||
|
||||
impl StreamingDecryptor {
|
||||
const CHUNK_SIZE: usize = 2048;
|
||||
const WINDOW_SIZE: usize = Self::CHUNK_SIZE * 3; // 6144
|
||||
|
||||
pub fn new(track_id: &str) -> Self {
|
||||
Self {
|
||||
blowfish_key: generate_blowfish_key(track_id),
|
||||
buffer: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Process incoming data and return decrypted output
|
||||
/// May return less data than input as it buffers to maintain 6144-byte windows
|
||||
pub fn process(&mut self, data: &[u8]) -> Vec<u8> {
|
||||
self.buffer.extend_from_slice(data);
|
||||
let mut output = Vec::new();
|
||||
|
||||
// Process complete windows
|
||||
while self.buffer.len() >= Self::WINDOW_SIZE {
|
||||
let encrypted_chunk = &self.buffer[0..Self::CHUNK_SIZE];
|
||||
let plain_part = &self.buffer[Self::CHUNK_SIZE..Self::WINDOW_SIZE];
|
||||
|
||||
let decrypted = decrypt_chunk(encrypted_chunk, &self.blowfish_key);
|
||||
output.extend_from_slice(&decrypted);
|
||||
output.extend_from_slice(plain_part);
|
||||
|
||||
self.buffer.drain(0..Self::WINDOW_SIZE);
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
/// Finalize decryption and return any remaining buffered data
|
||||
pub fn finalize(self) -> Vec<u8> {
|
||||
if self.buffer.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let remaining = self.buffer.len();
|
||||
|
||||
if remaining >= Self::CHUNK_SIZE {
|
||||
// Partial window: decrypt first 2048 bytes, keep rest as-is
|
||||
let encrypted_chunk = &self.buffer[0..Self::CHUNK_SIZE];
|
||||
let plain_part = &self.buffer[Self::CHUNK_SIZE..];
|
||||
|
||||
let decrypted = decrypt_chunk(encrypted_chunk, &self.blowfish_key);
|
||||
let mut output = Vec::with_capacity(remaining);
|
||||
output.extend_from_slice(&decrypted);
|
||||
output.extend_from_slice(plain_part);
|
||||
output
|
||||
} else {
|
||||
// Less than 2048 bytes: keep as-is
|
||||
self.buffer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user