this repo has no description
1use crate::sync::firehose::SequencedEvent;
2use cid::Cid;
3use serde::{Deserialize, Serialize};
4use std::str::FromStr;
5
6#[derive(Debug, Serialize, Deserialize)]
7pub struct FrameHeader {
8 pub op: i64,
9 pub t: String,
10}
11
12#[derive(Debug, Serialize, Deserialize)]
13pub struct CommitFrame {
14 pub seq: i64,
15 pub rebase: bool,
16 #[serde(rename = "tooBig")]
17 pub too_big: bool,
18 pub repo: String,
19 pub commit: Cid,
20 pub rev: String,
21 pub since: Option<String>,
22 #[serde(with = "serde_bytes")]
23 pub blocks: Vec<u8>,
24 pub ops: Vec<RepoOp>,
25 pub blobs: Vec<Cid>,
26 pub time: String,
27 #[serde(rename = "prevData", skip_serializing_if = "Option::is_none")]
28 pub prev_data: Option<Cid>,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
32struct JsonRepoOp {
33 action: String,
34 path: String,
35 cid: Option<String>,
36 prev: Option<String>,
37}
38
39#[derive(Debug, Serialize, Deserialize)]
40pub struct RepoOp {
41 pub action: String,
42 pub path: String,
43 pub cid: Option<Cid>,
44 #[serde(skip_serializing_if = "Option::is_none")]
45 pub prev: Option<Cid>,
46}
47
48#[derive(Debug, Serialize, Deserialize)]
49pub struct IdentityFrame {
50 pub did: String,
51 #[serde(skip_serializing_if = "Option::is_none")]
52 pub handle: Option<String>,
53 pub seq: i64,
54 pub time: String,
55}
56
57#[derive(Debug, Serialize, Deserialize)]
58pub struct AccountFrame {
59 pub did: String,
60 pub active: bool,
61 #[serde(skip_serializing_if = "Option::is_none")]
62 pub status: Option<String>,
63 pub seq: i64,
64 pub time: String,
65}
66
67#[derive(Debug, Serialize, Deserialize)]
68pub struct SyncFrame {
69 pub did: String,
70 pub rev: String,
71 #[serde(with = "serde_bytes")]
72 pub blocks: Vec<u8>,
73 pub seq: i64,
74 pub time: String,
75}
76
77#[derive(Debug, Serialize, Deserialize)]
78pub struct InfoFrame {
79 pub name: String,
80 #[serde(skip_serializing_if = "Option::is_none")]
81 pub message: Option<String>,
82}
83
84#[derive(Debug, Serialize, Deserialize)]
85pub struct ErrorFrameHeader {
86 pub op: i64,
87}
88
89#[derive(Debug, Serialize, Deserialize)]
90pub struct ErrorFrameBody {
91 pub error: String,
92 #[serde(skip_serializing_if = "Option::is_none")]
93 pub message: Option<String>,
94}
95
96pub struct CommitFrameBuilder {
97 pub seq: i64,
98 pub did: String,
99 pub commit_cid_str: String,
100 pub prev_cid_str: Option<String>,
101 pub ops_json: serde_json::Value,
102 pub blobs: Vec<String>,
103 pub time: chrono::DateTime<chrono::Utc>,
104}
105
106impl CommitFrameBuilder {
107 pub fn build(self) -> Result<CommitFrame, &'static str> {
108 let commit_cid = Cid::from_str(&self.commit_cid_str).map_err(|_| "Invalid commit CID")?;
109 let json_ops: Vec<JsonRepoOp> =
110 serde_json::from_value(self.ops_json).unwrap_or_else(|_| vec![]);
111 let ops: Vec<RepoOp> = json_ops
112 .into_iter()
113 .map(|op| RepoOp {
114 action: op.action,
115 path: op.path,
116 cid: op.cid.and_then(|s| Cid::from_str(&s).ok()),
117 prev: op.prev.and_then(|s| Cid::from_str(&s).ok()),
118 })
119 .collect();
120 let blobs: Vec<Cid> = self
121 .blobs
122 .iter()
123 .filter_map(|s| Cid::from_str(s).ok())
124 .collect();
125 let rev = placeholder_rev();
126 Ok(CommitFrame {
127 seq: self.seq,
128 rebase: false,
129 too_big: false,
130 repo: self.did,
131 commit: commit_cid,
132 rev,
133 since: self.prev_cid_str.as_ref().map(|_| placeholder_rev()),
134 blocks: Vec::new(),
135 ops,
136 blobs,
137 time: format_atproto_time(self.time),
138 prev_data: None,
139 })
140 }
141}
142
143fn placeholder_rev() -> String {
144 use jacquard::types::{integer::LimitedU32, string::Tid};
145 Tid::now(LimitedU32::MIN).to_string()
146}
147
148fn format_atproto_time(dt: chrono::DateTime<chrono::Utc>) -> String {
149 dt.format("%Y-%m-%dT%H:%M:%S%.3fZ").to_string()
150}
151
152impl TryFrom<SequencedEvent> for CommitFrame {
153 type Error = &'static str;
154
155 fn try_from(event: SequencedEvent) -> Result<Self, Self::Error> {
156 let builder = CommitFrameBuilder {
157 seq: event.seq,
158 did: event.did,
159 commit_cid_str: event.commit_cid.ok_or("Missing commit_cid in event")?,
160 prev_cid_str: event.prev_cid,
161 ops_json: event.ops.unwrap_or_default(),
162 blobs: event.blobs.unwrap_or_default(),
163 time: event.created_at,
164 };
165 builder.build()
166 }
167}