things3_cloud/
cloud_writer.rs1use crate::auth::load_auth;
2use crate::client::ThingsCloudClient;
3use crate::dirs::append_log_dir;
4use crate::log_cache::read_cached_head_index;
5use crate::wire::wire_object::WireObject;
6use anyhow::Result;
7use serde_json::json;
8use std::collections::BTreeMap;
9use tracing::{debug, error};
10
11pub trait CloudWriter {
12 fn commit(
13 &mut self,
14 changes: BTreeMap<String, WireObject>,
15 ancestor_index: Option<i64>,
16 ) -> Result<i64>;
17
18 fn head_index(&self) -> i64;
19}
20
21pub struct LoggingCloudWriter {
22 inner: Box<dyn CloudWriter>,
23}
24
25impl LoggingCloudWriter {
26 pub fn new(inner: Box<dyn CloudWriter>) -> Self {
27 Self { inner }
28 }
29}
30
31impl CloudWriter for LoggingCloudWriter {
32 fn commit(
33 &mut self,
34 changes: BTreeMap<String, WireObject>,
35 ancestor_index: Option<i64>,
36 ) -> Result<i64> {
37 let uuids = changes.keys().cloned().collect::<Vec<_>>();
38 let request_value = json!({
39 "ancestor_index": ancestor_index.unwrap_or(self.inner.head_index()),
40 "changes": &changes,
41 });
42 let request_json =
43 serde_json::to_string(&request_value).unwrap_or_else(|_| "{}".to_string());
44 debug!(
45 target: "things_cli::cloud_commit::request",
46 event = "cloud.commit.request",
47 ancestor_index,
48 change_count = uuids.len(),
49 uuids = ?uuids,
50 request_json = %request_json,
51 "cloud commit request"
52 );
53
54 match self.inner.commit(changes, ancestor_index) {
55 Ok(head_index) => {
56 debug!(
57 target: "things_cli::cloud_commit::success",
58 event = "cloud.commit.success",
59 ancestor_index,
60 change_count = uuids.len(),
61 uuids = ?uuids,
62 head_index,
63 "cloud commit succeeded"
64 );
65 Ok(head_index)
66 }
67 Err(err) => {
68 error!(
69 target: "things_cli::cloud_commit::error",
70 event = "cloud.commit.error",
71 ancestor_index,
72 change_count = uuids.len(),
73 uuids = ?uuids,
74 error = %err,
75 "cloud commit failed"
76 );
77 Err(err)
78 }
79 }
80 }
81
82 fn head_index(&self) -> i64 {
83 self.inner.head_index()
84 }
85}
86
87pub struct LiveCloudWriter {
88 client: ThingsCloudClient,
89}
90
91#[derive(Default)]
92pub struct DryRunCloudWriter {
93 head_index: i64,
94}
95
96impl DryRunCloudWriter {
97 pub fn new() -> Self {
98 Self::default()
99 }
100}
101
102impl LiveCloudWriter {
103 pub fn new() -> Result<Self> {
104 let (email, password) = load_auth()?;
105 let mut client = ThingsCloudClient::new(email, password)?;
106 let _ = client.authenticate();
107 client.head_index = read_cached_head_index(&append_log_dir());
108 Ok(Self { client })
109 }
110}
111
112impl CloudWriter for LiveCloudWriter {
113 fn commit(
114 &mut self,
115 changes: BTreeMap<String, WireObject>,
116 ancestor_index: Option<i64>,
117 ) -> Result<i64> {
118 self.client.commit(changes, ancestor_index)
119 }
120
121 fn head_index(&self) -> i64 {
122 self.client.head_index
123 }
124}
125
126impl CloudWriter for DryRunCloudWriter {
127 fn commit(
128 &mut self,
129 _changes: BTreeMap<String, WireObject>,
130 _ancestor_index: Option<i64>,
131 ) -> Result<i64> {
132 self.head_index += 1;
133 Ok(self.head_index)
134 }
135
136 fn head_index(&self) -> i64 {
137 self.head_index
138 }
139}