blackbull.server¶
blackbull.server
¶
Server
¶
An asyncio socket server that dispatches each connection through the
app's :class:~blackbull.server.protocol_registry.ProtocolRegistry.
The shared HTTP listener detects HTTP/1.1 vs HTTP/2 (and upgrades to
WebSocket); port-bound non-ASGI protocols registered via
:meth:BlackBull.raw_handler get their own listening socket.
When ssl_context or certfile is set, the HTTP listener runs as HTTPS.
Formerly ASGIServer — that name remains as a backward-compat alias.
ssl_context
property
writable
¶
The context a listener built from certfile/keyfile uses.
Assigning it re-points every bound listener that was carrying the
previous one — which is what makes configuring mTLS after
open_socket() work, and what keeps bound_listeners honest about
what is actually being served. A listener the caller stated carries
its own context and is left alone, because identity is the difference
between "the server's" and "its own".
client_connected_cb(reader, writer)
async
¶
Accept callback for the shared HTTP listener.
connection_protocol_factory(bound_binding=None)
¶
Factory for loop.create_server — one buffered protocol per accept.
Replaces the start_server callback pair: instead of a StreamReader
and StreamWriter over asyncio's own buffering, the connection owns a
single buffer the kernel writes into, and the actor reads by cursor.
The protocol spawns the serving task itself because a protocol factory
is synchronous. connection_made fires after the TLS handshake on
an SSL transport, so ALPN is already decided by the time the task runs
— same ordering the callback form relied on.
open_socket(port=0, unix_path=None, inherited_fd=None)
¶
Bind every listener this server was asked for.
A caller that named listeners= gets those. A caller that said it
the old way — a port, a Unix path, or an inherited fd — gets one
listener built from those arguments, so there is one binding path and
not two.
run(port=80)
async
¶
Run an asyncio socket server with the setting in this object.
shutdown()
async
¶
Drive the ASGI lifespan shutdown handshake.
startup()
async
¶
Drive the ASGI lifespan startup handshake.
Launches the app's lifespan task, delivers 'lifespan.startup', and waits for 'lifespan.startup.complete'. Raises RuntimeError on 'lifespan.startup.failed'. Stores the context manager so that shutdown() can deliver 'lifespan.shutdown' to the same task.
stop(drain_timeout=8.0)
async
¶
Stop accepting, then let the connections already being served finish.
Nothing in flight is cancelled while drain_timeout lasts: a cancelled
handler leaves a client holding a half-written response. Whatever is
left at the deadline is cancelled — a shutdown that must complete still
completes. Keep the budget inside
MultiWorkerServer.shutdown_timeout so the drain ends here and not
in a SIGKILL.