this repo has no description
1use cid::Cid; 2use serde::{Deserialize, Serialize}; 3use std::str::FromStr; 4use crate::sync::firehose::SequencedEvent; 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) 90 .map_err(|_| "Invalid commit CID")?; 91 let json_ops: Vec<JsonRepoOp> = serde_json::from_value(self.ops_json) 92 .unwrap_or_else(|_| vec![]); 93 let ops: Vec<RepoOp> = json_ops.into_iter().map(|op| { 94 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.blobs.iter() 102 .filter_map(|s| Cid::from_str(s).ok()) 103 .collect(); 104 let rev = placeholder_rev(); 105 Ok(CommitFrame { 106 seq: self.seq, 107 rebase: false, 108 too_big: false, 109 repo: self.did, 110 commit: commit_cid, 111 rev, 112 since: self.prev_cid_str.as_ref().map(|_| placeholder_rev()), 113 blocks: Vec::new(), 114 ops, 115 blobs, 116 time: format_atproto_time(self.time), 117 prev_data: None, 118 }) 119 } 120} 121 122fn placeholder_rev() -> String { 123 use jacquard::types::{integer::LimitedU32, string::Tid}; 124 Tid::now(LimitedU32::MIN).to_string() 125} 126 127fn format_atproto_time(dt: chrono::DateTime<chrono::Utc>) -> String { 128 dt.format("%Y-%m-%dT%H:%M:%S%.3fZ").to_string() 129} 130 131impl TryFrom<SequencedEvent> for CommitFrame { 132 type Error = &'static str; 133 134 fn try_from(event: SequencedEvent) -> Result<Self, Self::Error> { 135 let builder = CommitFrameBuilder { 136 seq: event.seq, 137 did: event.did, 138 commit_cid_str: event.commit_cid.ok_or("Missing commit_cid in event")?, 139 prev_cid_str: event.prev_cid, 140 ops_json: event.ops.unwrap_or_default(), 141 blobs: event.blobs.unwrap_or_default(), 142 time: event.created_at, 143 }; 144 builder.build() 145 } 146}