Skip to content

Commit a125d37

Browse files
committed
replication: adopt rad/self
Before this patch a `rad/self` would be replicated, however, there would be no corresponding `rad/id` at the top-level. This patch introduces the adding of the `rad/id` and creating a symbolic ref between `rad/id` and `rad/self` for each tracked peer. Signed-off-by: Fintan Halpenny <[email protected]>
1 parent be59768 commit a125d37

File tree

2 files changed

+91
-14
lines changed

2 files changed

+91
-14
lines changed

librad/src/git/replication.rs

+42-14
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use super::{
2020
refs::{self, Refs},
2121
storage::{self, Storage},
2222
tracking,
23-
types::{reference, Force, Namespace, Reference},
23+
types::{reference, Force, Namespace, One, Reference},
2424
};
2525
use crate::{
2626
identities::git::{Person, Project, Revision, SomeIdentity, VerifiedPerson, VerifiedProject},
@@ -429,6 +429,40 @@ fn ensure_rad_id(storage: &Storage, urn: &Urn, tip: ext::Oid) -> Result<ext::Oid
429429
.map_err(|e| Error::Store(e.into()))
430430
}
431431

432+
fn adopt_rad_self(storage: &Storage, urn: &Urn, peer: PeerId) -> Result<(), Error> {
433+
let rad_self = Reference::rad_self(Namespace::from(urn), peer);
434+
435+
// We only need to crate the rad/id there's a rad/self
436+
if storage.has_ref(&rad_self)? {
437+
if let Some(person) =
438+
identities::person::verify(storage, &unsafe_into_urn(rad_self.clone()))?
439+
{
440+
let rad_id = unsafe_into_urn(Reference::rad_id(Namespace::from(person.urn())));
441+
if !storage.has_urn(&person.urn())? {
442+
ensure_rad_id(storage, &rad_id, person.content_id)?;
443+
symref(storage, &rad_id, rad_self)?;
444+
tracking::track(storage, &rad_id, peer)?;
445+
}
446+
}
447+
}
448+
449+
Ok(())
450+
}
451+
452+
fn symref(storage: &Storage, top_level: &Urn, symbolic: Reference<One>) -> Result<(), Error> {
453+
// Now point our view to the top-level
454+
Reference::try_from(top_level)
455+
.map_err(|e| Error::RefFromUrn {
456+
urn: top_level.clone(),
457+
source: e,
458+
})?
459+
.symbolic_ref::<_, PeerId>(symbolic, Force::False)
460+
.create(storage.as_raw())
461+
.and(Ok(()))
462+
.or_matches(is_exists_err, || Ok(()))
463+
.map_err(|e: git2::Error| Error::Store(e.into()))
464+
}
465+
432466
/// Untrack the list of `PeerId`s, which also has the side-effect of removing
433467
/// that peer's remote references in the storage.
434468
///
@@ -534,6 +568,7 @@ mod person {
534568
for peer_id in delegations.iter() {
535569
if peer_id != local_peer {
536570
tracking::track(storage, &urn, *peer_id)?;
571+
adopt_rad_self(storage, &urn, *peer_id)?;
537572
}
538573
}
539574

@@ -651,6 +686,7 @@ mod project {
651686
for peer in tracked {
652687
if peer != *local_peer {
653688
tracking::track(&storage, &urn, peer)?;
689+
adopt_rad_self(storage, &urn, peer)?;
654690
}
655691
}
656692

@@ -779,19 +815,11 @@ mod project {
779815
tracking::track(storage, &project_urn, peer)?;
780816

781817
// Now point our view to the top-level
782-
Reference::try_from(&delegate_urn)
783-
.map_err(|e| Error::RefFromUrn {
784-
urn: delegate_urn.clone(),
785-
source: e,
786-
})?
787-
.symbolic_ref::<_, PeerId>(
788-
Reference::rad_delegate(Namespace::from(project_urn), &delegate_urn),
789-
Force::False,
790-
)
791-
.create(storage.as_raw())
792-
.and(Ok(()))
793-
.or_matches(is_exists_err, || Ok(()))
794-
.map_err(|e: git2::Error| Error::Store(e.into()))
818+
symref(
819+
storage,
820+
&delegate_urn,
821+
Reference::rad_delegate(Namespace::from(project_urn), &delegate_urn),
822+
)
795823
}
796824

797825
/// Track all direct delegations of a `Project`.

test/src/test/integration/daemon/replication.rs

+49
Original file line numberDiff line numberDiff line change
@@ -466,3 +466,52 @@ fn track_peer() -> Result<(), anyhow::Error> {
466466
Ok(())
467467
})
468468
}
469+
470+
#[test]
471+
fn replication_includes_user() -> Result<(), anyhow::Error> {
472+
logging::init();
473+
474+
let mut harness = Harness::new();
475+
let alice = harness.add_peer("alice", RunConfig::default(), &[])?;
476+
let bob = harness.add_peer(
477+
"bob",
478+
RunConfig::default(),
479+
&[Seed {
480+
addrs: alice.listen_addrs.clone(),
481+
peer_id: alice.peer_id,
482+
}],
483+
)?;
484+
harness.enter(async move {
485+
let project = state::init_project(
486+
&alice.peer,
487+
&alice.owner,
488+
shia_le_pathbuf(alice.path.join("radicle")),
489+
)
490+
.await?;
491+
492+
state::clone_project(
493+
&bob.peer,
494+
project.urn(),
495+
alice.peer_id,
496+
alice.listen_addrs.clone(),
497+
None,
498+
)
499+
.await?;
500+
501+
state::track(&alice.peer, project.urn(), bob.peer_id).await?;
502+
state::fetch(
503+
&alice.peer,
504+
project.urn(),
505+
bob.peer_id,
506+
bob.listen_addrs.clone(),
507+
None,
508+
)
509+
.await?;
510+
511+
let bob_malkovich = state::get_user(&alice.peer, bob.owner.urn()).await?;
512+
513+
assert_eq!(bob_malkovich, Some(bob.owner.into_inner().into_inner()));
514+
515+
Ok(())
516+
})
517+
}

0 commit comments

Comments
 (0)