Initial commit: split VNOX monorepo into VNOX-Server
Unified server binary (vnox-serverd) combining: - Gateway (TCP, auth, channels, sessions, SQLite) - Voice-node (UDP relay, Opus, jitter buffer) Standalone gateway (vnox-gateway) and voice-node (vnox-voice-node) preserved as sub-crates.
This commit is contained in:
commit
e751e0bf5b
94 changed files with 9771 additions and 0 deletions
115
gateway/src/handler/channel/join.rs
Normal file
115
gateway/src/handler/channel/join.rs
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
use anyhow::Result;
|
||||
use tokio::net::TcpStream;
|
||||
use tracing::info;
|
||||
|
||||
use crate::{
|
||||
domain::{channels, session},
|
||||
net::{
|
||||
io,
|
||||
state::{BroadcastMsg, State},
|
||||
},
|
||||
proto::{
|
||||
self, ChannelStatePayload, ChatHistoryPayload, MemberInfo, PacketId, SessionCrypto,
|
||||
UserJoinPayload, encode_packet, to_payload,
|
||||
},
|
||||
};
|
||||
|
||||
use super::{broadcast_leave, set_channel};
|
||||
|
||||
const HISTORY_LIMIT: i64 = 50;
|
||||
|
||||
pub async fn join(
|
||||
stream: &mut TcpStream,
|
||||
seq: &mut u32,
|
||||
session_id: &str,
|
||||
channel_id: &str,
|
||||
crypto: &SessionCrypto,
|
||||
state: &State,
|
||||
) -> Result<()> {
|
||||
let prev_channel = session::get(&state.sessions, session_id)
|
||||
.await
|
||||
.and_then(|s| s.channel_id);
|
||||
|
||||
if prev_channel.as_deref() == Some(channel_id) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(prev) = prev_channel {
|
||||
channels::leave(&state.channels, &prev, session_id).await;
|
||||
broadcast_leave(state, &prev, session_id).await;
|
||||
}
|
||||
|
||||
let ch = match channels::get_channel(&state.channels, channel_id).await {
|
||||
Some(c) => c,
|
||||
None => {
|
||||
io::send_encrypted(
|
||||
stream,
|
||||
PacketId::Error,
|
||||
seq,
|
||||
&to_payload(&proto::ErrorPayload {
|
||||
code: proto::ErrorCode::ChannelNotFound as u32,
|
||||
message: "not found".into(),
|
||||
}),
|
||||
crypto,
|
||||
)
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
channels::join(&state.channels, channel_id, session_id).await;
|
||||
set_channel(state, session_id, Some(channel_id.into())).await;
|
||||
|
||||
let mut members = Vec::new();
|
||||
for sid in channels::members(&state.channels, channel_id).await {
|
||||
if let Some(s) = session::get(&state.sessions, &sid).await {
|
||||
members.push(MemberInfo {
|
||||
user_id: s.user_id.clone(),
|
||||
nickname: s.nickname.clone(),
|
||||
in_voice: ch.kind == channels::ChannelKind::Voice,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let sp = ChannelStatePayload {
|
||||
channel_id: ch.id.clone(),
|
||||
channel_name: ch.name.clone(),
|
||||
kind: ch.kind.as_str().into(),
|
||||
members,
|
||||
voice_endpoint: state.config.voice.bind.clone(),
|
||||
};
|
||||
io::send_encrypted(
|
||||
stream,
|
||||
PacketId::ChannelState,
|
||||
seq,
|
||||
&to_payload(&sp),
|
||||
crypto,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let history = state.storage.get_history(channel_id, HISTORY_LIMIT).await?;
|
||||
if !history.is_empty() {
|
||||
let hp = ChatHistoryPayload {
|
||||
channel_id: channel_id.into(),
|
||||
messages: history,
|
||||
};
|
||||
io::send_encrypted(stream, PacketId::ChatHistory, seq, &to_payload(&hp), crypto).await?;
|
||||
}
|
||||
|
||||
if let Some(sess) = session::get(&state.sessions, session_id).await {
|
||||
let jp = UserJoinPayload {
|
||||
channel_id: channel_id.into(),
|
||||
user_id: sess.user_id.clone(),
|
||||
nickname: sess.nickname.clone(),
|
||||
};
|
||||
let _ = state.broadcast.send(BroadcastMsg {
|
||||
channel_id: Some(channel_id.into()),
|
||||
exclude_session: Some(session_id.into()),
|
||||
target_session_id: None,
|
||||
data: encode_packet(PacketId::UserJoin, 0, &to_payload(&jp)),
|
||||
});
|
||||
}
|
||||
|
||||
info!("session {} joined {channel_id}", &session_id[..8]);
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue