use moka::future::Cache;
use std::time::Duration;
use crate::models::{GeoLocation, NearbyService, ServiceType};
const GEOCODE_TTL_SECS: u64 = 3600;
const PLACES_TTL_SECS: u64 = 900;
const MAX_GEOCODE_ENTRIES: u64 = 10_000;
const MAX_PLACES_ENTRIES: u64 = 50_000;
#[derive(Clone)]
pub struct GeoCache {
geocode: Cache<String, GeoLocation>,
reverse_geocode: Cache<String, GeoLocation>,
nearby: Cache<String, Vec<NearbyService>>,
}
impl Default for GeoCache {
fn default() -> Self {
Self::new()
}
}
impl GeoCache {
pub fn new() -> Self {
Self {
geocode: Cache::builder()
.max_capacity(MAX_GEOCODE_ENTRIES)
.time_to_live(Duration::from_secs(GEOCODE_TTL_SECS))
.build(),
reverse_geocode: Cache::builder()
.max_capacity(MAX_GEOCODE_ENTRIES)
.time_to_live(Duration::from_secs(GEOCODE_TTL_SECS))
.build(),
nearby: Cache::builder()
.max_capacity(MAX_PLACES_ENTRIES)
.time_to_live(Duration::from_secs(PLACES_TTL_SECS))
.build(),
}
}
fn geocode_key(address: &str) -> String {
address.to_lowercase().trim().to_string()
}
fn reverse_geocode_key(lat: f64, lng: f64) -> String {
format!("{:.6},{:.6}", lat, lng)
}
fn nearby_key(
lat: f64,
lng: f64,
service_type: ServiceType,
radius_meters: f64,
max_results: usize,
) -> String {
format!(
"{:.4},{:.4}:{:?}:{:.0}:{}",
lat, lng, service_type, radius_meters, max_results
)
}
pub async fn get_geocode(&self, address: &str) -> Option<GeoLocation> {
self.geocode.get(&Self::geocode_key(address)).await
}
pub async fn set_geocode(&self, address: &str, location: GeoLocation) {
self.geocode
.insert(Self::geocode_key(address), location)
.await;
}
pub async fn get_reverse_geocode(&self, lat: f64, lng: f64) -> Option<GeoLocation> {
self.reverse_geocode
.get(&Self::reverse_geocode_key(lat, lng))
.await
}
pub async fn set_reverse_geocode(&self, lat: f64, lng: f64, location: GeoLocation) {
self.reverse_geocode
.insert(Self::reverse_geocode_key(lat, lng), location)
.await;
}
pub async fn get_nearby(
&self,
lat: f64,
lng: f64,
service_type: ServiceType,
radius_meters: f64,
max_results: usize,
) -> Option<Vec<NearbyService>> {
self.nearby
.get(&Self::nearby_key(
lat,
lng,
service_type,
radius_meters,
max_results,
))
.await
}
pub async fn set_nearby(
&self,
lat: f64,
lng: f64,
service_type: ServiceType,
radius_meters: f64,
max_results: usize,
services: Vec<NearbyService>,
) {
self.nearby
.insert(
Self::nearby_key(lat, lng, service_type, radius_meters, max_results),
services,
)
.await;
}
}