Driving
The driver moves each swap forward in passes. A pass reads the chain and the server for one swap, saves what changed, and acts on it.
In the background
- Rust
- TypeScript
let mut updates = driver.subscribe();
tokio::spawn(driver.run());
while let Some(swap) = updates.next().await {
let record = swap.record().await?;
println!("{} {:?} {:?}", swap.swap_id(), record.status, swap.error());
}
const updates = driver.subscribe();
driver.run();
for await (const swap of updates) {
const { status } = await swap.record();
console.log(swap.swapId, status, swap.error?.message);
}
| Call | Effect |
|---|---|
run | Drives every stored swap that still has something to do, until stop. A swap created or restored joins at once. A second call does nothing. |
subscribe | Yields a handle each time a swap changes, and each time a pass on it fails. |
stop | Ends run after the pass in flight. Final: the driver does not run again, and its updates end once drained. |
wait_stopped | Resolves once nothing writes to the store. |
state | Idle, Running, Stopping or Stopped. |
An update is a prompt to render, not a ledger: under sustained lag the stream
drops updates rather than slow the driver. A handle keeps no copy of the
swap, so status, record and funds always return the
store's latest, and driver.get(swap_id)
returns any stored swap.
By hand
- Rust
- TypeScript
while !swap.status().await?.is_terminal() {
match swap.advance().await {
Ok(status) => println!("{status:?}"),
Err(error) if error.retryable() => {}
Err(error) => return Err(error.into()),
}
}
while (!(await swap.isTerminal())) {
try {
console.log(await swap.advance());
} catch (e) {
if (!(e instanceof DriverError && e.retryable)) throw e;
}
}
| Call | Effect |
|---|---|
step | One pass now. Returns the status. |
advance | Waits for a server signal or the poll interval, whichever comes first, then one pass. |
Handles and run mix freely: a swap never gets two passes at once. On a
SwapIn, a terminal status can still leave refunds moving.
Errors
A failing pass sets the swap's error, and the next pass retries. A pass that
works clears it and yields the swap once more.
| What fails | error | Then |
|---|---|---|
| Reading a chain | set | the swap waits for the chain |
| Broadcasting a claim or a refund | set | the next pass broadcasts again |
| Reading the server | not set | the swap moves on from the chain; server_status keeps the last label |
| The server taking a cancel, or a SwapIn's refund key | set | the next pass sends it again |
error.retryable() is true for an outage the
next pass may outlive, such as an unreachable chain or server, and false for
an error that needs attention.
The driver does not report whether the server is reachable.
client.signals({ onConnectionChange }) reports when the server's WebSocket
drops and when it is back, for a reconnecting hint.