roowho2_lib/server/
varlink_api.rs1use anyhow::Context;
2use serde::{Deserialize, Serialize};
3use zlink::{ReplyError, service::MethodReply};
4
5use crate::{
6 proto::{WhodStatusUpdate, WhodUserEntry, finger_protocol::FingerResponse},
7 server::rwhod::RwhodStatusStore,
8};
9
10#[zlink::proxy("no.ntnu.pvv.roowho2.rwhod")]
13pub trait VarlinkRwhodClientProxy {
14 async fn rwho(
15 &mut self,
16 all: bool,
17 ) -> zlink::Result<Result<VarlinkRwhoResponse, VarlinkRwhodClientError>>;
18
19 async fn ruptime(
20 &mut self,
21 ) -> zlink::Result<Result<VarlinkRuptimeResponse, VarlinkRwhodClientError>>;
22}
23
24#[derive(Debug, Deserialize)]
25#[serde(tag = "method", content = "parameters")]
26pub enum VarlinkRwhodClientRequest {
27 #[serde(rename = "no.ntnu.pvv.roowho2.rwhod.Rwho")]
28 Rwho {
29 all: bool,
31 },
32
33 #[serde(rename = "no.ntnu.pvv.roowho2.rwhod.Ruptime")]
34 Ruptime,
35}
36
37#[derive(Debug, Clone, PartialEq, Serialize)]
38#[serde(untagged)]
39pub enum VarlinkRwhodClientResponse {
40 Rwho(VarlinkRwhoResponse),
41 Ruptime(VarlinkRuptimeResponse),
42}
43
44pub type VarlinkRwhoResponse = Vec<(String, WhodUserEntry)>;
45pub type VarlinkRuptimeResponse = Vec<WhodStatusUpdate>;
46
47#[derive(Debug, Clone, PartialEq, ReplyError)]
48#[zlink(interface = "no.ntnu.pvv.roowho2.rwhod")]
49pub enum VarlinkRwhodClientError {
50 InvalidRequest,
51}
52
53#[zlink::proxy("no.ntnu.pvv.roowho2.finger")]
56pub trait VarlinkFingerClientProxy {
57 async fn finger(
58 &mut self,
59 user_queries: Vec<String>,
60 ) -> zlink::Result<Result<VarlinkFingerResponse, VarlinkFingerClientError>>;
61}
62
63#[derive(Debug, Deserialize)]
64#[serde(tag = "method", content = "parameters")]
65pub enum VarlinkFingerClientRequest {
66 #[serde(rename = "no.ntnu.pvv.roowho2.finger.Finger")]
67 Finger { user_queries: Vec<String> },
68}
69
70#[derive(Debug, Serialize)]
71#[serde(untagged)]
72pub enum VarlinkFingerClientResponse {
73 Finger(VarlinkFingerResponse),
74}
75
76pub type VarlinkFingerResponse = FingerResponse;
77
78#[derive(Debug, Clone, PartialEq, ReplyError)]
79#[zlink(interface = "no.ntnu.pvv.roowho2.finger")]
80pub enum VarlinkFingerClientError {
81 InvalidRequest,
82}
83
84#[derive(Debug, Deserialize)]
87#[serde(untagged)]
88#[allow(unused)]
89pub enum VarlinkMethod {
90 Rwhod(VarlinkRwhodClientRequest),
91 Finger(VarlinkFingerClientRequest),
92}
93
94#[derive(Debug, Serialize)]
95#[serde(untagged)]
96#[allow(unused)]
97pub enum VarlinkReply {
98 Rwhod(VarlinkRwhodClientResponse),
99 Finger(VarlinkFingerClientResponse),
100}
101
102#[derive(Debug, Clone, PartialEq, Serialize)]
103#[serde(untagged)]
104#[allow(unused)]
105pub enum VarlinkReplyError {
106 Rwhod(VarlinkRwhodClientError),
107 Finger(VarlinkFingerClientError),
108}
109
110#[derive(Debug, Clone)]
111pub struct VarlinkRoowhoo2ClientServer {
112 whod_status_store: RwhodStatusStore,
113}
114
115impl VarlinkRoowhoo2ClientServer {
116 pub fn new(whod_status_store: RwhodStatusStore) -> Self {
117 Self { whod_status_store }
118 }
119}
120
121impl VarlinkRoowhoo2ClientServer {
122 async fn handle_rwho_request(&self, _all: bool) -> VarlinkRwhoResponse {
124 let store = self.whod_status_store.read().await;
125
126 let mut all_user_entries = Vec::with_capacity(store.len());
127 for status_update in store.values() {
128 all_user_entries.extend_from_slice(
129 &status_update
130 .users
131 .iter()
132 .map(|user| (status_update.hostname.clone(), user.clone()))
133 .collect::<Vec<(String, WhodUserEntry)>>(),
134 );
135 }
136
137 all_user_entries
138 }
139
140 async fn handle_ruptime_request(&self) -> VarlinkRuptimeResponse {
141 let store = self.whod_status_store.read().await;
142 store.values().cloned().collect()
143 }
144}
145
146impl zlink::Service for VarlinkRoowhoo2ClientServer {
147 type MethodCall<'de> = VarlinkMethod;
148 type ReplyParams<'se> = VarlinkReply;
149 type ReplyStreamParams = ();
150 type ReplyStream = futures_util::stream::Empty<zlink::Reply<()>>;
151 type ReplyError<'se> = VarlinkReplyError;
152
153 async fn handle<'service, Sock: zlink::connection::Socket>(
154 &'service mut self,
155 call: &'service zlink::Call<Self::MethodCall<'_>>,
156 _conn: &mut zlink::Connection<Sock>,
157 ) -> MethodReply<Self::ReplyParams<'service>, Self::ReplyStream, Self::ReplyError<'service>>
158 {
159 match call.method() {
160 VarlinkMethod::Rwhod(VarlinkRwhodClientRequest::Rwho { all }) => {
161 MethodReply::Single(Some(VarlinkReply::Rwhod(VarlinkRwhodClientResponse::Rwho(
162 self.handle_rwho_request(*all).await,
163 ))))
164 }
165 VarlinkMethod::Rwhod(VarlinkRwhodClientRequest::Ruptime) => {
166 MethodReply::Single(Some(VarlinkReply::Rwhod(
167 VarlinkRwhodClientResponse::Ruptime(self.handle_ruptime_request().await),
168 )))
169 }
170 VarlinkMethod::Finger(VarlinkFingerClientRequest::Finger { user_queries: _ }) => {
171 unimplemented!()
172 }
173 }
174 }
175}
176
177pub async fn varlink_client_server_task(
178 socket: zlink::unix::Listener,
179 whod_status_store: RwhodStatusStore,
180) -> anyhow::Result<()> {
181 let service = VarlinkRoowhoo2ClientServer::new(whod_status_store);
182
183 let server = zlink::Server::new(socket, service);
184
185 tracing::info!("Starting Rwhod client API server");
186
187 server
188 .run()
189 .await
190 .context("Rwhod client API server failed")?;
191
192 Ok(())
193}