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