use bytes::{BufMut, BytesMut};
use tokio::io::AsyncWriteExt;
use tokio::net::TcpStream;
use crate::error::PgWireError;
#[derive(Debug, Clone)]
pub struct CancelToken {
addr: String,
pid: i32,
secret: i32,
}
impl CancelToken {
pub fn new(addr: String, pid: i32, secret: i32) -> Self {
Self { addr, pid, secret }
}
pub fn addr(&self) -> &str {
&self.addr
}
pub fn pid(&self) -> i32 {
self.pid
}
pub async fn cancel(&self) -> Result<(), PgWireError> {
const CANCEL_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(5);
let result = tokio::time::timeout(CANCEL_TIMEOUT, async {
let mut stream = TcpStream::connect(&self.addr).await?;
let mut buf = BytesMut::with_capacity(16);
buf.put_i32(16); buf.put_i32(80877102); buf.put_i32(self.pid);
buf.put_i32(self.secret);
stream.write_all(&buf).await?;
stream.shutdown().await?;
Ok::<(), PgWireError>(())
})
.await;
match result {
Ok(inner) => inner,
Err(_elapsed) => Err(PgWireError::Protocol(
"cancel request timed out after 5 seconds".into(),
)),
}
}
}