use std::collections::{BTreeMap, HashMap};
use std::sync::{Arc, Mutex, RwLock};
use std::fs::File;
use std::time::{Duration, Instant};
use std::io::Write;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ZeroCopyDirection {
FileToSocket,
PipeToSocket,
SocketToFile,
}
#[derive(Debug, Clone)]
pub struct ZeroCopySenderConfig {
pub chunk_size: usize,
pub timeout: Duration,
pub max_retries: u32,
pub enable_compression: bool,
pub compression_level: u8,
}
impl Default for ZeroCopySenderConfig {
fn default() -> Self {
Self {
chunk_size: 64 * 1024,
timeout: Duration::from_secs(30),
max_retries: 3,
enable_compression: false,
compression_level: 6,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct ZeroCopySenderStats {
pub total_bytes: u64,
pub success_count: u64,
pub error_count: u64,
pub avg_speed: f64,
pub peak_speed: f64,
pub sendfile_count: u64,
pub splice_count: u64,
pub total_duration: Duration,
pub last_transfer: Option<Instant>,
}
impl std::fmt::Display for ZeroCopySenderStats {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f,
"零拷贝传输统计:\n 总传输字节数: {} bytes ({:.2} MB)\n 成功次数: {}\n 失败次数: {}\n 平均速度: {:.2} bytes/sec\n 峰值速度: {:.2} bytes/sec\n sendfile 调用: {}\n splice 调用: {}\n 总耗时: {:?}",
self.total_bytes,
self.total_bytes as f64 / 1024.0 / 1024.0,
self.success_count,
self.error_count,
self.avg_speed,
self.peak_speed,
self.sendfile_count,
self.splice_count,
self.total_duration
)
}
}
#[derive(Debug)]
pub struct ZeroCopySender {
config: ZeroCopySenderConfig,
stats: Arc<Mutex<ZeroCopySenderStats>>,
sendfile: Option<SendFile>,
splice: Splice,
current_pos: u64,
}
impl ZeroCopySender {
pub fn new(config: Option<ZeroCopySenderConfig>) -> io::Result<Self> {
let config: _ = config.unwrap_or_default();
let splice: _ = Splice::new();
Ok(Self {
config,
stats: Arc::new(Mutex::new(ZeroCopySenderStats::default())),
sendfile: None,
splice,
current_pos: 0,
})
}
pub fn from_file(file_path: &str, config: Option<ZeroCopySenderConfig>) -> io::Result<Self> {
let mut sender = Self::new(config)?;
let file: _ = File::open(file_path)?;
sender.sendfile = Some(SendFile::new(file)?);
Ok(sender)
}
pub fn send_to_socket<W: Write + AsRawFd>(
&mut self,
socket: &mut W,
max_bytes: usize,
) -> io::Result<u64> {
let start_time: _ = Instant::now();
let mut total_sent = 0u64;
if self.sendfile.is_none() {
return Err(io::Error::new(
io::ErrorKind::Other,
"sendfile not initialized",
));
}
let sendfile: _ = self.sendfile.as_mut().unwrap();
sendfile.current_pos = self.current_pos;
match sendfile.send_to(socket, max_bytes) {
Ok(bytes_sent) => {
total_sent = bytes_sent;
self.current_pos += bytes_sent;
self.update_stats_on_success(bytes_sent, &start_time);
println!("✅ 零拷贝传输成功: {} bytes", bytes_sent);
Ok(bytes_sent)
}
Err(e) => {
self.update_stats_on_error(&start_time);
println!("❌ 零拷贝传输失败: {}", e);
Err(e)
}
}
}
pub fn send_pipe_to_socket(
&self,
pipe: &std::os::unix::net::UnixStream,
socket: &impl AsRawFd,
max_bytes: usize,
) -> io::Result<u64> {
let start_time: _ = Instant::now();
let out_fd: _ = socket.as_raw_fd();
match self.splice.pipe_to_fd(pipe, out_fd, max_bytes) {
Ok(bytes_sent) => {
self.update_stats_on_success(bytes_sent, &start_time);
println!("✅ 管道到套接字零拷贝传输成功: {} bytes", bytes_sent);
Ok(bytes_sent)
}
Err(e) => {
self.update_stats_on_error(&start_time);
println!("❌ 管道到套接字零拷贝传输失败: {}", e);
Err(e)
}
}
}
pub fn set_position(&mut self, pos: u64) {
self.current_pos = pos;
if let Some(sendfile) = &mut self.sendfile {
sendfile.current_pos = pos;
}
}
pub fn position(&self) -> u64 {
self.current_pos
}
pub fn reset(&mut self) {
self.current_pos = 0;
if let Some(sendfile) = &mut self.sendfile {
sendfile.reset();
}
let mut stats = self.stats.lock().unwrap();
*stats = ZeroCopySenderStats::default();
}
pub fn get_stats(&self) -> ZeroCopySenderStats {
self.stats.lock().unwrap().clone()
}
pub fn progress(&self) -> f64 {
if let Some(sendfile) = &self.sendfile {
let file_size: _ = sendfile.file_size();
if file_size > 0 {
return (self.current_pos as f64 / file_size as f64) * 100.0;
}
}
0.0
}
pub fn speed(&self) -> f64 {
let stats: _ = self.stats.lock().unwrap();
stats.avg_speed
}
pub fn can_continue(&self) -> bool {
if let Some(sendfile) = &self.sendfile {
self.current_pos < sendfile.file_size()
} else {
false
}
}
fn update_stats_on_success(&self, bytes: u64, start_time: &Instant) {
let mut stats = self.stats.lock().unwrap();
stats.total_bytes += bytes;
stats.success_count += 1;
stats.last_transfer = Some(Instant::now());
let elapsed: _ = start_time.elapsed();
stats.total_duration += elapsed;
if elapsed.as_secs_f64() > 0.0 {
let current_speed: _ = bytes as f64 / elapsed.as_secs_f64();
stats.avg_speed = (stats.avg_speed * (stats.success_count - 1) as f64 + current_speed)
/ stats.success_count as f64;
if current_speed > stats.peak_speed {
stats.peak_speed = current_speed;
}
}
if self.sendfile.is_some() {
stats.sendfile_count += 1;
} else {
stats.splice_count += 1;
}
}
fn update_stats_on_error(&self, start_time: &Instant) {
let mut stats = self.stats.lock().unwrap();
stats.error_count += 1;
stats.total_duration += start_time.elapsed();
}
}
impl Default for ZeroCopySender {
fn default() -> Self {
Self::new(None).expect("Failed to create default ZeroCopySender")
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_zero_copy_sender_creation() {
let config: _ = ZeroCopySenderConfig::default();
let sender: _ = ZeroCopySender::new(Some(config)).expect("创建发送器失败");
let stats: _ = sender.get_stats();
assert_eq!(stats.total_bytes, 0);
assert_eq!(stats.success_count, 0);
assert_eq!(stats.error_count, 0);
println!("✅ 测试通过: 零拷贝发送器创建");
}
#[test]
fn test_position_setting() {
let mut sender = ZeroCopySender::new(None).expect("创建发送器失败");
sender.set_position(1024);
assert_eq!(sender.position(), 1024);
println!("✅ 测试通过: 文件位置设置");
}
#[test]
fn test_progress_calculation() {
let test_file_path: _ = "/tmp/amberjs_zero_copy_test.bin";
let test_data: _ = vec![42u8; 1024];
std::fs::write(test_file_path, &test_data).expect("写入测试文件失败");
let mut sender =
ZeroCopySender::from_file(test_file_path, None).expect("创建发送器失败");
sender.set_position(512);
let progress: _ = sender.progress();
assert!(progress > 0.0 && progress < 100.0);
println!("进度: {:.1}%", progress);
std::fs::remove_file(test_file_path).ok();
println!("✅ 测试通过: 进度计算");
}
#[test]
fn test_transfer_stats() {
let sender: _ = ZeroCopySender::new(None).expect("创建发送器失败");
let start_time: _ = Instant::now();
sender.update_stats_on_success(1024, &start_time);
let stats: _ = sender.get_stats();
assert_eq!(stats.total_bytes, 1024);
assert_eq!(stats.success_count, 1);
assert_eq!(stats.error_count, 0);
println!("✅ 测试通过: 传输统计");
}
}