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}