use std::fs::File;
use std::io::{self, Read};
use std::path::Path;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use zisk_common::io::{StreamWrite, UnixSocketStreamWriter};
fn read_binary_file<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
let mut file = File::open(path)?;
let mut buffer = Vec::new();
file.read_to_end(&mut buffer)?;
Ok(buffer)
}
fn main() -> io::Result<()> {
let args: Vec<String> = std::env::args().collect();
if args.len() != 3 {
eprintln!("Usage: {} <binary_file> <socket_path>", args[0]);
eprintln!("Example: {} hints.bin /tmp/hints.sock", args[0]);
std::process::exit(1);
}
let file_path = &args[1];
let socket_path = &args[2];
let file_data = read_binary_file(file_path)?;
println!("Read {} bytes from: {}", file_data.len(), file_path);
println!("========================================");
println!("Hints Unix Socket Server");
println!("========================================");
println!("Binary file: {}", file_path);
println!("Socket path: {}", socket_path);
println!();
let mut writer = UnixSocketStreamWriter::new(socket_path).map_err(io::Error::other)?;
println!("Unix socket server created successfully");
println!("Waiting for client connection...");
writer.open().map_err(io::Error::other)?;
println!("Client connected! Starting hint data transfer...");
let shutdown = Arc::new(AtomicBool::new(false));
let shutdown_clone = Arc::clone(&shutdown);
thread::spawn(move || {
println!("Press '0' + Enter to close at any time");
let stdin = io::stdin();
let mut buffer = String::new();
loop {
buffer.clear();
if stdin.read_line(&mut buffer).is_ok() && buffer.trim() == "0" {
println!("Shutdown signal received!");
shutdown_clone.store(true, Ordering::Relaxed);
break;
}
}
});
thread::sleep(Duration::from_millis(500));
let mut offset = 0;
let mut hint_count = 0;
let mut first_hint = true;
let start_time = std::time::Instant::now();
loop {
if shutdown.load(Ordering::Relaxed) {
println!("\nShutdown requested, exiting...");
break;
}
if offset >= file_data.len() {
panic!("Reached end of file data unexpectedly!");
}
let mut hint_total_len = 8;
let hint_header = u64::from_le_bytes(file_data[offset..offset + 8].try_into().unwrap());
let hint_id = (hint_header >> 32) as u32 & 0x7FFF_FFFF;
if first_hint {
assert!(hint_id == 0, "Invalid hint file format: first hint must be START");
println!("Received START hint");
first_hint = false;
}
let hint_data_len = hint_header & 0x_FFFF_FFFF;
let pad = (8 - (hint_data_len % 8)) % 8; let data_len_with_pad = hint_data_len + pad as u64;
hint_total_len += data_len_with_pad;
if (offset + hint_total_len as usize) > file_data.len() {
eprintln!("Error: Hint data length exceeds file ends");
return Ok(());
}
let data_with_pad = &file_data[offset..offset + hint_total_len as usize];
match writer.write(data_with_pad) {
Ok(_) => {
if hint_count % 100 == 0 && hint_id != 0 && hint_id != 1 {
println!(
"#{} Hint id: 0x{:x}, sent: {} bytes, offset: {}",
hint_count, hint_id, hint_total_len, offset
);
}
}
Err(e) => {
eprintln!("Error writing to Unix socket: {}", e);
break;
}
}
offset += hint_total_len as usize;
if hint_id != 1 && hint_id != 0 {
hint_count += 1;
}
if hint_id == 1 {
println!(
"Received END hint. All hints sent, total: {}, time elapsed: {:?}",
hint_count,
start_time.elapsed()
);
break;
}
}
println!("Closing connection...");
let _ = writer.close();
println!("Server shutting down...");
Ok(())
}