forest/cli_shared/cli/
client.rs

1// Copyright 2019-2025 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4use std::{
5    net::{IpAddr, Ipv4Addr, SocketAddr},
6    path::PathBuf,
7    str::FromStr,
8};
9
10use directories::ProjectDirs;
11use serde::{Deserialize, Serialize};
12use serde_with::serde_as;
13
14use crate::daemon::db_util::ImportMode;
15
16#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
17#[serde(transparent)]
18#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
19pub struct ChunkSize(pub u32);
20impl Default for ChunkSize {
21    fn default() -> Self {
22        ChunkSize(500_000)
23    }
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
27#[serde(transparent)]
28#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
29pub struct BufferSize(pub u32);
30impl Default for BufferSize {
31    fn default() -> Self {
32        BufferSize(1)
33    }
34}
35
36#[serde_as]
37#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
38#[serde(default)]
39#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
40pub struct Client {
41    pub data_dir: PathBuf,
42    pub genesis_file: Option<PathBuf>,
43    pub enable_rpc: bool,
44    pub enable_metrics_endpoint: bool,
45    pub enable_health_check: bool,
46    pub snapshot_height: Option<i64>,
47    pub snapshot_head: Option<i64>,
48    pub snapshot_path: Option<PathBuf>,
49    pub import_mode: ImportMode,
50    /// Skips loading import CAR file and assumes it's already been loaded.
51    /// Will use the CIDs in the header of the file to index the chain.
52    pub skip_load: bool,
53    /// When importing CAR files, chunk key-value pairs before committing them
54    /// to the database.
55    pub chunk_size: ChunkSize,
56    /// When importing CAR files, maintain a read-ahead buffer measured in
57    /// number of chunks.
58    pub buffer_size: BufferSize,
59    pub encrypt_keystore: bool,
60    /// Metrics bind, e.g. 127.0.0.1:6116
61    pub metrics_address: SocketAddr,
62    /// RPC bind, e.g. 127.0.0.1:1234
63    pub rpc_address: SocketAddr,
64    /// Path to a list of RPC methods to allow/disallow.
65    pub rpc_filter_list: Option<PathBuf>,
66    /// Healthcheck bind, e.g. 127.0.0.1:2346
67    pub healthcheck_address: SocketAddr,
68    /// Load actors from the bundle file (possibly generating it if it doesn't exist)
69    pub load_actors: bool,
70}
71
72impl Default for Client {
73    fn default() -> Self {
74        let dir = ProjectDirs::from("com", "ChainSafe", "Forest").expect("failed to find project directories, please set FOREST_CONFIG_PATH environment variable manually.");
75        Self {
76            data_dir: dir.data_dir().to_path_buf(),
77            genesis_file: None,
78            enable_rpc: true,
79            enable_metrics_endpoint: true,
80            enable_health_check: true,
81            snapshot_path: None,
82            import_mode: ImportMode::default(),
83            snapshot_height: None,
84            snapshot_head: None,
85            skip_load: false,
86            chunk_size: ChunkSize::default(),
87            buffer_size: BufferSize::default(),
88            encrypt_keystore: true,
89            metrics_address: FromStr::from_str("0.0.0.0:6116").unwrap(),
90            rpc_address: SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), crate::rpc::DEFAULT_PORT),
91            rpc_filter_list: None,
92            healthcheck_address: SocketAddr::new(
93                IpAddr::V4(Ipv4Addr::LOCALHOST),
94                crate::health::DEFAULT_HEALTHCHECK_PORT,
95            ),
96            load_actors: true,
97        }
98    }
99}
100
101impl Client {
102    pub fn default_rpc_token_path(&self) -> PathBuf {
103        self.data_dir.join("token")
104    }
105
106    pub fn rpc_v1_endpoint(&self) -> Result<url::Url, url::ParseError> {
107        format!("http://{}/rpc/v1", self.rpc_address)
108            .as_str()
109            .parse()
110    }
111}