1use crate::primitives::RawJson;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum MsgKind {
12 Request,
13 Response,
14}
15
16#[derive(Debug, Clone, PartialEq)]
17pub struct Message {
18 pub msg_kind: MsgKind,
19 pub frames: Vec<Frame>,
20}
21
22pub mod frame_type {
25 pub const END: u8 = 0x00;
26 pub const REQ_HEADER: u8 = 0x01;
27 pub const PUSH_COMMIT: u8 = 0x02;
28 pub const PULL_HEADER: u8 = 0x03;
29 pub const SUBSCRIPTION: u8 = 0x04;
30 pub const RESP_HEADER: u8 = 0x10;
31 pub const PUSH_RESULT: u8 = 0x11;
32 pub const SUB_START: u8 = 0x12;
33 pub const COMMIT: u8 = 0x13;
34 pub const SEGMENT_REF: u8 = 0x14;
35 pub const SEGMENT_INLINE: u8 = 0x15;
36 pub const SUB_END: u8 = 0x16;
37 pub const LEASE: u8 = 0x19;
38 pub const PUSH_RESULT_DETAILS: u8 = 0x1B;
39 pub const ERROR: u8 = 0x1F;
40
41 pub const REQUEST_TYPES: &[u8] = &[REQ_HEADER, PUSH_COMMIT, PULL_HEADER, SUBSCRIPTION];
42 pub const RESPONSE_TYPES: &[u8] = &[
43 RESP_HEADER,
44 PUSH_RESULT,
45 SUB_START,
46 COMMIT,
47 SEGMENT_REF,
48 SEGMENT_INLINE,
49 SUB_END,
50 LEASE,
51 PUSH_RESULT_DETAILS,
52 ERROR,
53 ];
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57pub enum Op {
58 Upsert,
59 Delete,
60}
61
62impl Op {
63 pub fn name(self) -> &'static str {
64 match self {
65 Op::Upsert => "upsert",
66 Op::Delete => "delete",
67 }
68 }
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub enum SubStatus {
73 Active,
74 Revoked,
75 Reset,
76}
77
78impl SubStatus {
79 pub fn name(self) -> &'static str {
80 match self {
81 SubStatus::Active => "active",
82 SubStatus::Revoked => "revoked",
83 SubStatus::Reset => "reset",
84 }
85 }
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
89pub enum PushStatus {
90 Applied,
91 Cached,
92 Rejected,
93}
94
95impl PushStatus {
96 pub fn name(self) -> &'static str {
97 match self {
98 PushStatus::Applied => "applied",
99 PushStatus::Cached => "cached",
100 PushStatus::Rejected => "rejected",
101 }
102 }
103}
104
105#[derive(Debug, Clone, Copy, PartialEq, Eq)]
106pub enum MediaType {
107 Rows,
108 Sqlite,
109}
110
111impl MediaType {
112 pub fn name(self) -> &'static str {
113 match self {
114 MediaType::Rows => "rows",
115 MediaType::Sqlite => "sqlite",
116 }
117 }
118}
119
120#[derive(Debug, Clone, PartialEq)]
122pub struct Operation {
123 pub table: String,
124 pub row_id: String,
125 pub op: Op,
126 pub base_version: Option<i64>,
127 pub payload: Option<Vec<u8>>,
129}
130
131#[derive(Debug, Clone, PartialEq)]
133pub struct Change {
134 pub table_index: u16,
135 pub row_id: String,
136 pub op: Op,
137 pub row_version: Option<i64>,
138 pub scopes: Vec<(String, String)>,
139 pub row: Option<Vec<u8>>,
141}
142
143#[derive(Debug, Clone, PartialEq)]
145pub enum OpResult {
146 Applied {
147 op_index: i32,
148 },
149 Conflict {
150 op_index: i32,
151 code: String,
152 message: String,
153 server_version: i64,
154 server_row: Vec<u8>,
155 },
156 Error {
157 op_index: i32,
158 code: String,
159 message: String,
160 retryable: bool,
161 },
162}
163
164#[derive(Debug, Clone, PartialEq, Eq)]
165pub struct PushResultDetail {
166 pub op_index: i32,
167 pub details: RawJson,
168}
169
170#[derive(Debug, Clone, PartialEq)]
171pub enum Frame {
172 ReqHeader {
173 client_id: String,
174 schema_version: i32,
175 },
176 PushCommit {
177 client_commit_id: String,
178 operations: Vec<Operation>,
179 },
180 PullHeader {
181 limit_commits: i32,
182 limit_snapshot_rows: i32,
183 max_snapshot_pages: i32,
184 accept: u8,
185 },
186 Subscription {
187 id: String,
188 table: String,
189 scopes: Vec<(String, Vec<String>)>,
190 params: Option<RawJson>,
191 cursor: i64,
192 bootstrap_state: Option<RawJson>,
193 },
194 RespHeader {
195 required_schema_version: Option<i32>,
196 latest_schema_version: Option<i32>,
197 },
198 Lease {
200 lease_id: String,
201 expires_at_ms: i64,
202 },
203 PushResult {
204 client_commit_id: String,
205 status: PushStatus,
206 commit_seq: Option<i64>,
207 results: Vec<OpResult>,
208 },
209 PushResultDetails {
212 client_commit_id: String,
213 entries: Vec<PushResultDetail>,
214 },
215 SubStart {
216 id: String,
217 status: SubStatus,
218 reason_code: String,
219 effective_scopes: Vec<(String, Vec<String>)>,
220 bootstrap: bool,
221 },
222 Commit {
223 commit_seq: i64,
224 created_at_ms: i64,
225 actor_id: String,
226 tables: Vec<String>,
227 changes: Vec<Change>,
228 },
229 SegmentRef {
230 segment_id: String,
231 media_type: MediaType,
232 table: String,
233 byte_length: i64,
234 row_count: i64,
235 as_of_commit_seq: i64,
236 scope_digest: String,
237 row_cursor: Option<String>,
238 next_row_cursor: Option<String>,
239 url: Option<String>,
240 url_expires_at_ms: Option<i64>,
241 },
242 SegmentInline { payload: Vec<u8> },
245 SubEnd {
246 next_cursor: i64,
247 bootstrap_state: Option<RawJson>,
248 },
249 Error {
250 code: String,
251 message: String,
252 category: String,
253 retryable: bool,
254 recommended_action: String,
255 details: Option<RawJson>,
256 },
257 Unknown { frame_type: u8, payload: Vec<u8> },
260}