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

Pooling.pudu

Pudu61 lines2.9 KB

GitHub ↗
1/** @Examples.Pooling.Program — pooled connections, lifetimes, cookies, and decompression */2module Pooling34import Std.Compress.Gzip as Gzip5import Std.Concurrent as Concurrent6import Std.Http as Http7import Std.Http.Server.Reply as Reply8import Std.Http.Server.Route as Route9import Std.Http.Server as Server10import Std.Io as Io11import PuduLangHttpClient.Client as Client12import PuduLangHttpClient.Cookies as Cookies13import PuduLangHttpClient.Events as Events14import PuduLangHttpClient.Factory.Builder as Builder15import PuduLangHttpClient.Factory as Factory16import PuduLangHttpClient.Transport as Transport1718/// Starts a local server that sets a cookie, checks it, and compresses a report; answers its address.19fn serve() -> (Server.Running, Str) {20  let running = match Server.start("127.0.0.1", 0) {21    case Ok(found) => found22    case Err(problem) => panic(show(problem))23  }24  let server = Server.server(&Route.routing(&[25        Route.get("/login", |_request: Route.Request| Http.Response{..Reply.text(200, "welcome"), headers: [("set-cookie", "session=s3cr3t; Path=/; Max-Age=600")]}),26        Route.get("/report", fn(request: Route.Request) -> Http.Response {27            if Route.header(&request, "cookie") != Some("session=s3cr3t") { return Reply.text(401, "log in first") }28            Http.Response{..Reply.bytes(200, "text/plain", &Gzip.compressText("quarterly numbers", &Gzip.config())), headers: [("content-type", "text/plain"), ("content-encoding", "gzip")]}29          })30      ]))31  let _serving = Concurrent.start(fn() -> () { let _ran = Server.run(&server, &running, 0) })32  (running, "http://127.0.0.1:" + show(Server.portOf(&running)) + "/")33}3435/// Logs in and reads a compressed report over one kept-alive connection, answering 0 on success.36fn main() -> Int {37  let (running, base) = serve()38  let jar = Cookies.jar()39  let options = Factory.Options{listeners: Events.listeners().onPipelineChanged(fn(event: Events.PipelineChanged) -> () {40        let _said = Io.writeLine("pipeline " + event.client + " #" + show(event.generation) + " " + show(event.stage))41      }) }42  let factory = match Factory.buildWith(&options, [43      Builder.named("reports").withBaseAddress(base).withHandlerLifetime(60000).withTransport(Transport.defaults().withCookies(jar).withDecompression().withMaxConnectionsPerServer(8).withPooledConnectionIdleTimeout(30000))44    ]) {45    case Ok(built) => built46    case Err(invalid) => panic(Factory.explain(&invalid))47  }48  let client = Factory.createClient(&factory, "reports")49  let _welcome = Client.getText(&client, "login")50  let report = Client.getText(&client, "report")51  let stats = Factory.statistics(&factory, "reports")52  let _said = Io.writeLine(show(report) + " " + show(stats) + " saved cookies: " + Cookies.save(&jar))53  Factory.dispose(&factory)54  let _stopped = Server.stop(&running)55  let reused = match stats {56    case Some(found) => found.opened == 1 && found.reused == 157    case None => false58  }59  if report == Ok("quarterly numbers") && reused { 0 } else { 1 }60}61