Files
alknet/crates/alknet-core/src/testutil.rs
glm-5.1 ee1b3f3819 feat(core): implement StaticConfig/DynamicConfig split with ArcSwap hot-reload
Split alknet-core configuration into StaticConfig (immutable after startup)
and DynamicConfig (hot-reloadable at runtime via ArcSwap).

- Add StaticConfig struct in config/static_config.rs with all fields per ADR-030
- Add DynamicConfig struct with AuthPolicy, ForwardingPolicy, RateLimitConfig
- Add ForwardingPolicy with allow_all()/deny_all() defaults (ADR-031)
- Add ConfigReloadHandle with reload() method for runtime config updates
- Replace Arc<ServerAuthConfig> with Arc<ArcSwap<DynamicConfig>> in ServerHandler
- Add config_reload_handle() to Server for obtaining reload handles
- Add AuthPolicy with authenticate_publickey/authenticate_certificate methods
- All existing tests pass with the new config structure
- Default DynamicConfig produces identical behavior to current code
2026-06-07 14:03:46 +00:00

142 lines
3.7 KiB
Rust

use anyhow::Result;
use tokio::io::{AsyncRead, AsyncWrite, DuplexStream};
#[cfg(feature = "transport-traits")]
pub use crate::transport::{Transport, TransportAcceptor, TransportInfo, TransportKind};
#[cfg(not(feature = "transport-traits"))]
pub use local_traits::{Transport, TransportAcceptor, TransportInfo, TransportKind};
#[cfg(not(feature = "transport-traits"))]
mod local_traits {
use anyhow::Result;
use async_trait::async_trait;
use std::net::SocketAddr;
use tokio::io::{AsyncRead, AsyncWrite};
#[async_trait]
pub trait Transport: Send + Sync + 'static {
type Stream: AsyncRead + AsyncWrite + Unpin + Send + 'static;
async fn connect(&self) -> Result<Self::Stream>;
fn describe(&self) -> String;
}
#[async_trait]
pub trait TransportAcceptor: Send + Sync + 'static {
type Stream: AsyncRead + AsyncWrite + Unpin + Send + 'static;
async fn accept(&self) -> Result<(Self::Stream, TransportInfo)>;
}
#[derive(Debug, Clone)]
pub struct TransportInfo {
pub remote_addr: Option<SocketAddr>,
pub transport_kind: TransportKind,
}
#[derive(Debug, Clone)]
pub enum TransportKind {
Tcp,
Tls { server_name: Option<String> },
Iroh { endpoint_id: String },
}
}
pub struct MockStream {
inner: DuplexStream,
}
impl MockStream {
pub fn new(inner: DuplexStream) -> Self {
Self { inner }
}
}
impl AsyncRead for MockStream {
fn poll_read(
self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
buf: &mut tokio::io::ReadBuf<'_>,
) -> std::task::Poll<std::io::Result<()>> {
std::pin::Pin::new(&mut self.get_mut().inner).poll_read(cx, buf)
}
}
impl AsyncWrite for MockStream {
fn poll_write(
self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
buf: &[u8],
) -> std::task::Poll<std::io::Result<usize>> {
std::pin::Pin::new(&mut self.get_mut().inner).poll_write(cx, buf)
}
fn poll_flush(
self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<std::io::Result<()>> {
std::pin::Pin::new(&mut self.get_mut().inner).poll_flush(cx)
}
fn poll_shutdown(
self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<std::io::Result<()>> {
std::pin::Pin::new(&mut self.get_mut().inner).poll_shutdown(cx)
}
}
impl Unpin for MockStream {}
pub struct MockTransport {
buf_size: usize,
}
impl MockTransport {
pub fn new(buf_size: usize) -> Self {
Self { buf_size }
}
}
#[async_trait::async_trait]
impl Transport for MockTransport {
type Stream = MockStream;
async fn connect(&self) -> Result<Self::Stream> {
let (client, _) = tokio::io::duplex(self.buf_size);
Ok(MockStream::new(client))
}
fn describe(&self) -> String {
"mock".to_string()
}
}
pub struct MockTransportAcceptor {
buf_size: usize,
}
impl MockTransportAcceptor {
pub fn new(buf_size: usize) -> Self {
Self { buf_size }
}
}
#[async_trait::async_trait]
impl TransportAcceptor for MockTransportAcceptor {
type Stream = MockStream;
async fn accept(&self) -> Result<(Self::Stream, TransportInfo)> {
let (_, server) = tokio::io::duplex(self.buf_size);
let info = TransportInfo {
remote_addr: None,
transport_kind: TransportKind::Tcp,
};
Ok((MockStream::new(server), info))
}
}
pub fn mock_pair(buf_size: usize) -> (MockStream, MockStream) {
let (client, server) = tokio::io::duplex(buf_size);
(MockStream::new(client), MockStream::new(server))
}