use std::sync::Arc;
use hyphae::MapExt;
use myko_macros::{myko_command, myko_report, myko_report_output};
use crate::{
entities::server::{Server, ServerId},
prelude::*,
report::{ReportContext, ReportHandler},
};
#[myko_item]
pub struct Client {
#[belongs_to(Server)]
pub server_id: ServerId,
#[serde(default)]
pub address: Option<Arc<str>>,
pub windback: Option<Arc<str>>,
}
#[myko_report_output]
pub struct ClientStatusOutput {
pub online: bool,
}
#[myko_report(ClientStatusOutput)]
pub struct ClientStatus {
pub client_id: ClientId,
}
impl ReportHandler for ClientStatus {
type Output = ClientStatusOutput;
fn compute(&self, ctx: ReportContext) -> impl MaterializeDefinite<Arc<Self::Output>> {
let client_id = self.client_id.clone();
ctx.query_map(GetAllClients {})
.entries()
.map(move |clients| {
let online = clients
.iter()
.any(|(_, c)| c.id.as_ref() == client_id.as_ref());
Arc::new(ClientStatusOutput { online })
})
}
}
#[myko_report_output]
pub struct WindbackStatusOutput {
pub windback: Option<Arc<str>>,
}
#[myko_report(WindbackStatusOutput)]
pub struct WindbackStatus {}
impl ReportHandler for WindbackStatus {
type Output = WindbackStatusOutput;
fn compute(&self, ctx: ReportContext) -> impl MaterializeDefinite<Arc<Self::Output>> {
let client_id = ctx
.client_id()
.map(|id| ClientId::from(Arc::<str>::from(id)));
ctx.query_map(GetAllClients {})
.entries()
.map(move |clients| {
let windback = client_id
.as_ref()
.and_then(|cid| clients.iter().find(|(_, c)| c.id.as_ref() == cid.as_ref()))
.and_then(|(_, c)| c.windback.clone());
Arc::new(WindbackStatusOutput { windback })
})
}
}
#[myko_command(bool)]
pub struct SetClientWindbackTime {
pub windback: Arc<str>,
}
impl crate::command::CommandHandler for SetClientWindbackTime {
fn execute(
self,
ctx: crate::command::CommandContext,
) -> Result<bool, crate::command::CommandError> {
let client_id = ctx
.client_id()
.ok_or_else(|| crate::command::CommandError {
tx: ctx.tx().to_string(),
command_id: "SetClientWindbackTime".to_string(),
message: "No client_id in context - windback requires a WebSocket connection"
.to_string(),
})?;
let client = ctx
.exec_report(GetClientById {
id: ClientId::from(Arc::<str>::from(client_id.clone())),
})?
.ok_or_else(|| CommandError {
tx: ctx.tx().to_string(),
command_id: "SetClientWindbackTime".to_string(),
message: format!("Client {} not found", client_id),
})?;
let updated_client = Client {
id: client.id.clone(),
server_id: client.server_id.clone(),
address: client.address.clone(),
windback: Some(self.windback.clone()),
};
ctx.emit_set(&updated_client)?;
Ok(true)
}
}
#[myko_command(bool)]
pub struct ClearClientWindbackTime {}
impl crate::command::CommandHandler for ClearClientWindbackTime {
fn execute(
self,
ctx: crate::command::CommandContext,
) -> Result<bool, crate::command::CommandError> {
let client_id = ctx
.client_id()
.ok_or_else(|| crate::command::CommandError {
tx: ctx.tx().to_string(),
command_id: "ClearClientWindbackTime".to_string(),
message: "No client_id in context - windback requires a WebSocket connection"
.to_string(),
})?;
let client = ctx
.exec_report(GetClientById {
id: ClientId::from(Arc::<str>::from(client_id.clone())),
})?
.ok_or_else(|| CommandError {
tx: ctx.tx().to_string(),
command_id: "SetClientWindbackTime".to_string(),
message: format!("Client {} not found", client_id),
})?;
let updated_client = Client {
id: client.id.clone(),
server_id: client.server_id.clone(),
address: client.address.clone(),
windback: None,
};
ctx.emit_set(&updated_client)?;
Ok(true)
}
}