1use std::borrow::Cow;
2use std::ffi::{c_char, c_uint, CStr};
3use std::time::Duration;
4
5use serde::{Deserialize, Serialize};
6
7use crate::ffi::{vrt_backend_probe, VCL_DURATION, VCL_PROBE, VRT_BACKEND_PROBE_MAGIC};
8use crate::vcl::{IntoVCL, VclError, Workspace};
9
10#[derive(Debug, Clone, Deserialize, Serialize)]
11pub enum Request<T> {
12 Url(T),
13 Text(T),
14}
15
16#[derive(Debug, Clone, Deserialize, Serialize)]
17pub struct Probe<T = String> {
18 pub request: Request<T>,
19 pub timeout: Duration,
20 pub interval: Duration,
21 pub exp_status: c_uint,
22 pub window: c_uint,
23 pub threshold: c_uint,
24 pub initial: c_uint,
25}
26
27pub type CowProbe<'a> = Probe<Cow<'a, str>>;
28
29impl CowProbe<'_> {
30 pub fn to_owned(&self) -> Probe {
31 Probe {
32 request: match &self.request {
33 Request::Url(cow) => Request::Url(cow.to_string()),
34 Request::Text(cow) => Request::Text(cow.to_string()),
35 },
36 timeout: self.timeout,
37 interval: self.interval,
38 exp_status: self.exp_status,
39 window: self.window,
40 threshold: self.threshold,
41 initial: self.initial,
42 }
43 }
44}
45
46pub(crate) fn into_vcl_probe<T: AsRef<str>>(
48 src: Probe<T>,
49 ws: &mut Workspace,
50) -> Result<VCL_PROBE, VclError> {
51 let probe = ws.copy_value(vrt_backend_probe {
52 magic: VRT_BACKEND_PROBE_MAGIC,
53 timeout: src.timeout.into(),
54 interval: src.interval.into(),
55 exp_status: src.exp_status,
56 window: src.window,
57 initial: src.initial,
58 ..Default::default()
59 })?;
60
61 match src.request {
62 Request::Url(s) => {
63 probe.url = s.as_ref().into_vcl(ws)?.0;
64 }
65 Request::Text(s) => {
66 probe.request = s.as_ref().into_vcl(ws)?.0;
67 }
68 }
69
70 Ok(VCL_PROBE(probe))
71}
72
73pub(crate) fn from_vcl_probe<'a, T: From<Cow<'a, str>>>(value: VCL_PROBE) -> Option<Probe<T>> {
75 let pr = unsafe { value.0.as_ref()? };
76 assert!(
77 (pr.url.is_null() && !pr.request.is_null()) || pr.request.is_null() && !pr.url.is_null()
78 );
79 Some(Probe {
80 request: if pr.url.is_null() {
81 Request::Text(from_str(pr.request).into())
82 } else {
83 Request::Url(from_str(pr.url).into())
84 },
85 timeout: VCL_DURATION(pr.timeout).into(),
86 interval: VCL_DURATION(pr.interval).into(),
87 exp_status: pr.exp_status,
88 window: pr.window,
89 threshold: pr.threshold,
90 initial: pr.initial,
91 })
92}
93
94fn from_str<'a>(value: *const c_char) -> Cow<'a, str> {
96 if value.is_null() {
97 Cow::Borrowed("")
98 } else {
99 unsafe { CStr::from_ptr(value).to_string_lossy() }
101 }
102}