mooncat — a native ASGI 3.0 server for MoonBit (← uvicorn), built on moonbitlang/async and the moonasgi SEAM. HTTP/1.1, HTTP/2, WebSocket and HTTP/3; the protocols themselves are moonhttp, moontls and moonquic.
Dependencies
Moved on mooncakes from Lfan-ke/mooncat to moonbitstack/mooncat.
flowchart LR
net["moonbitlang/async<br/>(sockets · TLS · HTTP/1.1)"] --> cat["**mooncat**<br/>accept loop"]
cat -->|"Scope / Receive / Send"| asgi(["moonasgi SEAM"])
asgi --> app["your app<br/>(moonapi, …)"]// An ASGI app: respond 200 with a text body.
let app : @moonasgi.AsgiApp = (_scope, _receive, send) => {
send(@moonasgi.Event::HttpResponseStart(
status=200, headers=[("content-type", "text/plain")]))
send(@moonasgi.Event::HttpResponseBody(
body=b"Hello from mooncat!", more_body=false))
}
// Serve it (inside an async context / task group):
@mooncat.serve(app, host="127.0.0.1", port=12000)@mooncat.serve_tls(app,
certificate_file="certs/cert.pem", // PEM cert (OpenSSL platforms)
private_key_file="certs/key.pem", // PEM key (OpenSSL platforms)
pfx_file="certs/dev.pfx", // PKCS#12 (Windows / SChannel)
port=12000)let handle = @mooncat.ShutdownHandle::new()
g.spawn(() => @mooncat.serve_graceful(app, @mooncat.Config::new(port=12000), handle~))
// … later, from anywhere:
handle.shutdown() // stop accepting → drain in-flight → lifespan shutdown → close@mooncat.serve_h2c(app, host="127.0.0.1", port=12000)pub suberror LifespanError {
LifespanError(String)
}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
}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) -> Configpub(all) struct TlsCert {
certificate_file : String
private_key_file : String
pfx_file : String
}pub(all) struct WsConfig {
max_size : Int
}fn http_date(ms : Int64) -> Stringfn http_date_now() -> Stringlet port : Intfn quic_now() -> Int64async fn reload_watch(path : String, on_reload : async () -> Unit) -> Unitasync fn serve_graceful(app : async (Scope, async () -> Event, async (Event) -> Unit) -> Unit, config : Config, handle? : ShutdownHandle) -> Unitfn tls13_certificate_verify_check(key : PublicKey, context : String, transcript_hash : Bytes, body : Bytes) -> Boolfn tls13_certificate_verify_sign(key : PrivateKey, context : String, transcript_hash : Bytes) -> Bytesfn tls13_client_hello_x25519(client_hello : Bytes) -> Bytes?fn tls13_ecdhe_handshake_traffic_secret(private_key : Bytes, peer_public : Bytes, transcript_hash : Bytes, is_client : Bool) -> Bytesfn tls13_ecdhe_secrets_from_client_hello(client_hello : Bytes, server_private : Bytes, transcript_hash : Bytes) -> (Bytes, Bytes)?fn tls13_ecdhe_shared(private_key : Bytes, peer_public : Bytes) -> Bytesfn tls13_handshake_secret_from_ecdhe(private_key : Bytes, peer_public : Bytes) -> Bytesfn tls13_server_hs_secret_from_client_hello(client_hello : Bytes, server_private : Bytes, transcript_hash : Bytes) -> Bytes?fn tls13_x25519_public(private_key : Bytes) -> BytesInstall
Download zipmooncat — a native ASGI 3.0 server for MoonBit (← uvicorn), built on moonbitlang/async and the moonasgi SEAM. HTTP/1.1, HTTP/2, WebSocket and HTTP/3; the protocols themselves are moonhttp, moontls and moonquic.
Dependencies