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"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.9.0"
|
||||
@ -189,7 +195,7 @@ checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
@ -338,6 +344,17 @@ dependencies = [
|
||||
"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]]
|
||||
name = "errno-dragonfly"
|
||||
version = "0.1.2"
|
||||
@ -401,6 +418,12 @@ dependencies = [
|
||||
"anyhow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.28"
|
||||
@ -598,6 +621,12 @@ version = "0.2.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
@ -728,7 +757,7 @@ name = "pcap-sys"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cmake",
|
||||
"errno",
|
||||
"errno 0.2.8",
|
||||
"futures",
|
||||
"libc",
|
||||
"packets",
|
||||
@ -876,6 +905,15 @@ dependencies = [
|
||||
"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]]
|
||||
name = "rmp"
|
||||
version = "0.8.12"
|
||||
@ -913,6 +951,19 @@ dependencies = [
|
||||
"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]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
@ -1043,6 +1094,7 @@ dependencies = [
|
||||
"serde",
|
||||
"sparse-05-common",
|
||||
"structopt",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
@ -1154,6 +1206,19 @@ dependencies = [
|
||||
"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]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
|
||||
@ -15,4 +15,5 @@ rmp-serde = "1.1.2"
|
||||
serde = { version = "1.0.188", features = ["derive"] }
|
||||
sparse-05-common = { version = "0.1.0", path = "../sparse-05-common" }
|
||||
structopt = { version = "0.3.26", features = ["paw"] }
|
||||
tempfile = "3.8.0"
|
||||
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()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(&local_path)
|
||||
.await?;
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
use ansi_term::{Color, Style};
|
||||
use structopt::StructOpt;
|
||||
use ansi_term::Style;
|
||||
|
||||
use crate::commands::connect::shell::SparseCommands;
|
||||
|
||||
@ -30,14 +29,22 @@ pub fn print_help(arg: Option<SparseCommands>) {
|
||||
\n\
|
||||
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!(
|
||||
"\n{}{}\n\
|
||||
\n\
|
||||
The following shell commands are available:\n\
|
||||
\n\
|
||||
- #sysinfo\t\tprint information about the system you are connecting to
|
||||
- #help\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\
|
||||
- #sysinfo\t\t\t\tprint information about the system you are connecting to\n\
|
||||
- #help\t\t\t\t\tprints this help page, or alternatively prints info about a command passed as an argument\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().paint(""),
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
|
||||
use tokio::{
|
||||
fs,
|
||||
io::{self, AsyncReadExt},
|
||||
};
|
||||
use tokio::{fs, io::AsyncReadExt};
|
||||
|
||||
use sparse_05_common::messages::{
|
||||
Command, Response, FILE_BUFFER_BUFFER_SIZE, FILE_TRANSFER_PACKET_SIZE,
|
||||
|
||||
@ -2,12 +2,16 @@ use std::{
|
||||
io::{self, Read, Write},
|
||||
os::fd::AsRawFd,
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
},
|
||||
thread,
|
||||
};
|
||||
|
||||
use sparse_05_common::messages::{Capabilities, Command, Response};
|
||||
use structopt::StructOpt;
|
||||
use tempfile::NamedTempFile;
|
||||
use tokio::{
|
||||
io::{stderr, stdout, AsyncWriteExt},
|
||||
runtime::Handle,
|
||||
@ -118,6 +122,36 @@ async fn run_command(
|
||||
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(
|
||||
connection: Arc<Connection>,
|
||||
capabilities: Capabilities,
|
||||
@ -135,14 +169,24 @@ pub(super) async fn shell(
|
||||
|
||||
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();
|
||||
thread::spawn(move || {
|
||||
let mut stdin_buf = [0u8; 1024];
|
||||
loop {
|
||||
if pause_2.load(Ordering::Relaxed) {
|
||||
std::thread::sleep(std::time::Duration::from_millis(250));
|
||||
continue;
|
||||
}
|
||||
let mut stdin = std::io::stdin();
|
||||
let Ok(amount) = stdin.read(&mut stdin_buf) else {
|
||||
continue;
|
||||
};
|
||||
if pause_2.load(Ordering::Relaxed) {
|
||||
continue;
|
||||
}
|
||||
let stdin_buf = stdin_buf[..amount].to_vec();
|
||||
let stdin_sender = stdin_sender.clone();
|
||||
handle.spawn(async move {
|
||||
@ -229,17 +273,25 @@ pub(super) async fn shell(
|
||||
eprintln!("{e:?}")
|
||||
}
|
||||
}
|
||||
(Ok(SparseCommands::EditFile { remote_path }), _) => {}
|
||||
_ => {
|
||||
if let Err(e) = run_command(
|
||||
&mut stdin_receiver,
|
||||
input.to_string(),
|
||||
Arc::clone(&connection),
|
||||
)
|
||||
.await
|
||||
{
|
||||
(Ok(SparseCommands::EditFile { remote_path }), _) => {
|
||||
pause.store(true, Ordering::SeqCst);
|
||||
if let Err(e) = edit_file(Arc::clone(&connection), remote_path).await {
|
||||
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
|
||||
.send(conninfo.encrypt_and_sign_resp(Response::StartDownloadFile(id, packet_count))?)?;
|
||||
|
||||
let mut current_packet_count = 0;
|
||||
|
||||
loop {
|
||||
let mut file_data: Vec<Vec<u8>> = Vec::with_capacity(FILE_BUFFER_BUFFER_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()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(&file_path)?;
|
||||
let mut current_packet_count = 0;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user