#![doc = include_str!("../README.md")]
#![forbid(unsafe_code)]
pub mod upgrade;
pub mod websocket;
use std::fmt::Display;
use axum_core::body::Body;
use axum_core::response::IntoResponse;
use axum_core::response::Response;
use http::StatusCode;
pub use tokio_websockets::*;
pub use crate::{upgrade::WebSocketUpgrade, websocket::WebSocket};
#[derive(Debug)]
pub enum WebSocketError {
ConnectionNotUpgradeable,
Internal(tokio_websockets::Error),
InvalidConnectionHeader,
InvalidUpgradeHeader,
InvalidWebSocketVersionHeader,
MethodNotGet,
UpgradeFailed(hyper::Error),
}
impl Display for WebSocketError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
WebSocketError::ConnectionNotUpgradeable => {
write!(f, "connection is not upgradeable")
}
WebSocketError::Internal(e) => {
write!(f, "internal server error: {}", e)
}
WebSocketError::InvalidConnectionHeader => {
write!(f, "invalid `Connection` header")
}
WebSocketError::InvalidUpgradeHeader => {
write!(f, "invalid `Upgrade` header")
}
WebSocketError::InvalidWebSocketVersionHeader => {
write!(f, "invalid `Sec-WebSocket-Version` header")
}
WebSocketError::MethodNotGet => {
write!(f, "http request method must be `GET`")
}
WebSocketError::UpgradeFailed(e) => {
write!(f, "upgrade failed: {}", e)
}
}
}
}
impl std::error::Error for WebSocketError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
WebSocketError::Internal(e) => Some(e),
WebSocketError::UpgradeFailed(e) => Some(e),
_ => None,
}
}
}
impl IntoResponse for WebSocketError {
fn into_response(self) -> Response<Body> {
let status = match self {
WebSocketError::ConnectionNotUpgradeable => StatusCode::UPGRADE_REQUIRED,
WebSocketError::InvalidConnectionHeader
| WebSocketError::InvalidUpgradeHeader
| WebSocketError::InvalidWebSocketVersionHeader => StatusCode::BAD_REQUEST,
WebSocketError::MethodNotGet => StatusCode::METHOD_NOT_ALLOWED,
_ => StatusCode::INTERNAL_SERVER_ERROR,
};
Response::builder()
.status(status)
.body(Body::empty())
.unwrap()
}
}
impl From<tokio_websockets::Error> for WebSocketError {
fn from(e: tokio_websockets::Error) -> Self {
WebSocketError::Internal(e)
}
}
impl From<hyper::Error> for WebSocketError {
fn from(e: hyper::Error) -> Self {
WebSocketError::UpgradeFailed(e)
}
}