Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add ssh command #598

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 63 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ futures = { version = "0.3.31", default-features = false, features = [
"compat",
"io-compat",
] }
futures-util = "0.3"
names = { version = "0.14.0", default-features = false }
graphql-ws-client = { version = "0.11.1", features = [
"client-graphql-client",
Expand All @@ -66,6 +67,8 @@ async-tungstenite = { version = "0.28.2", features = [
"tokio-runtime",
"tokio-rustls-native-certs",
] }
termion = "2.0"
http = "0.2"
is-terminal = "0.4.13"
serde_with = "3.12.0"
ctrlc = "3.4.5"
Expand Down
1 change: 1 addition & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub mod redeploy;
pub mod run;
pub mod service;
pub mod shell;
pub mod ssh;
pub mod starship;
pub mod status;
pub mod unlink;
Expand Down
124 changes: 124 additions & 0 deletions src/commands/ssh.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
use anyhow::{Context, Result};
use is_terminal::IsTerminal;
use tokio::io::AsyncReadExt;
use tokio::select;

use super::*;
use crate::{consts::TICK_STRING, controllers::terminal::TerminalClient};

/// Connect to a service via SSH
#[derive(Parser)]
pub struct Args {
/// Project to connect to
#[arg(value_name = "project-name")]
project: String,

/// Service to connect to
#[arg(value_name = "service-name")]
service: String,

/// Deployment instance ID to connect to
#[arg(long = "deployment-instance", value_name = "deployment-instance-id")]
deployment_instance: Option<String>,
}

pub async fn command(args: Args, _json: bool) -> Result<()> {
let configs = Configs::new()?;
let token = configs
.get_railway_auth_token()
.context("No authentication token found. Please login first with 'railway login'")?;

let spinner = indicatif::ProgressBar::new_spinner()
.with_style(
indicatif::ProgressStyle::default_spinner()
.tick_chars(TICK_STRING)
.template("{spinner:.green} {msg}")?,
)
.with_message("Connecting to service...");
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make this message go away after connection


spinner.enable_steady_tick(std::time::Duration::from_millis(100));

let ws_url = format!("wss://{}", configs.get_relay_host_path());

let mut client = TerminalClient::new(
&ws_url,
&token,
&args.project,
&args.service,
args.deployment_instance.as_deref(),
)
.await?;

if !std::io::stdout().is_terminal() {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this before making ws connection

anyhow::bail!("SSH connection requires a terminal");
}

let size = termion::terminal_size()?;
client.send_window_size(size.0, size.1).await?;

let mut stdin = tokio::io::stdin();
let mut stdin_buf = [0u8; 1024];

let raw_mode = termion::raw::IntoRawMode::into_raw_mode(std::io::stdout())?;

spinner.finish();

let mut sigint = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::interrupt())?;
let mut sigterm = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())?;
let mut sigwinch =
tokio::signal::unix::signal(tokio::signal::unix::SignalKind::window_change())?;

// Main event loop
loop {
select! {
// Handle window resizes
_ = sigwinch.recv() => {
if let Ok(size) = termion::terminal_size() {
client.send_window_size(size.0, size.1).await?;
}
continue;
}
// Handle signals
_ = sigint.recv() => {
client.send_signal(2).await?; // SIGINT
continue;
}
_ = sigterm.recv() => {
client.send_signal(15).await?; // SIGTERM
break;
}
// Handle input from terminal
result = stdin.read(&mut stdin_buf) => {
match result {
Ok(0) => break, // EOF
Ok(n) => {
let data = String::from_utf8_lossy(&stdin_buf[..n]);
client.send_data(&data).await?;
}
Err(e) => {
eprintln!("Error reading from stdin: {}", e);
break;
}
}
}

// Handle messages from server
result = client.handle_server_messages() => {
match result {
Ok(()) => {
// PTY session has ended, exit immediately
drop(raw_mode);
std::process::exit(0);
}
Err(e) => {
eprintln!("Error handling server messages: {}", e);
break;
}
}
}
}
}

drop(raw_mode);
Ok(())
}
12 changes: 12 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ pub enum Environment {
Dev,
}

pub const SSH_CONNECTION_TIMEOUT_SECS: u64 = 10;
pub const SSH_MESSAGE_TIMEOUT_SECS: u64 = 5;
pub const SSH_RECONNECT_DELAY_SECS: u64 = 1;
pub const SSH_MAX_RECONNECT_ATTEMPTS: u32 = 3;
pub const SSH_MAX_EMPTY_MESSAGES: u32 = 5;

impl Configs {
pub fn new() -> Result<Self> {
let environment = Self::get_environment_id();
Expand Down Expand Up @@ -152,6 +158,12 @@ impl Configs {
}
}

/// Returns the host and path for relay server without protocol (e.g. "backboard.railway.com/relay")
/// Protocol is omitted to allow flexibility between https:// and wss:// usage
pub fn get_relay_host_path(&self) -> String {
format!("backboard.{}/relay", self.get_host())
}

pub fn get_backboard(&self) -> String {
format!("https://backboard.{}/graphql/v2", self.get_host())
}
Expand Down
1 change: 1 addition & 0 deletions src/controllers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ pub mod database;
pub mod deployment;
pub mod environment;
pub mod project;
pub mod terminal;
pub mod user;
pub mod variables;
Loading
Loading