node: Update sync status for private repos
Only public repos were being updated on node initialization.
This commit is contained in:
parent
9f36320d83
commit
f78e5a4281
|
|
@ -102,6 +102,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
|||
head,
|
||||
doc,
|
||||
refs,
|
||||
..
|
||||
} in repos
|
||||
{
|
||||
if doc.visibility.is_public() && options.private && !options.public {
|
||||
|
|
|
|||
|
|
@ -587,11 +587,9 @@ where
|
|||
assert_ne!(time, LocalTime::default());
|
||||
|
||||
let nid = self.node_id();
|
||||
let inventory = self.storage.inventory()?;
|
||||
|
||||
self.started_at = Some(time);
|
||||
self.clock = time;
|
||||
self.inventory = gossip::inventory(self.timestamp(), inventory.clone());
|
||||
|
||||
// Populate refs database. This is only useful as part of the upgrade process for nodes
|
||||
// that have been online since before the refs database was created.
|
||||
|
|
@ -622,28 +620,25 @@ where
|
|||
)
|
||||
.expect("Service::initialize: error adding local node to address database");
|
||||
|
||||
// Ensure that our inventory is recorded in our routing table, and we are seeding
|
||||
// all of it. It can happen that inventory is not properly seeded if for eg. the
|
||||
// user creates a new repository while the node is stopped.
|
||||
self.db
|
||||
.routing_mut()
|
||||
.insert(inventory.iter(), nid, time.into())?;
|
||||
|
||||
let announced = self
|
||||
.db
|
||||
.seeds()
|
||||
.seeded_by(&nid)?
|
||||
.collect::<Result<HashMap<_, _>, _>>()?;
|
||||
for rid in inventory {
|
||||
let repo = self.storage.repository(rid)?;
|
||||
for repo in self.storage.repositories()? {
|
||||
let rid = repo.rid;
|
||||
|
||||
// If we're not seeding this repo, just skip it.
|
||||
if !self.policies.is_seeding(&rid)? {
|
||||
warn!(target: "service", "Local repository {rid} is not seeded");
|
||||
continue;
|
||||
}
|
||||
// Add public repositories to inventory.
|
||||
if repo.doc.visibility.is_public() {
|
||||
self.storage.insert(rid);
|
||||
}
|
||||
// If we have no owned refs for this repo, then there's nothing to announce.
|
||||
let Ok(updated_at) = SyncedAt::load(&repo, nid) else {
|
||||
let Some(updated_at) = repo.synced_at else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
|
@ -672,6 +667,17 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
{
|
||||
let inventory = self.storage.inventory()?;
|
||||
// Ensure that our inventory is recorded in our routing table, and we are seeding
|
||||
// all of it. It can happen that inventory is not properly seeded if for eg. the
|
||||
// user creates a new repository while the node is stopped.
|
||||
self.db
|
||||
.routing_mut()
|
||||
.insert(inventory.iter(), nid, time.into())?;
|
||||
self.inventory = gossip::inventory(self.timestamp(), inventory);
|
||||
}
|
||||
|
||||
// Setup subscription filter for seeded repos.
|
||||
self.filter = Filter::new(
|
||||
self.policies
|
||||
|
|
|
|||
|
|
@ -838,7 +838,6 @@ fn test_refs_announcement_no_subscribe() {
|
|||
|
||||
#[test]
|
||||
fn test_refs_announcement_offline() {
|
||||
logger::init(log::Level::Debug);
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let mut alice = {
|
||||
let signer = MockSigner::default();
|
||||
|
|
@ -854,10 +853,10 @@ fn test_refs_announcement_offline() {
|
|||
},
|
||||
)
|
||||
};
|
||||
let inv = alice.inventory();
|
||||
let rid = inv.first().unwrap();
|
||||
let mut inv = alice.inventory();
|
||||
let rid = *inv.first().unwrap();
|
||||
let mut bob = Peer::new("bob", [8, 8, 8, 8]);
|
||||
bob.seed(rid, policy::Scope::All).unwrap();
|
||||
bob.seed(&rid, policy::Scope::All).unwrap();
|
||||
|
||||
// Make sure alice's service wasn't initialized before.
|
||||
assert_eq!(*alice.clock(), LocalTime::default());
|
||||
|
|
@ -868,25 +867,23 @@ fn test_refs_announcement_offline() {
|
|||
|
||||
// Alice announces the refs of all projects since she hasn't announced refs for these projects
|
||||
// yet.
|
||||
let mut messages = alice.messages(bob.id());
|
||||
for i in &inv {
|
||||
let msg = messages.next();
|
||||
for msg in alice.messages(bob.id()) {
|
||||
assert_matches!(
|
||||
msg,
|
||||
Some(Message::Announcement(Announcement {
|
||||
Message::Announcement(Announcement {
|
||||
node,
|
||||
message: AnnouncementMessage::Refs(RefsAnnouncement {
|
||||
rid,
|
||||
..
|
||||
}),
|
||||
..
|
||||
}))
|
||||
if node == alice.id && rid == *i
|
||||
})
|
||||
if node == alice.id && inv.remove(&rid)
|
||||
);
|
||||
}
|
||||
|
||||
// Create an issue without telling the node.
|
||||
let repo = alice.storage().repository(*rid).unwrap();
|
||||
let repo = alice.storage().repository(rid).unwrap();
|
||||
let old_refs = RefsAt::new(&repo, alice.id).unwrap();
|
||||
let mut issues = radicle::issue::Cache::no_cache(&repo).unwrap();
|
||||
issues
|
||||
|
|
@ -935,7 +932,7 @@ fn test_refs_announcement_offline() {
|
|||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(anns.len(), 1);
|
||||
assert_eq!(anns.first().unwrap().rid, *rid);
|
||||
assert_eq!(anns.first().unwrap().rid, rid);
|
||||
assert_eq!(anns.first().unwrap().refs.first().unwrap().at, new_refs.at);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ use crate::git::{refspec::Refspec, PatternString, Qualified, RefError, RefStr, R
|
|||
use crate::identity::{Did, PayloadError};
|
||||
use crate::identity::{Doc, DocAt, DocError};
|
||||
use crate::identity::{Identity, RepoId};
|
||||
use crate::node::SyncedAt;
|
||||
use crate::storage::git::NAMESPACES_GLOB;
|
||||
use crate::storage::refs::Refs;
|
||||
|
||||
|
|
@ -42,6 +43,8 @@ pub struct RepositoryInfo<V> {
|
|||
/// Local signed refs, if any.
|
||||
/// Repositories with this set to `None` are ones that are seeded but not forked.
|
||||
pub refs: Option<refs::SignedRefsAt>,
|
||||
/// Sync time of the repository.
|
||||
pub synced_at: Option<SyncedAt>,
|
||||
}
|
||||
|
||||
/// Describes one or more namespaces.
|
||||
|
|
|
|||
|
|
@ -13,16 +13,17 @@ use once_cell::sync::Lazy;
|
|||
use tempfile::TempDir;
|
||||
|
||||
use crate::crypto::Unverified;
|
||||
use crate::git;
|
||||
use crate::identity::doc::DocError;
|
||||
use crate::identity::{doc::DocAt, Doc, RepoId};
|
||||
use crate::identity::{Identity, Project};
|
||||
use crate::node::SyncedAt;
|
||||
use crate::storage::refs;
|
||||
use crate::storage::refs::{Refs, SignedRefs, SignedRefsAt};
|
||||
use crate::storage::{
|
||||
Inventory, ReadRepository, ReadStorage, Remote, Remotes, RepositoryError, RepositoryInfo,
|
||||
SetHead, SignRepository, WriteRepository, WriteStorage,
|
||||
};
|
||||
use crate::{git, node};
|
||||
|
||||
pub use crate::git::{
|
||||
ext, raw, refname, refspec, Oid, PatternStr, Qualified, RefError, RefString, UserInfo,
|
||||
|
|
@ -152,10 +153,10 @@ impl ReadStorage for Storage {
|
|||
.lock()
|
||||
.unwrap_or_else(|poisoned| poisoned.into_inner());
|
||||
|
||||
// If the cache hasn't been populated yet, we don't do anything, since this repo
|
||||
// will be loaded when the cache is populated.
|
||||
if let Some(ref mut repos) = *repos {
|
||||
repos.insert(rid);
|
||||
} else {
|
||||
*repos = Some(BTreeSet::from_iter([rid]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -211,12 +212,17 @@ impl ReadStorage for Storage {
|
|||
};
|
||||
// Nb. This will be `None` if they were not found.
|
||||
let refs = refs::SignedRefsAt::load(self.info.key, &repo)?;
|
||||
let synced_at = refs
|
||||
.as_ref()
|
||||
.map(|r| node::SyncedAt::new(r.at, &repo))
|
||||
.transpose()?;
|
||||
|
||||
repos.push(RepositoryInfo {
|
||||
rid,
|
||||
head,
|
||||
doc,
|
||||
refs,
|
||||
synced_at,
|
||||
});
|
||||
}
|
||||
Ok(repos)
|
||||
|
|
@ -298,11 +304,17 @@ impl Storage {
|
|||
rids.try_fold(Vec::new(), |mut infos, rid| {
|
||||
let repo = self.repository(*rid)?;
|
||||
let (_, head) = repo.head()?;
|
||||
let refs = refs::SignedRefsAt::load(self.info.key, &repo)?;
|
||||
let synced_at = refs
|
||||
.as_ref()
|
||||
.map(|r| SyncedAt::new(r.at, &repo))
|
||||
.transpose()?;
|
||||
let info = RepositoryInfo {
|
||||
rid: *rid,
|
||||
head,
|
||||
doc: repo.identity_doc()?.into(),
|
||||
refs: refs::SignedRefsAt::load(self.info.key, &repo)?,
|
||||
refs,
|
||||
synced_at,
|
||||
};
|
||||
infos.push(info);
|
||||
Ok(infos)
|
||||
|
|
|
|||
|
|
@ -411,8 +411,8 @@ impl SignedRefsAt {
|
|||
where
|
||||
S: ReadRepository,
|
||||
{
|
||||
let at = match repo.reference_oid(&remote, &SIGREFS_BRANCH) {
|
||||
Ok(at) => at,
|
||||
let at = match RefsAt::new(repo, remote) {
|
||||
Ok(RefsAt { at, .. }) => at,
|
||||
Err(e) if git::is_not_found_err(&e) => return Ok(None),
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,7 +25,13 @@ pub fn user() -> git::UserInfo {
|
|||
/// Create a new storage with a project.
|
||||
pub fn storage<P: AsRef<Path>, G: Signer>(path: P, signer: &G) -> Result<Storage, rad::InitError> {
|
||||
let path = path.as_ref();
|
||||
let storage = Storage::open(path.join("storage"), user())?;
|
||||
let storage = Storage::open(
|
||||
path.join("storage"),
|
||||
git::UserInfo {
|
||||
alias: Alias::new("Radcliff"),
|
||||
key: *signer.public_key(),
|
||||
},
|
||||
)?;
|
||||
|
||||
transport::local::register(storage.clone());
|
||||
transport::remote::mock::register(signer.public_key(), storage.path());
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ impl ReadStorage for MockStorage {
|
|||
head: r.head().unwrap().1,
|
||||
doc: r.doc.clone().into(),
|
||||
refs: None,
|
||||
synced_at: None,
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue