1use crate::{MessageDef, MessageHandler};
5
6pub trait Server: ServerMessages {
17 fn on_start(&mut self, context: &mut ServerContext<Self>) { let _ = context; }
19}
20
21pub trait ServerMessages: Sized {
24 const NAME: &'static str;
27
28 fn messages() -> &'static [MessageDef<Self>];
31}
32
33#[derive(Debug)]
35pub struct ServerContext<S> {
36 pub sid: xous::SID,
37 pub shutdown: bool,
38 pub(crate) handlers: Vec<(xous::MessageId, MessageHandler<S>)>,
41}
42
43impl<S> ServerContext<S> {
44 pub fn shutdown(&mut self) { self.shutdown = true; }
46
47 pub fn sid(&self) -> xous::SID { self.sid }
48
49 pub fn from_raw_sid(sid: xous::SID) -> Self { Self { sid, shutdown: false, handlers: Vec::new() } }
51}
52
53impl<S: Server> ServerContext<S> {
54 pub(crate) fn remove_handler(&mut self, msg_id: xous::MessageId) {
55 let idx = self.handlers.iter().position(|(id, _)| *id == msg_id).unwrap();
56 self.handlers.swap_remove(idx);
57 }
58}
59
60pub fn listen_and_connect<S: Server + Send + 'static>(mut server: S, pid: xous::PID) -> xous::CID {
62 let sid = create_sid(S::NAME);
63 std::thread::spawn(move || main_loop(&mut server, sid));
64 xous::connect_for_process(pid, sid).unwrap()
65}
66
67pub fn listen<S: Server + 'static>(mut server: S) {
69 let sid = create_sid(S::NAME);
70 main_loop(&mut server, sid);
71}
72
73pub fn listen_with<S: Server + 'static>(make_server: impl FnOnce(xous::SID) -> S) {
74 let sid = create_sid(S::NAME);
75 let mut server = make_server(sid);
76 main_loop(&mut server, sid);
77}
78
79fn main_loop<S: Server + 'static>(server: &mut S, sid: xous::SID) {
80 let mut lut = [None; 128];
83 for (id, handle) in S::messages() {
84 if *id > lut.len() {
85 panic!("message ID too large, either change the ID or increase LUT size");
86 }
87 if lut[*id].is_some() {
88 panic!("message ID {id} registered twice.");
89 }
90 lut[*id] = Some(handle);
91 }
92 let lut = lut;
93 let mut context = ServerContext::<S>::from_raw_sid(sid);
94 server.on_start(&mut context);
95 while !context.shutdown {
96 let msg = xous::receive_message(sid).unwrap();
97 match lut.get(msg.id()) {
98 Some(Some(handle)) => {
99 handle(server, msg, &mut context);
100 }
101 Some(None) => {
102 log::error!("Unexpected message for \"{}\" with message ID {}", S::NAME, msg.id())
103 }
104 None => {
105 if let Some((_, handler)) = context.handlers.iter().find(|s| s.0 == msg.id()) {
106 handler(server, msg, &mut context);
107 } else {
108 log::warn!("spurious event message for \"{}\": ID={}", S::NAME, msg.id());
109 }
110 }
111 }
112 }
113 xous::destroy_server(sid).unwrap();
114}
115
116pub fn create_sid(name: &str) -> xous::SID {
117 let sid = xous::create_server().unwrap();
118 if name.is_empty() {
119 log::info!("Starting anonymous server with sid={sid:?}");
120 } else {
121 log::info!("Starting server name={name:?}");
122 let names = xous_names::XousNames::new().unwrap();
124 names.register_name(sid, name).unwrap();
125 std::mem::forget(names);
127 }
128 sid
129}