use std::ops;
use crate::coding::{ReasonPhrase, TrackNamespace};
use crate::message::RequestErrorCode;
use crate::watch::State;
use crate::{message, serve::ServeError};
use super::{PublishNamespaceInfo, Subscriber};
#[derive(Default)]
struct PublishedNamespaceState {
done: bool,
}
pub struct PublishedNamespace {
session: Subscriber,
state: State<PublishedNamespaceState>,
pub info: PublishNamespaceInfo,
ok: bool,
error: Option<ServeError>,
}
impl PublishedNamespace {
pub(super) fn new(
session: Subscriber,
request_id: u64,
namespace: TrackNamespace,
) -> (PublishedNamespace, PublishedNamespaceRecv) {
let info = PublishNamespaceInfo {
request_id,
namespace,
};
let (send, recv) = State::default().split();
let send = Self {
session,
info,
ok: false,
error: None,
state: send,
};
let recv = PublishedNamespaceRecv {
state: recv,
request_id,
};
(send, recv)
}
pub fn ok(&mut self) -> Result<(), ServeError> {
if self.ok {
return Err(ServeError::Duplicate);
}
self.session.send_request_ok(
"publish_namespace",
message::RequestOk {
id: self.info.request_id,
params: Default::default(),
},
);
self.ok = true;
Ok(())
}
pub async fn closed(&self) -> Result<(), ServeError> {
loop {
let Some(modified) = self.state.lock().modified() else {
return Ok(());
};
modified.await;
}
}
pub fn close(mut self, err: ServeError) -> Result<(), ServeError> {
self.error = Some(err);
Ok(())
}
}
impl ops::Deref for PublishedNamespace {
type Target = PublishNamespaceInfo;
fn deref(&self) -> &PublishNamespaceInfo {
&self.info
}
}
impl Drop for PublishedNamespace {
fn drop(&mut self) {
let err = self.error.clone().unwrap_or(ServeError::Done);
if self.state.lock().done {
return;
}
if self.ok {
self.session.send_message(message::PublishNamespaceCancel {
id: self.info.request_id,
error_code: err.code(),
reason_phrase: ReasonPhrase(err.to_string()),
});
} else {
self.session.send_request_error(
"publish_namespace",
message::RequestError {
id: self.info.request_id,
error_code: RequestErrorCode::Uninterested as u64,
retry_interval: 0,
reason: ReasonPhrase(err.to_string()),
},
);
}
}
}
pub(super) struct PublishedNamespaceRecv {
state: State<PublishedNamespaceState>,
pub request_id: u64,
}
impl PublishedNamespaceRecv {
pub fn recv_done(self) -> Result<(), ServeError> {
if let Some(mut state) = self.state.lock_mut() {
state.done = true;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn recv_done_marks_namespace_done_before_drop() {
let state = State::<PublishedNamespaceState>::default();
let (send_state, recv_state) = state.split();
let recv = PublishedNamespaceRecv {
state: recv_state,
request_id: 0,
};
assert!(!send_state.lock().done);
recv.recv_done().unwrap();
assert!(send_state.lock().done);
assert!(send_state.lock().modified().is_none());
}
}