2023-05-19 13:01:12 +00:00
|
|
|
use std::{
|
2023-05-20 18:16:09 +00:00
|
|
|
collections::{HashMap, HashSet},
|
2023-05-19 13:01:12 +00:00
|
|
|
net::SocketAddr,
|
|
|
|
|
sync::{Arc, Mutex},
|
|
|
|
|
};
|
|
|
|
|
|
2023-05-18 07:44:54 +00:00
|
|
|
use tokio::sync::mpsc;
|
|
|
|
|
use tracing::debug;
|
2023-05-17 19:32:32 +00:00
|
|
|
|
2023-05-18 07:44:54 +00:00
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
|
|
|
|
|
pub(crate) struct DispatcherId(pub(crate) SocketAddr);
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
|
|
|
|
|
pub(crate) struct CameraId(pub(crate) SocketAddr);
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
|
|
|
|
|
pub(crate) struct Plate {
|
2023-05-19 13:01:12 +00:00
|
|
|
pub(crate) plate: String,
|
2023-05-20 18:16:09 +00:00
|
|
|
pub(crate) timestamp: Timestamp,
|
2023-05-18 07:44:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
|
|
|
|
|
pub(crate) struct Camera {
|
2023-05-20 18:16:09 +00:00
|
|
|
pub(crate) road: Road,
|
|
|
|
|
pub(crate) mile: Mile,
|
|
|
|
|
pub(crate) limit: Limit,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
|
|
|
|
|
pub(crate) struct Ticket {
|
|
|
|
|
pub(crate) plate: String,
|
2023-05-19 13:01:12 +00:00
|
|
|
pub(crate) road: u16,
|
2023-05-20 18:16:09 +00:00
|
|
|
pub(crate) mile1: u16,
|
|
|
|
|
pub(crate) timestamp1: u32,
|
|
|
|
|
pub(crate) mile2: u16,
|
|
|
|
|
pub(crate) timestamp2: u32,
|
|
|
|
|
pub(crate) speed: u16,
|
2023-05-18 07:44:54 +00:00
|
|
|
}
|
|
|
|
|
|
2023-05-19 13:01:12 +00:00
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
|
2023-05-20 18:16:09 +00:00
|
|
|
pub(crate) struct Road(pub(crate) u16);
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
|
|
|
|
|
pub(crate) struct Limit(pub(crate) u16);
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
|
|
|
|
|
pub(crate) struct Timestamp(pub(crate) u32);
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
|
|
|
|
|
pub(crate) struct Mile(pub(crate) u16);
|
2023-05-19 13:01:12 +00:00
|
|
|
|
2023-05-17 19:32:32 +00:00
|
|
|
pub(crate) struct DbHolder {
|
2023-05-19 13:01:12 +00:00
|
|
|
db: Db,
|
2023-05-17 19:32:32 +00:00
|
|
|
}
|
|
|
|
|
|
2023-05-18 07:44:54 +00:00
|
|
|
#[derive(Clone)]
|
2023-05-17 19:32:32 +00:00
|
|
|
pub(crate) struct Db {
|
2023-05-19 13:01:12 +00:00
|
|
|
state: Arc<Mutex<State>>,
|
2023-05-17 19:32:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
struct State {
|
2023-05-19 13:01:12 +00:00
|
|
|
cameras: HashMap<CameraId, Camera>,
|
2023-05-20 18:16:09 +00:00
|
|
|
dispatchers: HashMap<Road, Vec<(DispatcherId, mpsc::Sender<Ticket>)>>,
|
|
|
|
|
plates: HashMap<(Plate, Road), Vec<(Mile, Timestamp)>>,
|
|
|
|
|
ticketed_plates_by_day: HashSet<(Timestamp, String)>,
|
|
|
|
|
open_tickets: HashMap<Road, Vec<Ticket>>,
|
2023-05-17 19:32:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl DbHolder {
|
2023-05-19 13:01:12 +00:00
|
|
|
pub(crate) fn new() -> DbHolder {
|
|
|
|
|
DbHolder { db: Db::new() }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn db(&self) -> Db {
|
|
|
|
|
self.db.clone()
|
|
|
|
|
}
|
2023-05-17 19:32:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Db {
|
2023-05-19 13:01:12 +00:00
|
|
|
pub(crate) fn new() -> Db {
|
|
|
|
|
let state = Arc::new(Mutex::new(State {
|
|
|
|
|
cameras: HashMap::new(),
|
|
|
|
|
dispatchers: HashMap::new(),
|
|
|
|
|
plates: HashMap::new(),
|
2023-05-20 18:16:09 +00:00
|
|
|
ticketed_plates_by_day: HashSet::new(),
|
|
|
|
|
open_tickets: HashMap::new(),
|
2023-05-19 13:01:12 +00:00
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
Db { state }
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-20 18:16:09 +00:00
|
|
|
pub(crate) fn get_camera(&self, camera_id: CameraId) -> Option<Camera> {
|
|
|
|
|
let state = self.state.lock().unwrap();
|
|
|
|
|
state.cameras.get(&camera_id).cloned()
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-19 13:01:12 +00:00
|
|
|
pub(crate) fn add_camera(&self, camera_id: CameraId, camera: Camera) {
|
|
|
|
|
let mut state = self.state.lock().unwrap();
|
|
|
|
|
state.cameras.insert(camera_id, camera);
|
|
|
|
|
debug!(?state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn add_dispatcher(
|
|
|
|
|
&self,
|
|
|
|
|
dispatcher_id: DispatcherId,
|
|
|
|
|
roads: Vec<u16>,
|
2023-05-20 18:16:09 +00:00
|
|
|
writer_stream: mpsc::Sender<Ticket>,
|
2023-05-19 13:01:12 +00:00
|
|
|
) {
|
|
|
|
|
let mut state = self.state.lock().unwrap();
|
|
|
|
|
|
|
|
|
|
for r in roads.iter() {
|
|
|
|
|
state
|
|
|
|
|
.dispatchers
|
2023-05-20 18:16:09 +00:00
|
|
|
.entry(Road(*r))
|
|
|
|
|
.or_insert(Vec::new())
|
|
|
|
|
.push((dispatcher_id.clone(), writer_stream.clone()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
debug!(?state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn get_dispatcher_for_road(&self, road: Road) -> Option<mpsc::Sender<Ticket>> {
|
|
|
|
|
let state = self.state.lock().unwrap();
|
|
|
|
|
let senders = state.dispatchers.get(&road);
|
|
|
|
|
if senders.is_none() {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
senders.unwrap().first().map(|(_, s)| s.clone())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn add_open_ticket(&self, ticket: Ticket) {
|
|
|
|
|
let mut state = self.state.lock().unwrap();
|
|
|
|
|
state
|
|
|
|
|
.open_tickets
|
|
|
|
|
.entry(Road(ticket.road))
|
|
|
|
|
.or_insert(Vec::new())
|
|
|
|
|
.push(ticket);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn get_plates_by_road(
|
|
|
|
|
&self,
|
|
|
|
|
plate: Plate,
|
|
|
|
|
road: Road,
|
|
|
|
|
) -> Option<Vec<(Mile, Timestamp)>> {
|
|
|
|
|
let state = self.state.lock().unwrap();
|
|
|
|
|
state.plates.get(&(plate, road)).cloned()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn add_plate(&self, camera_id: CameraId, plate: Plate) {
|
|
|
|
|
let state = self.state.lock().unwrap();
|
|
|
|
|
let camera = self.get_camera(camera_id).unwrap();
|
|
|
|
|
|
|
|
|
|
match self
|
|
|
|
|
.state
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.plates
|
|
|
|
|
.get_mut(&(plate.clone(), camera.road.clone()))
|
|
|
|
|
{
|
|
|
|
|
Some(v) => v.push((camera.mile, plate.timestamp)),
|
|
|
|
|
None => {
|
|
|
|
|
self.state.lock().unwrap().plates.insert(
|
|
|
|
|
(plate.clone(), camera.road),
|
|
|
|
|
vec![(camera.mile, plate.timestamp)],
|
|
|
|
|
);
|
|
|
|
|
}
|
2023-05-19 13:01:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
debug!(?state);
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-20 18:16:09 +00:00
|
|
|
pub(crate) fn ticket_plate(&self, day: u32, plate_name: String) {
|
2023-05-19 13:01:12 +00:00
|
|
|
let mut state = self.state.lock().unwrap();
|
2023-05-20 18:16:09 +00:00
|
|
|
state
|
|
|
|
|
.ticketed_plates_by_day
|
|
|
|
|
.insert((Timestamp(day), plate_name));
|
2023-05-19 13:01:12 +00:00
|
|
|
debug!(?state);
|
|
|
|
|
}
|
2023-05-20 18:16:09 +00:00
|
|
|
|
|
|
|
|
pub(crate) fn is_plate_ticketed_for_day(&self, day: u32, plate_name: String) -> bool {
|
|
|
|
|
let state = self.state.lock().unwrap();
|
|
|
|
|
state
|
|
|
|
|
.ticketed_plates_by_day
|
|
|
|
|
.contains(&(Timestamp(day), plate_name))
|
|
|
|
|
// debug!(?state);
|
|
|
|
|
}
|
2023-05-17 19:32:32 +00:00
|
|
|
}
|