ant_service_management/
lib.rs

1// Copyright (C) 2024 MaidSafe.net limited.
2//
3// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3.
4// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
5// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
6// KIND, either express or implied. Please review the Licences for the specific language governing
7// permissions and limitations relating to use of the SAFE Network Software.
8
9pub mod auditor;
10pub mod control;
11pub mod daemon;
12pub mod error;
13pub mod faucet;
14pub mod node;
15pub mod rpc;
16
17#[macro_use]
18extern crate tracing;
19
20pub mod antctl_proto {
21    tonic::include_proto!("antctl_proto");
22}
23
24use async_trait::async_trait;
25use auditor::AuditorServiceData;
26use semver::Version;
27use serde::{Deserialize, Serialize};
28use service_manager::ServiceInstallCtx;
29use std::{
30    io::{Read, Write},
31    path::{Path, PathBuf},
32};
33
34pub use daemon::{DaemonService, DaemonServiceData};
35pub use error::{Error, Result};
36pub use faucet::{FaucetService, FaucetServiceData};
37pub use node::{NodeService, NodeServiceData};
38
39#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
40pub enum ServiceStatus {
41    /// The service has been added but not started for the first time
42    Added,
43    /// Last time we checked the service was running
44    Running,
45    /// The service has been stopped
46    Stopped,
47    /// The service has been removed
48    Removed,
49}
50
51#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
52pub enum NatDetectionStatus {
53    Public,
54    UPnP,
55    Private,
56}
57
58#[derive(Clone, Debug, PartialEq)]
59pub enum UpgradeResult {
60    Forced(String, String),
61    NotRequired,
62    Upgraded(String, String),
63    UpgradedButNotStarted(String, String, String),
64    Error(String),
65}
66
67#[derive(Clone, Debug, Eq, PartialEq)]
68pub struct UpgradeOptions {
69    pub auto_restart: bool,
70    pub env_variables: Option<Vec<(String, String)>>,
71    pub force: bool,
72    pub start_service: bool,
73    pub target_bin_path: PathBuf,
74    pub target_version: Version,
75}
76
77#[async_trait]
78pub trait ServiceStateActions {
79    fn bin_path(&self) -> PathBuf;
80    fn build_upgrade_install_context(&self, options: UpgradeOptions) -> Result<ServiceInstallCtx>;
81    fn data_dir_path(&self) -> PathBuf;
82    fn is_user_mode(&self) -> bool;
83    fn log_dir_path(&self) -> PathBuf;
84    fn name(&self) -> String;
85    fn pid(&self) -> Option<u32>;
86    fn on_remove(&mut self);
87    async fn on_start(&mut self, pid: Option<u32>, full_refresh: bool) -> Result<()>;
88    async fn on_stop(&mut self) -> Result<()>;
89    fn set_version(&mut self, version: &str);
90    fn status(&self) -> ServiceStatus;
91    fn version(&self) -> String;
92}
93
94#[derive(Clone, Debug, Serialize, Deserialize)]
95pub struct StatusSummary {
96    pub nodes: Vec<NodeServiceData>,
97    pub daemon: Option<DaemonServiceData>,
98    pub faucet: Option<FaucetServiceData>,
99}
100
101#[derive(Clone, Debug, Serialize, Deserialize)]
102pub struct NodeRegistry {
103    pub auditor: Option<AuditorServiceData>,
104    pub daemon: Option<DaemonServiceData>,
105    pub environment_variables: Option<Vec<(String, String)>>,
106    pub faucet: Option<FaucetServiceData>,
107    pub nat_status: Option<NatDetectionStatus>,
108    pub nodes: Vec<NodeServiceData>,
109    pub save_path: PathBuf,
110}
111
112impl NodeRegistry {
113    pub fn save(&self) -> Result<()> {
114        debug!(
115            "Saving node registry to {}",
116            self.save_path.to_string_lossy()
117        );
118        let path = Path::new(&self.save_path);
119        if let Some(parent) = path.parent() {
120            std::fs::create_dir_all(parent).inspect_err(|err| {
121                error!("Error creating node registry parent {parent:?}: {err:?}")
122            })?;
123        }
124
125        let json = serde_json::to_string(self)?;
126        let mut file = std::fs::File::create(self.save_path.clone())
127            .inspect_err(|err| error!("Error creating node registry file: {err:?}"))?;
128        file.write_all(json.as_bytes())
129            .inspect_err(|err| error!("Error writing to node registry: {err:?}"))?;
130
131        Ok(())
132    }
133
134    pub fn load(path: &Path) -> Result<Self> {
135        if !path.exists() {
136            debug!("Loading default node registry as {path:?} does not exist");
137            return Ok(NodeRegistry {
138                auditor: None,
139                daemon: None,
140                environment_variables: None,
141                faucet: None,
142                nat_status: None,
143                nodes: vec![],
144                save_path: path.to_path_buf(),
145            });
146        }
147        debug!("Loading node registry from {}", path.to_string_lossy());
148
149        let mut file = std::fs::File::open(path)
150            .inspect_err(|err| error!("Error opening node registry: {err:?}"))?;
151
152        let mut contents = String::new();
153        file.read_to_string(&mut contents)
154            .inspect_err(|err| error!("Error reading node registry: {err:?}"))?;
155
156        // It's possible for the file to be empty if the user runs a `status` command before any
157        // services were added.
158        if contents.is_empty() {
159            return Ok(NodeRegistry {
160                auditor: None,
161                daemon: None,
162                environment_variables: None,
163                faucet: None,
164                nat_status: None,
165                nodes: vec![],
166                save_path: path.to_path_buf(),
167            });
168        }
169
170        Self::from_json(&contents)
171    }
172
173    pub fn from_json(json: &str) -> Result<Self> {
174        let registry = serde_json::from_str(json)
175            .inspect_err(|err| error!("Error deserializing node registry: {err:?}"))?;
176        Ok(registry)
177    }
178
179    pub fn to_status_summary(&self) -> StatusSummary {
180        StatusSummary {
181            nodes: self.nodes.clone(),
182            daemon: self.daemon.clone(),
183            faucet: self.faucet.clone(),
184        }
185    }
186}
187
188pub fn get_local_node_registry_path() -> Result<PathBuf> {
189    let path = dirs_next::data_dir()
190        .ok_or_else(|| {
191            error!("Failed to get data_dir");
192            Error::UserDataDirectoryNotObtainable
193        })?
194        .join("autonomi")
195        .join("local_node_registry.json");
196    if let Some(parent) = path.parent() {
197        std::fs::create_dir_all(parent)
198            .inspect_err(|err| error!("Error creating node registry parent {parent:?}: {err:?}"))?;
199    }
200    Ok(path)
201}