TcpServerA minimal concurrent TCP server. start: accepts connections in the background, handling each in its own Task so they overlap; the *caller* decides when to stop accepting (stop) and then drains the in-flight handlers (join). Termination is deliberately external — a server doesn't know on its own when it should quit, so that policy lives with the caller.
A handler communicates through its own socket (or a caller-supplied channel); join is a drain *barrier*, not a result collector. Finished handlers are swept on each accept, so the task registry stays bounded by live concurrency rather than growing one entry per connection ever served — the tradeoff is that join does not return per-connection results.
Release the listening socket / bound port.
Connection-handler tasks currently tracked. Finished handlers are swept on each accept, so this reflects live concurrency, not the total number of connections served.
Bind and listen on address immediately (a ':0' port picks an ephemeral one — read it back with port); connections are not accepted until start:.
var server = TcpServer.new:{ var address = '127.0.0.1:0' }
Drain: wait for the accept loop to end and the in-flight handlers to finish. Returns self — handler results are not collected here (a handler writes to its socket or a caller-supplied channel); the registry is swept, so this drains only live handlers.
The bound local port (e.g. after an ephemeral ':0' bind).
Begin accepting in the background and return immediately. Each accepted connection is handled in its own Task, which owns the socket and closes it when the handler returns. The accept loop runs as its own Task so stop can cancel it — including a parked accept.
Stop accepting: cancel the accept loop, which aborts its parked accept. In-flight handler tasks keep running — drain them with join. A no-op before start:.