omega/src/transport/handlers/presence.rs
2026-07-27 20:36:23 +02:00

183 lines
5.7 KiB
Rust

use super::super::omikron_connection::{OmikronConnection, OmikronResult};
use crate::{
db::user_repo,
log_in,
models::IotaId,
sql::{connection_status::UserStatus, user_online_tracker},
};
use mtp::codec::{CommunicationType, CommunicationValue, DataType, DataValue};
use std::sync::Arc;
pub async fn user_connected(
_connection: Arc<OmikronConnection>,
value: CommunicationValue,
omikron_id: i64,
) -> OmikronResult<()> {
log_in!(crate::util::logger::PrintType::Omega, "User connected");
if let Some(user_id) = value.get_data(DataType::UserId).as_number() {
let status = value
.get_data(DataType::UserState)
.as_str()
.and_then(UserStatus::from_str)
.unwrap_or(UserStatus::user_online);
if let Ok(user_id) = i64::try_from(user_id) {
if let Some(session_id) = value
.get_data(DataType::SessionId)
.as_number()
.and_then(|id| i64::try_from(id).ok())
.filter(|id| *id > 0)
{
user_online_tracker::track_user_session_status(
user_id, session_id, status, omikron_id,
);
} else {
user_online_tracker::track_user_status(user_id, status, omikron_id);
}
}
}
Ok(())
}
pub async fn user_disconnected(
_: Arc<OmikronConnection>,
value: CommunicationValue,
omikron_id: i64,
) -> OmikronResult<()> {
log_in!(crate::util::logger::PrintType::Omega, "User disconnected");
if let Some(user_id) = value.get_data(DataType::UserId).as_number() {
if let Some(session_id) = value
.get_data(DataType::SessionId)
.as_number()
.and_then(|id| i64::try_from(id).ok())
.filter(|id| *id > 0)
{
user_online_tracker::untrack_user_session_status(
user_id as i64,
session_id,
omikron_id,
);
} else {
user_online_tracker::untrack_user_status(user_id as i64, omikron_id);
}
}
Ok(())
}
pub async fn client_changed(
_: Arc<OmikronConnection>,
value: CommunicationValue,
_: i64,
) -> OmikronResult<()> {
let Some(user_id) = value
.get_data(DataType::UserId)
.as_number()
.and_then(|id| i64::try_from(id).ok())
else {
return Ok(());
};
let Some(status) = value
.get_data(DataType::UserState)
.as_str()
.and_then(UserStatus::from_str)
else {
return Ok(());
};
// Connectivity is derived from routes. Clients may choose only public
// presence preferences, never server/offline states.
if matches!(
status,
UserStatus::user_offline | UserStatus::iota_offline | UserStatus::iota_online
) {
return Ok(());
}
user_online_tracker::update_user_session_status(user_id, status);
Ok(())
}
pub async fn iota_connected(
connection: Arc<OmikronConnection>,
value: CommunicationValue,
omikron_id: i64,
) -> OmikronResult<()> {
log_in!(crate::util::logger::PrintType::Omega, "IOTA connected");
let Some(iota_id) = value
.get_data(DataType::IotaId)
.as_number()
.map(|id| id as i64)
else {
return Ok(());
};
user_online_tracker::track_iota_connection(iota_id, omikron_id, true);
let mut user_ids = Vec::new();
match user_repo::get_users_by_iota_id(IotaId::from(iota_id)).await {
Ok(users) => {
for user in users {
user_ids.push(DataValue::SignedNumber(user.id.0.into()));
user_online_tracker::track_user_status(
user.id.0,
UserStatus::user_offline,
omikron_id,
);
}
}
Err(_) => log_in!(
crate::util::logger::PrintType::General,
"SQL error loading users for IOTA"
),
}
let response = CommunicationValue::new(CommunicationType::IotaUserData)
.with_id(value.get_id())
.add_typed_default(DataType::IotaId, DataValue::SignedNumber(iota_id.into()))
.add_typed_default(DataType::UserIds, DataValue::Array(user_ids));
let _ = connection.send(&response).await;
Ok(())
}
pub async fn iota_disconnected(
_: Arc<OmikronConnection>,
value: CommunicationValue,
omikron_id: i64,
) -> OmikronResult<()> {
log_in!(crate::util::logger::PrintType::Omega, "IOTA disconnected");
let Some(iota_id) = value
.get_data(DataType::IotaId)
.as_number()
.map(|id| id as i64)
else {
return Ok(());
};
if user_online_tracker::untrack_iota_connection(iota_id, omikron_id) {
if let Ok(users) = user_repo::get_users_by_iota_id(IotaId::from(iota_id)).await {
user_online_tracker::untrack_many_users(
&users.iter().map(|user| user.id.0).collect::<Vec<_>>(),
);
}
}
Ok(())
}
pub async fn sync_status(
_: Arc<OmikronConnection>,
value: CommunicationValue,
omikron_id: i64,
) -> OmikronResult<()> {
if let DataValue::Array(ids) = value.get_data(DataType::UserIds) {
for id in ids {
if let DataValue::SignedNumber(id) = id {
user_online_tracker::track_user_status(
*id as i64,
UserStatus::user_offline,
omikron_id,
);
}
}
}
if let DataValue::Array(ids) = value.get_data(DataType::IotaIds) {
for id in ids {
if let DataValue::SignedNumber(id) = id {
user_online_tracker::track_iota_connection(*id as i64, omikron_id, true);
}
}
}
Ok(())
}