use crate::client::Response;
use crate::error::{Error, Result};
use crate::wire::Method;
use core::ptr;
use nwep_sys as sys;
#[derive(Clone, Copy, Debug, Default)]
pub struct CacheStats {
pub hits: u64,
pub misses: u64,
pub stores: u64,
pub evictions: u64,
}
pub struct Cache {
raw: *mut sys::nwep_cache,
}
impl Cache {
pub fn new(max_bytes: usize, max_entries: usize) -> Result<Cache> {
let raw = unsafe { sys::nwep_cache_create(max_bytes, max_entries) };
if raw.is_null() {
return Err(Error::InternalAlloc);
}
Ok(Cache { raw })
}
pub fn put_signed(
&mut self,
method: Method,
path: &str,
response: &Response,
origin_pubkey: &[u8; 32],
now_secs: u64,
) -> Result<()> {
let cpath = std::ffi::CString::new(path).map_err(|_| Error::ProtoInvalidHeader)?;
let cmethod = method_cstr(method);
Error::check(unsafe {
sys::nwep_cache_put_signed(
self.raw,
cmethod.as_ptr(),
cpath.as_ptr(),
response.as_raw(),
origin_pubkey.as_ptr(),
now_secs,
)
})
}
pub fn get_signed(
&mut self,
method: Method,
path: &str,
origin_pubkey: &[u8; 32],
now_secs: u64,
) -> Option<Response> {
let cpath = std::ffi::CString::new(path).ok()?;
let cmethod = method_cstr(method);
let mut out: *mut sys::nwep_message = ptr::null_mut();
let rc = unsafe {
sys::nwep_cache_get_signed(
self.raw,
cmethod.as_ptr(),
cpath.as_ptr(),
origin_pubkey.as_ptr(),
now_secs,
&mut out,
)
};
if rc == 0 && !out.is_null() {
Some(Response::from_raw(out))
} else {
None
}
}
pub fn clear(&mut self) {
unsafe { sys::nwep_cache_clear(self.raw) };
}
pub fn stats(&self) -> CacheStats {
let mut s = CacheStats::default();
unsafe {
sys::nwep_cache_stats(
self.raw,
&mut s.hits,
&mut s.misses,
&mut s.stores,
&mut s.evictions,
)
};
s
}
pub fn as_ptr(&self) -> *mut sys::nwep_cache {
self.raw
}
}
impl Drop for Cache {
fn drop(&mut self) {
unsafe { sys::nwep_cache_free(self.raw) };
}
}
fn method_cstr(method: Method) -> std::ffi::CString {
std::ffi::CString::new(method.as_str()).unwrap_or_default()
}