Skip to content

Commit

Permalink
Add more useful print statements to most commands (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
ostenbom authored Aug 17, 2023
1 parent 9e0b3a8 commit 6f621bd
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 63 deletions.
26 changes: 19 additions & 7 deletions linkup-cli/src/background_booting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::background_local_server::{
use crate::background_tunnel::start_tunnel;
use crate::local_config::{LocalState, ServiceTarget};
use crate::start::save_state;
use crate::status::print_session_names;
use crate::{start::get_state, CliError};
use crate::{LINKUP_ENV_SEPARATOR, LINKUP_LOCALSERVER_PORT};

Expand All @@ -26,16 +27,20 @@ pub fn boot_background_services() -> Result<(), CliError> {
.expect("linkup url invalid");

if is_local_server_started().is_err() {
println!("starting linkup local server...");
println!("Starting linkup local server...");
start_local_server()?;
} else {
println!("Linkup local server was already running.. Try stopping linkup first if you have problems.");
}

wait_till_ok(format!("{}linkup-check", local_url))?;

if is_tunnel_started().is_err() {
println!("starting tunnel...");
println!("Starting tunnel...");
let tunnel = start_tunnel()?;
state.linkup.tunnel = tunnel;
} else {
println!("Cloudflare tunnel was already running.. Try stopping linkup first if you have problems.");
}

for service in &state.services {
Expand All @@ -61,21 +66,28 @@ pub fn boot_background_services() -> Result<(), CliError> {
let tunnel_url = state.linkup.tunnel.clone();

state.linkup.session_name = server_session_name.clone();
let state_to_print = state.clone();

save_state(state)?;

println!("{}", server_session_name);
println!("Waiting for tunnel to be ready at {}...", tunnel_url);

// If the tunnel is checked too quickly, it dies ¯\_(ツ)_/¯
thread::sleep(Duration::from_millis(1000));
wait_till_ok(format!("{}linkup-check", tunnel_url))?;

// final checks services are responding
// print status
println!();

print_session_names(&state_to_print);

Ok(())
}

fn load_config(url: &Url, desired_name: &str, config: StorableSession) -> Result<String, CliError> {
pub fn load_config(
url: &Url,
desired_name: &str,
config: StorableSession,
) -> Result<String, CliError> {
let client = Client::new();
let endpoint = url
.join("/linkup")
Expand Down Expand Up @@ -112,7 +124,7 @@ fn load_config(url: &Url, desired_name: &str, config: StorableSession) -> Result
}
}

fn server_config_from_state(state: &LocalState) -> (StorableSession, StorableSession) {
pub fn server_config_from_state(state: &LocalState) -> (StorableSession, StorableSession) {
let local_server_services = state
.services
.iter()
Expand Down
7 changes: 6 additions & 1 deletion linkup-cli/src/background_tunnel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ pub fn start_tunnel() -> Result<Url, CliError> {
attempt += 1;
match try_start_tunnel() {
Ok(url) => return Ok(url),
Err(CliError::StopErr(e)) => return Err(CliError::StopErr(format!("Failed to stop tunnel when retrying tunnel boot: {}", e))),
Err(CliError::StopErr(e)) => {
return Err(CliError::StopErr(format!(
"Failed to stop tunnel when retrying tunnel boot: {}",
e
)))
}
Err(err) => {
println!("Tunnel failed to boot within the time limit. Retrying...");
if attempt >= 3 {
Expand Down
6 changes: 3 additions & 3 deletions linkup-cli/src/local_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ use url::Url;

use linkup::{StorableDomain, StorableRewrite};

#[derive(Deserialize, Serialize)]
#[derive(Deserialize, Serialize, Clone)]
pub struct LocalState {
pub linkup: LinkupState,
pub domains: Vec<StorableDomain>,
pub services: Vec<LocalService>,
}

#[derive(Deserialize, Serialize)]
#[derive(Deserialize, Serialize, Clone)]
pub struct LinkupState {
pub session_name: String,
pub session_token: String,
Expand Down Expand Up @@ -82,7 +82,7 @@ pub fn config_to_state(yaml_config: YamlLocalConfig, config_path: String) -> Loc
session_token: random_token,
config_path,
remote: yaml_config.linkup.remote,
tunnel: Url::parse("http://localhost").expect("default url parses"),
tunnel: Url::parse("http://tunnel-not-yet-set").expect("default url parses"),
cache_routes: yaml_config.linkup.cache_routes,
};

Expand Down
25 changes: 11 additions & 14 deletions linkup-cli/src/local_server.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::{collections::HashMap, io};

use futures::stream::StreamExt;
use actix_web::{
http::header, middleware, web, App, HttpRequest, HttpResponse, HttpServer, Responder, guard, rt,
guard, http::header, middleware, rt, web, App, HttpRequest, HttpResponse, HttpServer, Responder,
};
use futures::stream::StreamExt;
use thiserror::Error;

use linkup::*;
Expand Down Expand Up @@ -55,7 +55,7 @@ async fn linkup_config_handler(
async fn linkup_ws_request_handler(
string_store: web::Data<MemoryStringStore>,
req: HttpRequest,
req_stream: web::Payload
req_stream: web::Payload,
) -> impl Responder {
let sessions = SessionAllocator::new(string_store.into_inner());

Expand Down Expand Up @@ -117,10 +117,8 @@ async fn linkup_ws_request_handler(
let status = response.status().as_u16();
if status != 101 {
return HttpResponse::BadGateway()
.append_header(header::ContentType::plaintext())
.body(
"The underlying server did not accept the websocket connection.",
);
.append_header(header::ContentType::plaintext())
.body("The underlying server did not accept the websocket connection.");
}

// Copy headers from the target back to the client.
Expand All @@ -136,11 +134,11 @@ async fn linkup_ws_request_handler(
let upgrade_result = response.upgrade().await;
let upgrade = match upgrade_result {
Ok(response) => response,
Err(_) => return HttpResponse::BadGateway()
.append_header(header::ContentType::plaintext())
.body(
"could not upgrade to websocket connection.",
),
Err(_) => {
return HttpResponse::BadGateway()
.append_header(header::ContentType::plaintext())
.body("could not upgrade to websocket connection.")
}
};

let (target_rx, mut target_tx) = tokio::io::split(upgrade);
Expand Down Expand Up @@ -176,7 +174,6 @@ async fn linkup_request_handler(
.map(|(k, v)| (k.to_string(), v.to_str().unwrap_or("").to_string()))
.collect::<HashMap<String, String>>();


let session_result = sessions
.get_request_session(url.clone(), headers.clone())
.await;
Expand Down Expand Up @@ -296,7 +293,7 @@ pub async fn local_linkup_main() -> io::Result<()> {
.service(
web::resource("{path:.*}")
.guard(guard::Header("upgrade", "websocket"))
.to(linkup_ws_request_handler)
.to(linkup_ws_request_handler),
)
.default_service(web::route().to(linkup_request_handler))
})
Expand Down
4 changes: 2 additions & 2 deletions linkup-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,9 @@ enum Commands {
},
#[clap(about = "Stop a running linkup session")]
Stop {},
#[clap(about = "Configure your linkup session to route traffic to a local service")]
#[clap(about = "Route session traffic to a local service")]
Local { service_name: String },
#[clap(about = "Configure your linkup session to route traffic to a remote service")]
#[clap(about = "Route session traffic to a remote service")]
Remote { service_name: String },
#[clap(about = "View linkup component and service status")]
Status {
Expand Down
46 changes: 37 additions & 9 deletions linkup-cli/src/remote_local.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use url::Url;

use crate::{
background_booting::boot_background_services,
local_config::ServiceTarget,
background_booting::{load_config, server_config_from_state},
local_config::{LocalState, ServiceTarget},
start::{get_state, save_state},
CliError,
CliError, LINKUP_LOCALSERVER_PORT,
};

pub fn remote(service_name: String) -> Result<(), CliError> {
let mut state = get_state()?;

let mut service = state
let service = state
.services
.iter_mut()
.find(|s| s.name == service_name)
Expand All @@ -18,16 +20,21 @@ pub fn remote(service_name: String) -> Result<(), CliError> {
)))?;
service.current = ServiceTarget::Remote;

save_state(state)?;
boot_background_services()?;
save_state(state.clone())?;
load_server_states(state)?;

println!(
"Linkup is routing {} traffic to the remote server",
service_name
);

Ok(())
}

pub fn local(service_name: String) -> Result<(), CliError> {
let mut state = get_state()?;

let mut service = state
let service = state
.services
.iter_mut()
.find(|s| s.name == service_name)
Expand All @@ -37,7 +44,28 @@ pub fn local(service_name: String) -> Result<(), CliError> {
)))?;
service.current = ServiceTarget::Local;

save_state(state)?;
boot_background_services()?;
save_state(state.clone())?;
load_server_states(state)?;

println!(
"Linkup is routing {} traffic to the local server",
service_name
);

Ok(())
}

fn load_server_states(state: LocalState) -> Result<(), CliError> {
let local_url = Url::parse(&format!("http://localhost:{}", LINKUP_LOCALSERVER_PORT))
.expect("linkup url invalid");

let (local_server_conf, remote_server_conf) = server_config_from_state(&state);
let _ = load_config(
&state.linkup.remote,
&state.linkup.session_name.clone(),
remote_server_conf,
)?;
let _ = load_config(&local_url, &state.linkup.session_name, local_server_conf)?;

Ok(())
}
5 changes: 3 additions & 2 deletions linkup-cli/src/start.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ use crate::{
};

pub fn start(config_arg: Option<String>) -> Result<(), CliError> {
// TODO: run `stop` to kill the previous local server?

let previous_state = get_state();
let config_path = config_path(config_arg)?;
let input_config = get_config(config_path.clone())?;
Expand All @@ -23,6 +21,9 @@ pub fn start(config_arg: Option<String>) -> Result<(), CliError> {
if let Ok(ps) = previous_state {
state.linkup.session_name = ps.linkup.session_name;
state.linkup.session_token = ps.linkup.session_token;

// Maintain tunnel state until it is rewritten
state.linkup.tunnel = ps.linkup.tunnel;
}

save_state(state)?;
Expand Down
65 changes: 40 additions & 25 deletions linkup-cli/src/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,26 +71,10 @@ pub fn status(json: bool) -> Result<(), CliError> {
.then(a.name.cmp(&b.name))
});

// Filter out domains that are subdomains of other domains
let filtered_domains = state
.domains
.iter()
.filter(|&d| {
!state
.domains
.iter()
.any(|other| other.domain != d.domain && d.domain.ends_with(&other.domain))
})
.map(|d| d.domain.clone())
.collect::<Vec<String>>();

let status = Status {
session: SessionStatus {
name: state.linkup.session_name.clone(),
domains: filtered_domains
.iter()
.map(|d| format!("{}.{}", state.linkup.session_name.clone(), d.clone()))
.collect(),
domains: format_state_domains(&state),
},
services,
};
Expand All @@ -101,14 +85,7 @@ pub fn status(json: bool) -> Result<(), CliError> {
serde_json::to_string_pretty(&status).expect("Failed to serialize status")
);
} else {
// Display session information
println!("Session Information:");
println!(" Session Name: {}", status.session.name);
println!(" Domains: ");
for domain in &status.session.domains {
println!(" {}", domain);
}
println!();
print_session_status(status.session);

// Display services information
println!("Service Information:");
Expand Down Expand Up @@ -140,6 +117,44 @@ pub fn status(json: bool) -> Result<(), CliError> {
Ok(())
}

pub fn print_session_names(state: &LocalState) {
print_session_status(SessionStatus {
name: state.linkup.session_name.clone(),
domains: format_state_domains(state),
});
}

fn format_state_domains(state: &LocalState) -> Vec<String> {
// Filter out domains that are subdomains of other domains
let filtered_domains = state
.domains
.iter()
.filter(|&d| {
!state
.domains
.iter()
.any(|other| other.domain != d.domain && d.domain.ends_with(&other.domain))
})
.map(|d| d.domain.clone())
.collect::<Vec<String>>();

return filtered_domains
.iter()
.map(|d| format!("{}.{}", state.linkup.session_name.clone(), d.clone()))
.collect();
}

fn print_session_status(session: SessionStatus) {
// Display session information
println!("Session Information:");
println!(" Session Name: {}", session.name);
println!(" Domains: ");
for domain in session.domains {
println!(" {}", domain);
}
println!();
}

fn linkup_status(tx: std::sync::mpsc::Sender<ServiceStatus>, state: &LocalState) {
let local_url = format!("http://localhost:{}", LINKUP_LOCALSERVER_PORT);

Expand Down

0 comments on commit 6f621bd

Please sign in to comment.