Skip to content

Commit

Permalink
Merge main/daemon/client binaries into single one
Browse files Browse the repository at this point in the history
Instead of shipping 3 distinct binaries: csshw.exe, csshw-client.exe and
csshw-daemon.exe, csshw.exe now has client and daemon subcommands.
The separate daemon taskbar icon will have to be re-introduced with a
follow up change.
  • Loading branch information
whme committed Aug 6, 2023
1 parent 4c6936f commit 4ca37ac
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 103 deletions.
8 changes: 0 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,6 @@ default-run = "csshw"
name = "csshw"
path = "src/main.rs"

[[bin]]
name = "csshw-daemon"
path = "src/daemon/main.rs"

[[bin]]
name = "csshw-client"
path = "src/client/main.rs"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
Expand Down
5 changes: 0 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ _Cluster SSH tool for Windows inspired by [csshX](https://github.com/brockgr/css
- ``Default terminal application`` is set to ``Windows Console Host`` in the windows Terminal Startup Settings (Windows 11 only)

## Overview
csshW consist of 3 executables:
- ``csshw`` - a launcher that starts the daemon application and serves as main entry point
- ``csshw-daemon`` - spawns and positions the client windows and propagates any key-strokes to them
- ``csshw-client`` - launches the SSH client and replays key-strokes received from the daemon

csshW will launch 1 daemon and N client windows (with N being the number of hosts to SSH onto).<br>
Key-strokes performed while having the daemon console focussed will be sent to all clients simoultaneously and be replayed by them.<br>
Focussing a client will cause any key-strokes to be sent to this client only.
Expand Down
11 changes: 1 addition & 10 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
extern crate embed_resource;

fn main() {
embed_resource::compile_for(
"res/csshw.rc",
["csshw", "csshw-client"],
embed_resource::NONE,
);
embed_resource::compile_for(
"res/csshw_daemon.rc",
["csshw-daemon"],
embed_resource::NONE,
);
embed_resource::compile_for("res/csshw.rc", ["csshw"], embed_resource::NONE);
}
58 changes: 12 additions & 46 deletions src/client/main.rs → src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ use std::io::{self, BufReader};
use std::path::Path;
use std::time::Duration;

use clap::Parser;
use csshw::utils::constants::DEFAULT_SSH_USERNAME_KEY;
use csshw::utils::{
use crate::utils::constants::DEFAULT_SSH_USERNAME_KEY;
use crate::utils::{
arrange_console as arrange_client_console, get_console_input_buffer, set_console_title,
};
use serde_derive::{Deserialize, Serialize};
Expand All @@ -21,7 +20,7 @@ use windows::Win32::System::Console::{
GenerateConsoleCtrlEvent, WriteConsoleInputW, INPUT_RECORD, INPUT_RECORD_0, KEY_EVENT,
};

use csshw::{
use crate::{
serde::{deserialization::Deserialize, SERIALIZED_INPUT_RECORD_0_LENGTH},
utils::constants::{PIPE_NAME, PKG_NAME},
};
Expand All @@ -31,37 +30,6 @@ use windows::Win32::UI::WindowsAndMessaging::{LoadImageW, IMAGE_ICON, LR_DEFAULT

const DEFAULT_USERNAME_HOST_PLACEHOLDER: &str = "{{USERNAME_AT_HOST}}";

/// Daemon CLI. Manages client consoles and user input
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
/// Host(s) to connect to
#[clap(required = true)]
host: String,

/// Username used to connect to the hosts
#[clap(required = true)]
username: String,

/// X coordinates of the upper left corner of the console window
/// in reference to the upper left corner of the screen
#[clap(required = true)]
x: i32,

/// Y coordinates of the upper left corner of the console window
/// in reference to the upper left corner of the screen
#[clap(required = true)]
y: i32,

/// Width of the console window
#[clap(required = true)]
width: i32,

/// Height of the console window
#[clap(required = true)]
height: i32,
}

/// If not present the default config will be written to the default
/// configuration place, under windows this is `%AppData%`
#[derive(Serialize, Deserialize)]
Expand Down Expand Up @@ -115,10 +83,10 @@ fn write_console_input(input_record: INPUT_RECORD_0) {
};
}

/// Use `args.username` or load the adequate one from SSH config.
/// Use `username` or load the adequate one from SSH config.
///
/// Returns `<username>@<host>`.
fn get_username_and_host(args: &Args, config: &ClientConfig) -> String {
fn get_username_and_host(username: &str, host: &str, config: &ClientConfig) -> String {
let mut ssh_config = SshConfig::default();

let ssh_config_path = Path::new(config.ssh_config_path.as_str());
Expand All @@ -133,18 +101,18 @@ fn get_username_and_host(args: &Args, config: &ClientConfig) -> String {
}

let default_params = ssh_config.default_params();
let host_specific_params = ssh_config.query(args.host.clone());
let host_specific_params = ssh_config.query(host.clone());

let username: String = if args.username.as_str() == DEFAULT_SSH_USERNAME_KEY {
let username: String = if username == DEFAULT_SSH_USERNAME_KEY {
// FIXME: find a better default
host_specific_params
.user
.unwrap_or(default_params.user.unwrap_or("undefined".to_string()))
} else {
args.username.clone()
username.to_owned()
};

return format!("{}@{}", username, args.host);
return format!("{}@{}", username, host);
}

/// Launch the SSH process.
Expand Down Expand Up @@ -240,8 +208,7 @@ async fn run(child: &mut Child) {
}
}

#[tokio::main]
async fn main() {
pub async fn main(host: String, username: String, x: i32, y: i32, width: i32, height: i32) {
unsafe {
LoadImageW(
GetModuleHandleW(None).unwrap(),
Expand All @@ -253,11 +220,10 @@ async fn main() {
)
.unwrap()
};
let args = Args::parse();
arrange_client_console(args.x, args.y, args.width, args.height);
arrange_client_console(x, y, width, height);
let config: ClientConfig = confy::load(PKG_NAME, "client-config").unwrap();

let username_host = get_username_and_host(&args, &config);
let username_host = get_username_and_host(&username, &host, &config);

// Set the console title (child might overwrite it, so we have to set it again later)
let console_title = format!("{} - {}", PKG_NAME, username_host.clone());
Expand Down
28 changes: 5 additions & 23 deletions src/daemon/main.rs → src/daemon/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ use std::{
time::Duration,
};

use clap::Parser;
use csshw::{
use crate::{
serde::{serialization::Serialize, SERIALIZED_INPUT_RECORD_0_LENGTH},
spawn_console_process,
utils::{
Expand Down Expand Up @@ -42,19 +41,6 @@ use windows::{

mod workspace;

/// Daemon CLI. Manages client consoles and user input
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
/// Username used to connect to the hosts
#[clap(short, long)]
username: Option<String>,

/// Host(s) to connect to
#[clap(required = true)]
hosts: Vec<String>,
}

struct Daemon {
hosts: Vec<String>,
username: Option<String>,
Expand Down Expand Up @@ -185,8 +171,9 @@ fn launch_client_console(
// The first argument must be `--` to ensure all following arguments are treated
// as positional arguments and not as options if they start with `-`.
return spawn_console_process(
&format!("{PKG_NAME}-client.exe"),
&format!("{PKG_NAME}.exe"),
vec![
"client",
"--",
host,
username
Expand Down Expand Up @@ -313,8 +300,7 @@ fn disable_processed_input_mode() {
}
}

#[tokio::main]
async fn main() {
pub async fn main(hosts: Vec<String>, username: Option<String>) {
unsafe {
LoadImageW(
GetModuleHandleW(None).unwrap(),
Expand All @@ -326,10 +312,6 @@ async fn main() {
)
.unwrap()
};
let args = Args::parse();
let daemon: Daemon = Daemon {
hosts: args.hosts,
username: args.username,
};
let daemon: Daemon = Daemon { hosts, username };
daemon.launch().await;
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use windows::Win32::System::Threading::{
CreateProcessW, CREATE_NEW_CONSOLE, PROCESS_INFORMATION, STARTUPINFOW,
};

pub mod client;
pub mod daemon;
pub mod serde;
pub mod utils;

Expand Down
81 changes: 70 additions & 11 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#![deny(clippy::implicit_return)]
#![allow(clippy::needless_return)]
use clap::Parser;
use clap::{Parser, Subcommand};
use csshw::client::main as client_main;
use csshw::daemon::main as daemon_main;
use csshw::spawn_console_process;

const PKG_NAME: &str = env!("CARGO_PKG_NAME");
Expand All @@ -9,16 +11,46 @@ const PKG_NAME: &str = env!("CARGO_PKG_NAME");
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
#[clap(subcommand)]
command: Option<Commands>,
/// Username used to connect to the hosts
#[clap(short, long)]
username: Option<String>,

/// Host(s) to connect to
#[clap(required = true)]
/// Hosts to connect to
#[clap(required = false)]
hosts: Vec<String>,
}

fn main() {
#[derive(Debug, Subcommand)]
enum Commands {
Client {
/// Host to connect to
host: String,
/// Username used to connect to the hosts
username: String,
/// X coordinates of the upper left corner of the console window
/// in reference to the upper left corner of the screen
x: i32,
/// Y coordinates of the upper left corner of the console window
/// in reference to the upper left corner of the screen
y: i32,
/// Width of the console window
width: i32,
/// Height of the console window
height: i32,
},
Daemon {
/// Username used to connect to the hosts
#[clap(long, short = 'u')]
username: Option<String>,

/// Host(s) to connect to
hosts: Vec<String>,
},
}

#[tokio::main]
async fn main() {
match std::env::current_exe() {
Ok(path) => match path.parent() {
None => {
Expand All @@ -36,11 +68,38 @@ fn main() {
}

let args = Args::parse();
let mut daemon_args: Vec<&str> = Vec::new();
if let Some(username) = args.username.as_ref() {
daemon_args.push("-u");
daemon_args.push(username);

match &args.command {
Some(Commands::Client {
host,
username,
x,
y,
width,
height,
}) => {
client_main(
host.to_owned(),
username.to_owned(),
x.to_owned(),
y.to_owned(),
width.to_owned(),
height.to_owned(),
)
.await;
}
Some(Commands::Daemon { username, hosts }) => {
daemon_main(hosts.to_owned(), username.clone()).await;
}
None => {
let mut daemon_args: Vec<&str> = Vec::new();
daemon_args.push("daemon");
if let Some(username) = args.username.as_ref() {
daemon_args.push("-u");
daemon_args.push(username);
}
daemon_args.extend(args.hosts.iter().map(|host| -> &str { return host }));
spawn_console_process(&format!("{PKG_NAME}.exe"), daemon_args);
}
}
daemon_args.extend(args.hosts.iter().map(|host| -> &str { return host }));
spawn_console_process(&format!("{PKG_NAME}-daemon.exe"), daemon_args);
}

0 comments on commit 4ca37ac

Please sign in to comment.