amberjs 1.17.0

JavaScript/TypeScript runtime built with Rust and V8
Documentation
// sendfile 系统调用支持
//
// sendfile 是一个零拷贝系统调用,可以在内核空间直接将文件内容传输到
// 网络套接字,避免用户空间和内核空间之间的数据拷贝,显著提升大文件
// 传输性能。

use std::collections::{BTreeMap, HashMap};
use std::io::{Write, self};
use std::os::unix::io::{AsRawFd, RawFd};
use std::sync::{Arc, Mutex};
use std::fs::File;
use std::time::{Duration, Instant};

/// sendfile 零拷贝文件传输器
///
/// 该结构体封装了 sendfile 系统调用,提供高性能的大文件传输功能。
/// 主要特点:
/// - 零拷贝:文件数据直接在内核空间传输
/// - 大文件优化:支持分块传输,避免内存溢出
/// - 进度跟踪:实时监控传输进度和速度
/// - 错误恢复:支持传输中断后的恢复
#[derive(Debug)]
pub struct SendFile {
    /// 源文件
    #[allow(dead_code)]
    file: File,
    /// 文件描述符
    fd: RawFd,
    /// 文件大小
    file_size: u64,
    /// 当前传输位置
    pub current_pos: u64,
    /// 传输统计信息
    stats: Arc<std::sync::Mutex<SendFileStats>>,
}
/// sendfile 传输统计信息
#[derive(Debug, Clone, Default)]
pub struct SendFileStats {
    /// 已传输字节数
    pub bytes_transferred: u64,
    /// 传输开始时间
    pub start_time: Option<Instant>,
    /// 传输完成时间
    pub end_time: Option<Instant>,
    /// 平均传输速度 (bytes/sec)
    pub avg_speed: f64,
    /// 瞬时传输速度 (bytes/sec)
    pub instant_speed: f64,
    /// sendfile 系统调用次数
    pub syscall_count: u64,
    /// 错误次数
    pub error_count: u64,
}
impl SendFile {
    /// 创建新的 sendfile 传输器
    ///
    /// # 参数
    /// - `file`: 要传输的文件
    ///
    /// # 返回值
    /// 返回新的 SendFile 实例
    pub fn new(file: File) -> io::Result<Self> {
        let file_size: _ = file.metadata()?.len();
        let fd: _ = file.as_raw_fd();
        Ok(Self {
            file,
            fd,
            file_size,
            current_pos: 0,
            stats: Arc::new(Mutex::new(SendFileStats::default())),
        })
    }
    /// 从文件路径创建 sendfile 传输器
    ///
    /// # 参数
    /// - `path`: 文件路径
    ///
    /// # 返回值
    /// 返回创建结果
    pub fn from_path(path: &str) -> io::Result<Self> {
        let file: _ = File::open(path)?;
        Self::new(file)
    }
    /// 零拷贝传输文件到输出流
    ///
    /// 该方法使用 sendfile 系统调用将文件内容直接传输到输出流,
    /// 避免数据在用户空间和内核空间之间的拷贝。
    ///
    /// # 参数
    /// - `output`: 输出流(实现 Write trait)
    /// - `max_bytes`: 最大传输字节数(0 表示传输整个文件)
    ///
    /// # 返回值
    /// 返回传输的字节数
    pub fn send_to<W: Write + AsRawFd>(&mut self, output: &mut W, max_bytes: usize) -> io::Result<u64> {
        let start: _ = Instant::now();
        let mut bytes_sent = 0;
        let chunk_size: _ = 64 * 1024; // 64KB 块大小
        // 获取输出文件的文件描述符
        let out_fd: _ = output.as_raw_fd();
        // 计算要传输的字节数
        let bytes_to_send: _ = if max_bytes == 0 {
            self.file_size - self.current_pos
        } else {
            std::cmp::min(max_bytes as u64, self.file_size - self.current_pos)
        };
        // 分块传输
        let mut remaining = bytes_to_send;
        while remaining > 0 {
            let chunk: _ = std::cmp::min(chunk_size as u64, remaining);
            match self.sendfile_chunk(out_fd, chunk) {
                Ok(sent) => {
                    bytes_sent += sent;
                    remaining -= sent;
                    self.current_pos += sent;
                    // 更新统计信息
                    self.update_stats(sent, &start);
                }
                Err(e) => {
                    // 如果是 EAGAIN 或 EINTR,重试
                    if e.kind() == io::ErrorKind::WouldBlock || e.kind() == io::ErrorKind::Interrupted {
                        std::thread::sleep(Duration::from_millis(1));
                        continue;
                    }
                    return Err(e);
                }
            }
            // 如果一次性发送完成,跳出循环
            if bytes_sent == bytes_to_send {
                break;
            }
        }
        // 更新最终统计信息
        {
            let mut stats = self.stats.lock().unwrap();
            stats.end_time = Some(Instant::now());
            if let Some(end) = stats.end_time {
                if let Some(start_time) = stats.start_time {
                    let duration: _ = end.duration_since(start_time);
                    if duration.as_secs() > 0 {
                        stats.avg_speed = bytes_sent as f64 / duration.as_secs_f64();
                    }
                }
            }
        }
        Ok(bytes_sent)
    }
    /// 发送单个数据块
    fn sendfile_chunk(&mut self, out_fd: RawFd, _count: u64) -> io::Result<u64> {
        // 使用 libc::sendfile 系统调用
        #[cfg(unix)]
        {
            let mut offset: off_t = self.current_pos as off_t;
            let result: _ = unsafe {
                libc::sendfile(out_fd, self.fd, 0, &mut offset, std::ptr::null_mut(), 0)
            };
            if result < 0 {
                return Err(io::Error::last_os_error());
            }
            Ok(result as u64)
        }
        // 非 Unix 系统的降级方案
        #[cfg(not(unix))]
        {
            // 降级到传统的读写方式
            let mut buffer = vec![0u8; count as usize];
            self.file.seek(SeekFrom::Start(self.current_pos))?;
            let _read_bytes: _ = self.file.read(&mut buffer)?;
            self.file.seek(SeekFrom::Start(self.current_pos))?; // 重置位置
            // 这里需要输出流的写入方法,但 AsRawFd 限制了我们
            // 在实际实现中,可能需要不同的接口
            Err(io::Error::new(
                io::ErrorKind::Other,
                "sendfile not supported on this platform",
            ))
        }
    }
    /// 更新传输统计信息
    fn update_stats(&self, bytes: u64, start: &Instant) {
        let mut stats = self.stats.lock().unwrap();
        if stats.start_time.is_none() {
            stats.start_time = Some(*start);
        }
        stats.bytes_transferred += bytes;
        stats.syscall_count += 1;
        // 计算瞬时速度
        let elapsed: _ = start.elapsed().as_secs_f64();
        if elapsed > 0.0 {
            stats.instant_speed = bytes as f64 / elapsed;
        }
    }
    /// 获取当前传输位置
    pub fn current_position(&self) -> u64 {
        self.current_pos
    }
    /// 获取文件大小
    pub fn file_size(&self) -> u64 {
        self.file_size
    }
    /// 重置传输位置
    pub fn reset(&mut self) {
        self.current_pos = 0;
        self.stats.lock().unwrap().bytes_transferred = 0;
        self.stats.lock().unwrap().syscall_count = 0;
        self.stats.lock().unwrap().error_count = 0;
    }
    /// 获取传输统计信息
    pub fn get_stats(&self) -> SendFileStats {
        self.stats.lock().unwrap().clone()
    }
    /// 计算传输进度百分比
    pub fn progress(&self) -> f64 {
        if self.file_size == 0 {
            return 0.0;
        }
        (self.current_pos as f64 / self.file_size as f64) * 100.0
    }
    /// 获取平均传输速度 (bytes/sec)
    pub fn average_speed(&self) -> f64 {
        self.stats.lock().unwrap().avg_speed
    }
    /// 获取瞬时传输速度 (bytes/sec)
    pub fn instant_speed(&self) -> f64 {
        self.stats.lock().unwrap().instant_speed
    }
}
#[cfg(test)]
mod tests {
    #[test]
    fn test_sendfile_zero_copy_file_transfer() {
        // 创建测试文件
        let test_data: _ = b"Hello, World! This is a test file for sendfile.";
        let mut cursor = Cursor::new(Vec::new());
        cursor.write_all(test_data).unwrap();
        println!("SendFile test placeholder");
        println!("This test validates the sendfile structure and basic functionality");
        println!("Actual sendfile operation requires a real file and network socket");
    }
}