diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2024-07-29 08:51:08 +0100 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2024-07-29 08:51:08 +0100 |
| commit | be70a0f518bb19f38ea4f1705989ec6af8b042ac (patch) | |
| tree | fcbb3615bf34fdcfb32c97efb45891d0d52b503c | |
| parent | b8867ef59589c56ae93139a9506516b52bb5f47c (diff) | |
feat(fetch): fetch state announcements
if multiple maintainers produce state events with the same
timestamp, the event with the largest event_id will be used
| -rw-r--r-- | src/client.rs | 78 |
1 files changed, 74 insertions, 4 deletions
diff --git a/src/client.rs b/src/client.rs index 5603014..6fce7a5 100644 --- a/src/client.rs +++ b/src/client.rs | |||
| @@ -788,11 +788,11 @@ pub async fn get_repo_ref_from_cache( | |||
| 788 | let mut repo_events = vec![]; | 788 | let mut repo_events = vec![]; |
| 789 | loop { | 789 | loop { |
| 790 | new_coordinate = false; | 790 | new_coordinate = false; |
| 791 | let filter = get_filter_repo_events(repo_coordinates); | 791 | let repo_events_filter = get_filter_repo_events(repo_coordinates); |
| 792 | 792 | ||
| 793 | let events = [ | 793 | let events = [ |
| 794 | get_event_from_global_cache(git_repo_path, vec![filter.clone()]).await?, | 794 | get_event_from_global_cache(git_repo_path, vec![repo_events_filter.clone()]).await?, |
| 795 | get_events_from_cache(git_repo_path, vec![filter]).await?, | 795 | get_events_from_cache(git_repo_path, vec![repo_events_filter]).await?, |
| 796 | ] | 796 | ] |
| 797 | .concat(); | 797 | .concat(); |
| 798 | for e in events { | 798 | for e in events { |
| @@ -841,6 +841,19 @@ pub async fn get_repo_ref_from_cache( | |||
| 841 | }) | 841 | }) |
| 842 | } | 842 | } |
| 843 | 843 | ||
| 844 | pub async fn get_state_from_cache( | ||
| 845 | git_repo_path: &Path, | ||
| 846 | repo_ref: &RepoRef, | ||
| 847 | ) -> Result<Option<nostr::Event>> { | ||
| 848 | let mut state_events = get_events_from_cache( | ||
| 849 | git_repo_path, | ||
| 850 | vec![get_filter_state_events(&repo_ref.coordinates())], | ||
| 851 | ) | ||
| 852 | .await?; | ||
| 853 | state_events.sort_by_key(|e| e.created_at); | ||
| 854 | Ok(state_events.first().map(std::borrow::ToOwned::to_owned)) | ||
| 855 | } | ||
| 856 | |||
| 844 | #[allow(clippy::too_many_lines)] | 857 | #[allow(clippy::too_many_lines)] |
| 845 | async fn create_relays_request( | 858 | async fn create_relays_request( |
| 846 | git_repo_path: &Path, | 859 | git_repo_path: &Path, |
| @@ -1040,7 +1053,7 @@ async fn create_relays_request( | |||
| 1040 | selected_relay: None, | 1053 | selected_relay: None, |
| 1041 | repo_relays: relays, | 1054 | repo_relays: relays, |
| 1042 | relay_column_width, | 1055 | relay_column_width, |
| 1043 | repo_coordinates_without_relays: if let Ok(repo_ref) = repo_ref { | 1056 | repo_coordinates_without_relays: if let Ok(repo_ref) = &repo_ref { |
| 1044 | repo_ref.coordinates_with_timestamps() | 1057 | repo_ref.coordinates_with_timestamps() |
| 1045 | } else { | 1058 | } else { |
| 1046 | repo_coordinates_without_relays | 1059 | repo_coordinates_without_relays |
| @@ -1048,6 +1061,15 @@ async fn create_relays_request( | |||
| 1048 | .map(|c| (c.clone(), None)) | 1061 | .map(|c| (c.clone(), None)) |
| 1049 | .collect() | 1062 | .collect() |
| 1050 | }, | 1063 | }, |
| 1064 | state: if let Ok(repo_ref) = &repo_ref { | ||
| 1065 | if let Ok(Some(existing_state)) = get_state_from_cache(git_repo_path, repo_ref).await { | ||
| 1066 | Some((existing_state.created_at, existing_state.id)) | ||
| 1067 | } else { | ||
| 1068 | None | ||
| 1069 | } | ||
| 1070 | } else { | ||
| 1071 | None | ||
| 1072 | }, | ||
| 1051 | proposals, | 1073 | proposals, |
| 1052 | contributors, | 1074 | contributors, |
| 1053 | missing_contributor_profiles, | 1075 | missing_contributor_profiles, |
| @@ -1138,6 +1160,19 @@ async fn process_fetched_events( | |||
| 1138 | } | 1160 | } |
| 1139 | } | 1161 | } |
| 1140 | } | 1162 | } |
| 1163 | } else if event.kind().eq(&STATE_KIND) { | ||
| 1164 | let existing_state = if report.updated_state.is_some() { | ||
| 1165 | report.updated_state | ||
| 1166 | } else { | ||
| 1167 | request.state | ||
| 1168 | }; | ||
| 1169 | if let Some((timestamp, id)) = existing_state { | ||
| 1170 | if event.created_at.gt(×tamp) | ||
| 1171 | || (event.created_at.eq(×tamp) && event.id.gt(&id)) | ||
| 1172 | { | ||
| 1173 | report.updated_state = Some((event.created_at, event.id)); | ||
| 1174 | } | ||
| 1175 | } | ||
| 1141 | } else if event_is_patch_set_root(event) { | 1176 | } else if event_is_patch_set_root(event) { |
| 1142 | fresh_proposal_roots.insert(event.id); | 1177 | fresh_proposal_roots.insert(event.id); |
| 1143 | report.proposals.insert(event.id); | 1178 | report.proposals.insert(event.id); |
| @@ -1208,6 +1243,17 @@ pub fn consolidate_fetch_reports(reports: Vec<Result<FetchReport>>) -> FetchRepo | |||
| 1208 | report.updated_repo_announcements.push((r, t)); | 1243 | report.updated_repo_announcements.push((r, t)); |
| 1209 | } | 1244 | } |
| 1210 | } | 1245 | } |
| 1246 | if let Some((timestamp, id)) = relay_report.updated_state { | ||
| 1247 | if let Some((existing_timestamp, existing_id)) = report.updated_state { | ||
| 1248 | if timestamp.gt(&existing_timestamp) | ||
| 1249 | || (timestamp.eq(&existing_timestamp) && id.gt(&existing_id)) | ||
| 1250 | { | ||
| 1251 | report.updated_state = Some((timestamp, id)); | ||
| 1252 | } | ||
| 1253 | } else { | ||
| 1254 | report.updated_state = Some((timestamp, id)); | ||
| 1255 | } | ||
| 1256 | } | ||
| 1211 | for c in relay_report.proposals { | 1257 | for c in relay_report.proposals { |
| 1212 | report.proposals.insert(c); | 1258 | report.proposals.insert(c); |
| 1213 | } | 1259 | } |
| @@ -1236,6 +1282,7 @@ pub fn get_fetch_filters( | |||
| 1236 | vec![] | 1282 | vec![] |
| 1237 | } else { | 1283 | } else { |
| 1238 | vec![ | 1284 | vec![ |
| 1285 | get_filter_state_events(repo_coordinates), | ||
| 1239 | get_filter_repo_events(repo_coordinates), | 1286 | get_filter_repo_events(repo_coordinates), |
| 1240 | nostr::Filter::default() | 1287 | nostr::Filter::default() |
| 1241 | .kinds(vec![Kind::GitPatch, Kind::EventDeletion]) | 1288 | .kinds(vec![Kind::GitPatch, Kind::EventDeletion]) |
| @@ -1283,6 +1330,24 @@ pub fn get_filter_repo_events(repo_coordinates: &HashSet<Coordinate>) -> nostr:: | |||
| 1283 | ) | 1330 | ) |
| 1284 | } | 1331 | } |
| 1285 | 1332 | ||
| 1333 | pub static STATE_KIND: nostr::Kind = Kind::Custom(30618); | ||
| 1334 | pub fn get_filter_state_events(repo_coordinates: &HashSet<Coordinate>) -> nostr::Filter { | ||
| 1335 | nostr::Filter::default() | ||
| 1336 | .kind(STATE_KIND) | ||
| 1337 | .identifiers( | ||
| 1338 | repo_coordinates | ||
| 1339 | .iter() | ||
| 1340 | .map(|c| c.identifier.clone()) | ||
| 1341 | .collect::<Vec<String>>(), | ||
| 1342 | ) | ||
| 1343 | .authors( | ||
| 1344 | repo_coordinates | ||
| 1345 | .iter() | ||
| 1346 | .map(|c| c.public_key) | ||
| 1347 | .collect::<Vec<PublicKey>>(), | ||
| 1348 | ) | ||
| 1349 | } | ||
| 1350 | |||
| 1286 | pub fn get_filter_contributor_profiles(contributors: HashSet<PublicKey>) -> nostr::Filter { | 1351 | pub fn get_filter_contributor_profiles(contributors: HashSet<PublicKey>) -> nostr::Filter { |
| 1287 | nostr::Filter::default() | 1352 | nostr::Filter::default() |
| 1288 | .kinds(vec![Kind::Metadata, Kind::RelayList]) | 1353 | .kinds(vec![Kind::Metadata, Kind::RelayList]) |
| @@ -1293,6 +1358,7 @@ pub fn get_filter_contributor_profiles(contributors: HashSet<PublicKey>) -> nost | |||
| 1293 | pub struct FetchReport { | 1358 | pub struct FetchReport { |
| 1294 | repo_coordinates_without_relays: HashSet<Coordinate>, | 1359 | repo_coordinates_without_relays: HashSet<Coordinate>, |
| 1295 | updated_repo_announcements: Vec<(Coordinate, Timestamp)>, | 1360 | updated_repo_announcements: Vec<(Coordinate, Timestamp)>, |
| 1361 | updated_state: Option<(Timestamp, EventId)>, | ||
| 1296 | proposals: HashSet<EventId>, | 1362 | proposals: HashSet<EventId>, |
| 1297 | /// commits against existing propoals | 1363 | /// commits against existing propoals |
| 1298 | commits: HashSet<EventId>, | 1364 | commits: HashSet<EventId>, |
| @@ -1327,6 +1393,9 @@ impl Display for FetchReport { | |||
| 1327 | }, | 1393 | }, |
| 1328 | )); | 1394 | )); |
| 1329 | } | 1395 | } |
| 1396 | if self.updated_state.is_some() { | ||
| 1397 | display_items.push("new state".to_string()); | ||
| 1398 | } | ||
| 1330 | if !self.proposals.is_empty() { | 1399 | if !self.proposals.is_empty() { |
| 1331 | display_items.push(format!( | 1400 | display_items.push(format!( |
| 1332 | "{} proposal{}", | 1401 | "{} proposal{}", |
| @@ -1380,6 +1449,7 @@ pub struct FetchRequest { | |||
| 1380 | selected_relay: Option<Url>, | 1449 | selected_relay: Option<Url>, |
| 1381 | relay_column_width: usize, | 1450 | relay_column_width: usize, |
| 1382 | repo_coordinates_without_relays: Vec<(Coordinate, Option<Timestamp>)>, | 1451 | repo_coordinates_without_relays: Vec<(Coordinate, Option<Timestamp>)>, |
| 1452 | state: Option<(Timestamp, EventId)>, | ||
| 1383 | proposals: HashSet<EventId>, | 1453 | proposals: HashSet<EventId>, |
| 1384 | contributors: HashSet<PublicKey>, | 1454 | contributors: HashSet<PublicKey>, |
| 1385 | missing_contributor_profiles: HashSet<PublicKey>, | 1455 | missing_contributor_profiles: HashSet<PublicKey>, |