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 5 : #[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 1 : #[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 1 : pub async fn handle_request(tli: Arc<Timeline>, request: Request) -> anyhow::Result<Response> {
26 1 : let response = tli
27 1 : .map_control_file(|state| {
28 1 : let old_control_file = state.clone();
29 1 : let new_control_file = state_apply_diff(&old_control_file, &request)?;
30 :
31 1 : info!(
32 1 : "patching control file, old: {:?}, new: {:?}, patch: {:?}",
33 1 : old_control_file, new_control_file, request
34 1 : );
35 1 : *state = new_control_file.clone();
36 1 :
37 1 : Ok(Response {
38 1 : old_control_file,
39 1 : new_control_file,
40 1 : })
41 1 : })
42 3 : .await?;
43 :
44 1 : Ok(response)
45 1 : }
46 :
47 1 : fn state_apply_diff(
48 1 : state: &TimelinePersistentState,
49 1 : request: &Request,
50 1 : ) -> anyhow::Result<TimelinePersistentState> {
51 1 : let mut json_value = serde_json::to_value(state)?;
52 :
53 1 : if let Value::Object(a) = &mut json_value {
54 1 : if let Value::Object(b) = &request.updates {
55 1 : 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 1 : let new_state: TimelinePersistentState = serde_json::from_value(json_value)?;
64 1 : Ok(new_state)
65 1 : }
66 :
67 1 : fn json_apply_diff(
68 1 : object: &mut serde_json::Map<String, Value>,
69 1 : updates: &serde_json::Map<String, Value>,
70 1 : apply_keys: &Vec<String>,
71 1 : ) -> anyhow::Result<()> {
72 2 : for key in apply_keys {
73 1 : if let Some(new_value) = updates.get(key) {
74 1 : if let Some(existing_value) = object.get_mut(key) {
75 1 : *existing_value = new_value.clone();
76 1 : } 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 1 : Ok(())
85 1 : }
|