mayuri 0.2.0

An Asynchronous WebSocket Client Library.
Documentation
use std::sync::{
    Arc,
    atomic::{AtomicU8, Ordering},
};

use super::enums::State;
use super::errors::URIError;
use fluent_uri::{Uri, component::Authority, encoding::EStr};
pub const CRLF: &str = "\r\n";
pub const DEFAULT_PORT_SECURE: u16 = 443;
pub const DEFAULT_PORT_INSECURE: u16 = 80;

pub const ACCEPT_KEY_NAME: &str = "sec-websocket-accept";

pub fn get_uri(uri_string: String) -> Result<Uri<String>, URIError> {
    Uri::parse(uri_string).map_err(|e| URIError::MalformedURIError(e.to_string()))
}

#[must_use]
pub fn get_host(auth: &Authority<'_>) -> String {
    auth.host().to_owned()
}

#[must_use]
pub fn is_secured(uri: &Uri<String>) -> bool {
    let scheme = uri.scheme().to_string();
    scheme == "wss"
}

pub fn get_port(uri: &Uri<String>) -> Result<u16, URIError> {
    let auth = uri.authority();
    match auth {
        Some(a) => a.port_to_u16()?.map_or_else(
            || {
                if is_secured(uri) {
                    Ok(DEFAULT_PORT_SECURE)
                } else {
                    Ok(DEFAULT_PORT_INSECURE)
                }
            },
            Ok,
        ),
        None => Err(URIError::IncompleteURIError(
            "Authority for the URI is not found".into(),
        )),
    }
}

pub fn get_socket_address(uri: &Uri<String>) -> Result<String, URIError> {
    let host = uri.authority().map_or_else(
        || {
            Err(URIError::IncompleteURIError(
                "Authority for the URI is not found".into(),
            ))
        },
        |auth| Ok(get_host(&auth)),
    )?;
    let port = get_port(uri)?;

    Ok(format!("{host}:{port}"))
}

pub fn get_resource_target(uri: &Uri<String>) -> Result<String, URIError> {
    let mut path = uri.path().to_string();
    if path.is_empty() {
        path = String::from("/");
    }

    let query = uri.query().unwrap_or(EStr::EMPTY).to_string();

    Ok(path + &query)
}

#[macro_export]
macro_rules! safe_get_handshake_item {
    ($v:expr, $i:expr, $t:expr) => {
        $v.get($i).map_or_else(
            || {
                Err(WebSocketError::Handshake(
                    HandshakeFailureError::HeaderError(
                        "`$t` header not found in handshake response".into(),
                    ),
                ))
            },
            Ok,
        )
    };
}

pub fn get_connection_state(store: &Arc<AtomicU8>) -> State {
    State::from_repr(store.load(Ordering::Relaxed).into()).unwrap_or(State::ERROR)
}
pub fn set_connection_state(state: State, store: &Arc<AtomicU8>) {
    store.store(state.as_u8(), Ordering::Relaxed);
}