Last updated

πŸ”—Overview

powpow is a high-performance, event notification library for Nim. It provides a low-level event loop and timer wheel, as well as higher-level abstractions for building TCP, UDP, HTTP/1.1 and WebSocket servers. It is designed to be minimal and efficient, with a focus on low-latency event handling and minimal overhead, providing a solid foundation for high-performance networked applications in Nim.

It is also used as a networking backend by Supranim β€” switch on --features:powpowwhen compiling a Supranim app.

πŸ”—Design philosophy

  • Low-level, minimal, high-performance. powpow does not ship a router, template engine or ORM. It gives you an event loop, sockets and protocol parsers, and lets you (or a framework) build the rest on top.
  • Bring-your-own-router. The HTTP server exposes an OnRequestCallback and leaves routing entirely to the caller (see HTTP server).
  • Zero-copy where it counts. Request fields are materialized lazily from byte offsets; files are sent with sendfile; responses can be streamed.
  • Platform-native event notification. Built on top of epoll (Linux), kqueue (BSD, macOS) and IOCP (Windows), with a poll fallback β€” plus an opt-in Linux io_uring backend (guide) that drives everything through submission/completion ops instead of readiness events.

πŸ”—Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                     β”‚         powpow.nim           β”‚  (aggregate entry, re-exports)
                     β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”   β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                β”‚     loop     β”‚   β”‚     platform     β”‚
                β”‚  timer wheel β”‚   β”‚ epoll|kqueue|    β”‚
                β”‚  defer/idle  β”‚   β”‚ poll|iocp        β”‚
                β””β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚           β”‚              β”‚
   β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”΄β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”
   β”‚ signal  β”‚  β”‚  net   β”‚   β”‚  proto    β”‚
   β”‚relay+OS β”‚  β”‚tcp udp β”‚   β”‚http ws    β”‚
   β”‚ signals β”‚  β”‚dns tls β”‚   β”‚httpserver β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚multithreadβ”‚
                             β”‚ratelimit  β”‚
                             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The aggregate module src/powpow.nim re-exports:

  • types β€” core shared types
  • platform β€” the active I/O backend (except close, which lives on Loop)
  • loop β€” the event loop
  • net β€” TCP, UDP, DNS, TLS, socket helpers, raw-fd streams
  • proto β€” HTTP, WebSocket, multi-threaded server, rate limiter
  • signal β€” the signal relay and OS signal handling
  • fswatch β€” file system monitoring
  • stream β€” raw-fd streaming (IoStream, re-exported via net)

πŸ”—Feature matrix

AreaStatus
Core event loop ( loop.nim)Done β€” single-threaded reactor, 4-level timer wheel, deferred/idle/observer hooks, thread-safe postToLoop/ stop
TCP networking ( net/tcp.nim)Done β€” non-blocking server/client, connection pooling, corking, sendv, zero-copy file send, UDS, closeAfterDrain
UDP networking ( net/udp.nim)Done β€” bound and connected sockets
Async DNS ( net/dns.nim)Done β€” in-loop resolver, /etc/hosts + resolv.conf, A/AAAA, TTL cache
OS signals ( signal.nim)Done β€” signalfd (Linux), self-pipe (macOS/BSD/POSIX), Ctrl+C (Windows)
File system watching ( fswatch.nim)Done β€” kqueue (macOS/BSD), inotify (Linux); Windows not yet implemented
Raw-fd streaming ( stream.nim)Done β€” IoStream for pipes/socketpair/UDS/IPC; edge-triggered drain, write buffering, read backpressure; Windows not yet implemented
HTTP/1.1 parser ( proto/http.nim)Done β€” incremental zero-copy, chunked, streaming, multipart
HTTP server ( proto/httpserver.nim)Done β€” own-router design, static files, Range/conditional requests, pipelining
WebSocket ( proto/ws.nim)Done: RFC 6455 with standalone and HTTP-upgrade servers, wss:// on both ends, subprotocols, custom headers, keepalive timers, a self-managed client ( newWsClient) with auto-reconnect, and deflate
Multi-threaded HTTP server ( proto/multithread.nim)Done β€” SO_REUSEPORT, one loop per worker
Thread pool ( threadpool.nim)Done β€” N workers + dispatch thread owning a private loop; generic submitWork[T] results delivered as serialized callbacks; graceful drain close + discard shutdown
TLS ( net/tls.nim)Done β€” OpenSSL, implicit + upgrade (not on Windows)
DTLS ( net/dtls.nim)Done β€” DTLS 1.2 (RFC 6347) over the UDP backend: one socket, per-peer sessions, stateless HMAC cookie exchange, retransmission timers, idle/handshake sweepers (not on Windows)
SIMD scanning ( proto/simdscan.nim)Done β€” SSE2 CRLF detection with scalar fallback
Rate limiting ( proto/ratelimit.nim)Done β€” sliding window per IP, multi-window support (e.g. hourly + daily quotas checked atomically)
io_uring backend ( io/uring.nim)Done β€” opt-in Linux submission-based backend: full io_uring API binding, probe-based feature detection, zero-copy SEND_ZC + SPLICE file sends, registered buffers ( -d:powpowIoUring)
HTTP/2 ( proto/http2*.nim)Experimental β€” RFC 7540 server + multiplexing client with full HPACK, h2c (prior knowledge + Upgrade) and h2 over TLS/ALPN, flow control, GOAWAY draining; no push/priority yet (see HTTP/2)
HTTP/3 (QUIC)Not planned

