actr_cli/commands/
check.rs1use crate::commands::Command;
7use crate::error::{ActrCliError, Result};
8use actr_config::ConfigParser;
9use async_trait::async_trait;
10use clap::Args;
11use tracing::{debug, error, info};
12
13#[derive(Args)]
14pub struct CheckCommand {
15 #[arg(value_name = "ACTR_URI")]
18 pub uris: Vec<String>,
19
20 #[arg(short = 'f', long = "file")]
22 pub config_file: Option<String>,
23
24 #[arg(short, long)]
26 pub verbose: bool,
27
28 #[arg(long, default_value = "10")]
30 pub timeout: u64,
31}
32
33#[async_trait]
34impl Command for CheckCommand {
35 async fn execute(&self) -> Result<()> {
36 let config_path = self.config_file.as_deref().unwrap_or("Actr.toml");
37
38 let uris_to_check = if self.uris.is_empty() {
40 info!(
42 "đ Loading Actor-RTC service URIs from configuration: {}",
43 config_path
44 );
45 self.load_uris_from_config(config_path).await?
46 } else {
47 info!("đ Checking provided Actor-RTC service URIs");
49 self.validate_provided_uris()?
50 };
51
52 if uris_to_check.is_empty() {
53 info!("âšī¸ No Actor-RTC service URIs to check");
54 return Ok(());
55 }
56
57 info!(
58 "đĻ Checking {} Actor-RTC service URIs...",
59 uris_to_check.len()
60 );
61
62 let mut total_checked = 0;
63 let mut available_count = 0;
64 let mut unavailable_count = 0;
65
66 for uri in &uris_to_check {
67 total_checked += 1;
68 let is_available = self.check_actr_uri(uri).await?;
69
70 if is_available {
71 available_count += 1;
72 } else {
73 unavailable_count += 1;
74 }
75 }
76
77 info!("");
79 info!("đ Actor-RTC Service Check Summary:");
80 info!(" Total checked: {}", total_checked);
81 info!(" â
Available: {}", available_count);
82 info!(" â Unavailable: {}", unavailable_count);
83
84 if unavailable_count > 0 {
85 error!(
86 "â ī¸ {} Actor-RTC services are not available in the current network",
87 unavailable_count
88 );
89 return Err(ActrCliError::dependency_error(
90 "Some Actor-RTC services are unavailable",
91 ));
92 } else {
93 info!("đ All Actor-RTC services are available and accessible!");
94 }
95
96 Ok(())
97 }
98}
99
100impl CheckCommand {
101 async fn load_uris_from_config(&self, config_path: &str) -> Result<Vec<String>> {
103 let config = ConfigParser::from_file(config_path)
105 .map_err(|e| ActrCliError::config_error(format!("Failed to load config: {e}")))?;
106
107 let mut uris = Vec::new();
108
109 for dependency in &config.dependencies {
112 let uri = if dependency.actr_type.manufacturer.is_empty() {
113 format!("actr://{}/", dependency.actr_type.name)
114 } else {
115 format!(
116 "actr://{}:{}/",
117 dependency.actr_type.manufacturer, dependency.actr_type.name
118 )
119 };
120 uris.push(uri);
121 debug!(
122 "Added dependency URI: {} (alias: {})",
123 uris.last().unwrap(),
124 dependency.alias
125 );
126 }
127
128 if uris.is_empty() {
129 info!(
130 "âšī¸ No dependencies found in configuration file: {}",
131 config_path
132 );
133 } else {
134 info!(
135 "đ Found {} actr:// service URIs in configuration",
136 uris.len()
137 );
138 }
139
140 Ok(uris)
141 }
142
143 fn validate_provided_uris(&self) -> Result<Vec<String>> {
145 let mut valid_uris = Vec::new();
146
147 for uri in &self.uris {
148 if uri.starts_with("actr://") {
149 valid_uris.push(uri.clone());
150 } else {
151 error!(
152 "â Invalid service URI protocol: {} (only actr:// service URIs are supported)",
153 uri
154 );
155 return Err(ActrCliError::dependency_error(format!(
156 "Invalid service URI protocol: {uri} (only actr:// service URIs are supported)"
157 )));
158 }
159 }
160
161 Ok(valid_uris)
162 }
163
164 async fn check_actr_uri(&self, uri: &str) -> Result<bool> {
166 info!("đ Checking Actor-RTC service: {}", uri);
167
168 let service_uri = match self.parse_actr_uri(uri) {
170 Ok(parsed) => parsed,
171 Err(e) => {
172 error!("â [{}] Invalid Actor-RTC service URI format: {}", uri, e);
173 return Ok(false);
174 }
175 };
176
177 match service_uri {
178 ActrUri::Service { service_name } => {
179 self.check_service_availability(&service_name).await
180 }
181 }
182 }
183
184 fn parse_actr_uri(&self, uri: &str) -> Result<ActrUri> {
186 if !uri.starts_with("actr://") {
187 return Err(ActrCliError::dependency_error(
188 "Service URI must start with actr://",
189 ));
190 }
191
192 let uri_part = &uri[7..]; if uri_part.ends_with('/') {
196 let service_name = uri_part.trim_end_matches('/').to_string();
197 if service_name.is_empty() {
198 return Err(ActrCliError::dependency_error(
199 "Service name cannot be empty",
200 ));
201 }
202 return Ok(ActrUri::Service { service_name });
203 }
204
205 Err(ActrCliError::dependency_error(
206 "Invalid actr:// service URI format. Use 'actr://service-name/'",
207 ))
208 }
209
210 async fn check_service_availability(&self, service_name: &str) -> Result<bool> {
212 debug!("Checking service availability: actr://{}/", service_name);
213
214 if service_name.is_empty() {
217 error!("â [actr://{}] Invalid empty service name", service_name);
218 return Ok(false);
219 }
220
221 if self.verbose {
222 info!(
223 "â
[actr://{}] URI format is valid (service discovery not yet implemented)",
224 service_name
225 );
226 } else {
227 info!("â
[actr://{}] URI format valid", service_name);
228 }
229
230 Ok(true)
231 }
232}
233
234#[derive(Debug, Clone)]
236enum ActrUri {
237 Service { service_name: String },
239}