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}