use crate::error::{Error, check};
use crate::ffi;
use crate::types::Tstamp;
use std::ffi::CString;
pub const POOL_MAX_SERVERS: usize = 32;
pub const POOL_HEALTH_CHECK_FAILURES: i32 = 3;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PoolStrategy {
RoundRobin,
Random,
}
impl From<ffi::nwep_pool_strategy> for PoolStrategy {
fn from(s: ffi::nwep_pool_strategy) -> Self {
match s {
ffi::nwep_pool_strategy_NWEP_POOL_RANDOM => PoolStrategy::Random,
_ => PoolStrategy::RoundRobin,
}
}
}
fn pool_strategy_to_ffi(s: PoolStrategy) -> ffi::nwep_pool_strategy {
match s {
PoolStrategy::RoundRobin => ffi::nwep_pool_strategy_NWEP_POOL_ROUND_ROBIN,
PoolStrategy::Random => ffi::nwep_pool_strategy_NWEP_POOL_RANDOM,
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ServerHealth {
Healthy,
Unhealthy,
}
impl From<ffi::nwep_server_health> for ServerHealth {
fn from(h: ffi::nwep_server_health) -> Self {
match h {
ffi::nwep_server_health_NWEP_SERVER_UNHEALTHY => ServerHealth::Unhealthy,
_ => ServerHealth::Healthy,
}
}
}
#[derive(Clone, Debug)]
pub struct PoolServer {
pub url: String,
pub health: ServerHealth,
pub consecutive_failures: i32,
pub last_success: Tstamp,
pub last_failure: Tstamp,
}
impl PoolServer {
fn from_ffi(p: &ffi::nwep_pool_server) -> Self {
let url = unsafe {
std::ffi::CStr::from_ptr(p.url.as_ptr())
.to_string_lossy()
.into_owned()
};
PoolServer {
url,
health: ServerHealth::from(p.health),
consecutive_failures: p.consecutive_failures,
last_success: p.last_success,
last_failure: p.last_failure,
}
}
}
#[derive(Clone, Debug)]
pub struct PoolSettings {
pub strategy: PoolStrategy,
pub max_failures: i32,
}
impl Default for PoolSettings {
fn default() -> Self {
let mut s = unsafe { std::mem::zeroed::<ffi::nwep_log_server_pool_settings>() };
unsafe { ffi::nwep_log_server_pool_settings_default(&mut s) };
PoolSettings {
strategy: PoolStrategy::from(s.strategy),
max_failures: s.max_failures,
}
}
}
pub struct LogServerPool {
ptr: *mut ffi::nwep_log_server_pool,
}
unsafe impl Send for LogServerPool {}
impl LogServerPool {
pub fn new(settings: Option<&PoolSettings>) -> Result<Self, Error> {
let mut ptr: *mut ffi::nwep_log_server_pool = std::ptr::null_mut();
let rc = match settings {
Some(s) => {
let mut ffi_s = unsafe { std::mem::zeroed::<ffi::nwep_log_server_pool_settings>() };
unsafe { ffi::nwep_log_server_pool_settings_default(&mut ffi_s) };
ffi_s.strategy = pool_strategy_to_ffi(s.strategy);
ffi_s.max_failures = s.max_failures;
unsafe { ffi::nwep_log_server_pool_new(&mut ptr, &ffi_s) }
}
None => unsafe { ffi::nwep_log_server_pool_new(&mut ptr, std::ptr::null()) },
};
check(rc)?;
Ok(LogServerPool { ptr })
}
pub fn add(&mut self, url: &str) -> Result<(), Error> {
let curl = CString::new(url)
.map_err(|_| crate::error::Error::from_code(crate::error::ERR_INTERNAL_INVALID_ARG))?;
check(unsafe { ffi::nwep_log_server_pool_add(self.ptr, curl.as_ptr()) })
}
pub fn remove(&mut self, url: &str) -> Result<(), Error> {
let curl = CString::new(url)
.map_err(|_| crate::error::Error::from_code(crate::error::ERR_INTERNAL_INVALID_ARG))?;
check(unsafe { ffi::nwep_log_server_pool_remove(self.ptr, curl.as_ptr()) })
}
pub fn select(&mut self) -> Result<PoolServer, Error> {
let mut out = unsafe { std::mem::zeroed::<ffi::nwep_pool_server>() };
check(unsafe { ffi::nwep_log_server_pool_select(self.ptr, &mut out) })?;
Ok(PoolServer::from_ffi(&out))
}
pub fn mark_success(&mut self, url: &str, now: Tstamp) {
if let Ok(curl) = CString::new(url) {
unsafe { ffi::nwep_log_server_pool_mark_success(self.ptr, curl.as_ptr(), now) }
}
}
pub fn mark_failure(&mut self, url: &str, now: Tstamp) {
if let Ok(curl) = CString::new(url) {
unsafe { ffi::nwep_log_server_pool_mark_failure(self.ptr, curl.as_ptr(), now) }
}
}
pub fn size(&self) -> usize {
unsafe { ffi::nwep_log_server_pool_size(self.ptr) }
}
pub fn healthy_count(&self) -> usize {
unsafe { ffi::nwep_log_server_pool_healthy_count(self.ptr) }
}
pub fn get(&self, index: usize) -> Result<PoolServer, Error> {
let mut out = unsafe { std::mem::zeroed::<ffi::nwep_pool_server>() };
check(unsafe { ffi::nwep_log_server_pool_get(self.ptr, index, &mut out) })?;
Ok(PoolServer::from_ffi(&out))
}
pub fn reset_health(&mut self) {
unsafe { ffi::nwep_log_server_pool_reset_health(self.ptr) }
}
}
impl Drop for LogServerPool {
fn drop(&mut self) {
if !self.ptr.is_null() {
unsafe { ffi::nwep_log_server_pool_free(self.ptr) }
}
}
}