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