Skip to main content

degenbot_cli_core/
context.rs

1//! The driver-domain context a command executes against (ADR-051 D8).
2//!
3//! The database path / chain id / node URIs are resolved through the
4//! `degenbot-config` resolvers — the SAME cascades the Python console reads —
5//! over an injectable [`EnvVars`] seam (never `std::env`), with the CLI override
6//! values the argv facade threaded in.
7
8use std::path::PathBuf;
9
10use degenbot_config::{
11    resolve_chain_id, resolve_database_path, resolve_node_http_uri, resolve_node_uris, EnvVars,
12    Resolved, ResolvedNodeUris,
13};
14
15/// The resolved inputs a console command runs against.
16pub struct CliContext<'a> {
17    env: &'a dyn EnvVars,
18    database: Option<String>,
19    chain_id: Option<String>,
20    node_http: Option<String>,
21    node_ws: Option<String>,
22}
23
24impl<'a> CliContext<'a> {
25    /// A context over `env` with no CLI overrides (env + defaults only).
26    #[must_use]
27    pub fn new(env: &'a dyn EnvVars) -> Self {
28        Self {
29            env,
30            database: None,
31            chain_id: None,
32            node_http: None,
33            node_ws: None,
34        }
35    }
36
37    /// Set the `--database` override (highest-precedence layer).
38    #[must_use]
39    pub fn with_database(mut self, database: impl Into<String>) -> Self {
40        self.database = Some(database.into());
41        self
42    }
43
44    /// Set the `--chain-id` override.
45    #[must_use]
46    pub fn with_chain_id(mut self, chain_id: impl Into<String>) -> Self {
47        self.chain_id = Some(chain_id.into());
48        self
49    }
50
51    /// Set the `--node-http` override.
52    #[must_use]
53    pub fn with_node_http(mut self, uri: impl Into<String>) -> Self {
54        self.node_http = Some(uri.into());
55        self
56    }
57
58    /// Set the `--node-ws` override.
59    #[must_use]
60    pub fn with_node_ws(mut self, uri: impl Into<String>) -> Self {
61        self.node_ws = Some(uri.into());
62        self
63    }
64
65    /// The env seam (the resolvers' only env reader).
66    #[must_use]
67    pub fn env(&self) -> &'a dyn EnvVars {
68        self.env
69    }
70
71    /// The `--database` override, if any.
72    #[must_use]
73    pub fn database_override(&self) -> Option<&str> {
74        self.database.as_deref()
75    }
76
77    /// Resolve the database path: `--database` > `DEGENBOT_DB_PATH` > the
78    /// built-in default. Never fails.
79    #[must_use]
80    pub fn database_path(&self) -> Resolved<PathBuf> {
81        resolve_database_path(self.env, self.database.as_deref())
82    }
83
84    /// Resolve the session chain id: `--chain-id` > `DEGENBOT_DEFAULT_CHAIN_ID`.
85    ///
86    /// # Errors
87    ///
88    /// [`degenbot_config::ConfigError`] when neither layer supplied a value, or
89    /// the winning layer is not an integer.
90    pub fn chain_id(&self) -> Result<Resolved<u64>, degenbot_config::ConfigError> {
91        resolve_chain_id(self.env, self.chain_id.as_deref())
92    }
93
94    /// Resolve the HTTP node URI for `chain_id`: `--node-http` >
95    /// `DEGENBOT_RPC_HTTP_CHAINID_<id>`.
96    ///
97    /// The updater arms resolve the chain they actually operate on (which may
98    /// differ from the session chain id, e.g. a validated Aave deployment).
99    ///
100    /// # Errors
101    ///
102    /// [`degenbot_config::ConfigError`] when no layer supplied the URI.
103    pub fn node_http_uri_for(
104        &self,
105        chain_id: u64,
106    ) -> Result<Resolved<String>, degenbot_config::ConfigError> {
107        resolve_node_http_uri(self.env, chain_id, self.node_http.as_deref())
108    }
109
110    /// Resolve the HTTP node URI for the session chain id.
111    ///
112    /// # Errors
113    ///
114    /// [`degenbot_config::ConfigError`] when the chain id or endpoint is
115    /// unresolved.
116    pub fn node_http_uri(&self) -> Result<Resolved<String>, degenbot_config::ConfigError> {
117        let chain_id = self.chain_id()?;
118        self.node_http_uri_for(chain_id.value)
119    }
120
121    /// Resolve both node URIs for the session chain id.
122    ///
123    /// # Errors
124    ///
125    /// [`degenbot_config::ConfigError`] when the chain id or either endpoint is
126    /// unresolved.
127    pub fn node_uris(&self) -> Result<ResolvedNodeUris, degenbot_config::ConfigError> {
128        let chain_id = self.chain_id()?;
129        resolve_node_uris(
130            self.env,
131            chain_id.value,
132            self.node_http.as_deref(),
133            self.node_ws.as_deref(),
134        )
135    }
136}