lenso-runner 0.2.5

Native Tokio Runtime Driver and Runner for Lenso vNext.
Documentation
use super::wire;
use serde_json::{Value, json};
use std::{
    process::{ChildStdin, ChildStdout},
    sync::{
        Arc, Mutex,
        atomic::{AtomicBool, Ordering},
        mpsc,
    },
    thread,
    time::Duration,
};

#[derive(Clone, Debug)]
pub struct Relay {
    input: mpsc::SyncSender<Value>,
    stop: Arc<Mutex<Option<Value>>>,
    pub finished: Arc<AtomicBool>,
}

impl Relay {
    pub fn start(
        mut input: ChildStdin,
        mut output: ChildStdout,
        events: mpsc::SyncSender<wire::Event>,
        invalid: Arc<AtomicBool>,
    ) -> Self {
        let (send, receive) = mpsc::sync_channel(8);
        let stop = Arc::new(Mutex::new(None));
        let stopping = stop.clone();
        let writer_invalid = invalid.clone();
        thread::spawn(move || {
            loop {
                if let Some(message) = stopping.lock().expect("stop slot").take() {
                    let _ = wire::write(&mut input, &message);
                    break;
                }
                match receive.recv_timeout(Duration::from_millis(5)) {
                    Ok(message) => {
                        if wire::write(&mut input, &message).is_err() {
                            writer_invalid.store(true, Ordering::Release);
                            break;
                        }
                    }
                    Err(mpsc::RecvTimeoutError::Timeout) => {}
                    Err(mpsc::RecvTimeoutError::Disconnected) => break,
                }
            }
        });
        let finished = Arc::new(AtomicBool::new(false));
        let done = finished.clone();
        thread::spawn(move || {
            loop {
                match wire::read::<Value>(&mut output) {
                    Ok(Some(message)) => {
                        if events
                            .try_send(wire::Event::Application { message })
                            .is_err()
                        {
                            invalid.store(true, Ordering::Release);
                            break;
                        }
                    }
                    Ok(None) => break,
                    Err(_) => {
                        invalid.store(true, Ordering::Release);
                        break;
                    }
                }
            }
            done.store(true, Ordering::Release);
        });
        Self {
            input: send,
            stop,
            finished,
        }
    }

    pub fn send(&self, message: Value) -> bool {
        self.input.try_send(message).is_ok()
    }

    pub fn stop(&self, message: Option<Value>) {
        let mut slot = self.stop.lock().expect("stop slot");
        if slot.is_none() {
            *slot = Some(message.unwrap_or_else(|| json!({"version":1,"id":0,"op":"stop"})));
        }
    }
}