use std::collections::{BinaryHeap, HashSet};
use crate::request::Request;
pub struct Scheduler {
queue: BinaryHeap<PrioritizedRequest>,
seen: HashSet<Vec<u8>>,
counter: u64,
include_kwargs: bool,
include_headers: bool,
keep_fragments: bool,
}
struct PrioritizedRequest {
neg_priority: i32,
counter: u64,
request: Request,
}
impl PartialEq for PrioritizedRequest {
fn eq(&self, other: &Self) -> bool {
self.neg_priority == other.neg_priority && self.counter == other.counter
}
}
impl Eq for PrioritizedRequest {}
impl PartialOrd for PrioritizedRequest {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for PrioritizedRequest {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.neg_priority
.cmp(&other.neg_priority)
.then_with(|| self.counter.cmp(&other.counter))
}
}
impl Scheduler {
pub fn new(include_kwargs: bool, include_headers: bool, keep_fragments: bool) -> Self {
Self {
queue: BinaryHeap::new(),
seen: HashSet::new(),
counter: 0,
include_kwargs,
include_headers,
keep_fragments,
}
}
pub fn enqueue(&mut self, mut request: Request) -> bool {
let fp = request
.update_fingerprint(
self.include_kwargs,
self.include_headers,
self.keep_fragments,
)
.to_vec();
if !request.dont_filter && self.seen.contains(&fp) {
return false;
}
self.seen.insert(fp);
let entry = PrioritizedRequest {
neg_priority: -request.priority,
counter: self.counter,
request,
};
self.counter += 1;
self.queue.push(entry);
true
}
pub fn dequeue(&mut self) -> Option<Request> {
self.queue.pop().map(|entry| entry.request)
}
pub fn len(&self) -> usize {
self.queue.len()
}
pub fn is_empty(&self) -> bool {
self.queue.is_empty()
}
pub fn snapshot(&self) -> (Vec<&Request>, &HashSet<Vec<u8>>) {
let mut entries: Vec<_> = self.queue.iter().collect();
entries.sort_by(|a, b| {
a.neg_priority
.cmp(&b.neg_priority)
.then_with(|| a.counter.cmp(&b.counter))
});
let requests: Vec<&Request> = entries.iter().map(|e| &e.request).collect();
(requests, &self.seen)
}
pub fn seen_count(&self) -> usize {
self.seen.len()
}
}