use crate::room::participant::ParticipantIdentity;
use livekit_protocol::RpcError as RpcError_Proto;
use std::{error::Error, fmt::Display, time::Duration};
#[derive(Debug, Clone)]
pub struct PerformRpcData {
pub destination_identity: String,
pub method: String,
pub payload: String,
pub response_timeout: Duration,
}
impl Default for PerformRpcData {
fn default() -> Self {
Self {
destination_identity: Default::default(),
method: Default::default(),
payload: Default::default(),
response_timeout: Duration::from_secs(15),
}
}
}
#[derive(Debug, Clone)]
pub struct RpcInvocationData {
pub request_id: String,
pub caller_identity: ParticipantIdentity,
pub payload: String,
pub response_timeout: Duration,
}
#[derive(Debug, Clone)]
pub struct RpcError {
pub code: u32,
pub message: String,
pub data: Option<String>,
}
impl RpcError {
pub const MAX_MESSAGE_BYTES: usize = 256;
pub const MAX_DATA_BYTES: usize = 15360;
pub fn new(code: u32, message: String, data: Option<String>) -> Self {
Self {
code,
message: truncate_bytes(&message, Self::MAX_MESSAGE_BYTES),
data: data.map(|d| truncate_bytes(&d, Self::MAX_DATA_BYTES)),
}
}
pub fn from_proto(proto: RpcError_Proto) -> Self {
Self::new(proto.code, proto.message, Some(proto.data))
}
pub fn to_proto(&self) -> RpcError_Proto {
RpcError_Proto {
code: self.code,
message: self.message.clone(),
data: self.data.clone().unwrap_or_default(),
}
}
}
impl Display for RpcError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "RPC Error: {} ({})", self.message, self.code)
}
}
impl Error for RpcError {}
#[derive(Debug, Clone, Copy)]
pub enum RpcErrorCode {
ApplicationError = 1500,
ConnectionTimeout = 1501,
ResponseTimeout = 1502,
RecipientDisconnected = 1503,
ResponsePayloadTooLarge = 1504,
SendFailed = 1505,
UnsupportedMethod = 1400,
RecipientNotFound = 1401,
RequestPayloadTooLarge = 1402,
UnsupportedServer = 1403,
UnsupportedVersion = 1404,
}
impl RpcErrorCode {
pub(crate) fn message(&self) -> &'static str {
match self {
Self::ApplicationError => "Application error in method handler",
Self::ConnectionTimeout => "Connection timeout",
Self::ResponseTimeout => "Response timeout",
Self::RecipientDisconnected => "Recipient disconnected",
Self::ResponsePayloadTooLarge => "Response payload too large",
Self::SendFailed => "Failed to send",
Self::UnsupportedMethod => "Method not supported at destination",
Self::RecipientNotFound => "Recipient not found",
Self::RequestPayloadTooLarge => "Request payload too large",
Self::UnsupportedServer => "RPC not supported by server",
Self::UnsupportedVersion => "Unsupported RPC version",
}
}
}
impl RpcError {
pub(crate) fn built_in(code: RpcErrorCode, data: Option<String>) -> Self {
Self::new(code as u32, code.message().to_string(), data)
}
}
pub const MAX_PAYLOAD_BYTES: usize = 15360;
pub(crate) fn byte_length(s: &str) -> usize {
s.as_bytes().len()
}
pub(crate) fn truncate_bytes(s: &str, max_bytes: usize) -> String {
if byte_length(s) <= max_bytes {
return s.to_string();
}
let mut result = String::new();
for c in s.chars() {
if byte_length(&(result.clone() + &c.to_string())) > max_bytes {
break;
}
result.push(c);
}
result
}