ExtraChat/server/src/handlers/message.rs

57 lines
1.7 KiB
Rust

use std::sync::Arc;
use std::sync::atomic::Ordering;
use anyhow::{Context, Result};
use tokio::sync::RwLock;
use crate::{ClientState, ErrorResponse, MessageRequest, MessageResponse, ResponseContainer, State, util, WsStream};
use crate::types::protocol::ResponseKind;
use crate::util::send;
pub async fn message(state: Arc<RwLock<State>>, client_state: Arc<RwLock<ClientState>>, conn: &mut WsStream, number: u32, req: MessageRequest) -> Result<()> {
let (lodestone_id, sender, world) = match &client_state.read().await.user {
Some(u) => (u.lodestone_id, u.name.clone(), u.world),
None => return Ok(()),
};
let id = req.channel.as_simple().to_string();
let members = sqlx::query!(
// language=sqlite
"select lodestone_id from user_channels where channel_id = ?",
id,
)
.fetch_all(&state.read().await.db)
.await
.context("could not query database for members")?;
let in_channel = members
.iter()
.any(|m| m.lodestone_id as u64 == lodestone_id);
if !in_channel {
return send(conn, number, ErrorResponse::new(req.channel, "not in channel")).await;
}
state.read().await.messages_sent.fetch_add(1, Ordering::SeqCst);
let resp = ResponseContainer {
number: 0,
kind: ResponseKind::Message(MessageResponse {
channel: req.channel,
sender,
world: util::id_from_world(world),
message: req.message,
}),
};
for member in members {
let client = match state.read().await.clients.get(&(member.lodestone_id as u64)).cloned() {
Some(c) => c,
None => continue,
};
client.read().await.tx.send(resp.clone()).await.ok();
}
Ok(())
}