1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
use crate::{Args, CommandConfig, ReturnValue, ShellError, Spanned, Value}; use serde::{Deserialize, Serialize}; use std::io; pub trait Plugin { fn config(&mut self) -> Result<CommandConfig, ShellError>; #[allow(unused)] fn begin_filter(&mut self, args: Args) -> Result<(), ShellError> { Err(ShellError::string( "`begin_filter` not implemented in plugin", )) } #[allow(unused)] fn filter(&mut self, input: Spanned<Value>) -> Result<Vec<ReturnValue>, ShellError> { Err(ShellError::string("`filter` not implemented in plugin")) } #[allow(unused)] fn sink(&mut self, args: Args, input: Vec<Spanned<Value>>) {} fn quit(&mut self) { return; } } pub fn serve_plugin(plugin: &mut dyn Plugin) { let args = std::env::args(); if args.len() > 1 { let input = std::fs::read_to_string(args.skip(1).next().unwrap()); if let Ok(input) = input { let command = serde_json::from_str::<NuCommand>(&input); match command { Ok(NuCommand::config) => { send_response(plugin.config()); } Ok(NuCommand::begin_filter { params }) => { send_response( plugin .begin_filter(params) .map(|_| Vec::<ReturnValue>::new()), ); } Ok(NuCommand::filter { params }) => { send_response(plugin.filter(params)); } Ok(NuCommand::sink { params }) => { plugin.sink(params.0, params.1); return; } Ok(NuCommand::quit) => { plugin.quit(); return; } e => { send_response(ShellError::string(format!( "Could not handle plugin message: {} {:?}", input, e ))); return; } } } } else { loop { let mut input = String::new(); match io::stdin().read_line(&mut input) { Ok(_) => { let command = serde_json::from_str::<NuCommand>(&input); match command { Ok(NuCommand::config) => { send_response(plugin.config()); } Ok(NuCommand::begin_filter { params }) => { send_response( plugin .begin_filter(params) .map(|_| Vec::<ReturnValue>::new()), ); } Ok(NuCommand::filter { params }) => { send_response(plugin.filter(params)); } Ok(NuCommand::sink { params }) => { plugin.sink(params.0, params.1); break; } Ok(NuCommand::quit) => { plugin.quit(); break; } e => { send_response(ShellError::string(format!( "Could not handle plugin message: {} {:?}", input, e ))); break; } } } e => { send_response(ShellError::string(format!( "Could not handle plugin message: {:?}", e, ))); break; } } } } } #[derive(Debug, Serialize, Deserialize)] pub struct JsonRpc<T> { jsonrpc: String, pub method: String, pub params: T, } impl<T> JsonRpc<T> { pub fn new<U: Into<String>>(method: U, params: T) -> Self { JsonRpc { jsonrpc: "2.0".into(), method: method.into(), params, } } } fn send_response<T: Serialize>(result: T) { let response = JsonRpc::new("response", result); let response_raw = serde_json::to_string(&response).unwrap(); println!("{}", response_raw); } #[derive(Debug, Serialize, Deserialize)] #[serde(tag = "method")] #[allow(non_camel_case_types)] pub enum NuCommand { config, begin_filter { params: Args }, filter { params: Spanned<Value> }, sink { params: (Args, Vec<Spanned<Value>>) }, quit, }