Skip to main content

get_or_spawn

Function get_or_spawn 

Source
pub fn get_or_spawn<KeyType: 'static>(
    keyname: impl ToString,
    spawn: impl FnOnce() -> Command,
) -> Result<PersistentChild>
Expand description

A combination of the spawn ang get commands, letting you “lazyly” spawn processes.

§Examples

use std::{
    io::BufRead,
    mem,
    process::{Command, Stdio},
};

use duat::{
    prelude::*,
    process::{self, is_interrupt},
};

// Private key for processes.
struct Key;
struct PluginWithProcesses;

impl Plugin for PluginWithProcesses {
    fn plug(self, _: &Plugins) {
        let pname = "process1";
        let mut child = process::get_or_spawn::<Key>(pname, || {
            let mut command = Command::new("your-command-name");
            command
                .stdin(Stdio::piped())
                .stdout(Stdio::piped())
                .stderr(Stdio::piped());
            command
        })
        .unwrap();

        let mut stdout = child.stdout.take().unwrap();
        let join_stdout = std::thread::spawn(move || {
            let mut line = String::new();
            loop {
                match stdout.read_line(&mut line) {
                    // The Child has exited.
                    Ok(0) => break stdout,
                    Ok(_) => do_stuff_with_line(mem::take(&mut line)),
                    // Duat is about to reload.
                    Err(err) if is_interrupt(&err) => break stdout,
                    Err(err) => context::error!("{err}"),
                }
            }
        });

        let mut stderr = child.stderr.take().unwrap();
        let join_stderr = std::thread::spawn(move || {
            // Similar thing as above...
            stderr
        });

        hook::add_once::<ConfigUnloaded>(move |_, _| {
            let stdout = join_stdout.join().unwrap();
            let stderr = join_stderr.join().unwrap();

            child.stdout = Some(stdout);
            child.stderr = Some(stderr);
            process::store::<Key>(pname, child);
        });
    }
}