use std::collections::{HashMap, VecDeque};
use std::net::SocketAddr;
use std::time::Duration;
use crate::server::connection::ConnectionId;
use crate::utils::clock::Instant;
pub const MAX_OBSERVERS: usize = 64;
pub const MAX_OBSERVERS_PER_IP: usize = 4;
pub const OBSERVER_MAX_AGE: Duration = Duration::from_secs(24 * 60 * 60);
pub const RECENT_NOTIFICATIONS: usize = 256;
pub const SEQUENCE_MASK: u32 = 0x00FF_FFFF;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Observer {
pub peer: SocketAddr,
pub token: Vec<u8>,
pub path: String,
pub query: Option<String>,
pub block_szx: Option<u8>,
pub connection_id: ConnectionId,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Registered {
Added,
Replaced,
Full,
PeerFull,
}
#[derive(Debug, Clone)]
struct Sent {
peer: SocketAddr,
message_id: u16,
token: Vec<u8>,
}
#[derive(Debug, Clone)]
struct Entry {
observer: Observer,
confirmed: Instant,
}
#[derive(Debug)]
pub struct Observers {
list: Vec<Entry>,
cap: usize,
per_ip: usize,
max_age: Duration,
sequence: u32,
sent: VecDeque<Sent>,
pending: HashMap<(SocketAddr, u16), Vec<u8>>,
}
impl Default for Observers {
fn default() -> Self {
Observers::new(MAX_OBSERVERS, MAX_OBSERVERS_PER_IP, OBSERVER_MAX_AGE)
}
}
impl Observers {
pub fn new(cap: usize, per_ip: usize, max_age: Duration) -> Observers {
Observers {
list: Vec::new(),
cap,
per_ip,
max_age,
sequence: 2,
sent: VecDeque::new(),
pending: HashMap::new(),
}
}
pub fn len(&self) -> usize {
self.list.len()
}
pub fn is_empty(&self) -> bool {
self.list.is_empty()
}
pub fn next_sequence(&mut self) -> u32 {
let seq = self.sequence & SEQUENCE_MASK;
self.sequence = (self.sequence + 1) & SEQUENCE_MASK;
seq
}
pub fn register(&mut self, observer: Observer, now: Instant) -> Registered {
if let Some(existing) = self
.list
.iter_mut()
.find(|e| e.observer.peer == observer.peer && e.observer.token == observer.token)
{
*existing = Entry {
observer,
confirmed: now,
};
return Registered::Replaced;
}
let ip = observer.peer.ip();
if self
.list
.iter()
.filter(|e| e.observer.peer.ip() == ip)
.count()
>= self.per_ip
{
return Registered::PeerFull;
}
if self.list.len() >= self.cap {
return Registered::Full;
}
self.list.push(Entry {
observer,
confirmed: now,
});
Registered::Added
}
pub fn expire(&mut self, now: Instant) -> Vec<Observer> {
let max_age = self.max_age;
let mut expired = Vec::new();
self.list.retain(|e| {
let keep = now.saturating_duration_since(e.confirmed) < max_age;
if !keep {
expired.push(e.observer.clone());
}
keep
});
for observer in &expired {
self.pending
.retain(|(p, _), t| !(*p == observer.peer && *t == observer.token));
}
expired
}
pub fn needs_confirmation(&self, peer: SocketAddr, token: &[u8], now: Instant) -> bool {
let half = self.max_age / 2;
self.list.iter().any(|e| {
e.observer.peer == peer
&& e.observer.token == token
&& now.saturating_duration_since(e.confirmed) >= half
})
}
pub fn deregister(&mut self, peer: SocketAddr, token: &[u8]) -> bool {
let before = self.list.len();
self.list
.retain(|e| !(e.observer.peer == peer && e.observer.token == token));
self.pending
.retain(|(p, _), t| !(*p == peer && t.as_slice() == token));
before != self.list.len()
}
pub fn of_path(&self, path: &str) -> Vec<Observer> {
self.list
.iter()
.filter(|e| e.observer.path == path)
.map(|e| e.observer.clone())
.collect()
}
pub fn all(&self) -> Vec<Observer> {
self.list.iter().map(|e| e.observer.clone()).collect()
}
pub fn record(&mut self, peer: SocketAddr, message_id: u16, token: &[u8], confirmable: bool) {
self.sent
.retain(|s| !(s.peer == peer && s.message_id == message_id));
self.sent.push_back(Sent {
peer,
message_id,
token: token.to_vec(),
});
while self.sent.len() > RECENT_NOTIFICATIONS {
self.sent.pop_front();
}
self.pending.remove(&(peer, message_id));
if confirmable {
self.pending
.retain(|(p, _), t| !(*p == peer && t.as_slice() == token));
self.pending.insert((peer, message_id), token.to_vec());
}
}
pub fn acknowledge(&mut self, peer: SocketAddr, message_id: u16, now: Instant) -> bool {
let Some(token) = self.pending.remove(&(peer, message_id)) else {
return false;
};
if let Some(entry) = self
.list
.iter_mut()
.find(|e| e.observer.peer == peer && e.observer.token == token)
{
entry.confirmed = now;
}
true
}
pub fn awaiting_ack(&self, peer: SocketAddr, message_id: u16) -> bool {
self.pending.get(&(peer, message_id)).is_some_and(|token| {
self.list
.iter()
.any(|e| e.observer.peer == peer && &e.observer.token == token)
})
}
pub fn settle(&mut self, peer: SocketAddr, message_id: u16) {
self.pending.remove(&(peer, message_id));
}
pub fn pending_len(&self) -> usize {
self.pending.len()
}
pub fn reset(&mut self, peer: SocketAddr, message_id: u16) -> Option<Observer> {
let token = match self.pending.remove(&(peer, message_id)) {
Some(token) => token,
None => self
.sent
.iter()
.find(|s| s.peer == peer && s.message_id == message_id)?
.token
.clone(),
};
let observer = self
.list
.iter()
.find(|e| e.observer.peer == peer && e.observer.token == token)
.map(|e| e.observer.clone())?;
self.deregister(peer, &token);
Some(observer)
}
}