frame_conv/handle/
state.rs1use std::collections::{HashMap, VecDeque};
5use std::time::Duration;
6
7use frame_core::error::FailureReason;
8use liminal_protocol::wire::Generation;
9use liminal_sdk::remote::RemoteParticipantHandle;
10
11use crate::anomaly::{Anomaly, AnomalyCounters};
12use crate::envelope::Envelope;
13use crate::id::{ConversationId, ConversationSeq, CorrelationId, ParticipantRef};
14use crate::outcome::{DepartReason, JoinGrant};
15use crate::seam::StoreAdapter;
16use crate::store::ResumeStore;
17use crate::track::{CursorTracker, ExchangeRegistry};
18
19#[derive(Debug)]
22pub(crate) struct HeldReply {
23 pub(crate) envelope: Envelope,
24 pub(crate) responder: ParticipantRef,
25 pub(crate) seq: ConversationSeq,
26}
27
28#[derive(Debug)]
30pub(crate) struct HeldRequest {
31 pub(crate) envelope: Envelope,
32 pub(crate) requester: ParticipantRef,
33 pub(crate) seq: ConversationSeq,
34}
35
36#[derive(Debug, Clone)]
40pub(crate) enum QueuedItem {
41 Event {
42 envelope: Envelope,
43 publisher: ParticipantRef,
44 seq: ConversationSeq,
45 },
46 Joined {
47 peer: ParticipantRef,
48 seq: ConversationSeq,
49 },
50 Departed {
51 peer: ParticipantRef,
52 seq: ConversationSeq,
53 reason: DepartReason,
54 },
55 Failed {
56 peer: ParticipantRef,
57 seq: ConversationSeq,
58 failure: FailureReason,
59 },
60 Compacted {
61 seq: ConversationSeq,
62 },
63 Gap {
64 expected: ConversationSeq,
65 observed: ConversationSeq,
66 },
67}
68
69#[derive(Debug, Clone)]
72pub(crate) struct DeathNote {
73 pub(crate) peer: ParticipantRef,
74 pub(crate) failure: FailureReason,
75 pub(crate) seq: ConversationSeq,
76}
77
78pub struct ConversationHandle<S: ResumeStore> {
87 pub(crate) sdk: RemoteParticipantHandle<StoreAdapter<S>>,
88 pub(crate) conversation: ConversationId,
89 pub(crate) me: ParticipantRef,
90 pub(crate) grant: JoinGrant,
91 pub(crate) generation: Generation,
92 pub(crate) answer_window: Duration,
93 pub(crate) exchanges: ExchangeRegistry,
94 pub(crate) replies: HashMap<CorrelationId, HeldReply>,
95 pub(crate) requests_inbox: VecDeque<HeldRequest>,
96 pub(crate) events_inbox: VecDeque<QueuedItem>,
97 pub(crate) publications_inbox: VecDeque<QueuedItem>,
98 pub(crate) last_presented_publication: Option<u64>,
102 pub(crate) deaths: Vec<DeathNote>,
103 pub(crate) anomalies: Vec<Anomaly>,
104 pub(crate) counters: AnomalyCounters,
105 pub(crate) tracker: CursorTracker,
106 pub(crate) attached: bool,
107}
108
109impl<S: ResumeStore> std::fmt::Debug for ConversationHandle<S> {
110 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 formatter
112 .debug_struct("ConversationHandle")
113 .field("conversation", &self.conversation)
114 .field("participant", &self.me)
115 .field("attached", &self.attached)
116 .finish_non_exhaustive()
117 }
118}
119
120impl<S: ResumeStore> ConversationHandle<S> {
121 #[must_use]
123 pub const fn conversation(&self) -> ConversationId {
124 self.conversation
125 }
126
127 #[must_use]
129 pub const fn participant(&self) -> ParticipantRef {
130 self.me
131 }
132
133 #[must_use]
137 pub const fn grant(&self) -> &JoinGrant {
138 &self.grant
139 }
140
141 #[must_use]
145 pub const fn attached(&self) -> bool {
146 self.attached
147 }
148
149 pub fn drain_anomalies(&mut self) -> Vec<Anomaly> {
152 std::mem::take(&mut self.anomalies)
153 }
154
155 #[must_use]
158 pub const fn anomaly_counters(&self) -> AnomalyCounters {
159 self.counters
160 }
161}