1use std::sync::Arc;
2
3use hyphae::{JoinExt, MapExt, flat};
4
5use crate::{
6 entities::client::GetAllClients,
7 prelude::*,
8 report::{ReportContext, ReportHandler},
9};
10
11#[myko_item]
12pub struct Server {
13 pub version: String,
14 #[searchable]
15 pub address: String,
16 pub port: u16,
17 pub started_at: String, }
19
20#[myko_query(Server)]
21pub struct GetConnectedServer {}
22
23impl QueryHandler for GetConnectedServer {
24 fn test_entity(ctx: QueryTestCtx<Self>) -> bool {
25 let item_id = ctx.item.id.to_string();
26 let host_id = ctx.query_context.req.host_id.to_string();
27 item_id == host_id
28 }
29}
30
31#[myko_query(Server)]
32pub struct GetPeerServers {}
33
34impl QueryHandler for GetPeerServers {
35 fn test_entity(ctx: QueryTestCtx<Self>) -> bool {
36 let item_id = ctx.item.id.to_string();
37 let host_id = ctx.query_context.req.host_id.to_string();
38 item_id != host_id
39 }
40}
41
42#[myko_macros::myko_report_output]
49pub struct ServerStatsOutput {
50 pub server: Option<Arc<Server>>,
52 pub client_count: usize,
54 pub uptime_seconds: Option<i64>,
56}
57
58#[myko_macros::myko_report(ServerStatsOutput)]
81pub struct ServerStats {}
82
83impl ReportHandler for ServerStats {
84 type Output = ServerStatsOutput;
85
86 fn compute(&self, ctx: ReportContext) -> impl MaterializeDefinite<Arc<Self::Output>> {
87 ctx.query_map(GetConnectedServer {})
89 .entries()
90 .join(&ctx.query_map(GetAllClients {}).entries())
91 .map(flat!(|servers, clients| {
92 let server = servers.first().map(|(_, server)| server.clone());
93
94 let uptime_seconds = server.as_ref().and_then(|s| {
96 chrono::DateTime::parse_from_rfc3339(&s.started_at)
97 .ok()
98 .map(|started| {
99 let now = chrono::Utc::now();
100 (now - started.with_timezone(&chrono::Utc)).num_seconds()
101 })
102 });
103
104 Arc::new(ServerStatsOutput {
105 server,
106 client_count: clients.len(),
107 uptime_seconds,
108 })
109 }))
110 }
111}