Skip to main content

dope_session/protocol/
client.rs

1use crate::CodecLayer;
2use crate::SlotId;
3use crate::session::Egress;
4use dambi::Bytes;
5
6/// Client-side protocol.
7///
8/// One trait owns parsing AND handling — there is no separate `Framer` trait
9/// or `Framer` accessor. Per-connection parsing state lives in [`ConnState`];
10/// shared protocol config lives in `&self`. Reusable parsers are expressed as
11/// free functions or helper structs that `parse` delegates to.
12///
13/// [`ConnState`]: ClientProtocol::ConnState
14pub trait ClientProtocol: 'static {
15    type Head;
16    type ConnState: Default + 'static;
17    type CodecLayer: CodecLayer;
18
19    /// Try to parse one frame from the connection's ingress buffer.
20    ///
21    /// Return `Some((head, consumed))` to advance past `consumed` bytes and
22    /// fire [`on_response`](ClientProtocol::on_response). Return `None` to
23    /// wait for more bytes (no advance).
24    ///
25    /// `state` is mutable so a stateful parser can advance internal phases
26    /// (STARTTLS reply → length-prefixed messages, HTTP/1 → /2 upgrade, ...).
27    fn parse(&self, state: &mut Self::ConnState, buf: &Bytes) -> Option<(Self::Head, usize)>;
28
29    fn on_connect(
30        &mut self,
31        conn_id: SlotId,
32        conn_state: &mut Self::ConnState,
33        out: Egress<'_, Self::CodecLayer>,
34    ) {
35        let _ = (conn_id, conn_state, out);
36    }
37
38    fn on_response(
39        &mut self,
40        conn_id: SlotId,
41        conn_state: &mut Self::ConnState,
42        head: Self::Head,
43        out: Egress<'_, Self::CodecLayer>,
44    );
45
46    fn wants_close(&self, conn_state: &Self::ConnState) -> bool {
47        let _ = conn_state;
48        false
49    }
50
51    fn on_disconnect(
52        &mut self,
53        conn_id: SlotId,
54        conn_state: &mut Self::ConnState,
55        out: Egress<'_, Self::CodecLayer>,
56    ) {
57        let _ = (conn_id, conn_state, out);
58    }
59}