nushell/src/commands/plugin.rs

159 lines
5.5 KiB
Rust
Raw Normal View History

2019-07-02 09:56:20 +02:00
use crate::commands::command::SinkCommandArgs;
2019-06-27 18:47:24 +02:00
use crate::errors::ShellError;
use crate::prelude::*;
use serde::{self, Deserialize, Serialize};
use std::io::prelude::*;
use std::io::BufReader;
use std::io::Write;
2019-06-27 18:47:24 +02:00
#[derive(Debug, Serialize, Deserialize)]
pub struct JsonRpc<T> {
jsonrpc: String,
pub method: String,
pub params: T,
}
2019-06-27 18:47:24 +02:00
impl<T> JsonRpc<T> {
pub fn new<U: Into<String>>(method: U, params: T) -> Self {
JsonRpc {
jsonrpc: "2.0".into(),
method: method.into(),
params,
}
}
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "method")]
#[allow(non_camel_case_types)]
pub enum NuResult {
2019-07-02 09:56:20 +02:00
response {
params: Result<VecDeque<ReturnValue>, ShellError>,
},
2019-06-27 18:47:24 +02:00
}
2019-07-02 09:56:20 +02:00
pub fn filter_plugin(plugin_name: String, args: CommandArgs) -> Result<OutputStream, ShellError> {
2019-06-27 18:47:24 +02:00
let mut path = std::path::PathBuf::from(".");
path.push("target");
path.push("debug");
path.push(format!("nu_plugin_{}", plugin_name));
2019-07-02 09:56:20 +02:00
path = if path.exists() {
path
} else {
std::path::PathBuf::from(format!("nu_plugin_{}", plugin_name))
};
2019-06-27 18:47:24 +02:00
let mut child = std::process::Command::new(path)
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.spawn()
.expect("Failed to spawn child process");
{
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
2019-06-27 18:47:24 +02:00
let _reader = BufReader::new(stdout);
2019-06-27 18:47:24 +02:00
2019-07-02 09:56:20 +02:00
let request = JsonRpc::new("begin_filter", args.args);
2019-06-27 18:47:24 +02:00
let request_raw = serde_json::to_string(&request).unwrap();
stdin.write(format!("{}\n", request_raw).as_bytes())?;
2019-06-27 18:47:24 +02:00
}
2019-06-27 18:47:24 +02:00
let mut eos = VecDeque::new();
eos.push_back(Value::Primitive(Primitive::EndOfStream));
2019-07-02 09:56:20 +02:00
let stream = args
.input
2019-06-27 18:47:24 +02:00
.chain(eos)
.map(move |v| match v {
Value::Primitive(Primitive::EndOfStream) => {
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
2019-06-27 18:47:24 +02:00
let _ = BufReader::new(stdout);
2019-06-27 18:47:24 +02:00
let request: JsonRpc<std::vec::Vec<Value>> = JsonRpc::new("quit", vec![]);
let request_raw = serde_json::to_string(&request).unwrap();
let _ = stdin.write(format!("{}\n", request_raw).as_bytes()); // TODO: Handle error
2019-06-27 18:47:24 +02:00
VecDeque::new()
}
_ => {
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
2019-06-27 18:47:24 +02:00
let mut reader = BufReader::new(stdout);
let request = JsonRpc::new("filter", v);
let request_raw = serde_json::to_string(&request).unwrap();
let _ = stdin.write(format!("{}\n", request_raw).as_bytes()); // TODO: Handle error
2019-06-27 18:47:24 +02:00
let mut input = String::new();
match reader.read_line(&mut input) {
Ok(_) => {
let response = serde_json::from_str::<NuResult>(&input);
match response {
2019-07-02 09:56:20 +02:00
Ok(NuResult::response { params }) => match params {
Ok(params) => params,
Err(e) => {
let mut result = VecDeque::new();
result.push_back(ReturnValue::Value(Value::Error(Box::new(e))));
result
}
},
Err(e) => {
2019-06-27 18:47:24 +02:00
let mut result = VecDeque::new();
result.push_back(ReturnValue::Value(Value::Error(Box::new(
2019-07-02 09:56:20 +02:00
ShellError::string(format!(
"Error while processing input: {:?} {}",
e, input
)),
2019-06-27 18:47:24 +02:00
))));
result
}
}
}
2019-07-02 09:56:20 +02:00
Err(e) => {
2019-06-27 18:47:24 +02:00
let mut result = VecDeque::new();
result.push_back(ReturnValue::Value(Value::Error(Box::new(
2019-07-02 09:56:20 +02:00
ShellError::string(format!("Error while processing input: {:?}", e)),
2019-06-27 18:47:24 +02:00
))));
result
}
}
}
})
.flatten();
Ok(stream.boxed())
}
2019-07-02 09:56:20 +02:00
pub fn sink_plugin(plugin_name: String, args: SinkCommandArgs) -> Result<(), ShellError> {
let mut path = std::path::PathBuf::from(".");
path.push("target");
path.push("debug");
path.push(format!("nu_plugin_{}", plugin_name));
path = if path.exists() {
path
} else {
std::path::PathBuf::from(format!("nu_plugin_{}", plugin_name))
};
let mut child = std::process::Command::new(path)
.stdin(std::process::Stdio::piped())
.spawn()
.expect("Failed to spawn child process");
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
let request = JsonRpc::new("sink", (args.args, args.input));
let request_raw = serde_json::to_string(&request).unwrap();
stdin.write(format!("{}\n", request_raw).as_bytes())?;
let _ = child.wait();
Ok(())
}