Line data Source code
1 : use std::sync::Arc;
2 :
3 : use serde::{Deserialize, Serialize};
4 : use serde_json::Value;
5 : use tracing::info;
6 :
7 : use crate::{state::TimelinePersistentState, timeline::Timeline};
8 :
9 0 : #[derive(Deserialize, Debug, Clone)]
10 : pub struct Request {
11 : /// JSON object with fields to update
12 : pub updates: serde_json::Value,
13 : /// List of fields to apply
14 : pub apply_fields: Vec<String>,
15 : }
16 :
17 : #[derive(Serialize)]
18 : pub struct Response {
19 : pub old_control_file: TimelinePersistentState,
20 : pub new_control_file: TimelinePersistentState,
21 : }
22 :
23 : /// Patch control file with given request. Will update the persistent state using
24 : /// fields from the request and persist the new state on disk.
25 0 : pub async fn handle_request(tli: Arc<Timeline>, request: Request) -> anyhow::Result<Response> {
26 0 : let response = tli
27 0 : .map_control_file(|state| {
28 0 : let old_control_file = state.clone();
29 0 : let new_control_file = state_apply_diff(&old_control_file, &request)?;
30 :
31 0 : info!(
32 0 : "patching control file, old: {:?}, new: {:?}, patch: {:?}",
33 : old_control_file, new_control_file, request
34 : );
35 0 : *state = new_control_file.clone();
36 0 :
37 0 : Ok(Response {
38 0 : old_control_file,
39 0 : new_control_file,
40 0 : })
41 0 : })
42 0 : .await?;
43 :
44 0 : Ok(response)
45 0 : }
46 :
47 0 : fn state_apply_diff(
48 0 : state: &TimelinePersistentState,
49 0 : request: &Request,
50 0 : ) -> anyhow::Result<TimelinePersistentState> {
51 0 : let mut json_value = serde_json::to_value(state)?;
52 :
53 0 : if let Value::Object(a) = &mut json_value {
54 0 : if let Value::Object(b) = &request.updates {
55 0 : json_apply_diff(a, b, &request.apply_fields)?;
56 : } else {
57 0 : anyhow::bail!("request.updates is not a json object")
58 : }
59 : } else {
60 0 : anyhow::bail!("TimelinePersistentState is not a json object")
61 : }
62 :
63 0 : let new_state: TimelinePersistentState = serde_json::from_value(json_value)?;
64 0 : Ok(new_state)
65 0 : }
66 :
67 0 : fn json_apply_diff(
68 0 : object: &mut serde_json::Map<String, Value>,
69 0 : updates: &serde_json::Map<String, Value>,
70 0 : apply_keys: &Vec<String>,
71 0 : ) -> anyhow::Result<()> {
72 0 : for key in apply_keys {
73 0 : if let Some(new_value) = updates.get(key) {
74 0 : if let Some(existing_value) = object.get_mut(key) {
75 0 : *existing_value = new_value.clone();
76 0 : } else {
77 0 : anyhow::bail!("key not found in original object: {}", key);
78 : }
79 : } else {
80 0 : anyhow::bail!("key not found in request.updates: {}", key);
81 : }
82 : }
83 :
84 0 : Ok(())
85 0 : }
|