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 77pub struct CommitFrameBuilder { 78 pub seq: i64, 79 pub did: String, 80 pub commit_cid_str: String, 81 pub prev_cid_str: Option<String>, 82 pub ops_json: serde_json::Value, 83 pub blobs: Vec<String>, 84 pub time: chrono::DateTime<chrono::Utc>, 85} 86 87impl CommitFrameBuilder { 88 pub fn build(self) -> Result<CommitFrame, &'static str> { 89 let commit_cid = Cid::from_str(&self.commit_cid_str).map_err(|_| "Invalid commit CID")?; 90 let json_ops: Vec<JsonRepoOp> = 91 serde_json::from_value(self.ops_json).unwrap_or_else(|_| vec![]); 92 let ops: Vec<RepoOp> = json_ops 93 .into_iter() 94 .map(|op| RepoOp { 95 action: op.action, 96 path: op.path, 97 cid: op.cid.and_then(|s| Cid::from_str(&s).ok()), 98 prev: op.prev.and_then(|s| Cid::from_str(&s).ok()), 99 }) 100 .collect(); 101 let blobs: Vec<Cid> = self 102 .blobs 103 .iter() 104 .filter_map(|s| Cid::from_str(s).ok()) 105 .collect(); 106 let rev = placeholder_rev(); 107 Ok(CommitFrame { 108 seq: self.seq, 109 rebase: false, 110 too_big: false, 111 repo: self.did, 112 commit: commit_cid, 113 rev, 114 since: self.prev_cid_str.as_ref().map(|_| placeholder_rev()), 115 blocks: Vec::new(), 116 ops, 117 blobs, 118 time: format_atproto_time(self.time), 119 prev_data: None, 120 }) 121 } 122} 123 124fn placeholder_rev() -> String { 125 use jacquard::types::{integer::LimitedU32, string::Tid}; 126 Tid::now(LimitedU32::MIN).to_string() 127} 128 129fn format_atproto_time(dt: chrono::DateTime<chrono::Utc>) -> String { 130 dt.format("%Y-%m-%dT%H:%M:%S%.3fZ").to_string() 131} 132 133impl TryFrom<SequencedEvent> for CommitFrame { 134 type Error = &'static str; 135 136 fn try_from(event: SequencedEvent) -> Result<Self, Self::Error> { 137 let builder = CommitFrameBuilder { 138 seq: event.seq, 139 did: event.did, 140 commit_cid_str: event.commit_cid.ok_or("Missing commit_cid in event")?, 141 prev_cid_str: event.prev_cid, 142 ops_json: event.ops.unwrap_or_default(), 143 blobs: event.blobs.unwrap_or_default(), 144 time: event.created_at, 145 }; 146 builder.build() 147 } 148}