saluki_components/sources/dogstatsd/replay/
capture_api.rs1use std::path::Path;
6
7use saluki_api::{
8 extract::State,
9 routing::{post, Router},
10 APIHandler, Json, StatusCode,
11};
12use saluki_config::parse_duration;
13use serde::{Deserialize, Serialize};
14
15use super::DogStatsDCaptureControl;
16
17#[derive(Deserialize)]
19pub struct CaptureTriggerBody {
20 pub duration: String,
22
23 #[serde(default)]
26 pub path: Option<String>,
27
28 #[serde(default)]
30 pub compressed: bool,
31}
32
33#[derive(Serialize)]
35pub struct CaptureTriggerResponseBody {
36 pub path: String,
38}
39
40#[derive(Clone)]
42pub struct DogStatsDCaptureAPIHandler {
43 capture_control: DogStatsDCaptureControl,
44}
45
46impl DogStatsDCaptureAPIHandler {
47 pub fn new(capture_control: DogStatsDCaptureControl) -> Self {
49 Self { capture_control }
50 }
51
52 async fn trigger_handler(
53 State(capture_control): State<DogStatsDCaptureControl>, Json(body): Json<CaptureTriggerBody>,
54 ) -> Result<Json<CaptureTriggerResponseBody>, (StatusCode, String)> {
55 let duration = parse_duration(&body.duration).map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?;
56 let requested_dir = body.path.as_deref().map(Path::new);
57
58 let capture_path = capture_control
59 .start_capture(requested_dir, duration, body.compressed)
60 .map_err(|e| (StatusCode::PRECONDITION_FAILED, e.to_string()))?;
61
62 Ok(Json(CaptureTriggerResponseBody {
63 path: capture_path.display().to_string(),
64 }))
65 }
66}
67
68impl APIHandler for DogStatsDCaptureAPIHandler {
69 type State = DogStatsDCaptureControl;
70
71 fn generate_initial_state(&self) -> Self::State {
72 self.capture_control.clone()
73 }
74
75 fn generate_routes(&self) -> Router<Self::State> {
76 Router::new().route("/dogstatsd/capture/trigger", post(Self::trigger_handler))
77 }
78}