feat: added the ability to edit files remotely
This commit is contained in:
parent
eb5e86067b
commit
ae24c2e0ad
69
Cargo.lock
generated
69
Cargo.lock
generated
@ -133,6 +133,12 @@ version = "1.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "2.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block-buffer"
|
name = "block-buffer"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@ -189,7 +195,7 @@ checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term",
|
"ansi_term",
|
||||||
"atty",
|
"atty",
|
||||||
"bitflags",
|
"bitflags 1.3.2",
|
||||||
"strsim",
|
"strsim",
|
||||||
"textwrap",
|
"textwrap",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
@ -338,6 +344,17 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd"
|
||||||
|
dependencies = [
|
||||||
|
"errno-dragonfly",
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno-dragonfly"
|
name = "errno-dragonfly"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
@ -401,6 +418,12 @@ dependencies = [
|
|||||||
"anyhow",
|
"anyhow",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.28"
|
version = "0.3.28"
|
||||||
@ -598,6 +621,12 @@ version = "0.2.147"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.17"
|
version = "0.4.17"
|
||||||
@ -728,7 +757,7 @@ name = "pcap-sys"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cmake",
|
"cmake",
|
||||||
"errno",
|
"errno 0.2.8",
|
||||||
"futures",
|
"futures",
|
||||||
"libc",
|
"libc",
|
||||||
"packets",
|
"packets",
|
||||||
@ -876,6 +905,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rmp"
|
name = "rmp"
|
||||||
version = "0.8.12"
|
version = "0.8.12"
|
||||||
@ -913,6 +951,19 @@ dependencies = [
|
|||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "0.38.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c0c3dde1fc030af041adc40e79c0e7fbcf431dd24870053d187d7c66e4b87453"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.0",
|
||||||
|
"errno 0.3.3",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@ -1043,6 +1094,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"sparse-05-common",
|
"sparse-05-common",
|
||||||
"structopt",
|
"structopt",
|
||||||
|
"tempfile",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1154,6 +1206,19 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"fastrand",
|
||||||
|
"redox_syscall",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
|||||||
@ -15,4 +15,5 @@ rmp-serde = "1.1.2"
|
|||||||
serde = { version = "1.0.188", features = ["derive"] }
|
serde = { version = "1.0.188", features = ["derive"] }
|
||||||
sparse-05-common = { version = "0.1.0", path = "../sparse-05-common" }
|
sparse-05-common = { version = "0.1.0", path = "../sparse-05-common" }
|
||||||
structopt = { version = "0.3.26", features = ["paw"] }
|
structopt = { version = "0.3.26", features = ["paw"] }
|
||||||
|
tempfile = "3.8.0"
|
||||||
tokio = { version = "1.32.0", features = ["io-std", "net", "fs", "macros", "rt"] }
|
tokio = { version = "1.32.0", features = ["io-std", "net", "fs", "macros", "rt"] }
|
||||||
|
|||||||
@ -14,6 +14,7 @@ pub async fn download_file(
|
|||||||
let mut target_file = fs::OpenOptions::new()
|
let mut target_file = fs::OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
.create(true)
|
.create(true)
|
||||||
|
.truncate(true)
|
||||||
.open(&local_path)
|
.open(&local_path)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
use ansi_term::{Color, Style};
|
use ansi_term::Style;
|
||||||
use structopt::StructOpt;
|
|
||||||
|
|
||||||
use crate::commands::connect::shell::SparseCommands;
|
use crate::commands::connect::shell::SparseCommands;
|
||||||
|
|
||||||
@ -30,14 +29,22 @@ pub fn print_help(arg: Option<SparseCommands>) {
|
|||||||
\n\
|
\n\
|
||||||
Uploads the file at the local file path, overwriting the file at the remote file path"
|
Uploads the file at the local file path, overwriting the file at the remote file path"
|
||||||
),
|
),
|
||||||
|
Some(SparseCommands::EditFile { .. }) => println!(
|
||||||
|
"#edit [remote_file_path]\n\
|
||||||
|
\n\
|
||||||
|
downloads the file specified to edit locally with the editor specified by the EDITOR environment variable"
|
||||||
|
),
|
||||||
None => println!(
|
None => println!(
|
||||||
"\n{}{}\n\
|
"\n{}{}\n\
|
||||||
\n\
|
\n\
|
||||||
The following shell commands are available:\n\
|
The following shell commands are available:\n\
|
||||||
\n\
|
\n\
|
||||||
- #sysinfo\t\tprint information about the system you are connecting to
|
- #sysinfo\t\t\t\tprint information about the system you are connecting to\n\
|
||||||
- #help\t\tprints this help page, or alternatively prints info about a command passed as an argument\n\
|
- #help\t\t\t\t\tprints this help page, or alternatively prints info about a command passed as an argument\n\
|
||||||
- #exit\t\texit from the shell and disconnect from the remote server\n\
|
- #upload [local_file] [remote_file]\tuploads the file located at the local path specified to the remote path\n\
|
||||||
|
- #download [remote_file] [local_file]\tdownloads the file from the server at the path specified and saves it to the local path\n\
|
||||||
|
- #edit [remote_file]\t\t\tdownloads the remote file specified and opens it locally in an editor\n\
|
||||||
|
- #exit\t\t\t\t\texit from the shell and disconnect from the remote server\n\
|
||||||
",
|
",
|
||||||
Style::new().bold().paint("SHELL COMMANDS"),
|
Style::new().bold().paint("SHELL COMMANDS"),
|
||||||
Style::new().paint(""),
|
Style::new().paint(""),
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
use std::{path::PathBuf, sync::Arc};
|
use std::{path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
use tokio::{
|
use tokio::{fs, io::AsyncReadExt};
|
||||||
fs,
|
|
||||||
io::{self, AsyncReadExt},
|
|
||||||
};
|
|
||||||
|
|
||||||
use sparse_05_common::messages::{
|
use sparse_05_common::messages::{
|
||||||
Command, Response, FILE_BUFFER_BUFFER_SIZE, FILE_TRANSFER_PACKET_SIZE,
|
Command, Response, FILE_BUFFER_BUFFER_SIZE, FILE_TRANSFER_PACKET_SIZE,
|
||||||
|
|||||||
@ -2,12 +2,16 @@ use std::{
|
|||||||
io::{self, Read, Write},
|
io::{self, Read, Write},
|
||||||
os::fd::AsRawFd,
|
os::fd::AsRawFd,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::Arc,
|
sync::{
|
||||||
|
atomic::{AtomicBool, Ordering},
|
||||||
|
Arc,
|
||||||
|
},
|
||||||
thread,
|
thread,
|
||||||
};
|
};
|
||||||
|
|
||||||
use sparse_05_common::messages::{Capabilities, Command, Response};
|
use sparse_05_common::messages::{Capabilities, Command, Response};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
use tempfile::NamedTempFile;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::{stderr, stdout, AsyncWriteExt},
|
io::{stderr, stdout, AsyncWriteExt},
|
||||||
runtime::Handle,
|
runtime::Handle,
|
||||||
@ -118,6 +122,36 @@ async fn run_command(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn edit_file(connection: Arc<Connection>, remote_path: PathBuf) -> anyhow::Result<()> {
|
||||||
|
let local_path = tempfile::NamedTempFile::new()?.into_temp_path();
|
||||||
|
|
||||||
|
commands::download::download_file(
|
||||||
|
Arc::clone(&connection),
|
||||||
|
remote_path.clone(),
|
||||||
|
local_path.to_owned(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let cmd = format!(
|
||||||
|
"{} {local_path:?}",
|
||||||
|
std::env::var("VISUAL")
|
||||||
|
.or(std::env::var("EDITOR"))
|
||||||
|
.unwrap_or("vim".to_owned())
|
||||||
|
);
|
||||||
|
|
||||||
|
tokio::process::Command::new("sh")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(cmd)
|
||||||
|
.spawn()?
|
||||||
|
.wait()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
commands::upload::upload_file(Arc::clone(&connection), local_path.to_owned(), remote_path)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) async fn shell(
|
pub(super) async fn shell(
|
||||||
connection: Arc<Connection>,
|
connection: Arc<Connection>,
|
||||||
capabilities: Capabilities,
|
capabilities: Capabilities,
|
||||||
@ -135,14 +169,24 @@ pub(super) async fn shell(
|
|||||||
|
|
||||||
let (stdin_sender, mut stdin_receiver) = channel(64);
|
let (stdin_sender, mut stdin_receiver) = channel(64);
|
||||||
|
|
||||||
|
let pause = Arc::new(AtomicBool::new(false));
|
||||||
|
let pause_2 = Arc::clone(&pause);
|
||||||
|
|
||||||
let handle = Handle::current();
|
let handle = Handle::current();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut stdin_buf = [0u8; 1024];
|
let mut stdin_buf = [0u8; 1024];
|
||||||
loop {
|
loop {
|
||||||
|
if pause_2.load(Ordering::Relaxed) {
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(250));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let mut stdin = std::io::stdin();
|
let mut stdin = std::io::stdin();
|
||||||
let Ok(amount) = stdin.read(&mut stdin_buf) else {
|
let Ok(amount) = stdin.read(&mut stdin_buf) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
if pause_2.load(Ordering::Relaxed) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let stdin_buf = stdin_buf[..amount].to_vec();
|
let stdin_buf = stdin_buf[..amount].to_vec();
|
||||||
let stdin_sender = stdin_sender.clone();
|
let stdin_sender = stdin_sender.clone();
|
||||||
handle.spawn(async move {
|
handle.spawn(async move {
|
||||||
@ -229,17 +273,25 @@ pub(super) async fn shell(
|
|||||||
eprintln!("{e:?}")
|
eprintln!("{e:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Ok(SparseCommands::EditFile { remote_path }), _) => {}
|
(Ok(SparseCommands::EditFile { remote_path }), _) => {
|
||||||
_ => {
|
pause.store(true, Ordering::SeqCst);
|
||||||
if let Err(e) = run_command(
|
if let Err(e) = edit_file(Arc::clone(&connection), remote_path).await {
|
||||||
&mut stdin_receiver,
|
|
||||||
input.to_string(),
|
|
||||||
Arc::clone(&connection),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
eprintln!("{e:?}");
|
eprintln!("{e:?}");
|
||||||
};
|
}
|
||||||
|
pause.store(false, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if !input.to_string().trim().is_empty() && !pause.load(Ordering::Relaxed) {
|
||||||
|
if let Err(e) = run_command(
|
||||||
|
&mut stdin_receiver,
|
||||||
|
input.to_string(),
|
||||||
|
Arc::clone(&connection),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
eprintln!("{e:?}");
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,8 +42,6 @@ pub(super) fn start_file_download<'a, 'b: 'a>(
|
|||||||
conninfo
|
conninfo
|
||||||
.send(conninfo.encrypt_and_sign_resp(Response::StartDownloadFile(id, packet_count))?)?;
|
.send(conninfo.encrypt_and_sign_resp(Response::StartDownloadFile(id, packet_count))?)?;
|
||||||
|
|
||||||
let mut current_packet_count = 0;
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut file_data: Vec<Vec<u8>> = Vec::with_capacity(FILE_BUFFER_BUFFER_SIZE);
|
let mut file_data: Vec<Vec<u8>> = Vec::with_capacity(FILE_BUFFER_BUFFER_SIZE);
|
||||||
let mut buffer = [0u8; FILE_TRANSFER_PACKET_SIZE];
|
let mut buffer = [0u8; FILE_TRANSFER_PACKET_SIZE];
|
||||||
|
|||||||
@ -43,6 +43,7 @@ pub(super) fn start_file_upload<'a, 'b: 'a>(
|
|||||||
let mut target_file = OpenOptions::new()
|
let mut target_file = OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
.create(true)
|
.create(true)
|
||||||
|
.truncate(true)
|
||||||
.open(&file_path)?;
|
.open(&file_path)?;
|
||||||
let mut current_packet_count = 0;
|
let mut current_packet_count = 0;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user