
Abort.pudu
Pudu60 lines2.0 KB
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] }15161718export 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}41424344export 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}525354fn requested(token: &Cancel.Token) -> Bool {55 match Cancel.reason(token) {56 case Some(Cancel.Requested(_)) => true57 case _ => false58 }59}60