OpenPay (1 crate, 2174 LOC, 14 tests)
op-payouts Multi-rail payout engine. Visa Direct, Mastercard Send,
ACH credits (NACHA), Fedwire + SWIFT MT103 + ISO 20022
pacs.008, SEPA SCT + SCT Inst (mod-97 IBAN), UK FPS,
FedNow, RTP, PayPal, Wise. Crypto: USDC/USDT on
ETH/Polygon/Base/Solana + BTC + Lightning with real
ERC-20 transfer(address,uint256) calldata. Offline-pure
drivers (emit wire payloads — operators transmit).
Smart Byte (1 crate, 2605 LOC, 38 tests)
smart-byte-nostr Nostr adapter. NIP-01 canonical event id + BIP-340
Schnorr sign/verify; from-scratch bech32 + NIP-19 TLV
(npub/nsec/note/nprofile/nevent/nrelay); NIP-04 legacy
AES-256-CBC DMs; NIP-44 v2 HKDF-SHA256→ChaCha20+HMAC
with bucketed padding; NIP-17 gift-wrap (kind 1059) +
seal (kind 13) + rumor (kind 14); NIP-05/11/13/26/65.
Relay client message vocabulary (REQ/EVENT/CLOSE/AUTH/
EOSE/OK/NOTICE/CLOSED) + in-memory router.
EOC (1 crate, 2024 LOC, 30 tests)
eoc-streaming Token-by-token + tool-call streaming primitives.
SSE framing (data: lines); Anthropic event mapper
(message_start/content_block_*/message_delta/stop/ping);
OpenAI delta mapper; Vercel AI SDK mapper. Bounded-channel
backpressure with watermarks; CancelToken propagation;
Last-Event-ID resumable streams; per-stream joule meter.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
119 lines
3.8 KiB
Rust
119 lines
3.8 KiB
Rust
//! Resumable streams via `Last-Event-ID`.
|
|
//!
|
|
//! When a client reconnects to a streaming endpoint it may include the
|
|
//! `Last-Event-ID` HTTP header. If the server still has a replay
|
|
//! window covering that id, it can send the missed events first and
|
|
//! then resume normal streaming. This module owns the in-memory event
|
|
//! log + replay logic; the actual transport binding (HTTP header
|
|
//! plumbing, etc.) is left to the host.
|
|
|
|
use std::collections::VecDeque;
|
|
use std::sync::Mutex;
|
|
|
|
use crate::error::{StreamError, StreamResult};
|
|
|
|
/// An identifier carried in the SSE `id:` field.
|
|
pub type LastEventId = String;
|
|
|
|
/// Bounded ring-buffer of recently emitted events keyed on id.
|
|
#[derive(Debug)]
|
|
pub struct EventLog<T: Clone + Send + 'static> {
|
|
inner: Mutex<EventLogInner<T>>,
|
|
capacity: usize,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct EventLogInner<T> {
|
|
/// Pairs of (id, event). Oldest first.
|
|
entries: VecDeque<(LastEventId, T)>,
|
|
}
|
|
|
|
impl<T: Clone + Send + 'static> EventLog<T> {
|
|
/// Construct a log retaining at most `capacity` entries.
|
|
pub fn new(capacity: usize) -> Self {
|
|
Self {
|
|
inner: Mutex::new(EventLogInner {
|
|
entries: VecDeque::with_capacity(capacity.max(1)),
|
|
}),
|
|
capacity: capacity.max(1),
|
|
}
|
|
}
|
|
|
|
/// Append a new event. Drops the oldest entry when capacity is hit.
|
|
pub fn push(&self, id: LastEventId, ev: T) -> StreamResult<()> {
|
|
let mut g = self.inner.lock().map_err(|_| {
|
|
StreamError::Backend("event log mutex poisoned".into())
|
|
})?;
|
|
if g.entries.len() == self.capacity {
|
|
g.entries.pop_front();
|
|
}
|
|
g.entries.push_back((id, ev));
|
|
Ok(())
|
|
}
|
|
|
|
/// Return all events strictly newer than `last_id`. If `last_id` is
|
|
/// `None`, returns the entire current window. Errors with
|
|
/// [`StreamError::ResumeOutOfRange`] when `last_id` is supplied but
|
|
/// not in the window (i.e. it predates the oldest retained event).
|
|
pub fn replay_after(&self, last_id: Option<&str>) -> StreamResult<Vec<T>> {
|
|
let g = self.inner.lock().map_err(|_| {
|
|
StreamError::Backend("event log mutex poisoned".into())
|
|
})?;
|
|
let Some(last_id) = last_id else {
|
|
return Ok(g.entries.iter().map(|(_, e)| e.clone()).collect());
|
|
};
|
|
// If the oldest entry's id is already newer than last_id we
|
|
// cannot guarantee no gap, so report out-of-range.
|
|
let mut found = false;
|
|
let mut out = Vec::new();
|
|
for (id, ev) in g.entries.iter() {
|
|
if found {
|
|
out.push(ev.clone());
|
|
} else if id == last_id {
|
|
found = true;
|
|
}
|
|
}
|
|
if !found {
|
|
return Err(StreamError::ResumeOutOfRange(last_id.to_string()));
|
|
}
|
|
Ok(out)
|
|
}
|
|
|
|
/// Current window length.
|
|
pub fn len(&self) -> usize {
|
|
self.inner
|
|
.lock()
|
|
.map(|g| g.entries.len())
|
|
.unwrap_or(0)
|
|
}
|
|
|
|
/// True if the window is empty.
|
|
pub fn is_empty(&self) -> bool {
|
|
self.len() == 0
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn replays_after_id() {
|
|
let log = EventLog::<&'static str>::new(4);
|
|
log.push("1".into(), "a").unwrap();
|
|
log.push("2".into(), "b").unwrap();
|
|
log.push("3".into(), "c").unwrap();
|
|
let r = log.replay_after(Some("1")).unwrap();
|
|
assert_eq!(r, vec!["b", "c"]);
|
|
}
|
|
|
|
#[test]
|
|
fn out_of_range_reports() {
|
|
let log = EventLog::<&'static str>::new(2);
|
|
log.push("1".into(), "a").unwrap();
|
|
log.push("2".into(), "b").unwrap();
|
|
log.push("3".into(), "c").unwrap(); // evicts "1"
|
|
let err = log.replay_after(Some("1")).unwrap_err();
|
|
assert!(matches!(err, StreamError::ResumeOutOfRange(_)));
|
|
}
|
|
}
|