1use crate::sim::{Sim, peer, unit};
7use planarian_ipc::{Request, Response};
8use planarian_schema::{ChangeId, Value};
9use std::io::{BufRead, BufReader, Write};
10use std::os::unix::net::UnixListener;
11use std::sync::mpsc;
12use std::time::{Duration, Instant};
13
14fn apply(sim: &mut Sim, change: &str, args: &[(&str, &str)]) -> Response {
15 let args = args.iter().map(|(k, v)| (k.to_string(), Value::Str(v.to_string()))).collect();
16 sim.core.as_mut().expect("core").handle(peer("root"), Request::Apply { change: ChangeId(change.into()), args })
17}
18
19pub fn serve(socket: &str) {
20 let mut sim = Sim::new();
21 for _ in 0..3 {
22 sim.tick();
23 }
24 for r in [
27 apply(&mut sim, "font-scale", &[("scale", "1.25")]),
28 apply(&mut sim, "listen-address", &[("service", "gym-web"), ("addr", "192.0.2.10")]),
29 ] {
30 eprintln!("{r:?}");
31 }
32 let core = sim.core.as_mut().expect("core");
33 eprintln!("{:?}", core.handle(peer("root"), Request::Stop { unit: unit("gym-cache") }));
34 sim.fake.w().blocked.insert(unit("gym-metrics"));
35 sim.fake.w().signal(&unit("gym-db"), 11);
36 for _ in 0..12 {
37 sim.tick();
38 }
39
40 let _ = std::fs::remove_file(socket);
41 let listener = UnixListener::bind(socket).unwrap_or_else(|e| panic!("{socket}: {e}"));
42 eprintln!("planarian-gym: serving the fake machine on {socket}");
43 type Job = (Request, mpsc::Sender<Response>);
44 let (tx, rx) = mpsc::channel::<Job>();
45 std::thread::spawn(move || {
46 for conn in listener.incoming().flatten() {
47 let tx = tx.clone();
48 std::thread::spawn(move || {
49 let mut line = String::new();
50 if BufReader::new(&conn).read_line(&mut line).is_err() {
51 return;
52 }
53 let resp = match serde_json::from_str::<Request>(&line) {
54 Ok(req) => {
55 let (rtx, rrx) = mpsc::channel();
56 if tx.send((req, rtx)).is_err() {
57 return;
58 }
59 rrx.recv().unwrap_or(Response::Error { message: "stopped".into() })
60 }
61 Err(e) => Response::Error { message: format!("bad request: {e}") },
62 };
63 let _ = (&conn).write_all(resp.encode().as_bytes());
64 });
65 }
66 });
67 let mut next = Instant::now();
69 loop {
70 match rx.recv_timeout(next.saturating_duration_since(Instant::now())) {
71 Ok((req, reply)) => {
72 let resp = sim.core.as_mut().expect("core").handle(peer("root"), req);
73 let _ = reply.send(resp);
74 }
75 Err(mpsc::RecvTimeoutError::Timeout) => {
76 sim.tick();
77 next = Instant::now() + Duration::from_secs(1);
78 }
79 Err(mpsc::RecvTimeoutError::Disconnected) => break,
80 }
81 }
82}