πŸ”—Feature details

πŸ”—Core event loop

  • Single-threaded non-blocking reactor
  • I/O multiplexing via kqueue (macOS/BSD), epoll (Linux), IOCP (Windows) or poll (fallback)
  • io_uring (Linux, opt-in): the same loop driven by submission/completion ops β€” one io_uring_enter per iteration, op-driven sockets, kernel-timeout sleeps (guide)
  • 4-level hierarchical timer wheel β€” O(1) insert/fire/cancel
  • One-shot and repeating interval timers
  • Deferred callbacks (executed before each I/O poll iteration)
  • Idle handlers (executed when no I/O events are pending)
  • Pointer-based fd watcher dispatch β€” zero hash-table lookups on the hot path
  • Generation-counter stale event detection
  • Dead watcher sweep with zombie/retired list for in-flight event safety
  • Thread-safe stop() via eventfd (Linux) or self-pipe (macOS/BSD)
  • Buffer pool for shared read buffers
  • Adaptive event capacity scaling (min 64, max 4096)

πŸ”—io_uring backend

  • Full io_uring API binding against linux/io_uring.h β€” all opcodes, register ops, SQE/CQE/setup/enter flags and the ABI structs, with io_uring_prep_* style helpers; no liburing dependency
  • Feature detection via IORING_REGISTER_PROBE (per-opcode bitmap) instead of kernel-version guessing
  • Op-driven sockets: one-shot ACCEPT/RECV/SEND/CONNECT per connection, multishot accept/recv on capable kernels
  • Zero-copy writes: IORING_OP_SEND_ZC for large payloads with IORING_CQE_F_NOTIF buffer-lifetime tracking
  • Zero-copy file sends: IORING_OP_SPLICE (file β†’ pipe β†’ socket)
  • Registered buffers: IORING_REGISTER_BUFFERS lifecycle + opt-in SEND_ZC_FIXED (-d:powpowSendZcFixed)

πŸ”—TCP networking

  • Non-blocking TCP server with connection pooling
  • Non-blocking TCP client with async connect (DNS resolved on the loop)
  • Edge-triggered I/O events
  • Write buffering with automatic corking (TCP_CORK / TCP_NOPUSH)
  • Scatter-gather writes via writev
  • Zero-copy file send via sendfile (Linux sendfile, macOS sendfile, POSIX fallback)
  • Graceful shutdown with close-after-drain (closeAfterDrain)
  • Unix domain socket support (macOS/BSD/Linux)
  • SO_LINGER{0} for fast shutdown
  • Per-connection read buffer pooling

