use futures::StreamExt;
use tokio::sync::oneshot;
use tokio_util::sync::CancellationToken;
use zendriver_interception::InterceptBuilder;
use zendriver_transport::SessionHandle;
pub(crate) fn spawn_signal(session: &SessionHandle) -> (oneshot::Receiver<()>, InterceptionGuard) {
let (tx, rx) = oneshot::channel();
let cancel = CancellationToken::new();
let task_cancel = cancel.clone();
let stream = InterceptBuilder::new(session)
.pattern("*Reese.js*")
.at_response()
.pattern("*_Incapsula_Resource*")
.at_response()
.subscribe();
let handle = tokio::spawn(async move {
let mut stream = Box::pin(stream);
let mut tx = Some(tx);
loop {
tokio::select! {
biased;
() = task_cancel.cancelled() => break,
next = stream.next() => {
let Some(paused) = next else { break };
let is_2xx = paused
.response
.as_ref()
.map(|r| (200..300).contains(&r.status))
.unwrap_or(false);
let _ = paused.continue_().await;
if is_2xx {
if let Some(t) = tx.take() {
let _ = t.send(());
}
break;
}
}
}
}
});
(
rx,
InterceptionGuard {
cancel,
handle: Some(handle),
},
)
}
pub(crate) struct InterceptionGuard {
cancel: CancellationToken,
handle: Option<tokio::task::JoinHandle<()>>,
}
impl Drop for InterceptionGuard {
fn drop(&mut self) {
self.cancel.cancel();
if let Some(h) = self.handle.take() {
h.abort();
}
}
}