use opentalk_roomserver_signaling::breakout::BREAKOUT_MODULE_ID;
use opentalk_roomserver_types::breakout::command::BreakoutCommand;
use opentalk_roomserver_types_chat::{CHAT_MODULE_ID, command::ChatCommand};
use opentalk_roomserver_types_ping::{PING_MODULE_ID, command::PingCommand};
use opentalk_roomserver_types_polls::{POLLS_MODULE_ID, command::PollsCommand};
use opentalk_roomserver_types_timer::{TIMER_MODULE_ID, TimerCommand};
use opentalk_types_common::modules::ModuleId;
use serde::{Deserialize, Serialize};
pub use {
opentalk_roomserver_types_e2ee::{E2EE_MODULE_ID, E2eeCommand},
opentalk_roomserver_types_livekit::{
LIVEKIT_MODULE_ID, LiveKitCommand, MicrophoneRestrictionState,
},
};
#[derive(Debug, Serialize, Deserialize)]
pub struct SignalingCommand {
#[serde(skip_serializing_if = "Option::is_none")]
pub transaction_id: Option<u64>,
#[serde(flatten)]
pub content: SignalingModuleCommand,
}
impl SignalingCommand {
pub fn namespace(&self) -> ModuleId {
self.content.namespace()
}
}
impl From<SignalingModuleCommand> for SignalingCommand {
fn from(content: SignalingModuleCommand) -> Self {
Self {
transaction_id: None,
content,
}
}
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "namespace", content = "content", rename_all = "snake_case")]
pub enum SignalingModuleCommand {
Breakout(BreakoutCommand),
Ping(PingCommand),
Chat(ChatCommand),
#[serde(rename = "livekit")]
LiveKit(LiveKitCommand),
E2ee(E2eeCommand),
Timer(TimerCommand),
Polls(PollsCommand),
}
impl SignalingModuleCommand {
pub fn namespace(&self) -> ModuleId {
match self {
Self::Breakout(..) => BREAKOUT_MODULE_ID,
Self::Ping(..) => PING_MODULE_ID,
Self::Chat(..) => CHAT_MODULE_ID,
Self::LiveKit(..) => LIVEKIT_MODULE_ID,
Self::E2ee(..) => E2EE_MODULE_ID,
Self::Timer(..) => TIMER_MODULE_ID,
Self::Polls(..) => POLLS_MODULE_ID,
}
}
}
#[cfg(test)]
mod tests {
use insta::assert_snapshot;
use opentalk_roomserver_types::breakout::command::BreakoutCommand;
use opentalk_roomserver_types_chat::command::ChatCommand;
use opentalk_roomserver_types_livekit::LiveKitCommand;
use opentalk_roomserver_types_ping::command::PingCommand;
use opentalk_roomserver_types_polls::{
ChoiceId, PollId,
command::{Choices, PollsCommand, Vote},
};
use opentalk_roomserver_types_timer::{Start, TimerCommand, command::Kind};
use opentalk_types_common::modules::ModuleId;
use serde::Deserialize;
use super::SignalingModuleCommand;
use crate::api::command::SignalingCommand;
#[derive(Debug, Clone, Deserialize)]
pub struct NamespaceOnly {
pub namespace: ModuleId,
}
#[test]
fn serialize_command_breakout() {
let command = SignalingCommand {
transaction_id: None,
content: SignalingModuleCommand::Breakout(BreakoutCommand::Stop { delay: None }),
};
let raw = serde_json::to_string_pretty(&command).unwrap();
assert_snapshot!(raw, @r#"
{
"namespace": "breakout",
"content": {
"action": "stop"
}
}
"#);
let namespace_only: NamespaceOnly = serde_json::from_str(&raw).unwrap();
assert_eq!(namespace_only.namespace, command.namespace());
}
#[test]
fn serialize_command_chat() {
let command = SignalingCommand {
transaction_id: None,
content: SignalingModuleCommand::Chat(ChatCommand::DisableChat),
};
let raw = serde_json::to_string_pretty(&command).unwrap();
assert_snapshot!(raw, @r#"
{
"namespace": "chat",
"content": {
"action": "disable_chat"
}
}
"#);
let namespace_only: NamespaceOnly = serde_json::from_str(&raw).unwrap();
assert_eq!(namespace_only.namespace, command.namespace());
}
#[test]
fn serialize_command_ping() {
let command = SignalingCommand {
transaction_id: None,
content: SignalingModuleCommand::Ping(PingCommand::Ping),
};
let raw = serde_json::to_string_pretty(&command).unwrap();
assert_snapshot!(raw, @r#"
{
"namespace": "ping",
"content": {
"action": "ping"
}
}
"#);
let namespace_only: NamespaceOnly = serde_json::from_str(&raw).unwrap();
assert_eq!(namespace_only.namespace, command.namespace());
}
#[test]
fn serialize_command_livekit() {
let command = SignalingCommand {
transaction_id: None,
content: SignalingModuleCommand::LiveKit(LiveKitCommand::CreateNewAccessToken),
};
let raw = serde_json::to_string_pretty(&command).unwrap();
assert_snapshot!(raw, @r#"
{
"namespace": "livekit",
"content": {
"action": "create_new_access_token"
}
}
"#);
let namespace_only: NamespaceOnly = serde_json::from_str(&raw).unwrap();
assert_eq!(namespace_only.namespace, command.namespace());
}
#[test]
fn serialize_command_timer() {
let command = SignalingCommand {
transaction_id: None,
content: SignalingModuleCommand::Timer(TimerCommand::Start(Start {
kind: Kind::Stopwatch,
style: None,
title: None,
enable_ready_check: false,
})),
};
let raw = serde_json::to_string_pretty(&command).unwrap();
assert_snapshot!(raw, @r#"
{
"namespace": "timer",
"content": {
"action": "start",
"kind": "stopwatch",
"style": null,
"title": null,
"enable_ready_check": false
}
}
"#);
let namespace_only: NamespaceOnly = serde_json::from_str(&raw).unwrap();
assert_eq!(namespace_only.namespace, command.namespace());
}
#[test]
fn serialize_command_polls() {
let command = SignalingCommand {
transaction_id: None,
content: SignalingModuleCommand::Polls(PollsCommand::Vote(Vote {
poll_id: PollId::nil(),
choices: Choices::Single {
choice_id: ChoiceId::from_u32(0),
},
})),
};
let raw = serde_json::to_string_pretty(&command).unwrap();
assert_snapshot!(raw, @r#"
{
"namespace": "polls",
"content": {
"action": "vote",
"poll_id": "00000000-0000-0000-0000-000000000000",
"choice_id": 0
}
}
"#);
let namespace_only: NamespaceOnly = serde_json::from_str(&raw).unwrap();
assert_eq!(namespace_only.namespace, command.namespace());
}
}