use crate::proto::b64_decode;
use serde_json::{json, Value};
use std::path::PathBuf;
#[derive(Debug, Clone)]
pub struct ExecOutput {
pub code: Option<i64>,
pub stdout: Vec<u8>,
pub stderr: Vec<u8>,
}
impl ExecOutput {
pub fn stdout_str(&self) -> String {
String::from_utf8_lossy(&self.stdout).trim_end().to_string()
}
}
pub fn exec<I, S>(program: &str, args: I) -> Result<ExecOutput, String>
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
let args: Vec<String> = args.into_iter().map(|s| s.as_ref().to_string()).collect();
let v = crate::exec::run(&json!({ "program": program, "args": args }));
if v["ok"] != json!(true) {
return Err(v["err"].as_str().unwrap_or("exec_failed").to_string());
}
Ok(ExecOutput {
code: v["code"].as_i64(),
stdout: v["stdout"]
.as_str()
.and_then(b64_decode)
.unwrap_or_default(),
stderr: v["stderr"]
.as_str()
.and_then(b64_decode)
.unwrap_or_default(),
})
}
pub fn exec_stdin<I, S>(program: &str, args: I, input: &str) -> Result<ExecOutput, String>
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
let args: Vec<String> = args.into_iter().map(|s| s.as_ref().to_string()).collect();
let v = crate::exec::run(&json!({ "program": program, "args": args, "stdin": input }));
if v["ok"] != json!(true) {
return Err(v["err"].as_str().unwrap_or("exec_failed").to_string());
}
Ok(ExecOutput {
code: v["code"].as_i64(),
stdout: v["stdout"]
.as_str()
.and_then(b64_decode)
.unwrap_or_default(),
stderr: v["stderr"]
.as_str()
.and_then(b64_decode)
.unwrap_or_default(),
})
}
#[derive(Debug, Clone)]
pub struct Entry {
pub path: PathBuf,
pub name: String,
pub dir: bool,
pub size: u64,
}
pub fn walk(root: &str, ext: Option<&str>) -> Vec<Entry> {
let mut req = json!({ "path": root });
if let Some(x) = ext {
req["ext"] = json!(x);
}
entries_from(crate::fsops::handle("fs_walk", &req))
}
pub fn walk_filtered(
root: &str,
depth: Option<usize>,
dirs_only: bool,
ext: Option<&str>,
contains: Option<&str>,
) -> Vec<Entry> {
let mut req = json!({ "path": root, "dirs_only": dirs_only });
if let Some(d) = depth {
req["depth"] = json!(d);
}
if let Some(x) = ext {
req["ext"] = json!(x);
}
if let Some(c) = contains {
req["contains"] = json!(c);
}
entries_from(crate::fsops::handle("fs_walk", &req))
}
fn entries_from(v: Value) -> Vec<Entry> {
v["entries"]
.as_array()
.map(|a| {
a.iter()
.map(|e| Entry {
path: PathBuf::from(e["path"].as_str().unwrap_or("")),
name: e["name"].as_str().unwrap_or("").to_string(),
dir: e["dir"].as_bool().unwrap_or(false),
size: e["size"].as_u64().unwrap_or(0),
})
.collect()
})
.unwrap_or_default()
}
pub fn read_file(path: &str) -> Result<Vec<u8>, String> {
let v = crate::fsops::handle("fs_read", &json!({ "path": path }));
if v["ok"] != json!(true) {
return Err(v["err"].as_str().unwrap_or("read_failed").to_string());
}
Ok(v["b64"].as_str().and_then(b64_decode).unwrap_or_default())
}
pub fn write_file(path: &str, bytes: &[u8]) -> Result<(), String> {
let v = crate::fsops::handle(
"fs_write",
&json!({ "path": path, "b64": crate::proto::b64_encode(bytes) }),
);
if v["ok"] == json!(true) {
Ok(())
} else {
Err(v["err"].as_str().unwrap_or("write_failed").to_string())
}
}