chadtmiller.com/knotless
git that lives in your Atmosphere account
1
10
Pages hear a repository change and a check end, live
crates/knotless-run/tests/run.rs+8−2
| @@ -4488,7 +4488,13 @@ fn a_run_shows_as_it_runs() { | ||
owner.git(&work, &["commit", "-q", "-am", "it holds"]); | ||
owner.git(&work, &["push", "-q", "origin", "main"]); | ||
js.ring(&owner.account.did, &ref_key); | ||
wait_until(|| changed.lock().unwrap().contains("event: changed")); | ||
// With data, as a browser hears no event without. | ||
wait_until(|| { | ||
changed | ||
.lock() | ||
.unwrap() | ||
.contains("event: changed\ndata: null") | ||
}); | ||
| ||
// Running, what it printed shows, masked; and not before. | ||
let running = || { | ||
| @@ -4514,7 +4520,7 @@ fn a_run_shows_as_it_runs() { | ||
}); | ||
assert!(!said.lock().unwrap().contains("event: ended")); | ||
std::fs::write(go.join("go"), "").unwrap(); | ||
wait_until(|| said.lock().unwrap().contains("event: ended")); | ||
wait_until(|| said.lock().unwrap().contains("event: ended\ndata: null")); | ||
let said = said.lock().unwrap().clone(); | ||
assert!(!said.contains("s3cret"), "{said}"); | ||
assert!(said.contains("event: steps"), "{said}"); | ||
crates/knotless-serve/src/web/live.rs+6−2
| @@ -23,6 +23,10 @@ use tokio::sync::broadcast::Receiver; | ||
/// How long one following lasts. | ||
const FOLLOW: Duration = Duration::from_secs(600); | ||
| ||
/// What `changed` and `ended` carry, which says nothing: a browser drops an | ||
/// event with no data, unheard, and axum sends an empty one with none. | ||
const NOTHING: &str = "null"; | ||
| ||
/// How long after a write others are waited for, so that a burst of them, | ||
/// as a push or a run makes, draws a page again once. | ||
const SETTLE: Duration = Duration::from_millis(250); | ||
| @@ -50,7 +54,7 @@ pub async fn follow_repo( | ||
while !changes.recv().await.ok().is_none_or(|t| t == topic) {} | ||
tokio::time::sleep(SETTLE).await; | ||
while changes.try_recv().is_ok() {} | ||
Some((Event::default().event("changed").data(""), changes)) | ||
Some((Event::default().event("changed").data(NOTHING), changes)) | ||
} | ||
}); | ||
Ok(events(&app, changed)) | ||
| @@ -125,7 +129,7 @@ impl Following { | ||
} | ||
if kept.ended { | ||
self.ended = true; | ||
said.push(Event::default().event("ended").data("")); | ||
said.push(Event::default().event("ended").data(NOTHING)); | ||
} | ||
said | ||
} | ||
docs/reference/api.md+2−2
| @@ -301,8 +301,8 @@ and ends as the server stops; a browser then asks again by itself. | ||
| ||
| Path | Parameters | Events | | ||
| --- | --- | --- | | ||
| `GET /_live/repo` | `repo`: the repository's `at://` URI | `changed`, with no data, a quarter of a second after the index takes in or lets go a record about the repository, once for those that came meanwhile | | ||
| `GET /_live/check` | `repo` and `uri`, as `dev.knotless.getCheck`; the `Last-Event-ID` header, where the output was had to | `output`: what the run printed since, a JSON string, its `id` the byte where it ends in all the run printed; `steps`: the steps that ended, as the record has them, each time more do; `going`: the name of the step going, a JSON string, or null between steps; `ended`, once, as the run's steps are over | | ||
| `GET /_live/repo` | `repo`: the repository's `at://` URI | `changed`, its data `null`, a quarter of a second after the index takes in or lets go a record about the repository, once for those that came meanwhile | | ||
| `GET /_live/check` | `repo` and `uri`, as `dev.knotless.getCheck`; the `Last-Event-ID` header, where the output was had to | `output`: what the run printed since, a JSON string, its `id` the byte where it ends in all the run printed; `steps`: the steps that ended, as the record has them, each time more do; `going`: the name of the step going, a JSON string, or null between steps; `ended`, its data `null`, once, as the run's steps are over | | ||
| ||
## Moderation | ||