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

Abort.pudu

Pudu60 lines2.0 KB

GitHub ↗
1/** @Transport.Abort.Module — a connection closed when its request is cancelled mid-exchange */2module PuduLangHttpClient.Transport.Abort34import Std.Concurrent.Cancel as Cancel5import Std.Concurrent as Concurrent6import PuduLangHttpClient.Constants.Defaults as Defaults7import PuduLangHttpClient.Transport.Wire as Wire8import PuduLangHttpClient.Utils.Shared as Shared910/** @Transport.Abort.Stage — whether the exchange is running, finished, or was aborted */11export type Stage = Running | Finished | Aborted1213/** @Transport.Abort.Guard — the stage one exchange is in, shared with its watcher */14export type Guard = { stage: Shared.Shared[Stage] }1516/// A guard over an exchange on the link: a watcher closes the link as soon as the token is cancelled17/// while the exchange runs, which wakes a read or write blocked on it.18export fn watch(link: &Wire.Link, token: &Cancel.Token) -> Guard {19  let guard = Guard{stage: Shared.shared(Running)}20  let held = *link21  let watched = *token22  let _watching = Concurrent.start(fn() -> () {23      var going = true24      while going {25        let _slept = Concurrent.sleep(Defaults.ABORT_POLL)26        going = Shared.change(&guard.stage, fn(stage: Stage) -> (Stage, Bool) {27            match stage {28              case Running => {29                if requested(&watched) {30                  Wire.close(&held)31                  (Aborted, false)32                } else { (Running, true) }33              }34              case other => (other, false)35            }36          })37      }38    })39  guard40}4142/// Ends the exchange and answers whether the watcher aborted it; once this answers, the watcher never43/// touches the link again.44export fn finish(guard: &Guard) -> Bool {45  Shared.change(&guard.stage, fn(stage: Stage) -> (Stage, Bool) {46      match stage {47        case Running => (Finished, false)48        case other => (other, other == Aborted)49      }50    })51}5253/// Whether the token was cancelled by request rather than by its deadline.54fn requested(token: &Cancel.Token) -> Bool {55  match Cancel.reason(token) {56    case Some(Cancel.Requested(_)) => true57    case _ => false58  }59}60