/src/bot.rs
Rust | 120 lines | 102 code | 18 blank | 0 comment | 3 complexity | dcc97812a6e4901fd321962294d6a7aa MD5 | raw file
- use std::{
- env,
- fs::{self, OpenOptions},
- io::{Read, Write},
- path::{Path, PathBuf},
- process::{Command, Stdio},
- };
- use crate::error::Error;
- pub trait Bot {
- fn name(&self) -> String;
- fn help(&self) -> Result<String, Error>;
- fn execute(&self, args: &str) -> Result<String, Error>;
- }
- pub struct CommandBot {
- path: PathBuf,
- }
- impl CommandBot {
- pub fn new<P: AsRef<Path>>(path: P) -> Self {
- Self {
- path: path.as_ref().to_path_buf(),
- }
- }
- fn command(&self) -> Command {
- Command::new(&self.path)
- }
- }
- impl Bot for CommandBot {
- fn name(&self) -> String {
- self.path
- .as_path()
- .file_stem()
- .map(|s| s.to_string_lossy().into_owned())
- .unwrap_or_default()
- }
- fn help(&self) -> Result<String, Error> {
- let output = self.command().arg("--help").output()?;
- Ok(String::from_utf8_lossy(&output.stdout).into_owned())
- }
- fn execute(&self, args: &str) -> Result<String, Error> {
- let mut command = self
- .command()
- .stdin(Stdio::piped())
- .stdout(Stdio::piped())
- .spawn()?;
- {
- let mut stdin = command.stdin.take().expect("Command to have stdin");
- write!(stdin, "{}", args)?;
- }
- let out = command.wait_with_output().expect("Failed output").stdout;
- Ok(String::from_utf8_lossy(&out).to_string())
- }
- }
- pub struct EditBot {
- tempfile: PathBuf,
- }
- impl EditBot {
- pub fn new() -> Result<Self, Error> {
- Ok(Self {
- tempfile: crate::util::create_tempfile_with_name("ntd-edit.txt")?,
- })
- }
- }
- impl Bot for EditBot {
- fn name(&self) -> String {
- "edit".to_string()
- }
- fn help(&self) -> Result<String, Error> {
- Ok("@edit Edit the input using your $EDITOR.
- Note that this is currently hardcoded in Rust as most editors need access to terminal stdin and stdout.
- Needs: -
- Provides: -
- ".to_string())
- }
- fn execute(&self, args: &str) -> Result<String, Error> {
- {
- let mut file = OpenOptions::new()
- .write(true)
- .create(true)
- .truncate(true)
- .open(&self.tempfile)?;
- write!(file, "{}", args)?;
- }
- let editor = env::var("EDITOR").unwrap_or_else(|_| "nano".to_string());
- let _command = Command::new(&editor)
- .arg(self.tempfile.as_os_str())
- .spawn()?
- .wait()?;
- let content = {
- let mut file = OpenOptions::new().read(true).open(&self.tempfile)?;
- let mut string = String::new();
- file.read_to_string(&mut string)?;
- string
- };
- Ok(content)
- }
- }
- impl Drop for EditBot {
- fn drop(&mut self) {
- let _ = fs::remove_file(&self.tempfile);
- }
- }