πŸ”—Async DNS

  • In-loop DNS resolver (RFC 1035) β€” no blocking getaddrinfo, no worker threads
  • Reads /etc/hosts and /etc/resolv.conf (system resolver config)
  • A + AAAA queries with A-fallback; retries with timeout/attempts
  • TTL-based result cache + negative caching
  • resolveAddrAsync for users; connect uses it automatically
  • Numeric IP literals resolve inline (zero DNS I/O)

πŸ”—OS signals

  • In-process SignalRelay pub/sub bus (listen / listenOnce / unlisten)
  • watchOsSignal / watchOsSignals deliver real OS signals through the loop
  • OsSignal enum: SIGHUP, SIGINT, SIGQUIT, SIGUSR1/2, SIGPIPE, SIGALRM, SIGTERM, SIGURG, SIGCHLD, SIGIO
  • Platform-native delivery: signalfd (Linux), self-pipe (macOS/BSD/POSIX), SetConsoleCtrlHandler Ctrl+C (Windows) β€” no global signal handlers
  • Graceful shutdown on SIGINT/SIGTERM without blocking the loop

πŸ”—Raw-fd streaming

  • IoStream wraps an arbitrary non-blocking fd and drives it from the loop
  • openStream for pipes, subprocess stdio, UDS and regular files; newStreamPair creates a full-duplex socketpair
  • Connection-style write path: direct write drained until EAGAIN, remainder buffered and flushed on Write events; 32 MiB queued-write cap
  • pause/resume give real read backpressure (a paused reader fills the kernel pipe buffer and blocks the writer)
  • close is the single terminal transition and fires onClose exactly once; closeAfterWrite flushes then delivers EOF to the peer
  • Platform notes: regular files work on kqueue but not epoll; Windows compiles the module away (IOCP is sockets-only)

πŸ”—HTTP/1.1 parser

  • Incremental, zero-copy parser β€” materialize strings lazily from byte offsets
  • O(1) method dispatch via first-byte switch
  • Pipelined request support
  • Streaming body handling via callback
  • Chunked transfer encoding
  • Body streaming to file
  • Multipart form data support

πŸ”—HTTP server

  • Implement-your-own-router β€” lower-level callback-based design
  • OnRequestCallback* = proc(req: HttpRequest, res: HttpResponse) {.gcsafe.}
  • Higher-level frameworks implement routing on top of this callback
  • Streaming response body
  • Static file serving with MIME type detection
  • Conditional requests (If-Modified-Since, If-None-Match)
  • Range requests with 206 Partial Content
  • Directory listing
  • CORS headers
  • Streaming multipart upload handling
  • Pipelined request-response processing

πŸ”—WebSocket

  • RFC 6455 compliant
  • Standalone WebSocket server mode
  • HTTP upgrade from HttpServer routes
  • Text, binary, ping/pong, and close frames
  • Per-message deflate extension
  • Masked frame handling

πŸ”—Multi-threaded HTTP server

  • SO_REUSEPORT kernel-level connection distribution
  • One event loop + listen socket per worker thread
  • Zero cross-thread communication β€” no single-threaded acceptor bottleneck
  • Graceful shutdown via shutdown pipe

πŸ”—SIMD-accelerated scanning

  • SSE2-accelerated CRLF detection
  • Scalar fallback for non-x86 architectures

πŸ”—Platform abstraction

  • kqueue β€” macOS/BSD (high-performance, edge-triggered)
  • epoll β€” Linux (with eventfd wake)
  • poll β€” POSIX fallback
  • iocp β€” Windows (I/O Completion Ports)

πŸ”—Networking common

  • Platform-agnostic socket API and address resolution (IPv4 + IPv6)
  • Socket options: non-blocking, SO_REUSEADDR, SO_REUSEPORT, TCP_NODELAY
  • sendfile zero-copy file transmission
  • Cross-platform error handling (EAGAIN, EINPROGRESS, etc.)
  • Auto-initialization (WSAStartup on Windows, SIGPIPE ignore on POSIX)

πŸ”—Where to go next