Add metadata request & response; bump to 0.3.1

pull/38/head v0.3.1
Chip Senkbeil 3 years ago
parent f24bb6067d
commit 3c68bb3377
No known key found for this signature in database
GPG Key ID: 35EF1F8EC72A4131

2
Cargo.lock generated

@ -199,7 +199,7 @@ dependencies = [
[[package]]
name = "distant"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"bytes",
"derive_more",

@ -2,7 +2,7 @@
name = "distant"
description = "Operate on a remote computer through file and process manipulation"
categories = ["command-line-utilities"]
version = "0.3.0"
version = "0.3.1"
authors = ["Chip Senkbeil <chip@senkbeil.org>"]
edition = "2018"
homepage = "https://github.com/chipsenkbeil/distant"

@ -126,6 +126,12 @@ pub enum RequestPayload {
dst: PathBuf,
},
/// Retrieves filesystem metadata for the specified path on the remote machine
Metadata {
/// The path to the file, directory, or symlink on the remote machine
path: PathBuf,
},
/// Runs a process on the remote machine
ProcRun {
/// Name of the command to run
@ -233,6 +239,12 @@ pub enum ResponsePayload {
entries: Vec<DirEntry>,
},
/// Response to reading metadata
Metadata {
/// Metadata associated with queried path
data: Metadata,
},
/// Response to starting a new process
ProcStart {
/// Arbitrary id associated with running process
@ -291,9 +303,36 @@ pub struct DirEntry {
pub depth: usize,
}
/// Represents metadata about some filesystem object (file, directory, symlink) on remote machine
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub struct Metadata {
/// Represents the type of the entry as a file/dir/symlink
pub file_type: FileType,
/// Size of the file/directory/symlink in bytes
pub len: u64,
/// Whether or not the file/directory/symlink is marked as unwriteable
pub readonly: bool,
/// Represents the last time (in milliseconds) when the file/directory/symlink was accessed;
/// can be optional as certain systems don't support this
pub accessed: Option<u128>,
/// Represents when (in milliseconds) the file/directory/symlink was created;
/// can be optional as certain systems don't support this
pub created: Option<u128>,
/// Represents the last time (in milliseconds) when the file/directory/symlink was modified;
/// can be optional as certain systems don't support this
pub modified: Option<u128>,
}
/// Represents the type associated with a dir entry
#[derive(Copy, Clone, Debug, PartialEq, Eq, IsVariant, Serialize, Deserialize)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, AsRefStr, IsVariant, Serialize, Deserialize)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
#[strum(serialize_all = "snake_case")]
pub enum FileType {
Dir,
File,

@ -270,6 +270,22 @@ fn format_shell(res: Response) -> ResponseOut {
.collect::<Vec<String>>()
.join("\n"),
)),
ResponsePayload::Metadata { data } => ResponseOut::Stdout(format!(
concat!(
"Type: {}\n",
"Len: {}\n",
"Readonly: {}\n",
"Created: {}\n",
"Last Accessed: {}\n",
"Last Modified: {}\n",
),
data.file_type.as_ref(),
data.len,
data.readonly,
data.created.unwrap_or_default(),
data.accessed.unwrap_or_default(),
data.modified.unwrap_or_default(),
)),
ResponsePayload::ProcEntries { entries } => ResponseOut::Stdout(format!(
"{}\n",
entries

@ -1,9 +1,12 @@
use super::{Process, State};
use crate::data::{
DirEntry, FileType, Request, RequestPayload, Response, ResponsePayload, RunningProcess,
DirEntry, FileType, Metadata, Request, RequestPayload, Response, ResponsePayload,
RunningProcess,
};
use log::*;
use std::{error::Error, net::SocketAddr, path::PathBuf, process::Stdio, sync::Arc};
use std::{
error::Error, net::SocketAddr, path::PathBuf, process::Stdio, sync::Arc, time::SystemTime,
};
use tokio::{
io::{self, AsyncReadExt, AsyncWriteExt},
process::Command,
@ -37,6 +40,7 @@ pub(super) async fn process(
RequestPayload::Remove { path, force } => remove(path, force).await,
RequestPayload::Copy { src, dst } => copy(src, dst).await,
RequestPayload::Rename { src, dst } => rename(src, dst).await,
RequestPayload::Metadata { path } => metadata(path).await,
RequestPayload::ProcRun { cmd, args } => proc_run(addr, state, tx, cmd, args).await,
RequestPayload::ProcKill { id } => proc_kill(state, id).await,
RequestPayload::ProcStdin { id, data } => proc_stdin(state, id, data).await,
@ -190,6 +194,39 @@ async fn rename(src: PathBuf, dst: PathBuf) -> Result<ResponsePayload, Box<dyn E
Ok(ResponsePayload::Ok)
}
async fn metadata(path: PathBuf) -> Result<ResponsePayload, Box<dyn Error>> {
let metadata = tokio::fs::metadata(path).await?;
Ok(ResponsePayload::Metadata {
data: Metadata {
accessed: metadata
.accessed()
.ok()
.and_then(|t| t.duration_since(SystemTime::UNIX_EPOCH).ok())
.map(|d| d.as_millis()),
created: metadata
.created()
.ok()
.and_then(|t| t.duration_since(SystemTime::UNIX_EPOCH).ok())
.map(|d| d.as_millis()),
modified: metadata
.modified()
.ok()
.and_then(|t| t.duration_since(SystemTime::UNIX_EPOCH).ok())
.map(|d| d.as_millis()),
len: metadata.len(),
readonly: metadata.permissions().readonly(),
file_type: if metadata.is_dir() {
FileType::Dir
} else if metadata.is_file() {
FileType::File
} else {
FileType::SymLink
},
},
})
}
async fn proc_run(
addr: SocketAddr,
state: HState,

Loading…
Cancel
Save