Skip to content

Commit

Permalink
feat: introduce MPSC on the status command (#8)
Browse files Browse the repository at this point in the history
### Description
This PR uses [MPSC](https://doc.rust-lang.org/std/sync/mpsc/) on the
status command to improve performance.

### Benchmark
From:
![Screenshot 2023-05-17 at 19 21
33](https://github.com/mentimeter/linkup/assets/5747313/eb03a583-7c3f-436f-bb79-c7e5c9ab7b10)

To:
![Screenshot 2023-05-17 at 19 28
38](https://github.com/mentimeter/linkup/assets/5747313/ab3dde1d-974a-460d-a717-9b48bfc979b9)

**_Note: Benchmarks include one `timeout`_**
![Screenshot 2023-05-17 at 19 36
13](https://github.com/mentimeter/linkup/assets/5747313/4855bb70-1c4d-4a40-ae2f-4a66303f8448)
  • Loading branch information
augustoccesar authored May 19, 2023
1 parent 7882bec commit 870360e
Showing 1 changed file with 65 additions and 42 deletions.
107 changes: 65 additions & 42 deletions linkup-cli/src/status.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use colored::{ColoredString, Colorize};
use serde::{Deserialize, Serialize};
use std::time::Duration;
use std::{thread, time::Duration};

use crate::{
local_config::{LocalState, ServiceTarget},
Expand Down Expand Up @@ -58,9 +58,18 @@ impl From<Result<reqwest::blocking::Response, reqwest::Error>> for ServerStatus
pub fn status(json: bool) -> Result<(), CliError> {
let state = get_state()?;

let mut services = linkup_status(&state);
let service_statuses = service_status(&state)?;
services.extend(service_statuses);
let (tx, rx) = std::sync::mpsc::channel();
linkup_status(tx.clone(), &state);
service_status(tx.clone(), &state);

drop(tx);

let mut services = rx.iter().collect::<Vec<ServiceStatus>>();
services.sort_by(|a, b| {
a.component_kind
.cmp(&b.component_kind)
.then(a.name.cmp(&b.name))
});

// Filter out domains that are subdomains of other domains
let filtered_domains = state
Expand Down Expand Up @@ -129,56 +138,70 @@ pub fn status(json: bool) -> Result<(), CliError> {
Ok(())
}

fn linkup_status(state: &LocalState) -> Vec<ServiceStatus> {
let mut linkup_statuses: Vec<ServiceStatus> = Vec::new();

fn linkup_status(tx: std::sync::mpsc::Sender<ServiceStatus>, state: &LocalState) {
let local_url = format!("http://localhost:{}", LINKUP_LOCALSERVER_PORT);
linkup_statuses.push(ServiceStatus {
name: "local_server".to_string(),
component_kind: "linkup".to_string(),
location: local_url.to_string(),
status: server_status(local_url),
});

// linkup_statuses.append(local_status);

linkup_statuses.push(ServiceStatus {
name: "remote_server".to_string(),
component_kind: "linkup".to_string(),
location: state.linkup.remote.to_string(),
status: server_status(state.linkup.remote.to_string()),
});
let local_tx = tx.clone();
thread::spawn(move || {
let service_status = ServiceStatus {
name: "local_server".to_string(),
component_kind: "linkup".to_string(),
location: local_url.clone(),
status: server_status(local_url),
};

linkup_statuses.push(ServiceStatus {
name: "tunnel".to_string(),
component_kind: "linkup".to_string(),
location: state.linkup.tunnel.to_string(),
status: server_status(state.linkup.tunnel.to_string()),
local_tx.send(service_status).unwrap();
});

linkup_statuses
}
let remote_tx = tx.clone();
// TODO(augustoccesar): having to clone this remote on the ServiceStatus feels unnecessary. Look if it can be reference
let remote = state.linkup.remote.to_string();
thread::spawn(move || {
let service_status = ServiceStatus {
name: "remote_server".to_string(),
component_kind: "linkup".to_string(),
location: remote.clone(),
status: server_status(remote),
};

fn service_status(state: &LocalState) -> Result<Vec<ServiceStatus>, CliError> {
let mut service_statuses: Vec<ServiceStatus> = Vec::new();
remote_tx.send(service_status).unwrap();
});

for service in state.services.iter().cloned() {
let url = match service.current {
ServiceTarget::Local => service.local.clone(),
ServiceTarget::Remote => service.remote.clone(),
// NOTE(augustoccesar): last usage of tx on this context, no need to clone it
let tunnel_tx = tx;
let tunnel = state.linkup.tunnel.to_string();
thread::spawn(move || {
let service_status = ServiceStatus {
name: "tunnel".to_string(),
component_kind: "linkup".to_string(),
location: tunnel.clone(),
status: server_status(tunnel),
};

let status = server_status(url.to_string());
tunnel_tx.send(service_status).unwrap();
});
}

service_statuses.push(ServiceStatus {
name: service.name,
location: url.to_string(),
component_kind: service.current.to_string(),
status,
fn service_status(tx: std::sync::mpsc::Sender<ServiceStatus>, state: &LocalState) {
for service in state.services.iter().cloned() {
let tx = tx.clone();

thread::spawn(move || {
let url = match service.current {
ServiceTarget::Local => service.local.clone(),
ServiceTarget::Remote => service.remote.clone(),
};

let service_status = ServiceStatus {
name: service.name,
location: url.to_string(),
component_kind: service.current.to_string(),
status: server_status(url.to_string()),
};

tx.send(service_status).unwrap();
});
}

Ok(service_statuses)
}

fn server_status(url: String) -> ServerStatus {
Expand Down

0 comments on commit 870360e

Please sign in to comment.