pub struct Session<P: Protocol, S: ClientState> { /* private fields */ }Expand description
A typed reflector session.
P is the protocol marker (DPlus, super::DExtra,
super::Dcs). S is the connection state marker
(Configured, Connecting, etc.). Methods are gated by
impl blocks on specific Session<P, S> shapes — calling
send_voice on a Session<P, Configured> is a compile error, not
a runtime error.
The Session<P, S> is a thin wrapper over SessionCore (the
protocol-erased state machine). The phantom types add zero
runtime cost — the entire typestate machinery compiles away.
Implementations§
Source§impl<P: Protocol> Session<P, Configured>
impl<P: Protocol> Session<P, Configured>
Sourcepub const fn builder() -> SessionBuilder<P, Missing, Missing, Missing, Missing>
pub const fn builder() -> SessionBuilder<P, Missing, Missing, Missing, Missing>
Entry point for building a typed Session<P, Configured>.
Returns a builder with every required field marked
Missing. Chain .callsign(), .local_module(),
.reflector_module(), and .peer() in any order, then call
.build(). Skipping any of the four setters turns the
.build() call into a compile error.
§Example
use dstar_gateway_core::session::client::{Configured, DExtra, Session};
use dstar_gateway_core::types::{Callsign, Module};
let session: Session<DExtra, Configured> =
Session::<DExtra, Configured>::builder()
.callsign(Callsign::try_from_str("W1AW")?)
.local_module(Module::try_from_char('B')?)
.reflector_module(Module::try_from_char('C')?)
.peer("127.0.0.1:30001".parse()?)
.build();Source§impl<P: Protocol, S: ClientState> Session<P, S>
impl<P: Protocol, S: ClientState> Session<P, S>
Sourcepub const fn state_kind(&self) -> ClientStateKind
pub const fn state_kind(&self) -> ClientStateKind
Runtime discriminator for the current state.
Sourcepub const fn peer(&self) -> SocketAddr
pub const fn peer(&self) -> SocketAddr
The reflector address this session was built to talk to.
Sourcepub const fn local_callsign(&self) -> Callsign
pub const fn local_callsign(&self) -> Callsign
The local station callsign.
Sourcepub fn diagnostics(&mut self) -> Vec<Diagnostic>
pub fn diagnostics(&mut self) -> Vec<Diagnostic>
Drain accumulated diagnostics, if any.
Returns a Vec (not an iterator) because the underlying sink
lives inside the session; returning a borrowed iterator would
force the caller to hold a &mut Session for the lifetime of
the iterator. Most consumers call this periodically and
process the batch.
Source§impl<P: Protocol + NoAuthRequired> Session<P, Configured>
impl<P: Protocol + NoAuthRequired> Session<P, Configured>
Sourcepub fn connect(
self,
now: Instant,
) -> Result<Session<P, Connecting>, Failed<Self, Error>>
pub fn connect( self, now: Instant, ) -> Result<Session<P, Connecting>, Failed<Self, Error>>
Send the LINK/connect packet and transition to Connecting.
§Errors
Returns the original session in the error position if the state machine refuses the transition (e.g., codec encoder failure). This lets the caller retry without rebuilding.
Source§impl Session<DPlus, Configured>
impl Session<DPlus, Configured>
Sourcepub fn authenticate(
self,
hosts: HostList,
) -> Result<Session<DPlus, Authenticated>, Failed<Self, Error>>
pub fn authenticate( self, hosts: HostList, ) -> Result<Session<DPlus, Authenticated>, Failed<Self, Error>>
Source§impl Session<DPlus, Authenticated>
impl Session<DPlus, Authenticated>
Sourcepub fn connect(
self,
now: Instant,
) -> Result<Session<DPlus, Connecting>, Failed<Self, Error>>
pub fn connect( self, now: Instant, ) -> Result<Session<DPlus, Connecting>, Failed<Self, Error>>
Send LINK1 and transition to Connecting.
§Errors
Returns the original session in the error position if the state machine refuses the transition.
Sourcepub fn host_list(&self) -> &HostList
pub fn host_list(&self) -> &HostList
Get the cached host list from the TCP auth step.
The Authenticated state is entered only after
SessionCore::attach_host_list succeeds, so the host list is
always present here. A None would indicate a bug in
SessionCore; we fall back to a module-level empty
sentinel rather than panic so lib code stays
expect_used-clean.
Source§impl<P: Protocol> Session<P, Connecting>
impl<P: Protocol> Session<P, Connecting>
Sourcepub fn promote(self) -> Result<Session<P, Connected>, Failed<Self, Error>>
pub fn promote(self) -> Result<Session<P, Connected>, Failed<Self, Error>>
Promote a session that has reached Connected state.
The shell calls this after observing Event::Connected from
the event stream. promote only succeeds if the core is
already in ClientStateKind::Connected; any other state
returns a Failed with a StateError::WrongState error.
If the session was rejected mid-handshake the caller should
inspect the failed session’s Session::state_kind — it may
already be in ClientStateKind::Closed.
§Errors
Returns Err(Failed) if the session is not yet in
ClientStateKind::Connected. The session field of the
Failed carries the unchanged Session<P, Connecting>.
Source§impl<P: Protocol> Session<P, Connected>
impl<P: Protocol> Session<P, Connected>
Sourcepub fn disconnect(
self,
now: Instant,
) -> Result<Session<P, Disconnecting>, Failed<Self, Error>>
pub fn disconnect( self, now: Instant, ) -> Result<Session<P, Disconnecting>, Failed<Self, Error>>
Initiate a graceful disconnect.
Enqueues the UNLINK packet and transitions to
Disconnecting. The caller must continue to drive the
Driver loop (polling poll_transmit / poll_event) until
either the UNLINK ACK arrives (emitting Event::Disconnected
with super::DisconnectReason::UnlinkAcked) or the
disconnect deadline expires (emitting Event::Disconnected
with super::DisconnectReason::DisconnectTimeout).
§Errors
Returns the original session in the error position if the state machine refuses the transition (e.g., codec encoder failure).
Sourcepub fn disconnect_in_place(&mut self, now: Instant) -> Result<(), Error>
pub fn disconnect_in_place(&mut self, now: Instant) -> Result<(), Error>
Enqueue an UNLINK packet without consuming the session.
Used by the tokio shell’s SessionLoop to trigger a disconnect
from within the event loop, where consuming self isn’t
possible. After this returns, the internal state machine has
transitioned to Disconnecting, but the typestate parameter
on this handle is still Connected. The caller should exit
the event loop and construct a Session<P, Disconnecting> or
wait for the internal state to reach Closed.
§Errors
Returns Error if the core’s SessionCore::enqueue_disconnect
call fails (e.g., the codec encoder rejects the UNLINK packet).
Sourcepub fn send_header(
&mut self,
now: Instant,
header: &DStarHeader,
stream_id: StreamId,
) -> Result<(), Error>
pub fn send_header( &mut self, now: Instant, header: &DStarHeader, stream_id: StreamId, ) -> Result<(), Error>
Send a voice header and start a new outbound voice stream.
The header is cached internally; subsequent
Self::send_voice / Self::send_eot calls will reference
it (DCS embeds the full header in every voice frame, so the
cache is mandatory there).
This method takes &mut self, NOT self — voice TX does not
change the typestate. The session stays in Connected until
disconnect or a timeout closes it.
§Errors
Returns Error::Protocol if the codec encoder fails.
Sourcepub fn send_voice(
&mut self,
now: Instant,
stream_id: StreamId,
seq: u8,
frame: &VoiceFrame,
) -> Result<(), Error>
pub fn send_voice( &mut self, now: Instant, stream_id: StreamId, seq: u8, frame: &VoiceFrame, ) -> Result<(), Error>
Send a voice data frame.
This method takes &mut self, NOT self.
§Errors
Returns Error::Protocol if the codec encoder fails.
On DCS, returns Error::Protocol with
crate::error::DcsError::NoTxHeader if Self::send_header
has not been called first.
Sourcepub fn send_eot(
&mut self,
now: Instant,
stream_id: StreamId,
seq: u8,
) -> Result<(), Error>
pub fn send_eot( &mut self, now: Instant, stream_id: StreamId, seq: u8, ) -> Result<(), Error>
Send a voice EOT packet, ending the outbound stream.
This method takes &mut self, NOT self. The session stays
in Connected after EOT — the caller may begin a new stream
by calling Self::send_header again.
§Errors
Returns Error::Protocol if the codec encoder fails.
On DCS, returns Error::Protocol with
crate::error::DcsError::NoTxHeader if Self::send_header
has not been called first.
Source§impl<P: Protocol> Session<P, Disconnecting>
impl<P: Protocol> Session<P, Disconnecting>
Sourcepub fn promote(self) -> Result<Session<P, Closed>, Failed<Self, Error>>
pub fn promote(self) -> Result<Session<P, Closed>, Failed<Self, Error>>
Promote to Closed once the UNLINK ACK arrives or the deadline fires.
Same pattern as Session::<P, Connecting>::promote. The
shell watches for Event::Disconnected and then calls this.
§Errors
Returns Err(Failed) if the session is not yet in
ClientStateKind::Closed (the disconnect ACK hasn’t arrived
yet).