Sign in

    moonbitstack/mooncat/config does not have a README file

    Config

    pub(all) struct Config {
    host : String
    port : Int
    backlog : Int
    dual_stack : Bool
    reuse_addr : Bool
    server_headers : Map[String, String]
    max_connections : Int?
    allow_failure : Bool
    graceful_timeout : Int?
    root_path : String
    logger : Logger
    timeout_keep_alive : Int
    limit_max_requests : Int?
    limit_concurrency : Int?
    max_head_size : Int
    date_header : Bool
    proxy_headers : Bool
    forwarded_allow_ips : Array[String]
    ws : WsConfig
    }

    Server configuration (← uvicorn Config): the bind address, the listen backlog, and the HTTP/1.1 transport knobs the moonbitlang/async server exposes. Constructed once and handed to serve_config.

    backlog mirrors uvicorn's listen(2) backlog. The current moonbitlang/async transport does not expose a backlog setter on its TCP listener — TcpServer calls listen() itself with a fixed depth and offers no way to re-listen — so the value is recorded on the config for parity and future use but is not applied to the socket. This is a transport-capability gap, not a behavioural choice, and it is the one field here that does nothing.

    The remaining fields map one-to-one onto knobs mooncat does honour: dual_stack / reuse_addr on the listening socket, server_headers stamped onto every response (uvicorn's Server: header lives here), max_connections for the parallel-client ceiling, and allow_failure for whether a handler error tears the whole server down.

    Config::bind

    fn Config::bind(self : Config) -> String

    The host:port string used to resolve the listen address.

    Config::new

    fn Config::new(host? : String, port? : Int, backlog? : Int, dual_stack? : Bool, reuse_addr? : Bool, server_headers? : Map[String, String], max_connections? : Int, allow_failure? : Bool, graceful_timeout? : Int, root_path? : String, logger? : Logger, timeout_keep_alive? : Int, limit_max_requests? : Int, limit_concurrency? : Int, max_head_size? : Int, date_header? : Bool, proxy_headers? : Bool, forwarded_allow_ips? : Array[String], ws? : WsConfig) -> Config

    Build a Config, defaulting to uvicorn's own defaults: host 127.0.0.1, port 12000, backlog 2048, a 5-second idle keep-alive timeout, a 16 KiB request-head cap, the Date header on, proxy headers trusted from 127.0.0.1, and no request-count or concurrency limit. Transport knobs default to the async server's own defaults: reuse_addr on (uvicorn sets SO_REUSEADDR), single-stack binding, no extra response headers, an unbounded connection ceiling, and allow_failure on so a single failing handler never crashes the listener.

    graceful_timeout bounds how long serve_graceful waits for in-flight requests to drain before it runs lifespan shutdown anyway (← uvicorn's timeout_graceful_shutdown); None waits until the last request finishes, as uvicorn does by default.

    Logger

    pub struct Logger {
    out :
    Logger

    access : Bool
    }

    How much the server says, and where it goes.

    Logger::access_line

    fn Logger::access_line(self : Logger, client : String, verb : String, target : String, http_version : String, status : Int) -> Unit

    Write the one-line-per-request access log (uvicorn's uvicorn.access), in the same shape: peer, request line, status.

    Logger::enabled

    fn Logger::enabled(self : Logger, level :
    Level
    ) -> Bool

    Whether a line at level would be written.

    Logger::log

    fn Logger::log(self : Logger, level :
    Level
    , message : String) -> Unit

    Write one server-lifecycle line (uvicorn's uvicorn.error logger, which carries ordinary startup messages as well as failures).

    Logger::new

    fn Logger::new(level? :
    Level
    , access? : Bool, write? : (String) -> Unit) -> Logger

    A logger printing to stdout at level, with the access log on — uvicorn's defaults. access off silences the per-request lines while keeping the server's own.

    Logger::silent

    fn Logger::silent() -> Logger

    A logger that says nothing, for an embedder that does its own reporting or a test that would rather not have output.

    WsConfig

    pub(all) struct WsConfig {
    max_size : Int
    }

    The WebSocket knobs uvicorn exposes on its own config (--ws-max-size).

    max_size is the ceiling on a received payload, in bytes: it bounds a single frame and, across continuation frames, a reassembled message, and a peer that announces more fails the connection with 1009. It is the knob with teeth on the receive side — an unbounded length is exactly what a hostile client sends.

    uvicorn's remaining WebSocket knobs are not here rather than here-and-ignored: --ws-ping-interval / --ws-ping-timeout need a heartbeat task alongside a reader that can be interrupted between messages and resumed, --ws-max-queue needs that same reader pumping a bounded queue, and neither is expressible while a native blocking read cannot be cancelled and resumed mid-stream; --ws-per-message-deflate needs a raw DEFLATE codec, which the async library's gzip package (gzip-framed streams only) does not provide. Accepting the extension without one would corrupt every frame.

    WsConfig::new

    fn WsConfig::new(max_size? : Int) -> WsConfig

    Build a WsConfig, defaulting max_size to uvicorn's own 16 MiB.

    http_date

    fn http_date(ms : Int64) -> String

    Format a Unix-epoch millisecond count as an HTTP-date in the IMF-fixdate form RFC 7231 §7.1.1.1 makes mandatory for a Date header: Sun, 06 Nov 1994 08:49:37 GMT, always GMT, always fixed-width.

    The calendar and the format are moondate's; what is here is the millisecond clock mooncat reads, brought down to the whole second the header is written to.

    http_date_now

    fn http_date_now() -> String

    The current instant as an HTTP-date, reformatted only when the epoch second has moved on.

    port

    let port : Int

    The default port for the TCP serving entry points.

    HTTP/1.1, including WebSocket upgrades, uses one listener. TLS and h2c are separate server modes with their own listeners, so they cannot all bind this port at once. quic_serve takes an explicit UDP address; it may use the same number because UDP and TCP have separate port spaces.

    reason

    fn reason(code : Int) -> String

    The reason phrase an access line pairs with a status. Lives here rather than beside the native server because the access line is written on every backend.