use std::collections::HashMap;
use std::sync::{Arc, Mutex, RwLock};
use super::{NetworkConfig, NetworkStats};
use memmap2::{Mmap, MmapOptions};
use std::time::{Duration, Instant};
use std::task::Poll;
use std::task::Context;
use std::pin::Pin;
#[derive(Debug, thiserror::Error)]
pub enum ZeroCopyError {
#[error("I/O 错误: {0}")]
Io(#[from] std::io::Error),
#[error("内存映射错误: {0}")]
Mmap(String),
#[error("传输被取消")]
Cancelled,
#[error("超时")]
Timeout,
}
#[derive(Debug, Clone)]
pub struct TransferRequest {
pub id: u64,
pub source: Vec<u8>,
pub destination: String,
pub priority: u8,
pub timeout_ms: u64,
}
#[derive(Debug, Clone)]
pub struct TransferStats {
pub total_transfers: u64,
pub successful_transfers: u64,
pub failed_transfers: u64,
pub total_bytes_transferred: u64,
pub average_transfer_time_ns: u64,
pub zero_copy_ratio: f64,
}
pub struct ZeroCopyFuture {
id: u64,
receiver: oneshot::Receiver<Result<u64, ZeroCopyError>>,
}
impl ZeroCopyFuture {
pub fn new(id: u64, receiver: oneshot::Receiver<Result<u64, ZeroCopyError>>) -> Self {
Self { id, receiver }
}
}
impl Future for ZeroCopyFuture {
type Output = Result<u64, ZeroCopyError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match Pin::new(&mut self.receiver).poll(cx) {
Poll::Ready(result) => Poll::Ready(result.unwrap_or(Err(ZeroCopyError::Cancelled))),
Poll::Pending => Poll::Pending,
}
}
}
pub struct AsyncZeroCopy {
config: NetworkConfig,
stats: Arc<RwLock<TransferStats>>,
active_transfers: Arc<RwLock<std::collections::HashMap<u64, TransferRequest>>>,
transfer_counter: Arc<RwLock<u64>>,
}
impl AsyncZeroCopy {
pub fn new(config: NetworkConfig) -> Self {
Self {
stats: Arc::new(Mutex::new(TransferStats {
total_transfers: 0,
successful_transfers: 0,
failed_transfers: 0,
total_bytes_transferred: 0,
average_transfer_time_ns: 0,
zero_copy_ratio: 0.0,
})),
active_transfers: Arc::new(Mutex::new(std::collections::HashMap::new())),
transfer_counter: Arc::new(Mutex::new(0)),
config,
}
}
pub async fn transfer(&self, request: TransferRequest) -> Result<ZeroCopyFuture, ZeroCopyError> {
let id: _ = {
let mut counter = self.transfer_counter.write().await;
*counter += 1;
*counter
};
let (sender, receiver) = oneshot::channel();
let request_with_id: _ = TransferRequest { id, ..request };
{
let mut active = self.active_transfers.write().await;
active.insert(id, request_with_id.clone());
}
let stats: _ = Arc::clone(&self.stats);
let active_transfers: _ = Arc::clone(&self.active_transfers);
tokio::spawn(async move {
let start: _ = std::time::Instant::now();
let result: _ = Self::perform_transfer(request_with_id).await;
let mut stats_guard = stats.write().await;
stats_guard.total_transfers += 1;
match &result {
Ok(bytes) => {
stats_guard.successful_transfers += 1;
stats_guard.total_bytes_transferred += *bytes;
stats_guard.average_transfer_time_ns =
(stats_guard.average_transfer_time_ns + start.elapsed().as_nanos() as u64) / 2;
stats_guard.zero_copy_ratio = stats_guard.successful_transfers as f64
/ stats_guard.total_transfers as f64;
}
Err(_) => {
stats_guard.failed_transfers += 1;
}
}
active_transfers.write().await.remove(&id);
let _: _ = sender.send(result);
});
Ok(ZeroCopyFuture::new(id, receiver))
}
async fn perform_transfer(request: TransferRequest) -> Result<u64, ZeroCopyError> {
let mmap: _ = Self::create_memory_map(&request.source)?;
let bytes_sent: _ = request.source.len();
tokio::time::sleep(Duration::from_micros(100)).await;
Ok(bytes_sent as u64)
}
fn create_memory_map(data: &[u8]) -> Result<Mmap, ZeroCopyError> {
let temp_file: _ = std::env::temp_dir()
.join(format!("amberjs_async_zero_copy_{}", std::process::id()));
let file: _ = std::fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&temp_file)?;
file.set_len(data.len() as u64)?;
unsafe {
let mmap: _ = MmapOptions::new()
.map(&file)
.map_err(|e| ZeroCopyError::Mmap(e.to_string()))?;
std::ptr::copy_nonoverlapping(
data.as_ptr(),
mmap.as_ptr() as *mut u8,
data.len()
);
Ok(mmap)
}
}
pub async fn cancel_transfer(&self, id: u64) -> Result<(), ZeroCopyError> {
let mut active = self.active_transfers.write().await;
active.remove(&id);
Ok(())
}
pub async fn get_stats(&self) -> TransferStats {
self.stats.read().await.clone()
}
pub async fn get_active_transfers_count(&self) -> usize {
self.active_transfers.read().await.len()
}
}
impl Drop for AsyncZeroCopy {
fn drop(&mut self) {
let temp_file: _ = std::env::temp_dir()
.join(format!("amberjs_async_zero_copy_{}", std::process::id()));
let _: _ = std::fs::remove_file(temp_file);
}
}