use stun_codec::convert::TryAsRef;
use stun_codec::rfc5389::attributes::ErrorCode;
use stun_codec::{Attribute, Message, MessageClass, Method, TransactionId};
pub use crate::error::{MessageError, MessageErrorKind};
pub type MessageResult<T> = Result<T, MessageError>;
#[derive(Debug, Clone)]
pub struct InvalidMessage {
method: Method,
class: MessageClass,
transaction_id: TransactionId,
error: MessageError,
}
impl InvalidMessage {
pub fn method(&self) -> Method {
self.method
}
pub fn class(&self) -> MessageClass {
self.class
}
pub fn transaction_id(&self) -> TransactionId {
self.transaction_id
}
pub fn error(&self) -> &MessageError {
&self.error
}
pub(crate) fn new(
method: Method,
class: MessageClass,
transaction_id: TransactionId,
error: MessageError,
) -> Self {
InvalidMessage {
method,
class,
transaction_id,
error,
}
}
}
pub type Response<A> = std::result::Result<SuccessResponse<A>, ErrorResponse<A>>;
#[derive(Debug, Clone)]
pub struct Request<A>(Message<A>);
impl<A: Attribute> Request<A> {
pub fn new(method: Method) -> Self {
Request(Message::new(
MessageClass::Request,
method,
TransactionId::new(rand::random()),
))
}
pub fn from_message(message: Message<A>) -> MessageResult<Self> {
track_assert_eq!(
message.class(),
MessageClass::Request,
MessageErrorKind::InvalidInput
);
track!(check_unknown_attributes(&message))?;
Ok(Request(message))
}
pub fn method(&self) -> Method {
self.0.method()
}
pub fn transaction_id(&self) -> TransactionId {
self.0.transaction_id()
}
pub fn get_attribute<T>(&self) -> Option<&T>
where
T: Attribute,
A: TryAsRef<T>,
{
self.0.get_attribute()
}
pub fn attributes(&self) -> impl Iterator<Item = &A> {
self.0.attributes()
}
pub fn add_attribute(&mut self, attribute: A) {
self.0.add_attribute(attribute);
}
pub fn into_message(self) -> Message<A> {
self.0
}
}
impl<A: Attribute> AsRef<Message<A>> for Request<A> {
fn as_ref(&self) -> &Message<A> {
&self.0
}
}
impl<A: Attribute> AsMut<Message<A>> for Request<A> {
fn as_mut(&mut self) -> &mut Message<A> {
&mut self.0
}
}
#[derive(Debug, Clone)]
pub struct Indication<A>(Message<A>);
impl<A: Attribute> Indication<A> {
pub fn new(method: Method) -> Self {
Indication(Message::new(
MessageClass::Indication,
method,
TransactionId::new(rand::random()),
))
}
pub fn from_message(message: Message<A>) -> MessageResult<Self> {
track_assert_eq!(
message.class(),
MessageClass::Indication,
MessageErrorKind::InvalidInput
);
track!(check_unknown_attributes(&message))?;
Ok(Indication(message))
}
pub fn method(&self) -> Method {
self.0.method()
}
pub fn transaction_id(&self) -> TransactionId {
self.0.transaction_id()
}
pub fn get_attribute<T>(&self) -> Option<&T>
where
T: Attribute,
A: TryAsRef<T>,
{
self.0.get_attribute()
}
pub fn attributes(&self) -> impl Iterator<Item = &A> {
self.0.attributes()
}
pub fn add_attribute(&mut self, attribute: A) {
self.0.add_attribute(attribute);
}
pub fn into_message(self) -> Message<A> {
self.0
}
}
impl<A: Attribute> AsRef<Message<A>> for Indication<A> {
fn as_ref(&self) -> &Message<A> {
&self.0
}
}
impl<A: Attribute> AsMut<Message<A>> for Indication<A> {
fn as_mut(&mut self) -> &mut Message<A> {
&mut self.0
}
}
#[derive(Debug, Clone)]
pub struct SuccessResponse<A>(Message<A>);
impl<A: Attribute> SuccessResponse<A> {
pub fn new(request: &Request<A>) -> Self {
SuccessResponse(Message::new(
MessageClass::SuccessResponse,
request.method(),
request.transaction_id(),
))
}
pub fn from_message(message: Message<A>) -> MessageResult<Self> {
track_assert_eq!(
message.class(),
MessageClass::SuccessResponse,
MessageErrorKind::InvalidInput
);
track!(check_unknown_attributes(&message))?;
Ok(SuccessResponse(message))
}
pub fn method(&self) -> Method {
self.0.method()
}
pub fn transaction_id(&self) -> TransactionId {
self.0.transaction_id()
}
pub fn get_attribute<T>(&self) -> Option<&T>
where
T: Attribute,
A: TryAsRef<T>,
{
self.0.get_attribute()
}
pub fn attributes(&self) -> impl Iterator<Item = &A> {
self.0.attributes()
}
pub fn add_attribute(&mut self, attribute: A) {
self.0.add_attribute(attribute);
}
pub fn into_message(self) -> Message<A> {
self.0
}
}
impl<A: Attribute> AsRef<Message<A>> for SuccessResponse<A> {
fn as_ref(&self) -> &Message<A> {
&self.0
}
}
impl<A: Attribute> AsMut<Message<A>> for SuccessResponse<A> {
fn as_mut(&mut self) -> &mut Message<A> {
&mut self.0
}
}
#[derive(Debug, Clone)]
pub struct ErrorResponse<A>(Message<A>);
impl<A: Attribute> ErrorResponse<A> {
pub fn new(request: &Request<A>, error: ErrorCode) -> Self
where
A: From<ErrorCode>,
{
let mut message = Message::new(
MessageClass::ErrorResponse,
request.method(),
request.transaction_id(),
);
message.add_attribute(error);
ErrorResponse(message)
}
pub fn from_message(message: Message<A>) -> MessageResult<Self> {
track_assert_eq!(
message.class(),
MessageClass::ErrorResponse,
MessageErrorKind::InvalidInput
);
track!(check_unknown_attributes(&message))?;
let contains_error_code = message
.attributes()
.map(|a| a.get_type())
.chain(message.unknown_attributes().map(|a| a.get_type()))
.any(|t| t.as_u16() == ErrorCode::CODEPOINT);
track_assert!(contains_error_code, MessageErrorKind::InvalidInput);
Ok(ErrorResponse(message))
}
pub fn method(&self) -> Method {
self.0.method()
}
pub fn transaction_id(&self) -> TransactionId {
self.0.transaction_id()
}
pub fn get_attribute<T>(&self) -> Option<&T>
where
T: Attribute,
A: TryAsRef<T>,
{
self.0.get_attribute()
}
pub fn attributes(&self) -> impl Iterator<Item = &A> {
self.0.attributes()
}
pub fn add_attribute(&mut self, attribute: A) {
self.0.add_attribute(attribute);
}
pub fn into_message(self) -> Message<A> {
self.0
}
}
impl<A: Attribute> AsRef<Message<A>> for ErrorResponse<A> {
fn as_ref(&self) -> &Message<A> {
&self.0
}
}
impl<A: Attribute> AsMut<Message<A>> for ErrorResponse<A> {
fn as_mut(&mut self) -> &mut Message<A> {
&mut self.0
}
}
fn check_unknown_attributes<A: Attribute>(message: &Message<A>) -> MessageResult<()> {
let required_unknowns = message
.unknown_attributes()
.filter_map(|a| {
if a.get_type().is_comprehension_required() {
Some(a.get_type())
} else {
None
}
})
.collect::<Vec<_>>();
track_assert!(
required_unknowns.is_empty(),
MessageErrorKind::UnknownAttributes(required_unknowns)
);
Ok(())
}