Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-httpclient

Named HTTP clients for Pudu: a client factory, delegating handlers, pooled keep-alive connections, handler lifetimes, logging, and resilience

0.1.1Apache-2.01

InstallClose

Persistence.pudu

Pudu34 lines1.8 KB

GitHub ↗
1/** @Domain.Persistence.Module — which connections stay open and which pooled ones are reused */2module PuduLangHttpClient.Domain.Persistence34import Std.Http.Message as Message5import PuduLangHttpClient.Domain.Expiry as Expiry6import PuduLangHttpClient.Domain.Headers as Headers78/** @Domain.Persistence.Idle — one pooled connection waiting for its next request */9export type Idle[C] = { link: C, created: Int, lastUsed: Int }1011/** @Domain.Persistence.Limits — how long a pooled connection may live and sit unused */12export type Limits = { lifetime: Int, idleTimeout: Int }1314/// Whether the connection may carry another request after this exchange: neither side asked to15/// close it, the body was framed by a length or chunks rather than by closing, and an HTTP/1.016/// response asked to keep it alive.17export fn keepsAlive(version: Str, requestHeaders: &Array[(Str, Str)], responseHeaders: &Array[(Str, Str)], framing: &Message.Framing) -> Bool {18  let asked = Headers.values(requestHeaders, "connection").concat(Headers.values(responseHeaders, "connection"))19  let closing = asked.filter(|value: Str| Headers.lists(value, "close")).length() > 020  let legacy = version == "HTTP/1.0"21  let kept = asked.filter(|value: Str| Headers.lists(value, "keep-alive")).length() > 022  !closing && *framing != Message.UntilClose && (!legacy || kept)23}2425/// Whether a pooled connection may still be reused at `now`.26export fn usable[C](idle: &Idle[C], limits: &Limits, now: Int) -> Bool {27  !Expiry.elapsed(idle.created, limits.lifetime, now) && !Expiry.elapsed(idle.lastUsed, limits.idleTimeout, now)28}2930/// The pooled connections split into those still usable at `now` and those to close.31export fn sweep[C](idle: &Array[Idle[C]], limits: &Limits, now: Int) -> (Array[Idle[C]], Array[Idle[C]]) {32  (idle.filter(|one: Idle[C]| usable(&one, limits, now)), idle.filter(|one: Idle[C]| !usable(&one, limits, now)))33}34