stateroom_stdio/
lib.rs

1use std::process::Command;
2
3use interactive_process::InteractiveProcess;
4use stateroom::{
5    MessageFromProcess, MessagePayload, MessageToProcess, StateroomContext, StateroomService,
6    StateroomServiceFactory,
7};
8
9pub struct StdioProcessServiceFactory {
10    command: String,
11}
12
13impl StdioProcessServiceFactory {
14    #[must_use]
15    pub fn new(command: &str) -> Self {
16        StdioProcessServiceFactory {
17            command: command.to_string(),
18        }
19    }
20}
21
22impl<T: StateroomContext + Send + Sync + 'static> StateroomServiceFactory<T> for StdioProcessServiceFactory {
23    type Service = StdioProcessService;
24    type Error = std::io::Error;
25
26    fn build(&self, _room_id: &str, context: T) -> Result<Self::Service, Self::Error> {
27        let process = InteractiveProcess::new(Command::new(&self.command), move |line| {
28            let line = line.expect("Error reading line from stdin.");
29            let message: MessageFromProcess =
30                serde_json::from_str(&line).expect("Couldn't parse message from process.");
31
32            match message {
33                MessageFromProcess::Message {
34                    recipient,
35                    message: MessagePayload::Bytes(message),
36                } => {
37                    context.send_binary(recipient, &message);
38                }
39                MessageFromProcess::Message {
40                    recipient,
41                    message: MessagePayload::Text(message),
42                } => {
43                    context.send_message(recipient, &message);
44                }
45            }
46        })?;
47
48        Ok(StdioProcessService { process })
49    }
50}
51
52pub struct StdioProcessService {
53    process: InteractiveProcess,
54}
55
56impl StdioProcessService {
57    fn send_to_process(&mut self, message: &MessageToProcess) {
58        self.process
59            .send(&serde_json::to_string(&message).expect("Could not jsonify message."))
60            .expect("Could not send message to process.");
61    }
62}
63
64impl StateroomService for StdioProcessService {
65    fn connect(&mut self, client: stateroom::ClientId) {
66        self.send_to_process(&MessageToProcess::Connect { client });
67    }
68
69    fn disconnect(&mut self, client: stateroom::ClientId) {
70        self.send_to_process(&MessageToProcess::Disconnect { client });
71    }
72
73    fn message(&mut self, sender: stateroom::ClientId, message: &str) {
74        self.send_to_process(&MessageToProcess::Message {
75            client: sender,
76            message: MessagePayload::Text(message.to_string()),
77        });
78    }
79
80    fn binary(&mut self, sender: stateroom::ClientId, message: &[u8]) {
81        self.send_to_process(&MessageToProcess::Message {
82            client: sender,
83            message: MessagePayload::Bytes(message.to_vec()),
84        });
85    }
86
87    fn timer(&mut self) {
88        self.send_to_process(&MessageToProcess::Timer);
89    }
90}