1use std::borrow::Cow;
13use std::ffi::{c_char, c_uint, CStr};
14use std::time::Duration;
15
16use serde::{Deserialize, Serialize};
17
18use crate::ffi::{vrt_backend_probe, VCL_DURATION, VCL_PROBE, VRT_BACKEND_PROBE_MAGIC};
19use crate::vcl::{IntoVCL, VclError, Workspace};
20
21#[derive(Debug, Clone, Deserialize, Serialize)]
23pub enum Request<T> {
24 Url(T),
26 Text(T),
28}
29
30#[derive(Debug, Clone, Deserialize, Serialize)]
35pub struct Probe<T = String> {
36 pub request: Request<T>,
38 pub timeout: Duration,
40 pub interval: Duration,
42 pub exp_status: c_uint,
44 pub window: c_uint,
46 pub threshold: c_uint,
48 pub initial: c_uint,
50}
51
52pub type CowProbe<'a> = Probe<Cow<'a, str>>;
54
55impl CowProbe<'_> {
56 pub fn to_owned(&self) -> Probe {
58 Probe {
59 request: match &self.request {
60 Request::Url(cow) => Request::Url(cow.to_string()),
61 Request::Text(cow) => Request::Text(cow.to_string()),
62 },
63 timeout: self.timeout,
64 interval: self.interval,
65 exp_status: self.exp_status,
66 window: self.window,
67 threshold: self.threshold,
68 initial: self.initial,
69 }
70 }
71}
72
73pub(crate) fn into_vcl_probe<T: AsRef<str>>(
75 src: Probe<T>,
76 ws: &mut Workspace,
77) -> Result<VCL_PROBE, VclError> {
78 let probe = ws.copy_value(vrt_backend_probe {
79 magic: VRT_BACKEND_PROBE_MAGIC,
80 timeout: src.timeout.into(),
81 interval: src.interval.into(),
82 exp_status: src.exp_status,
83 window: src.window,
84 initial: src.initial,
85 ..Default::default()
86 })?;
87
88 match src.request {
89 Request::Url(s) => {
90 probe.url = s.as_ref().into_vcl(ws)?.0;
91 }
92 Request::Text(s) => {
93 probe.request = s.as_ref().into_vcl(ws)?.0;
94 }
95 }
96
97 Ok(VCL_PROBE(probe))
98}
99
100pub(crate) fn from_vcl_probe<'a, T: From<Cow<'a, str>>>(value: VCL_PROBE) -> Option<Probe<T>> {
102 let pr = unsafe { value.0.as_ref()? };
103 assert!(
104 (pr.url.is_null() && !pr.request.is_null()) || pr.request.is_null() && !pr.url.is_null()
105 );
106 Some(Probe {
107 request: if pr.url.is_null() {
108 Request::Text(from_str(pr.request).into())
109 } else {
110 Request::Url(from_str(pr.url).into())
111 },
112 timeout: VCL_DURATION(pr.timeout).into(),
113 interval: VCL_DURATION(pr.interval).into(),
114 exp_status: pr.exp_status,
115 window: pr.window,
116 threshold: pr.threshold,
117 initial: pr.initial,
118 })
119}
120
121fn from_str<'a>(value: *const c_char) -> Cow<'a, str> {
123 if value.is_null() {
124 Cow::Borrowed("")
125 } else {
126 unsafe { CStr::from_ptr(value).to_string_lossy() }
128 }
129}