use rand::seq::SliceRandom;
use std::sync::atomic::Ordering;
use tokio::sync::mpsc;
use crate::core::models::target::{Target, TargetMap};
use super::STOP_SIGNAL;
pub struct Dispatcher {
target_map: TargetMap,
batch_size: usize,
}
impl Dispatcher {
pub fn new(target_map: TargetMap) -> Self {
Self {
target_map,
batch_size: 8192,
}
}
pub fn with_batch_size(mut self, batch_size: usize) -> Self {
self.batch_size = batch_size;
self
}
pub fn run_shuffled(self) -> mpsc::Receiver<Target> {
let (tx, rx) = mpsc::channel(self.batch_size * 2);
tokio::spawn(async move {
let mut batch = Vec::with_capacity(self.batch_size);
for mut unit in self.target_map.units {
for target in unit.iter() {
if STOP_SIGNAL.load(Ordering::Relaxed) {
return;
}
batch.push(target);
if batch.len() >= self.batch_size {
batch.shuffle(&mut rand::rng());
for t in batch.drain(..) {
if tx.send(t).await.is_err() || STOP_SIGNAL.load(Ordering::Relaxed) {
return;
}
}
}
}
}
if !batch.is_empty() {
batch.shuffle(&mut rand::rng());
for t in batch {
if tx.send(t).await.is_err() || STOP_SIGNAL.load(Ordering::Relaxed) {
return;
}
}
}
});
rx
}
}