braid_run/
callback_handling.rs1use axum::response::IntoResponse;
5use tracing::{debug, error, warn};
6
7use braid_types::{BraidHttpApiCallback, PerCamSaveData, RawCamName};
8use event_stream_types::TolerantJson;
9use http::StatusCode;
10use strand_cam_bui_types::RecordingPath;
11
12use crate::mainbrain::*;
13
14fn update_camera_image_dimensions(
17 app_state: &BraidAppState,
18 raw_cam_name: &RawCamName,
19 current_image_png: &braid_types::PngImageData,
20) {
21 let Some(dimensions) = current_image_png.dimensions() else {
22 warn!(
23 "could not determine image dimensions for camera \"{}\"",
24 raw_cam_name.as_str()
25 );
26 return;
27 };
28 let mut tracker = app_state.shared_store.write().unwrap();
29 if (*tracker)
30 .as_ref()
31 .camera_image_dimensions
32 .get(raw_cam_name)
33 != Some(&dimensions)
34 {
35 tracker.modify(|store| {
36 store
37 .camera_image_dimensions
38 .insert(raw_cam_name.clone(), dimensions);
39 });
40 }
41}
42
43fn start_saving_mp4s_all_cams(app_state: &BraidAppState, start_saving: bool) {
44 let mut tracker = app_state.shared_store.write().unwrap();
45 tracker.modify(|store| {
46 if start_saving {
47 store.fake_mp4_recording_path = Some(RecordingPath::new("".to_string()));
48 } else {
49 store.fake_mp4_recording_path = None;
50 }
51 });
52}
53
54pub(crate) async fn callback_handler(
55 axum::extract::State(app_state): axum::extract::State<crate::mainbrain::BraidAppState>,
56 session_key: axum_token_auth::SessionKey,
57 TolerantJson(payload): TolerantJson<BraidHttpApiCallback>,
58) -> impl IntoResponse {
59 session_key.is_present();
60 let fut = async {
61 use BraidHttpApiCallback::*;
62 match payload {
63 NewCamera(cam_info) => {
64 debug!("got NewCamera {:?}", cam_info.raw_cam_name.as_str());
65 let http_camserver_info = cam_info.http_camserver_info.unwrap();
66 let cam_settings_data = cam_info.cam_settings_data.unwrap();
67 let camera_periodic_signal_period_usec =
68 cam_info.camera_periodic_signal_period_usec;
69 let mut cam_manager3 = app_state.cam_manager.clone();
70 cam_manager3
71 .register_new_camera(
72 &cam_info.raw_cam_name,
73 &http_camserver_info,
74 camera_periodic_signal_period_usec,
75 )
76 .map_err(|msg| (StatusCode::BAD_REQUEST, msg))?;
77
78 update_camera_image_dimensions(
79 &app_state,
80 &cam_info.raw_cam_name,
81 &cam_info.current_image_png,
82 );
83
84 let mut current_cam_data = app_state.per_cam_data_arc.write().unwrap();
85 if current_cam_data
86 .insert(
87 cam_info.raw_cam_name.clone(),
88 PerCamSaveData {
89 cam_settings_data: Some(cam_settings_data),
90 feature_detect_settings: None,
91 current_image_png: cam_info.current_image_png,
92 },
93 )
94 .is_some()
95 {
96 panic!("camera {} already known", cam_info.raw_cam_name.as_str());
97 }
98 }
99 UpdateCurrentImage(image_info) => {
100 debug!(
102 "got new image for camera \"{}\"",
103 image_info.raw_cam_name.as_str()
104 );
105 update_camera_image_dimensions(
106 &app_state,
107 &image_info.raw_cam_name,
108 &image_info.inner.current_image_png,
109 );
110 let mut current_cam_data = app_state.per_cam_data_arc.write().unwrap();
111 current_cam_data
112 .get_mut(&image_info.raw_cam_name)
113 .unwrap()
114 .current_image_png = image_info.inner.current_image_png;
115 }
116 UpdateCamSettings(cam_settings) => {
117 let mut current_cam_data = app_state.per_cam_data_arc.write().unwrap();
118 current_cam_data
119 .get_mut(&cam_settings.raw_cam_name)
120 .unwrap()
121 .cam_settings_data = Some(cam_settings.inner);
122 }
123 UpdateFeatureDetectSettings(feature_detect_settings) => {
124 let raw_cam_name = feature_detect_settings.raw_cam_name.clone();
125 let do_update = feature_detect_settings
126 .inner
127 .current_feature_detect_settings
128 .do_update_background_model;
129 {
130 let mut current_cam_data = app_state.per_cam_data_arc.write().unwrap();
131 current_cam_data
132 .get_mut(&raw_cam_name)
133 .unwrap()
134 .feature_detect_settings = Some(feature_detect_settings.inner);
135 }
136 let mut tracker = app_state.shared_store.write().unwrap();
139 if (*tracker)
140 .as_ref()
141 .background_model_updating
142 .get(&raw_cam_name)
143 != Some(&do_update)
144 {
145 tracker.modify(|store| {
146 store
147 .background_model_updating
148 .insert(raw_cam_name, do_update);
149 });
150 }
151 }
152 DoRecordCsvTables(value) => {
153 debug!("got DoRecordCsvTables({})", value);
154 toggle_saving_csv_tables(
155 value,
156 app_state.expected_framerate_arc.clone(),
157 app_state.output_base_dirname.clone(),
158 app_state.braidz_write_tx_weak.clone(),
159 app_state.per_cam_data_arc.clone(),
160 app_state.shared_store.clone(),
161 )
162 .await;
163 }
164 DoRecordMp4Files(start_saving) => {
165 debug!("got DoRecordMp4Files({start_saving})");
166
167 app_state
168 .strand_cam_http_session_handler
169 .toggle_saving_mp4_files_all(start_saving)
170 .await
171 .map_err(|_e| {
172 (
173 StatusCode::INTERNAL_SERVER_ERROR,
174 "toggle_saving_mp4_files_all failed",
175 )
176 })?;
177
178 start_saving_mp4s_all_cams(&app_state, start_saving);
179 }
180 SetExperimentUuid(value) => {
181 debug!("got SetExperimentUuid({})", value);
182 if let Some(braidz_write_tx) = app_state.braidz_write_tx_weak.upgrade() {
183 braidz_write_tx
185 .send(flydra2::SaveToDiskMsg::SetExperimentUuid(value))
186 .await
187 .unwrap();
188 }
189 }
190 SetPostTriggerBufferSize(val) => {
191 debug!("got SetPostTriggerBufferSize({val})");
192
193 app_state
194 .strand_cam_http_session_handler
195 .set_post_trigger_buffer_all(val)
196 .await
197 .map_err(|_e| {
198 (
199 StatusCode::INTERNAL_SERVER_ERROR,
200 "set_post_trigger_buffer_all failed",
201 )
202 })?;
203
204 {
205 let mut tracker = app_state.shared_store.write().unwrap();
206 tracker.modify(|store| {
207 store.post_trigger_buffer_size = val;
208 });
209 }
210 }
211 PostTriggerMp4Recording => {
212 debug!("got PostTriggerMp4Recording");
213
214 let is_saving = {
215 let tracker = app_state.shared_store.read().unwrap();
216 (*tracker).as_ref().fake_mp4_recording_path.is_some()
217 };
218
219 if !is_saving {
220 app_state
221 .strand_cam_http_session_handler
222 .initiate_post_trigger_mp4_all()
223 .await
224 .map_err(|_e| {
225 (
226 StatusCode::INTERNAL_SERVER_ERROR,
227 "initiate_post_trigger_mp4_all failed",
228 )
229 })?;
230
231 start_saving_mp4s_all_cams(&app_state, true);
232 } else {
233 debug!("Already saving, not initiating again.");
234 }
235 }
236 DoTakeNewBackgroundImage => {
237 debug!("got DoTakeNewBackgroundImage");
238 app_state
239 .strand_cam_http_session_handler
240 .take_new_background_all()
241 .await
242 .map_err(|_e| {
243 (
244 StatusCode::INTERNAL_SERVER_ERROR,
245 "take_new_background_all failed",
246 )
247 })?;
248 }
249 SetBackgroundUpdating(value) => {
250 debug!("got SetBackgroundUpdating({value})");
251 let per_cam_cfgs: Vec<(RawCamName, String)> = {
255 let current_cam_data = app_state.per_cam_data_arc.read().unwrap();
256 current_cam_data
257 .iter()
258 .filter_map(|(cam_name, cam_data)| {
259 match &cam_data.feature_detect_settings {
260 Some(settings) => {
261 let mut cfg = settings.current_feature_detect_settings.clone();
262 cfg.do_update_background_model = value;
263 match serde_yaml::to_string(&cfg) {
264 Ok(yaml) => Some((cam_name.clone(), yaml)),
265 Err(e) => {
266 error!(
267 "serializing object detection config for \
268 \"{}\": {e}",
269 cam_name.as_str()
270 );
271 None
272 }
273 }
274 }
275 None => {
276 warn!(
277 "not setting background updating for camera \"{}\": \
278 no feature detection settings received yet",
279 cam_name.as_str()
280 );
281 None
282 }
283 }
284 })
285 .collect()
286 };
287 for (cam_name, cfg_yaml) in per_cam_cfgs {
288 app_state
289 .strand_cam_http_session_handler
290 .send_obj_detection_config(&cam_name, cfg_yaml)
291 .await
292 .map_err(|_e| {
293 (
294 StatusCode::INTERNAL_SERVER_ERROR,
295 "send_obj_detection_config failed",
296 )
297 })?;
298 }
299 }
300 DoQuit => {
301 debug!("got DoQuit");
302 app_state
305 .shtdwn_q_tx
306 .send(())
307 .await
308 .map_err(|_e| (StatusCode::INTERNAL_SERVER_ERROR, "shutdown send failed"))?;
309 }
310 }
311 Ok::<_, (StatusCode, &'static str)>(())
312 };
313 fut.await
314}