@smbcloud / cli / commits / b0e71f1

check internet connection before hitting endpoint

joko committed Jul 2, 2025 at 23:10 UTC b0e71f14430ff8f24d3391c4d6b61581f37afaef
4 files changed +68 -4
crates/cli/src/main.rs
+20 -1
@@ -12,7 +12,7 @@ use smbcloud_cli::{
12 cli::{Cli, Commands},
13 deploy::process_deploy,
14 };
15 -use smbcloud_networking::environment::Environment;
15 +use smbcloud_networking::{check_internet_connection, environment::Environment};
16 use std::{
17 fs::{create_dir_all, OpenOptions},
18 path::PathBuf,
@@ -111,6 +111,25 @@ async fn run() -> Result<CommandResult> {
111 setup_logging(cli.environment, None)?;
112 }
113
114 + // Check if the command requires internet connection
115 + let needs_internet = match &cli.command {
116 + Some(Commands::Me {})
117 + | Some(Commands::Deploy {})
118 + | Some(Commands::Login {})
119 + | Some(Commands::Logout {})
120 + | Some(Commands::Account { .. })
121 + | Some(Commands::Project { .. })
122 + | None => true,
123 + Some(Commands::Init {}) => true,
124 + };
125 +
126 + // Check internet connectivity for commands that need it
127 + if needs_internet && !check_internet_connection().await {
128 + return Err(anyhow!(
129 + "No internet connection. Please check your network settings and try again."
130 + ));
131 + }
132 +
133 match cli.command {
134 Some(Commands::Me {}) => process_me(cli.environment).await,
135 Some(Commands::Init {}) => process_project_init(cli.environment).await,
crates/smbcloud-model/src/error_codes.rs
+4 -2
@@ -29,7 +29,7 @@ pub enum ErrorCode {
29 Unknown = 0,
30 #[error("Parse error.")]
31 ParseError = 1,
32 - #[error("Network error.")]
32 + #[error("Network connectivity error.")]
33 NetworkError = 2,
34 #[error("Input error")]
35 InputError = 3,
@@ -74,7 +74,9 @@ impl ErrorCode {
74 ErrorCode::Unknown => "Unknown error.",
75 ErrorCode::ProjectNotFound => "Project not found.",
76 ErrorCode::ParseError => "Parse error.",
77 - ErrorCode::NetworkError => "Network error.",
77 + ErrorCode::NetworkError => {
78 + "Network error. Please check your internet connection and try again."
79 + }
80 ErrorCode::Unauthorized => "Unauthorized access.",
81 ErrorCode::InputError => "Input error.",
82 ErrorCode::MissingConfig => "Missing config.",
crates/smbcloud-networking/src/lib.rs
+2
@@ -2,6 +2,8 @@ pub mod constants;
2 pub mod environment;
3 pub mod network;
4
5 +pub use network::check_internet_connection;
6 +
7 use anyhow::{anyhow, Result};
8 use constants::{SMB_CLIENT_ID, SMB_CLIENT_SECRET};
9 use environment::Environment;
crates/smbcloud-networking/src/network.rs
+42 -1
@@ -1,12 +1,43 @@
1 -use log::error;
1 +use log::{debug, error};
2 use reqwest::{RequestBuilder, Response};
3 use serde::de::DeserializeOwned;
4 use smbcloud_model::error_codes::{ErrorCode, ErrorResponse};
5 +use std::time::Duration;
6 #[cfg(debug_assertions)]
7 const LOG_RESPONSE_BODY: bool = false; // You know what to do here.
8 #[cfg(not(debug_assertions))]
9 const LOG_RESPONSE_BODY: bool = false;
10
11 +/// Check if there is an active internet connection
12 +///
13 +/// This function attempts to connect to a reliable server (dns.google)
14 +/// with a short timeout. Returns true if the connection was successful.
15 +pub async fn check_internet_connection() -> bool {
16 + debug!("Checking internet connection");
17 + let client = reqwest::Client::builder()
18 + .timeout(Duration::from_secs(5))
19 + .build();
20 +
21 + if let Err(e) = client {
22 + error!("Failed to create client for connectivity check: {:?}", e);
23 + return false;
24 + }
25 +
26 + match client.unwrap().get("https://dns.google").send().await {
27 + Ok(response) => {
28 + debug!(
29 + "Internet connection check successful: {}",
30 + response.status()
31 + );
32 + response.status().is_success()
33 + }
34 + Err(e) => {
35 + error!("Internet connection check failed: {:?}", e);
36 + false
37 + }
38 + }
39 +}
40 +
41 pub async fn parse_error_response<T: DeserializeOwned>(
42 response: Response,
43 ) -> Result<T, ErrorResponse> {
@@ -44,6 +75,16 @@ pub async fn parse_error_response<T: DeserializeOwned>(
75 }
76
77 pub async fn request<R: DeserializeOwned>(builder: RequestBuilder) -> Result<R, ErrorResponse> {
78 + // Check internet connection before making the request
79 + if !check_internet_connection().await {
80 + error!("No internet connection available");
81 + return Err(ErrorResponse::Error {
82 + error_code: ErrorCode::NetworkError,
83 + message: "No internet connection. Please check your network settings and try again."
84 + .to_string(),
85 + });
86 + }
87 +
88 let response = builder.send().await;
89 let response = match response {
90 Ok(response) => response,