Skip to main content

roowho2_lib/server/varlink_api/
fingerd.rs

1use itertools::Itertools;
2use serde::{Deserialize, Serialize};
3use zlink::ReplyError;
4
5use crate::{
6    proto::finger_protocol::FingerResponseUserEntry,
7    server::{
8        fingerd::{self, FingerRequestInfo, FingerRequestNetworking, finger_utmp_users},
9        ignore_list::IgnoreList,
10    },
11};
12
13#[zlink::proxy("no.ntnu.pvv.roowho2.finger")]
14pub trait VarlinkFingerClientProxy {
15    async fn finger(
16        &mut self,
17        user_queries: Option<Vec<String>>,
18        match_fullnames: bool,
19        request_info: FingerRequestInfo,
20        request_networking: FingerRequestNetworking,
21        disable_user_account_db: bool,
22        raw_remote_output: bool,
23    ) -> zlink::Result<Result<VarlinkFingerResponse, VarlinkFingerClientError>>;
24}
25
26#[derive(Debug, Deserialize)]
27#[serde(tag = "method", content = "parameters")]
28pub enum VarlinkFingerClientRequest {
29    #[serde(rename = "no.ntnu.pvv.roowho2.finger.Finger")]
30    Finger {
31        user_queries: Option<Vec<String>>,
32        match_fullnames: bool,
33        request_info: FingerRequestInfo,
34        request_networking: FingerRequestNetworking,
35        disable_user_account_db: bool,
36        raw_remote_output: bool,
37    },
38}
39
40#[derive(Debug, Serialize)]
41#[serde(untagged)]
42pub enum VarlinkFingerClientResponse {
43    Finger(VarlinkFingerResponse),
44}
45
46pub type VarlinkFingerResponse = Vec<FingerResponseUserEntry>;
47
48#[derive(Debug, Clone, PartialEq, ReplyError)]
49#[zlink(interface = "no.ntnu.pvv.roowho2.finger")]
50pub enum VarlinkFingerClientError {
51    InvalidRequest,
52    TimedOut,
53    Disabled,
54}
55
56pub async fn handle_finger_request(
57    finger_ignore_list: &Option<IgnoreList>,
58    user_queries: Option<Vec<String>>,
59    match_fullnames: bool,
60    request_info: FingerRequestInfo,
61    _request_networking: FingerRequestNetworking,
62    _disable_user_account_db: bool,
63    _raw_remote_output: bool,
64) -> VarlinkFingerResponse {
65    tracing::debug!(
66      user_queries = ?user_queries,
67      match_fullnames = match_fullnames,
68      request_info = ?request_info,
69      "Handling Finger request",
70    );
71    match user_queries {
72        Some(usernames) => usernames
73            .into_iter()
74            .flat_map::<Vec<_>, _>(|username| {
75                fingerd::search_for_user(
76                    &username,
77                    match_fullnames,
78                    &request_info,
79                    finger_ignore_list.as_ref(),
80                )
81                .into_iter()
82                .map(|res| (username.clone(), res))
83                .collect()
84            })
85            .dedup_by(|a, b| match (&a.1, &b.1) {
86                (Ok(user_a), Ok(user_b)) => user_a.username == user_b.username,
87                _ => false,
88            })
89            .filter_map(|(username, user)| match user {
90                Ok(user_info) => Some(user_info),
91                Err(err) => {
92                    tracing::error!(
93                        "Error retrieving local user information for '{}': {}",
94                        username,
95                        err
96                    );
97                    None
98                }
99            })
100            .map(Box::new)
101            .map(FingerResponseUserEntry::Structured)
102            .collect(),
103
104        None => finger_utmp_users(&request_info, finger_ignore_list.as_ref())
105            .into_iter()
106            .filter_map(|res| match res {
107                Ok(user_info) => Some(user_info),
108                Err(err) => {
109                    tracing::error!("Error retrieving local user information: {}", err);
110                    None
111                }
112            })
113            .map(Box::new)
114            .map(FingerResponseUserEntry::Structured)
115            .collect(),
116    }
117}