Skip to main content

things3_cloud/
cmd_ctx.rs

1use std::collections::BTreeMap;
2
3use anyhow::Result;
4use chrono::{DateTime, TimeZone, Utc};
5
6use crate::{
7    app::Cli,
8    cloud_writer::{CloudWriter, DryRunCloudWriter, LiveCloudWriter, LoggingCloudWriter},
9    ids::ThingsId,
10    wire::wire_object::WireObject,
11};
12
13pub trait CmdCtx {
14    fn now_timestamp(&self) -> f64;
15    fn today_timestamp(&self) -> i64;
16    fn today(&self) -> DateTime<Utc> {
17        let ts = self.today_timestamp();
18        Utc.timestamp_opt(ts, 0)
19            .single()
20            .unwrap_or_else(Utc::now)
21            .date_naive()
22            .and_hms_opt(0, 0, 0)
23            .map(|d| Utc.from_utc_datetime(&d))
24            .unwrap_or_else(Utc::now)
25    }
26    fn next_id(&mut self) -> String;
27    fn commit_changes(
28        &mut self,
29        changes: BTreeMap<String, WireObject>,
30        ancestor_index: Option<i64>,
31    ) -> Result<i64>;
32    fn current_head_index(&self) -> i64;
33}
34
35#[derive(Default)]
36pub struct DefaultCmdCtx {
37    no_cloud: bool,
38    today_ts_override: Option<i64>,
39    now_ts_override: Option<f64>,
40    writer: Option<Box<dyn CloudWriter>>,
41}
42
43impl DefaultCmdCtx {
44    pub fn from_cli(cli: &Cli) -> Self {
45        Self {
46            no_cloud: cli.no_cloud,
47            today_ts_override: cli.today_ts,
48            now_ts_override: cli.now_ts,
49            writer: None,
50        }
51    }
52
53    fn writer_mut(&mut self) -> Result<&mut dyn CloudWriter> {
54        if self.writer.is_none() {
55            let inner: Box<dyn CloudWriter> = if self.no_cloud {
56                Box::new(DryRunCloudWriter::new())
57            } else {
58                Box::new(LiveCloudWriter::new()?)
59            };
60            self.writer = Some(Box::new(LoggingCloudWriter::new(inner)));
61        }
62        Ok(self.writer.as_deref_mut().expect("writer initialized"))
63    }
64}
65
66impl CmdCtx for DefaultCmdCtx {
67    fn now_timestamp(&self) -> f64 {
68        self.now_ts_override
69            .unwrap_or_else(crate::common::now_ts_f64)
70    }
71
72    fn today_timestamp(&self) -> i64 {
73        self.today_ts_override
74            .unwrap_or_else(|| crate::common::today_utc().timestamp())
75    }
76
77    fn next_id(&mut self) -> String {
78        ThingsId::random().to_string()
79    }
80
81    fn commit_changes(
82        &mut self,
83        changes: BTreeMap<String, WireObject>,
84        ancestor_index: Option<i64>,
85    ) -> Result<i64> {
86        self.writer_mut()?.commit(changes, ancestor_index)
87    }
88
89    fn current_head_index(&self) -> i64 {
90        self.writer.as_deref().map_or(0, CloudWriter::head_index)
91    }
92}