TLS 1.3, channel persistence, membership signaling
- TLS 1.3 on TCP (rustls + tokio-rustls, optional self-signed cert) - Server-side channel CRUD with SQLite persistence - Gateway → voice-node membership bridge via broadcast channel
This commit is contained in:
parent
523680e05d
commit
5534cd01f7
37 changed files with 771 additions and 160 deletions
|
|
@ -1,5 +1,5 @@
|
|||
use anyhow::Result;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tracing::{info, warn};
|
||||
|
||||
use crate::{
|
||||
|
|
@ -17,7 +17,7 @@ use crate::{
|
|||
/// Handle a ChannelCreate request — register a new channel in the store and
|
||||
/// broadcast the new ChannelState to all sessions so their sidebars update.
|
||||
pub async fn handle_channel_create(
|
||||
stream: &mut TcpStream,
|
||||
stream: &mut (impl AsyncRead + AsyncWrite + Unpin),
|
||||
seq: &mut u32,
|
||||
session_id: &str,
|
||||
payload: &[u8],
|
||||
|
|
@ -97,6 +97,17 @@ pub async fn handle_channel_create(
|
|||
|
||||
let created = channels::create(&state.channels, &channel_id, &channel_name, kind.clone()).await;
|
||||
|
||||
// Persist to DB (best-effort, log and continue on failure).
|
||||
if created {
|
||||
if let Err(e) = state
|
||||
.storage
|
||||
.create_channel(&channel_id, &channel_name, kind.as_str())
|
||||
.await
|
||||
{
|
||||
warn!("failed to persist channel to storage: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
if !created {
|
||||
io::send_encrypted(
|
||||
stream,
|
||||
|
|
@ -160,7 +171,7 @@ pub async fn handle_channel_create(
|
|||
/// Handle a ChannelDelete request — remove the channel from the store and
|
||||
/// broadcast the deletion to all sessions.
|
||||
pub async fn handle_channel_delete(
|
||||
stream: &mut TcpStream,
|
||||
stream: &mut (impl AsyncRead + AsyncWrite + Unpin),
|
||||
seq: &mut u32,
|
||||
session_id: &str,
|
||||
payload: &[u8],
|
||||
|
|
@ -190,6 +201,14 @@ pub async fn handle_channel_delete(
|
|||
}
|
||||
|
||||
let existed = channels::delete(&state.channels, &req.channel_id).await;
|
||||
|
||||
// Remove from DB (best-effort).
|
||||
if existed {
|
||||
if let Err(e) = state.storage.delete_channel(&req.channel_id).await {
|
||||
warn!("failed to remove channel from storage: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
if !existed {
|
||||
io::send_encrypted(
|
||||
stream,
|
||||
|
|
@ -229,7 +248,7 @@ pub async fn handle_channel_delete(
|
|||
|
||||
/// Handle a ChannelList request — reply with all known channels.
|
||||
pub async fn handle_channel_list(
|
||||
stream: &mut TcpStream,
|
||||
stream: &mut (impl AsyncRead + AsyncWrite + Unpin),
|
||||
seq: &mut u32,
|
||||
session_id: &str,
|
||||
crypto: &SessionCrypto,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use anyhow::Result;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tracing::info;
|
||||
|
||||
use crate::{
|
||||
|
|
@ -19,7 +19,7 @@ use super::{broadcast_leave, set_channel};
|
|||
const HISTORY_LIMIT: i64 = 50;
|
||||
|
||||
pub async fn join(
|
||||
stream: &mut TcpStream,
|
||||
stream: &mut (impl AsyncRead + AsyncWrite + Unpin),
|
||||
seq: &mut u32,
|
||||
session_id: &str,
|
||||
channel_id: &str,
|
||||
|
|
@ -110,6 +110,18 @@ pub async fn join(
|
|||
});
|
||||
}
|
||||
|
||||
if let Some(tx) = &state.voice_member_tx {
|
||||
if let Some(sess) = session::get(&state.sessions, session_id).await {
|
||||
let event = serde_json::json!({
|
||||
"type": "joined",
|
||||
"channel_id": channel_id,
|
||||
"session_id": session_id,
|
||||
"user_id": sess.user_id,
|
||||
});
|
||||
let _ = tx.send(event.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
info!("session {} joined {channel_id}", &session_id[..8]);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,39 @@
|
|||
use anyhow::Result;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tracing::info;
|
||||
|
||||
use crate::{domain::channels, net::state::State, proto::SessionCrypto};
|
||||
use crate::{domain::{channels, session}, net::state::State, proto::SessionCrypto};
|
||||
|
||||
use super::{broadcast_leave, set_channel};
|
||||
|
||||
pub async fn leave(
|
||||
_stream: &mut TcpStream,
|
||||
_stream: &mut (impl AsyncRead + AsyncWrite + Unpin),
|
||||
_seq: &mut u32,
|
||||
session_id: &str,
|
||||
channel_id: &str,
|
||||
_crypto: &SessionCrypto,
|
||||
state: &State,
|
||||
) -> Result<()> {
|
||||
let user_id = session::get(&state.sessions, session_id)
|
||||
.await
|
||||
.map(|s| s.user_id);
|
||||
|
||||
channels::leave(&state.channels, channel_id, session_id).await;
|
||||
set_channel(state, session_id, None).await;
|
||||
broadcast_leave(state, channel_id, session_id).await;
|
||||
|
||||
if let Some(tx) = &state.voice_member_tx {
|
||||
if let Some(ref uid) = user_id {
|
||||
let event = serde_json::json!({
|
||||
"type": "left",
|
||||
"channel_id": channel_id,
|
||||
"session_id": session_id,
|
||||
"user_id": uid,
|
||||
});
|
||||
let _ = tx.send(event.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
info!("session {} left {channel_id}", &session_id[..8]);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue