pub struct NamespaceStream {
send: FramedSendStream,
recv: FramedRecvStream,
request_id: VarInt,
draft: DraftVersion,
stream_id: u64,
origin: RequestOrigin,
closed: bool,
responded: bool,
}Expand description
One SUBSCRIBE_NAMESPACE and everything answering it, on a bidirectional stream of their own.
Draft-16 Section 3.3: “This specification only specifies two uses of bidirectional streams, the control stream, which begins with CLIENT_SETUP, and SUBSCRIBE_NAMESPACE.” This is the second use, and the only request on this draft that has a stream at all — every other one is still written on the control stream and identified by its Request ID.
The stream matters because two of the four messages that travel on it carry no Request ID. Section 9.21 puts NAMESPACE “on the response stream of a SUBSCRIBE_NAMESPACE request” and Section 9.23 says the same of NAMESPACE_DONE; both carry a Track Namespace Suffix, relative to a prefix only this subscription knows. Without the stream they name nothing.
§Reading and writing go through the connection
This handle owns both halves of the stream but not the session, so the
endpoint state machine and the observer stay where they were. Read with
Connection::recv_on_namespace_stream, answer the peer with
Connection::respond_ok_on_namespace_stream or
Connection::respond_error_on_namespace_stream, report namespaces with
Connection::send_on_namespace_stream, and withdraw with
Connection::cancel_namespace_stream or
Connection::finish_namespace_stream.
cancel, finish and
peer_cancelled are on the handle because a caller
may hold one without the connection. None of them moves the endpoint’s
record of the subscription, which is why the connection carries a wrapper
for each.
§Dropping this cancels the subscription, and correctly
Section 6.1: “A SUBSCRIBE_NAMESPACE can be cancelled by closing the stream
with either a FIN or RESET_STREAM.” Dropping a send stream sends a FIN and
dropping a receive stream sends STOP_SENDING, so a handle that falls out
of scope performs the first of those two forms exactly. That is why there
is no Drop impl here: on this draft the default is the cancellation,
and drafts 17 to 19 need one only because they made a FIN mean something
else.
What a drop cannot do is say so at the endpoint. It holds the stream and
not the session, so the subscription stays where it was in the endpoint’s
record while the stream it travelled on is gone. Call
Connection::finish_namespace_stream wherever that record matters.
All fields are private so the shape can grow without breaking callers.
Fields§
§send: FramedSendStream§recv: FramedRecvStream§request_id: VarInt§draft: DraftVersion§stream_id: u64§origin: RequestOrigin§closed: boolWhether this handle has already closed the stream, by either form.
responded: boolWhether a respond_* helper has written the answer on this stream.
Only ever true on a RequestOrigin::Peer stream.
Implementations§
Source§impl NamespaceStream
impl NamespaceStream
Sourcepub fn request_id(&self) -> VarInt
pub fn request_id(&self) -> VarInt
The Request ID the SUBSCRIBE_NAMESPACE on this stream carries.
Sourcepub fn stream_id(&self) -> u64
pub fn stream_id(&self) -> u64
The transport-level stream identifier, the same one
ClientEvent::StreamOpened reports.
Sourcepub fn draft(&self) -> DraftVersion
pub fn draft(&self) -> DraftVersion
The draft version this stream is framed for.
Sourcepub fn origin(&self) -> RequestOrigin
pub fn origin(&self) -> RequestOrigin
Which side opened this stream.
RequestOrigin::Peer means this endpoint owes the answer and the
respond_* helpers apply; RequestOrigin::Local means it is waiting
for one.
Sourcepub fn responded(&self) -> bool
pub fn responded(&self) -> bool
Whether the answer has been written on this stream by one of the
respond_* helpers.
Always false on a RequestOrigin::Local stream, which is answered by
the peer rather than here.
Sourcepub fn is_closed(&self) -> bool
pub fn is_closed(&self) -> bool
Whether cancel or finish has
already run on this handle.
Says nothing about the peer: a peer’s cancel is learned from
peer_cancelled or from the next read.
Sourcepub fn cancel(&mut self, code: u64) -> Result<(), ConnectionError>
pub fn cancel(&mut self, code: u64) -> Result<(), ConnectionError>
Cancel the subscription by resetting the stream, handing the peer
code.
The second of the two forms Section 6.1 allows. Both halves are shut —
a QUIC bidirectional stream has two independent halves, so resetting
only the send half would leave the peer free to keep writing namespaces
nobody will read. The send half is reset with code and the receive
half is stopped with the same value.
code is a plain u64 and has no default here, because draft-16
assigns none: its only registry of stream error codes is titled “Data
Stream Reset Error Codes” and every entry in it is specified by Section
10.4.3, which is about closing subgroup streams. A namespace
subscription’s stream is not a data stream, so a caller that wants to
end one without choosing a number should use finish,
the form that carries none.
This is the stream and nothing else. The endpoint’s record of the
subscription does not move, so a namespace already in flight is still
accepted after this returns. Connection::cancel_namespace_stream
does both and is what a caller holding a connection should reach for.
Idempotent, and errors from a stream that was already reset or finished are swallowed: the subscription is cancelled either way.
§Errors
ConnectionError::Transport carrying TransportError::Write if
code is outside the QUIC varint range (0..2^62). Nothing is sent in
that case and the handle is not marked closed, so a caller can retry
with a representable code.
Sourcepub async fn finish(&mut self) -> Result<(), ConnectionError>
pub async fn finish(&mut self) -> Result<(), ConnectionError>
Cancel the subscription by finishing the send half cleanly.
The first of the two forms Section 6.1 allows, and the one that needs no error code. The receive half is left open on purpose: a publisher that has already written namespaces has them in flight, and stopping the half they arrive on would discard what was sent before the FIN.
Like cancel, this is the stream and nothing else.
Connection::finish_namespace_stream is the same act with the
endpoint’s record attached.
Idempotent.
Sourcepub async fn peer_cancelled(&mut self) -> Result<Option<u64>, ConnectionError>
pub async fn peer_cancelled(&mut self) -> Result<Option<u64>, ConnectionError>
Wait for the peer to reset this stream, consuming nothing.
This sees one of Section 6.1’s two forms and not the other: a reset
arrives here, a FIN arrives as Ok(None) from
Connection::recv_on_namespace_stream. A caller that wants to
observe both has to read.
Returns Ok(Some(code)) with the peer’s application error code, or
Ok(None) meaning no reset is observable, now or ever — stop
asking. A caller that re-polls after Ok(None) spins.
Records nothing at the endpoint;
Connection::peer_cancelled_on_namespace_stream is the same wait
with the record attached. Cancel-safe, and it grants no flow-control
credit.
On WebTransport this always answers Ok(None): wtransport exposes no
reset-only observable, so a WebTransport caller learns of a peer reset
on its next read and not before.