Skip to main content

wowlab_sentinel/scheduler/
eligibility.rs

1//! Node access-policy evaluation for scheduler assignments.
2
3use uuid::Uuid;
4use wowlab_types::sim::FastMap;
5
6use super::repository::{NodePermission, OnlineNode};
7use crate::utils::filter_refresh::FilterMap;
8
9#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
10pub(super) enum Priority {
11    Public = 1,
12    Friends = 2,
13    Discord = 3,
14    Own = 4,
15}
16
17pub(super) struct EligibilityContext<'a> {
18    pub permissions: &'a [NodePermission],
19    pub filters: &'a FilterMap,
20    pub friend_memberships: &'a FastMap<Uuid, Vec<Uuid>>,
21    pub user_discord_ids: &'a FastMap<Uuid, String>,
22}
23
24pub(super) fn priority(
25    node: &OnlineNode,
26    job_user_id: Uuid,
27    context: &EligibilityContext<'_>,
28) -> Option<Priority> {
29    if node.user_id == job_user_id {
30        return Some(Priority::Own);
31    }
32
33    let mut best = None;
34
35    for permission in context
36        .permissions
37        .iter()
38        .filter(|permission| permission.public_key == node.public_key)
39    {
40        match permission.access_type.as_str() {
41            "public" => best = best.max(Some(Priority::Public)),
42            "discord" => {
43                best = best.max(discord_priority(permission, job_user_id, context));
44            }
45            "friends" => {
46                best = best.max(friends_priority(permission, job_user_id, context));
47            }
48            _ => {}
49        }
50    }
51
52    best
53}
54
55fn discord_priority(
56    permission: &NodePermission,
57    job_user_id: Uuid,
58    context: &EligibilityContext<'_>,
59) -> Option<Priority> {
60    let discord_id = context.user_discord_ids.get(&job_user_id)?;
61    let guild_id = permission.target_id.as_deref()?.parse::<u64>().ok()?;
62    let filters = context.filters.try_read().ok()?;
63
64    filters
65        .get(&guild_id)?
66        .filter
67        .might_contain(discord_id)
68        .then_some(Priority::Discord)
69}
70
71fn friends_priority(
72    permission: &NodePermission,
73    job_user_id: Uuid,
74    context: &EligibilityContext<'_>,
75) -> Option<Priority> {
76    let list_id = permission.target_id.as_deref()?.parse::<Uuid>().ok()?;
77
78    context
79        .friend_memberships
80        .get(&job_user_id)?
81        .contains(&list_id)
82        .then_some(Priority::Friends)
83}
84
85#[cfg(test)]
86mod tests;