1use crate::error::{Error, check};
2use crate::ffi;
3use crate::types::Tstamp;
4use std::ffi::CString;
5
6pub const POOL_MAX_SERVERS: usize = 32;
8
9pub const POOL_HEALTH_CHECK_FAILURES: i32 = 3;
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
14pub enum PoolStrategy {
15 RoundRobin,
17 Random,
19}
20
21impl From<ffi::nwep_pool_strategy> for PoolStrategy {
22 fn from(s: ffi::nwep_pool_strategy) -> Self {
23 match s {
24 ffi::nwep_pool_strategy_NWEP_POOL_RANDOM => PoolStrategy::Random,
25 _ => PoolStrategy::RoundRobin,
26 }
27 }
28}
29
30fn pool_strategy_to_ffi(s: PoolStrategy) -> ffi::nwep_pool_strategy {
31 match s {
32 PoolStrategy::RoundRobin => ffi::nwep_pool_strategy_NWEP_POOL_ROUND_ROBIN,
33 PoolStrategy::Random => ffi::nwep_pool_strategy_NWEP_POOL_RANDOM,
34 }
35}
36
37#[derive(Clone, Copy, Debug, PartialEq, Eq)]
39pub enum ServerHealth {
40 Healthy,
42 Unhealthy,
44}
45
46impl From<ffi::nwep_server_health> for ServerHealth {
47 fn from(h: ffi::nwep_server_health) -> Self {
48 match h {
49 ffi::nwep_server_health_NWEP_SERVER_UNHEALTHY => ServerHealth::Unhealthy,
50 _ => ServerHealth::Healthy,
51 }
52 }
53}
54
55#[derive(Clone, Debug)]
57pub struct PoolServer {
58 pub url: String,
60 pub health: ServerHealth,
62 pub consecutive_failures: i32,
64 pub last_success: Tstamp,
66 pub last_failure: Tstamp,
68}
69
70impl PoolServer {
71 fn from_ffi(p: &ffi::nwep_pool_server) -> Self {
72 let url = unsafe {
73 std::ffi::CStr::from_ptr(p.url.as_ptr())
74 .to_string_lossy()
75 .into_owned()
76 };
77 PoolServer {
78 url,
79 health: ServerHealth::from(p.health),
80 consecutive_failures: p.consecutive_failures,
81 last_success: p.last_success,
82 last_failure: p.last_failure,
83 }
84 }
85}
86
87#[derive(Clone, Debug)]
89pub struct PoolSettings {
90 pub strategy: PoolStrategy,
92 pub max_failures: i32,
94}
95
96impl Default for PoolSettings {
97 fn default() -> Self {
98 let mut s = unsafe { std::mem::zeroed::<ffi::nwep_log_server_pool_settings>() };
99 unsafe { ffi::nwep_log_server_pool_settings_default(&mut s) };
100 PoolSettings {
101 strategy: PoolStrategy::from(s.strategy),
102 max_failures: s.max_failures,
103 }
104 }
105}
106
107pub struct LogServerPool {
113 ptr: *mut ffi::nwep_log_server_pool,
114}
115
116unsafe impl Send for LogServerPool {}
117
118impl LogServerPool {
119 pub fn new(settings: Option<&PoolSettings>) -> Result<Self, Error> {
127 let mut ptr: *mut ffi::nwep_log_server_pool = std::ptr::null_mut();
128 let rc = match settings {
129 Some(s) => {
130 let mut ffi_s = unsafe { std::mem::zeroed::<ffi::nwep_log_server_pool_settings>() };
131 unsafe { ffi::nwep_log_server_pool_settings_default(&mut ffi_s) };
132 ffi_s.strategy = pool_strategy_to_ffi(s.strategy);
133 ffi_s.max_failures = s.max_failures;
134 unsafe { ffi::nwep_log_server_pool_new(&mut ptr, &ffi_s) }
135 }
136 None => unsafe { ffi::nwep_log_server_pool_new(&mut ptr, std::ptr::null()) },
137 };
138 check(rc)?;
139 Ok(LogServerPool { ptr })
140 }
141
142 pub fn add(&mut self, url: &str) -> Result<(), Error> {
148 let curl = CString::new(url)
149 .map_err(|_| crate::error::Error::from_code(crate::error::ERR_INTERNAL_INVALID_ARG))?;
150 check(unsafe { ffi::nwep_log_server_pool_add(self.ptr, curl.as_ptr()) })
151 }
152
153 pub fn remove(&mut self, url: &str) -> Result<(), Error> {
159 let curl = CString::new(url)
160 .map_err(|_| crate::error::Error::from_code(crate::error::ERR_INTERNAL_INVALID_ARG))?;
161 check(unsafe { ffi::nwep_log_server_pool_remove(self.ptr, curl.as_ptr()) })
162 }
163
164 pub fn select(&mut self) -> Result<PoolServer, Error> {
170 let mut out = unsafe { std::mem::zeroed::<ffi::nwep_pool_server>() };
171 check(unsafe { ffi::nwep_log_server_pool_select(self.ptr, &mut out) })?;
172 Ok(PoolServer::from_ffi(&out))
173 }
174
175 pub fn mark_success(&mut self, url: &str, now: Tstamp) {
177 if let Ok(curl) = CString::new(url) {
178 unsafe { ffi::nwep_log_server_pool_mark_success(self.ptr, curl.as_ptr(), now) }
179 }
180 }
181
182 pub fn mark_failure(&mut self, url: &str, now: Tstamp) {
186 if let Ok(curl) = CString::new(url) {
187 unsafe { ffi::nwep_log_server_pool_mark_failure(self.ptr, curl.as_ptr(), now) }
188 }
189 }
190
191 pub fn size(&self) -> usize {
193 unsafe { ffi::nwep_log_server_pool_size(self.ptr) }
194 }
195
196 pub fn healthy_count(&self) -> usize {
198 unsafe { ffi::nwep_log_server_pool_healthy_count(self.ptr) }
199 }
200
201 pub fn get(&self, index: usize) -> Result<PoolServer, Error> {
207 let mut out = unsafe { std::mem::zeroed::<ffi::nwep_pool_server>() };
208 check(unsafe { ffi::nwep_log_server_pool_get(self.ptr, index, &mut out) })?;
209 Ok(PoolServer::from_ffi(&out))
210 }
211
212 pub fn reset_health(&mut self) {
216 unsafe { ffi::nwep_log_server_pool_reset_health(self.ptr) }
217 }
218}
219
220impl Drop for LogServerPool {
221 fn drop(&mut self) {
222 if !self.ptr.is_null() {
223 unsafe { ffi::nwep_log_server_pool_free(self.ptr) }
224 }
225 }
226}