naia-server 0.25.0

A server that uses either UDP or WebRTC communication to send/receive messages to/from connected clients, and syncs registered Entities/Components to clients to whom they are in-scope.
use parking_lot::Mutex;
use std::{
    net::SocketAddr,
    sync::Arc,
};

use naia_shared::IdentityToken;

use naia_shared::transport::local::{LocalTransportHub, ServerRecvError, ServerSendError};

// ServerAuthIo - encapsulates all server auth logic (always uses hub-based multiplexing)
#[doc(hidden)]
pub struct ServerAuthIo {
    hub: LocalTransportHub,
    buffer: [u8; 1472],
}

impl ServerAuthIo {
    #[doc(hidden)]
    pub fn new(hub: LocalTransportHub) -> Self {
        Self {
            hub,
            buffer: [0; 1472],
        }
    }

    fn receive(&mut self) -> Result<Option<(SocketAddr, &[u8])>, ServerRecvError> {
        if let Some((client_addr, request_bytes)) = self.hub.try_recv_auth_request() {
            // Parse HTTP request
            let request = naia_shared::transport::bytes_to_request(&request_bytes);

            // Extract Authorization header if present
            if let Some(auth_header) = request.headers().get("Authorization") {
                let auth_str = auth_header.to_str().unwrap();
                let auth_bytes = base64::decode(auth_str).unwrap();
                let len = auth_bytes.len();
                self.buffer[0..len].copy_from_slice(&auth_bytes);
                Ok(Some((client_addr, &self.buffer[..len])))
            } else {
                // No auth header present
                Ok(None)
            }
        } else {
            Ok(None)
        }
    }

    fn accept(
        &mut self,
        address: &SocketAddr,
        identity_token: &IdentityToken,
    ) -> Result<(), ServerSendError> {
        // Build HTTP 200 response with identity token and server address in body
        let response_body = format!("{}\r\n{}", identity_token, self.hub.server_addr());
        let response = http::Response::builder()
            .status(200)
            .body(response_body.into_bytes())
            .unwrap();

        let response_bytes = naia_shared::transport::response_to_bytes(response);

        // Send to the specific client via hub
        self.hub
            .send_auth_response(address, response_bytes)
            .map_err(|_| ServerSendError)?;

        Ok(())
    }

    fn reject(&mut self, address: &SocketAddr) -> Result<(), ServerSendError> {
        // Build HTTP 401 response
        let response = http::Response::builder()
            .status(401)
            .body(Vec::new())
            .unwrap();

        let response_bytes = naia_shared::transport::response_to_bytes(response);

        // Send to the specific client via hub
        self.hub
            .send_auth_response(address, response_bytes)
            .map_err(|_| ServerSendError)?;

        Ok(())
    }
}

// LocalServerAuthSender wraps Arc<Mutex<ServerAuthIo>>
#[doc(hidden)]
#[derive(Clone)]
pub struct LocalServerAuthSender {
    auth_io: Arc<Mutex<ServerAuthIo>>,
}

impl LocalServerAuthSender {
    #[doc(hidden)]
    pub fn new(auth_io: Arc<Mutex<ServerAuthIo>>) -> Self {
        Self { auth_io }
    }

    #[doc(hidden)]
    pub fn accept(
        &self,
        address: &SocketAddr,
        identity_token: &IdentityToken,
    ) -> Result<(), ServerSendError> {
        self.auth_io.lock().accept(address, identity_token)
    }

    #[doc(hidden)]
    pub fn reject(&self, address: &SocketAddr) -> Result<(), ServerSendError> {
        self.auth_io.lock().reject(address)
    }
}

// LocalServerAuthReceiver wraps Arc<Mutex<ServerAuthIo>> with its own buffer
#[doc(hidden)]
#[derive(Clone)]
pub struct LocalServerAuthReceiver {
    auth_io: Arc<Mutex<ServerAuthIo>>,
    buffer: Box<[u8]>,
}

impl LocalServerAuthReceiver {
    #[doc(hidden)]
    pub fn new(auth_io: Arc<Mutex<ServerAuthIo>>) -> Self {
        Self {
            auth_io,
            buffer: Box::new([0; 1472]),
        }
    }

    #[doc(hidden)]
    pub fn receive(&mut self) -> Result<Option<(SocketAddr, &[u8])>, ServerRecvError> {
        let mut guard = self.auth_io.lock();
        match guard.receive() {
            Ok(option) => match option {
                Some((addr, buffer)) => {
                    self.buffer = buffer.into();
                    Ok(Some((addr, &self.buffer)))
                }
                None => Ok(None),
            },
            Err(err) => Err(err),
        }
    }
}