node: Rename `ProjId` -> `Id`

Remove `UserId` type.

Signed-off-by: Alexis Sellier <self@cloudhead.io>
This commit is contained in:
Alexis Sellier 2022-09-07 14:43:21 +02:00
parent c80ba01ed9
commit 927f062dc9
No known key found for this signature in database
16 changed files with 146 additions and 139 deletions

View File

@ -4,7 +4,7 @@ use crossbeam_channel as chan;
use nakamoto_net::Waker; use nakamoto_net::Waker;
use thiserror::Error; use thiserror::Error;
use crate::identity::ProjId; use crate::identity::Id;
use crate::protocol; use crate::protocol;
use crate::protocol::{CommandError, FetchLookup}; use crate::protocol::{CommandError, FetchLookup};
@ -55,28 +55,28 @@ pub struct Handle<W: Waker> {
impl<W: Waker> traits::Handle for Handle<W> { impl<W: Waker> traits::Handle for Handle<W> {
/// Retrieve or update the given project from the network. /// Retrieve or update the given project from the network.
fn fetch(&self, id: ProjId) -> Result<FetchLookup, Error> { fn fetch(&self, id: Id) -> Result<FetchLookup, Error> {
let (sender, receiver) = chan::bounded(1); let (sender, receiver) = chan::bounded(1);
self.commands.send(protocol::Command::Fetch(id, sender))?; self.commands.send(protocol::Command::Fetch(id, sender))?;
receiver.recv().map_err(Error::from) receiver.recv().map_err(Error::from)
} }
/// Start tracking the given project. Doesn't do anything if the project is already tracked. /// Start tracking the given project. Doesn't do anything if the project is already tracked.
fn track(&self, id: ProjId) -> Result<bool, Error> { fn track(&self, id: Id) -> Result<bool, Error> {
let (sender, receiver) = chan::bounded(1); let (sender, receiver) = chan::bounded(1);
self.commands.send(protocol::Command::Track(id, sender))?; self.commands.send(protocol::Command::Track(id, sender))?;
receiver.recv().map_err(Error::from) receiver.recv().map_err(Error::from)
} }
/// Untrack the given project and delete it from storage. /// Untrack the given project and delete it from storage.
fn untrack(&self, id: ProjId) -> Result<bool, Error> { fn untrack(&self, id: Id) -> Result<bool, Error> {
let (sender, receiver) = chan::bounded(1); let (sender, receiver) = chan::bounded(1);
self.commands.send(protocol::Command::Untrack(id, sender))?; self.commands.send(protocol::Command::Untrack(id, sender))?;
receiver.recv().map_err(Error::from) receiver.recv().map_err(Error::from)
} }
/// Notify the client that a project has been updated. /// Notify the client that a project has been updated.
fn updated(&self, id: ProjId) -> Result<(), Error> { fn updated(&self, id: Id) -> Result<(), Error> {
self.command(protocol::Command::AnnounceRefsUpdate(id)) self.command(protocol::Command::AnnounceRefsUpdate(id))
} }
@ -102,14 +102,14 @@ pub mod traits {
pub trait Handle { pub trait Handle {
/// Retrieve or update the project from network. /// Retrieve or update the project from network.
fn fetch(&self, id: ProjId) -> Result<FetchLookup, Error>; fn fetch(&self, id: Id) -> Result<FetchLookup, Error>;
/// Start tracking the given project. Doesn't do anything if the project is already /// Start tracking the given project. Doesn't do anything if the project is already
/// tracked. /// tracked.
fn track(&self, id: ProjId) -> Result<bool, Error>; fn track(&self, id: Id) -> Result<bool, Error>;
/// Untrack the given project and delete it from storage. /// Untrack the given project and delete it from storage.
fn untrack(&self, id: ProjId) -> Result<bool, Error>; fn untrack(&self, id: Id) -> Result<bool, Error>;
/// Notify the client that a project has been updated. /// Notify the client that a project has been updated.
fn updated(&self, id: ProjId) -> Result<(), Error>; fn updated(&self, id: Id) -> Result<(), Error>;
/// Send a command to the command channel, and wake up the event loop. /// Send a command to the command channel, and wake up the event loop.
fn command(&self, cmd: protocol::Command) -> Result<(), Error>; fn command(&self, cmd: protocol::Command) -> Result<(), Error>;
/// Ask the client to shutdown. /// Ask the client to shutdown.

View File

@ -9,7 +9,7 @@ use std::{fs, io, net};
use crate::client; use crate::client;
use crate::client::handle::traits::Handle; use crate::client::handle::traits::Handle;
use crate::identity::ProjId; use crate::identity::Id;
use crate::protocol::FetchLookup; use crate::protocol::FetchLookup;
use crate::protocol::FetchResult; use crate::protocol::FetchResult;
@ -110,7 +110,7 @@ fn drain<H: Handle>(stream: &UnixStream, handle: &H) -> Result<(), DrainError> {
Ok(()) Ok(())
} }
fn fetch<W: Write, H: Handle>(id: ProjId, mut writer: W, handle: &H) -> Result<(), DrainError> { fn fetch<W: Write, H: Handle>(id: Id, mut writer: W, handle: &H) -> Result<(), DrainError> {
match handle.fetch(id.clone()) { match handle.fetch(id.clone()) {
Err(e) => { Err(e) => {
return Err(DrainError::Client(e)); return Err(DrainError::Client(e));
@ -161,7 +161,7 @@ mod tests {
use std::{net, thread}; use std::{net, thread};
use super::*; use super::*;
use crate::identity::ProjId; use crate::identity::Id;
use crate::test; use crate::test;
#[test] #[test]
@ -169,7 +169,7 @@ mod tests {
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let handle = test::handle::Handle::default(); let handle = test::handle::Handle::default();
let socket = tmp.path().join("alice.sock"); let socket = tmp.path().join("alice.sock");
let projs = test::arbitrary::set::<ProjId>(1..3); let projs = test::arbitrary::set::<Id>(1..3);
thread::spawn({ thread::spawn({
let socket = socket.clone(); let socket = socket.clone();

View File

@ -4,7 +4,7 @@ use std::str::FromStr;
use git_ref_format as format; use git_ref_format as format;
use crate::collections::HashMap; use crate::collections::HashMap;
use crate::identity::UserId; use crate::identity::PublicKey;
use crate::storage::refs::Refs; use crate::storage::refs::Refs;
use crate::storage::RemoteId; use crate::storage::RemoteId;
@ -43,7 +43,7 @@ pub fn remote_refs(url: &Url) -> Result<HashMap<RemoteId, Refs>, ListRefsError>
let refs = remote.list()?; let refs = remote.list()?;
for r in refs { for r in refs {
let (id, refname) = parse_ref::<UserId>(r.name())?; let (id, refname) = parse_ref::<PublicKey>(r.name())?;
let entry = remotes.entry(id).or_insert_with(Refs::default); let entry = remotes.entry(id).or_insert_with(Refs::default);
entry.insert(refname, r.oid().into()); entry.insert(refname, r.oid().into());

View File

@ -12,48 +12,47 @@ use crate::hash;
use crate::serde_ext; use crate::serde_ext;
use crate::storage::Remotes; use crate::storage::Remotes;
pub use crypto::PublicKey;
pub static IDENTITY_PATH: Lazy<&Path> = Lazy::new(|| Path::new("radicle.json")); pub static IDENTITY_PATH: Lazy<&Path> = Lazy::new(|| Path::new("radicle.json"));
/// A user's identifier is simply their public key.
pub type UserId = crypto::PublicKey;
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum ProjIdError { pub enum IdError {
#[error("invalid digest: {0}")] #[error("invalid digest: {0}")]
InvalidDigest(#[from] hash::DecodeError), InvalidDigest(#[from] hash::DecodeError),
} }
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ProjId(hash::Digest); pub struct Id(hash::Digest);
impl fmt::Display for ProjId { impl fmt::Display for Id {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.encode()) write!(f, "{}", self.encode())
} }
} }
impl fmt::Debug for ProjId { impl fmt::Debug for Id {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ProjId({})", self.encode()) write!(f, "ProjId({})", self.encode())
} }
} }
impl ProjId { impl Id {
pub fn encode(&self) -> String { pub fn encode(&self) -> String {
multibase::encode(multibase::Base::Base58Btc, &self.0.as_ref()) multibase::encode(multibase::Base::Base58Btc, &self.0.as_ref())
} }
} }
impl FromStr for ProjId { impl FromStr for Id {
type Err = ProjIdError; type Err = IdError;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(hash::Digest::from_str(s)?)) Ok(Self(hash::Digest::from_str(s)?))
} }
} }
impl TryFrom<OsString> for ProjId { impl TryFrom<OsString> for Id {
type Error = ProjIdError; type Error = IdError;
fn try_from(value: OsString) -> Result<Self, Self::Error> { fn try_from(value: OsString) -> Result<Self, Self::Error> {
let string = value.to_string_lossy(); let string = value.to_string_lossy();
@ -61,13 +60,13 @@ impl TryFrom<OsString> for ProjId {
} }
} }
impl From<hash::Digest> for ProjId { impl From<hash::Digest> for Id {
fn from(digest: hash::Digest) -> Self { fn from(digest: hash::Digest) -> Self {
Self(digest) Self(digest)
} }
} }
impl serde::Serialize for ProjId { impl serde::Serialize for Id {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
S: serde::Serializer, S: serde::Serializer,
@ -76,7 +75,7 @@ impl serde::Serialize for ProjId {
} }
} }
impl<'de> serde::Deserialize<'de> for ProjId { impl<'de> serde::Deserialize<'de> for Id {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: serde::Deserializer<'de>, D: serde::Deserializer<'de>,
@ -143,7 +142,7 @@ impl fmt::Display for Did {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Project { pub struct Project {
/// The project identifier. /// The project identifier.
pub id: ProjId, pub id: Id,
/// The latest project identity document. /// The latest project identity document.
pub doc: Doc, pub doc: Doc,
/// The project remotes. /// The project remotes.
@ -177,7 +176,7 @@ pub struct Doc {
} }
impl Doc { impl Doc {
pub fn write<W: io::Write>(&self, mut writer: W) -> Result<ProjId, DocError> { pub fn write<W: io::Write>(&self, mut writer: W) -> Result<Id, DocError> {
let mut buf = Vec::new(); let mut buf = Vec::new();
let mut ser = let mut ser =
serde_json::Serializer::with_formatter(&mut buf, olpc_cjson::CanonicalFormatter::new()); serde_json::Serializer::with_formatter(&mut buf, olpc_cjson::CanonicalFormatter::new());
@ -185,7 +184,7 @@ impl Doc {
self.serialize(&mut ser)?; self.serialize(&mut ser)?;
let digest = hash::Digest::new(&buf); let digest = hash::Digest::new(&buf);
let id = ProjId::from(digest); let id = Id::from(digest);
// TODO: Currently, we serialize the document in canonical JSON. This isn't strictly // TODO: Currently, we serialize the document in canonical JSON. This isn't strictly
// necessary, as we could use CJSON just to get the hash, but then write a prettified // necessary, as we could use CJSON just to get the hash, but then write a prettified
@ -203,11 +202,12 @@ impl Doc {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use crate::crypto::PublicKey;
use quickcheck_macros::quickcheck; use quickcheck_macros::quickcheck;
use std::collections::HashSet; use std::collections::HashSet;
#[quickcheck] #[quickcheck]
fn prop_user_id_equality(a: UserId, b: UserId) { fn prop_key_equality(a: PublicKey, b: PublicKey) {
assert_ne!(a, b); assert_ne!(a, b);
let mut hm = HashSet::new(); let mut hm = HashSet::new();
@ -219,17 +219,17 @@ mod test {
} }
#[quickcheck] #[quickcheck]
fn prop_encode_decode(input: UserId) { fn prop_encode_decode(input: PublicKey) {
let encoded = input.to_string(); let encoded = input.to_string();
let decoded = UserId::from_str(&encoded).unwrap(); let decoded = PublicKey::from_str(&encoded).unwrap();
assert_eq!(input, decoded); assert_eq!(input, decoded);
} }
#[quickcheck] #[quickcheck]
fn prop_json_eq_str(user: UserId, proj: ProjId, did: Did) { fn prop_json_eq_str(pk: PublicKey, proj: Id, did: Did) {
let json = serde_json::to_string(&user).unwrap(); let json = serde_json::to_string(&pk).unwrap();
assert_eq!(format!("\"{}\"", user), json); assert_eq!(format!("\"{}\"", pk), json);
let json = serde_json::to_string(&proj).unwrap(); let json = serde_json::to_string(&proj).unwrap();
assert_eq!(format!("\"{}\"", proj), json); assert_eq!(format!("\"{}\"", proj), json);

View File

@ -21,7 +21,7 @@ use crate::address_manager::AddressManager;
use crate::clock::RefClock; use crate::clock::RefClock;
use crate::collections::{HashMap, HashSet}; use crate::collections::{HashMap, HashSet};
use crate::crypto; use crate::crypto;
use crate::identity::{ProjId, Project, UserId}; use crate::identity::{Id, Project, PublicKey};
use crate::protocol::config::ProjectTracking; use crate::protocol::config::ProjectTracking;
use crate::protocol::message::Message; use crate::protocol::message::Message;
use crate::protocol::peer::{Peer, PeerError, PeerState}; use crate::protocol::peer::{Peer, PeerError, PeerState};
@ -43,7 +43,7 @@ pub const MAX_TIME_DELTA: LocalDuration = LocalDuration::from_mins(60);
/// Network node identifier. /// Network node identifier.
pub type NodeId = crypto::PublicKey; pub type NodeId = crypto::PublicKey;
/// Network routing table. Keeps track of where projects are hosted. /// Network routing table. Keeps track of where projects are hosted.
pub type Routing = HashMap<ProjId, HashSet<NodeId>>; pub type Routing = HashMap<Id, HashSet<NodeId>>;
/// Seconds since epoch. /// Seconds since epoch.
pub type Timestamp = u64; pub type Timestamp = u64;
@ -91,11 +91,11 @@ pub enum FetchResult {
/// Commands sent to the protocol by the operator. /// Commands sent to the protocol by the operator.
#[derive(Debug)] #[derive(Debug)]
pub enum Command { pub enum Command {
AnnounceRefsUpdate(ProjId), AnnounceRefsUpdate(Id),
Connect(net::SocketAddr), Connect(net::SocketAddr),
Fetch(ProjId, chan::Sender<FetchLookup>), Fetch(Id, chan::Sender<FetchLookup>),
Track(ProjId, chan::Sender<bool>), Track(Id, chan::Sender<bool>),
Untrack(ProjId, chan::Sender<bool>), Untrack(Id, chan::Sender<bool>),
} }
/// Command-related errors. /// Command-related errors.
@ -151,8 +151,8 @@ impl<'r, T: WriteStorage<'r>, S: address_book::Store, G: crypto::Signer> Protoco
} }
} }
pub fn seeds(&self, proj: &ProjId) -> Box<dyn Iterator<Item = (&NodeId, &Peer)> + '_> { pub fn seeds(&self, id: &Id) -> Box<dyn Iterator<Item = (&NodeId, &Peer)> + '_> {
if let Some(peers) = self.routing.get(proj) { if let Some(peers) = self.routing.get(id) {
Box::new( Box::new(
peers peers
.iter() .iter()
@ -163,7 +163,7 @@ impl<'r, T: WriteStorage<'r>, S: address_book::Store, G: crypto::Signer> Protoco
} }
} }
pub fn tracked(&self) -> Result<Vec<ProjId>, storage::Error> { pub fn tracked(&self) -> Result<Vec<Id>, storage::Error> {
let tracked = match &self.config.project_tracking { let tracked = match &self.config.project_tracking {
ProjectTracking::All { blocked } => self ProjectTracking::All { blocked } => self
.storage .storage
@ -180,8 +180,8 @@ impl<'r, T: WriteStorage<'r>, S: address_book::Store, G: crypto::Signer> Protoco
/// Track a project. /// Track a project.
/// Returns whether or not the tracking policy was updated. /// Returns whether or not the tracking policy was updated.
pub fn track(&mut self, proj: ProjId) -> bool { pub fn track(&mut self, id: Id) -> bool {
self.out_of_sync = self.config.track(proj); self.out_of_sync = self.config.track(id);
self.out_of_sync self.out_of_sync
} }
@ -189,8 +189,8 @@ impl<'r, T: WriteStorage<'r>, S: address_book::Store, G: crypto::Signer> Protoco
/// Returns whether or not the tracking policy was updated. /// Returns whether or not the tracking policy was updated.
/// Note that when untracking, we don't announce anything to the network. This is because by /// Note that when untracking, we don't announce anything to the network. This is because by
/// simply not announcing it anymore, it will eventually be pruned by nodes. /// simply not announcing it anymore, it will eventually be pruned by nodes.
pub fn untrack(&mut self, proj: ProjId) -> bool { pub fn untrack(&mut self, id: Id) -> bool {
self.config.untrack(proj) self.config.untrack(id)
} }
/// Find the closest `n` peers by proximity in tracking graphs. /// Find the closest `n` peers by proximity in tracking graphs.
@ -236,13 +236,13 @@ impl<'r, T: WriteStorage<'r>, S: address_book::Store, G: crypto::Signer> Protoco
&mut self.context.io &mut self.context.io
} }
pub fn lookup(&self, proj: &ProjId) -> Lookup { pub fn lookup(&self, id: &Id) -> Lookup {
Lookup { Lookup {
local: self.context.storage.get(proj).unwrap(), local: self.context.storage.get(id).unwrap(),
remote: self remote: self
.context .context
.routing .routing
.get(proj) .get(id)
.map_or(vec![], |r| r.iter().cloned().collect()), .map_or(vec![], |r| r.iter().cloned().collect()),
} }
} }
@ -263,13 +263,13 @@ impl<'r, T: WriteStorage<'r>, S: address_book::Store, G: crypto::Signer> Protoco
fn get_inventories(&mut self) -> Result<(), storage::Error> { fn get_inventories(&mut self) -> Result<(), storage::Error> {
let mut msgs = Vec::new(); let mut msgs = Vec::new();
for proj in self.tracked()? { for id in self.tracked()? {
for (_, peer) in self.seeds(&proj) { for (_, peer) in self.seeds(&id) {
if peer.is_negotiated() { if peer.is_negotiated() {
msgs.push(( msgs.push((
peer.addr, peer.addr,
Message::GetInventory { Message::GetInventory {
ids: vec![proj.clone()], ids: vec![id.clone()],
}, },
)); ));
} }
@ -366,27 +366,27 @@ where
match cmd { match cmd {
Command::Connect(addr) => self.context.connect(addr), Command::Connect(addr) => self.context.connect(addr),
Command::Fetch(proj, resp) => { Command::Fetch(id, resp) => {
if !self.config.is_tracking(&proj) { if !self.config.is_tracking(&id) {
resp.send(FetchLookup::NotTracking).ok(); resp.send(FetchLookup::NotTracking).ok();
return; return;
} }
let seeds = self.seeds(&proj).collect::<Vec<_>>(); let seeds = self.seeds(&id).collect::<Vec<_>>();
let seeds = if let Some(seeds) = NonEmpty::from_vec(seeds) { let seeds = if let Some(seeds) = NonEmpty::from_vec(seeds) {
seeds seeds
} else { } else {
log::error!("No seeds found for {}", proj); log::error!("No seeds found for {}", id);
resp.send(FetchLookup::NotFound).ok(); resp.send(FetchLookup::NotFound).ok();
return; return;
}; };
log::debug!("Found {} seeds for {}", seeds.len(), proj); log::debug!("Found {} seeds for {}", seeds.len(), id);
let mut repo = match self.storage.repository(&proj) { let mut repo = match self.storage.repository(&id) {
Ok(repo) => repo, Ok(repo) => repo,
Err(err) => { Err(err) => {
log::error!("Error opening repo for {}: {}", proj, err); log::error!("Error opening repo for {}: {}", id, err);
resp.send(FetchLookup::Error(err.into())).ok(); resp.send(FetchLookup::Error(err.into())).ok();
return; return;
@ -407,7 +407,7 @@ where
host: Some(peer.addr.ip().to_string()), host: Some(peer.addr.ip().to_string()),
port: Some(peer.addr.port()), port: Some(peer.addr.port()),
// TODO: Fix upstream crate so that it adds a `/` when needed. // TODO: Fix upstream crate so that it adds a `/` when needed.
path: format!("/{}", proj).into(), path: format!("/{}", id).into(),
..Url::default() ..Url::default()
}) { }) {
Ok(()) => { Ok(()) => {
@ -424,21 +424,21 @@ where
} }
} }
} }
Command::Track(proj, resp) => { Command::Track(id, resp) => {
resp.send(self.track(proj)).ok(); resp.send(self.track(id)).ok();
} }
Command::Untrack(proj, resp) => { Command::Untrack(id, resp) => {
resp.send(self.untrack(proj)).ok(); resp.send(self.untrack(id)).ok();
} }
Command::AnnounceRefsUpdate(proj) => { Command::AnnounceRefsUpdate(id) => {
let user = *self.storage.public_key(); let signer = *self.storage.public_key();
let repo = self.storage.repository(&proj).unwrap(); let repo = self.storage.repository(&id).unwrap();
let remote = repo.remote(&user).unwrap(); let remote = repo.remote(&signer).unwrap();
let peers = self.peers.negotiated().map(|(_, p)| p.addr); let peers = self.peers.negotiated().map(|(_, p)| p.addr);
let refs = remote.refs.unverified(); let refs = remote.refs.unverified();
self.context self.context
.broadcast(Message::RefsUpdate { proj, user, refs }, peers); .broadcast(Message::RefsUpdate { id, signer, refs }, peers);
} }
} }
} }
@ -712,16 +712,16 @@ where
} }
/// Process a peer inventory update announcement by (maybe) fetching. /// Process a peer inventory update announcement by (maybe) fetching.
fn process_refs_update(&mut self, proj: &ProjId, _user: &UserId, remote: &Url) -> bool { fn process_refs_update(&mut self, id: &Id, _user: &PublicKey, remote: &Url) -> bool {
// TODO: Check that we're tracking this user as well. // TODO: Check that we're tracking this user as well.
if self.config.is_tracking(proj) { if self.config.is_tracking(id) {
self.fetch(proj, remote); self.fetch(id, remote);
} }
// TODO: If refs were updated, return `true`. // TODO: If refs were updated, return `true`.
false false
} }
fn fetch(&mut self, proj_id: &ProjId, remote: &Url) { fn fetch(&mut self, proj_id: &Id, remote: &Url) {
// TODO: Verify refs before adding them to storage. // TODO: Verify refs before adding them to storage.
let mut repo = self.storage.repository(proj_id).unwrap(); let mut repo = self.storage.repository(proj_id).unwrap();
repo.fetch(&Url { repo.fetch(&Url {

View File

@ -3,7 +3,7 @@ use std::net;
use git_url::Url; use git_url::Url;
use crate::collections::HashSet; use crate::collections::HashSet;
use crate::identity::{ProjId, UserId}; use crate::identity::{Id, PublicKey};
use crate::protocol::message::{Address, Envelope, Message}; use crate::protocol::message::{Address, Envelope, Message};
/// Peer-to-peer network. /// Peer-to-peer network.
@ -34,9 +34,9 @@ impl Network {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ProjectTracking { pub enum ProjectTracking {
/// Track all projects we come across. /// Track all projects we come across.
All { blocked: HashSet<ProjId> }, All { blocked: HashSet<Id> },
/// Track a static list of projects. /// Track a static list of projects.
Allowed(HashSet<ProjId>), Allowed(HashSet<Id>),
} }
impl Default for ProjectTracking { impl Default for ProjectTracking {
@ -54,9 +54,9 @@ pub enum RemoteTracking {
#[default] #[default]
DelegatesOnly, DelegatesOnly,
/// Track all remotes. /// Track all remotes.
All { blocked: HashSet<UserId> }, All { blocked: HashSet<PublicKey> },
/// Track a specific list of users as well as the project delegates. /// Track a specific list of users as well as the project delegates.
Allowed(HashSet<UserId>), Allowed(HashSet<PublicKey>),
} }
/// Protocol configuration. /// Protocol configuration.
@ -98,26 +98,26 @@ impl Config {
self.connect.contains(addr) self.connect.contains(addr)
} }
pub fn is_tracking(&self, proj: &ProjId) -> bool { pub fn is_tracking(&self, id: &Id) -> bool {
match &self.project_tracking { match &self.project_tracking {
ProjectTracking::All { blocked } => !blocked.contains(proj), ProjectTracking::All { blocked } => !blocked.contains(id),
ProjectTracking::Allowed(projs) => projs.contains(proj), ProjectTracking::Allowed(ids) => ids.contains(id),
} }
} }
/// Track a project. Returns whether the policy was updated. /// Track a project. Returns whether the policy was updated.
pub fn track(&mut self, proj: ProjId) -> bool { pub fn track(&mut self, id: Id) -> bool {
match &mut self.project_tracking { match &mut self.project_tracking {
ProjectTracking::All { .. } => false, ProjectTracking::All { .. } => false,
ProjectTracking::Allowed(projs) => projs.insert(proj), ProjectTracking::Allowed(ids) => ids.insert(id),
} }
} }
/// Untrack a project. Returns whether the policy was updated. /// Untrack a project. Returns whether the policy was updated.
pub fn untrack(&mut self, proj: ProjId) -> bool { pub fn untrack(&mut self, id: Id) -> bool {
match &mut self.project_tracking { match &mut self.project_tracking {
ProjectTracking::All { blocked } => blocked.insert(proj), ProjectTracking::All { blocked } => blocked.insert(id),
ProjectTracking::Allowed(projs) => projs.remove(&proj), ProjectTracking::Allowed(ids) => ids.remove(&id),
} }
} }
} }

View File

@ -4,7 +4,7 @@ use git_url::Url;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::crypto; use crate::crypto;
use crate::identity::{ProjId, UserId}; use crate::identity::Id;
use crate::protocol::{Context, NodeId, Timestamp, PROTOCOL_VERSION}; use crate::protocol::{Context, NodeId, Timestamp, PROTOCOL_VERSION};
use crate::storage; use crate::storage;
use crate::storage::refs::SignedRefs; use crate::storage::refs::SignedRefs;
@ -87,11 +87,11 @@ pub enum Message {
announcement: NodeAnnouncement, announcement: NodeAnnouncement,
}, },
/// Get a peer's inventory. /// Get a peer's inventory.
GetInventory { ids: Vec<ProjId> }, GetInventory { ids: Vec<Id> },
/// Send our inventory to a peer. Sent in response to [`Message::GetInventory`]. /// Send our inventory to a peer. Sent in response to [`Message::GetInventory`].
/// Nb. This should be the whole inventory, not a partial update. /// Nb. This should be the whole inventory, not a partial update.
Inventory { Inventory {
inv: Vec<ProjId>, inv: Vec<Id>,
timestamp: Timestamp, timestamp: Timestamp,
/// Original peer this inventory came from. We don't set this when we /// Original peer this inventory came from. We don't set this when we
/// are the originator, only when relaying. /// are the originator, only when relaying.
@ -101,9 +101,9 @@ pub enum Message {
/// their view of the project. /// their view of the project.
RefsUpdate { RefsUpdate {
/// Project under which the refs were updated. /// Project under which the refs were updated.
proj: ProjId, id: Id,
/// User signing. /// Signing key.
user: UserId, signer: crypto::PublicKey,
/// Updated refs. /// Updated refs.
refs: SignedRefs<crypto::Unverified>, refs: SignedRefs<crypto::Unverified>,
}, },
@ -144,7 +144,7 @@ impl Message {
}) })
} }
pub fn get_inventory(ids: impl Into<Vec<ProjId>>) -> Self { pub fn get_inventory(ids: impl Into<Vec<Id>>) -> Self {
Self::GetInventory { ids: ids.into() } Self::GetInventory { ids: ids.into() }
} }
} }

View File

@ -194,13 +194,20 @@ impl Peer {
})); }));
} }
} }
(PeerState::Negotiated { git, .. }, Message::RefsUpdate { proj, user, refs }) => { (
if refs.verified(&user).is_ok() { PeerState::Negotiated { git, .. },
Message::RefsUpdate {
id: proj,
signer,
refs,
},
) => {
if refs.verified(&signer).is_ok() {
// TODO: Buffer/throttle fetches. // TODO: Buffer/throttle fetches.
// TODO: Also pass the updated refs so that we can check whether // TODO: Also pass the updated refs so that we can check whether
// we need to fetch or not. // we need to fetch or not.
// TODO: Check that the refs are valid. // TODO: Check that the refs are valid.
if ctx.process_refs_update(&proj, &user, git) { if ctx.process_refs_update(&proj, &signer, git) {
// TODO: If refs were updated, propagate message to peers. // TODO: If refs were updated, propagate message to peers.
} }
} else { } else {

View File

@ -6,7 +6,7 @@ use thiserror::Error;
use crate::crypto::Verified; use crate::crypto::Verified;
use crate::git; use crate::git;
use crate::identity::ProjId; use crate::identity::Id;
use crate::storage::git::RADICLE_ID_REF; use crate::storage::git::RADICLE_ID_REF;
use crate::storage::refs::SignedRefs; use crate::storage::refs::SignedRefs;
use crate::storage::{BranchName, ReadRepository as _, WriteRepository as _}; use crate::storage::{BranchName, ReadRepository as _, WriteRepository as _};
@ -39,7 +39,7 @@ pub fn init<'r, S: storage::WriteStorage<'r>>(
description: &str, description: &str,
default_branch: BranchName, default_branch: BranchName,
storage: S, storage: S,
) -> Result<(ProjId, SignedRefs<Verified>), InitError> { ) -> Result<(Id, SignedRefs<Verified>), InitError> {
let pk = storage.public_key(); let pk = storage.public_key();
let delegate = identity::Delegate { let delegate = identity::Delegate {
// TODO: Use actual user name. // TODO: Use actual user name.
@ -114,11 +114,11 @@ pub enum CheckoutError {
#[error("storage: {0}")] #[error("storage: {0}")]
Storage(#[from] storage::Error), Storage(#[from] storage::Error),
#[error("project `{0}` was not found in storage")] #[error("project `{0}` was not found in storage")]
NotFound(ProjId), NotFound(Id),
} }
pub fn checkout<P: AsRef<Path>, S: storage::ReadStorage>( pub fn checkout<P: AsRef<Path>, S: storage::ReadStorage>(
proj: &ProjId, proj: &Id,
path: P, path: P,
storage: S, storage: S,
) -> Result<git2::Repository, CheckoutError> { ) -> Result<git2::Repository, CheckoutError> {

View File

@ -18,13 +18,13 @@ use crate::crypto::{self, PublicKey, Unverified, Verified};
use crate::git::Url; use crate::git::Url;
use crate::git::{RefError, RefStr}; use crate::git::{RefError, RefStr};
use crate::identity; use crate::identity;
use crate::identity::{ProjId, ProjIdError, Project, UserId}; use crate::identity::{Id, IdError, Project};
use crate::storage::refs::Refs; use crate::storage::refs::Refs;
use self::refs::SignedRefs; use self::refs::SignedRefs;
pub type BranchName = String; pub type BranchName = String;
pub type Inventory = Vec<ProjId>; pub type Inventory = Vec<Id>;
/// Storage error. /// Storage error.
#[derive(Error, Debug)] #[derive(Error, Debug)]
@ -38,7 +38,7 @@ pub enum Error {
#[error("git: {0}")] #[error("git: {0}")]
Git(#[from] git2::Error), Git(#[from] git2::Error),
#[error("id: {0}")] #[error("id: {0}")]
ProjId(#[from] ProjIdError), Id(#[from] IdError),
#[error("i/o: {0}")] #[error("i/o: {0}")]
Io(#[from] io::Error), Io(#[from] io::Error),
#[error("doc: {0}")] #[error("doc: {0}")]
@ -47,7 +47,7 @@ pub enum Error {
InvalidHead, InvalidHead,
} }
pub type RemoteId = UserId; pub type RemoteId = PublicKey;
/// Project remotes. Tracks the git state of a project. /// Project remotes. Tracks the git state of a project.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@ -113,7 +113,7 @@ impl<V> From<Remotes<V>> for HashMap<RemoteId, Refs> {
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct Remote<V> { pub struct Remote<V> {
/// ID of remote. /// ID of remote.
pub id: UserId, pub id: PublicKey,
/// Git references published under this remote, and their hashes. /// Git references published under this remote, and their hashes.
pub refs: SignedRefs<V>, pub refs: SignedRefs<V>,
/// Whether this remote is of a project delegate. /// Whether this remote is of a project delegate.
@ -124,7 +124,7 @@ pub struct Remote<V> {
} }
impl<V> Remote<V> { impl<V> Remote<V> {
pub fn new(id: UserId, refs: impl Into<SignedRefs<V>>) -> Self { pub fn new(id: PublicKey, refs: impl Into<SignedRefs<V>>) -> Self {
Self { Self {
id, id,
refs: refs.into(), refs: refs.into(),
@ -161,14 +161,14 @@ impl Remote<Verified> {
pub trait ReadStorage { pub trait ReadStorage {
fn public_key(&self) -> &PublicKey; fn public_key(&self) -> &PublicKey;
fn url(&self) -> Url; fn url(&self) -> Url;
fn get(&self, proj: &ProjId) -> Result<Option<Project>, Error>; fn get(&self, proj: &Id) -> Result<Option<Project>, Error>;
fn inventory(&self) -> Result<Inventory, Error>; fn inventory(&self) -> Result<Inventory, Error>;
} }
pub trait WriteStorage<'r>: ReadStorage { pub trait WriteStorage<'r>: ReadStorage {
type Repository: WriteRepository<'r>; type Repository: WriteRepository<'r>;
fn repository(&self, proj: &ProjId) -> Result<Self::Repository, Error>; fn repository(&self, proj: &Id) -> Result<Self::Repository, Error>;
fn sign_refs(&self, repository: &Self::Repository) -> Result<SignedRefs<Verified>, Error>; fn sign_refs(&self, repository: &Self::Repository) -> Result<SignedRefs<Verified>, Error>;
} }
@ -203,7 +203,7 @@ where
T: Deref<Target = S>, T: Deref<Target = S>,
S: ReadStorage + 'static, S: ReadStorage + 'static,
{ {
fn public_key(&self) -> &UserId { fn public_key(&self) -> &PublicKey {
self.deref().public_key() self.deref().public_key()
} }
@ -215,7 +215,7 @@ where
self.deref().inventory() self.deref().inventory()
} }
fn get(&self, proj: &ProjId) -> Result<Option<Project>, Error> { fn get(&self, proj: &Id) -> Result<Option<Project>, Error> {
self.deref().get(proj) self.deref().get(proj)
} }
} }
@ -227,7 +227,7 @@ where
{ {
type Repository = S::Repository; type Repository = S::Repository;
fn repository(&self, proj: &ProjId) -> Result<Self::Repository, Error> { fn repository(&self, proj: &Id) -> Result<Self::Repository, Error> {
self.deref().repository(proj) self.deref().repository(proj)
} }

View File

@ -11,7 +11,7 @@ pub use radicle_git_ext::Oid;
use crate::crypto::{Signer, Verified}; use crate::crypto::{Signer, Verified};
use crate::git; use crate::git;
use crate::identity::{self, IDENTITY_PATH}; use crate::identity::{self, IDENTITY_PATH};
use crate::identity::{ProjId, Project, UserId}; use crate::identity::{Id, Project, PublicKey};
use crate::storage::refs; use crate::storage::refs;
use crate::storage::refs::{Refs, SignedRefs}; use crate::storage::refs::{Refs, SignedRefs};
use crate::storage::{ use crate::storage::{
@ -38,7 +38,7 @@ impl fmt::Debug for Storage {
} }
impl ReadStorage for Storage { impl ReadStorage for Storage {
fn public_key(&self) -> &UserId { fn public_key(&self) -> &PublicKey {
self.signer.public_key() self.signer.public_key()
} }
@ -50,7 +50,7 @@ impl ReadStorage for Storage {
} }
} }
fn get(&self, id: &ProjId) -> Result<Option<Project>, Error> { fn get(&self, id: &Id) -> Result<Option<Project>, Error> {
// TODO: Don't create a repo here if it doesn't exist? // TODO: Don't create a repo here if it doesn't exist?
// Perhaps for checking we could have a `contains` method? // Perhaps for checking we could have a `contains` method?
let local = self.public_key(); let local = self.public_key();
@ -83,7 +83,7 @@ impl ReadStorage for Storage {
impl<'r> WriteStorage<'r> for Storage { impl<'r> WriteStorage<'r> for Storage {
type Repository = Repository; type Repository = Repository;
fn repository(&self, proj: &ProjId) -> Result<Self::Repository, Error> { fn repository(&self, proj: &Id) -> Result<Self::Repository, Error> {
Repository::open(self.path.join(proj.to_string())) Repository::open(self.path.join(proj.to_string()))
} }
@ -132,12 +132,12 @@ impl Storage {
} }
} }
pub fn projects(&self) -> Result<Vec<ProjId>, Error> { pub fn projects(&self) -> Result<Vec<Id>, Error> {
let mut projects = Vec::new(); let mut projects = Vec::new();
for result in fs::read_dir(&self.path)? { for result in fs::read_dir(&self.path)? {
let path = result?; let path = result?;
let id = ProjId::try_from(path.file_name())?; let id = Id::try_from(path.file_name())?;
projects.push(id); projects.push(id);
} }
@ -423,7 +423,7 @@ mod tests {
let mut rng = fastrand::Rng::new(); let mut rng = fastrand::Rng::new();
let signer = MockSigner::new(&mut rng); let signer = MockSigner::new(&mut rng);
let storage = Storage::open(tmp.path(), signer).unwrap(); let storage = Storage::open(tmp.path(), signer).unwrap();
let proj_id = arbitrary::gen::<ProjId>(1); let proj_id = arbitrary::gen::<Id>(1);
let alice = *storage.public_key(); let alice = *storage.public_key();
let project = storage.repository(&proj_id).unwrap(); let project = storage.repository(&proj_id).unwrap();
let backend = &project.backend; let backend = &project.backend;

View File

@ -11,7 +11,7 @@ use crate::crypto::{self, Signer};
use crate::crypto::{PublicKey, SecretKey}; use crate::crypto::{PublicKey, SecretKey};
use crate::git; use crate::git;
use crate::hash; use crate::hash;
use crate::identity::{Delegate, Did, Doc, ProjId, Project}; use crate::identity::{Delegate, Did, Doc, Id, Project};
use crate::storage; use crate::storage;
use crate::storage::refs::Refs; use crate::storage::refs::Refs;
use crate::test::storage::MockStorage; use crate::test::storage::MockStorage;
@ -155,10 +155,10 @@ impl Arbitrary for MockSigner {
} }
} }
impl Arbitrary for ProjId { impl Arbitrary for Id {
fn arbitrary(g: &mut quickcheck::Gen) -> Self { fn arbitrary(g: &mut quickcheck::Gen) -> Self {
let digest = hash::Digest::arbitrary(g); let digest = hash::Digest::arbitrary(g);
ProjId::from(digest) Id::from(digest)
} }
} }

View File

@ -1,7 +1,7 @@
use std::path::Path; use std::path::Path;
use crate::git; use crate::git;
use crate::identity::ProjId; use crate::identity::Id;
use crate::storage::git::Storage; use crate::storage::git::Storage;
use crate::storage::{ReadStorage, WriteStorage}; use crate::storage::{ReadStorage, WriteStorage};
use crate::test::arbitrary; use crate::test::arbitrary;
@ -9,7 +9,7 @@ use crate::test::crypto::MockSigner;
pub fn storage<P: AsRef<Path>>(path: P) -> Storage { pub fn storage<P: AsRef<Path>>(path: P) -> Storage {
let path = path.as_ref(); let path = path.as_ref();
let proj_ids = arbitrary::set::<ProjId>(3..5); let proj_ids = arbitrary::set::<Id>(3..5);
let signers = arbitrary::set::<MockSigner>(1..3); let signers = arbitrary::set::<MockSigner>(1..3);
let mut storages = signers let mut storages = signers
.into_iter() .into_iter()

View File

@ -2,29 +2,29 @@ use std::sync::{Arc, Mutex};
use crate::client::handle::traits; use crate::client::handle::traits;
use crate::client::handle::Error; use crate::client::handle::Error;
use crate::identity::ProjId; use crate::identity::Id;
use crate::protocol; use crate::protocol;
use crate::protocol::FetchLookup; use crate::protocol::FetchLookup;
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct Handle { pub struct Handle {
pub updates: Arc<Mutex<Vec<ProjId>>>, pub updates: Arc<Mutex<Vec<Id>>>,
} }
impl traits::Handle for Handle { impl traits::Handle for Handle {
fn fetch(&self, _id: ProjId) -> Result<FetchLookup, Error> { fn fetch(&self, _id: Id) -> Result<FetchLookup, Error> {
Ok(FetchLookup::NotFound) Ok(FetchLookup::NotFound)
} }
fn track(&self, _id: ProjId) -> Result<bool, Error> { fn track(&self, _id: Id) -> Result<bool, Error> {
Ok(true) Ok(true)
} }
fn untrack(&self, _id: ProjId) -> Result<bool, Error> { fn untrack(&self, _id: Id) -> Result<bool, Error> {
Ok(true) Ok(true)
} }
fn updated(&self, id: ProjId) -> Result<(), Error> { fn updated(&self, id: Id) -> Result<(), Error> {
self.updates.lock().unwrap().push(id); self.updates.lock().unwrap().push(id);
Ok(()) Ok(())

View File

@ -2,7 +2,7 @@ use git_url::Url;
use crate::crypto::{PublicKey, Verified}; use crate::crypto::{PublicKey, Verified};
use crate::git; use crate::git;
use crate::identity::{ProjId, Project}; use crate::identity::{Id, Project};
use crate::storage::refs; use crate::storage::refs;
use crate::storage::{ use crate::storage::{
Error, Inventory, ReadRepository, ReadStorage, Remote, RemoteId, WriteRepository, WriteStorage, Error, Inventory, ReadRepository, ReadStorage, Remote, RemoteId, WriteRepository, WriteStorage,
@ -38,7 +38,7 @@ impl ReadStorage for MockStorage {
} }
} }
fn get(&self, proj: &ProjId) -> Result<Option<Project>, Error> { fn get(&self, proj: &Id) -> Result<Option<Project>, Error> {
if let Some(proj) = self.inventory.iter().find(|p| p.id == *proj) { if let Some(proj) = self.inventory.iter().find(|p| p.id == *proj) {
return Ok(Some(proj.clone())); return Ok(Some(proj.clone()));
} }
@ -59,7 +59,7 @@ impl ReadStorage for MockStorage {
impl WriteStorage<'_> for MockStorage { impl WriteStorage<'_> for MockStorage {
type Repository = MockRepository; type Repository = MockRepository;
fn repository(&self, _proj: &ProjId) -> Result<Self::Repository, Error> { fn repository(&self, _proj: &Id) -> Result<Self::Repository, Error> {
Ok(MockRepository {}) Ok(MockRepository {})
} }

View File

@ -181,7 +181,7 @@ fn test_tracking() {
MockStorage::empty(), MockStorage::empty(),
fastrand::Rng::new(), fastrand::Rng::new(),
); );
let proj_id: identity::ProjId = test::arbitrary::gen(1); let proj_id: identity::Id = test::arbitrary::gen(1);
let (sender, receiver) = chan::bounded(1); let (sender, receiver) = chan::bounded(1);
alice.command(Command::Track(proj_id.clone(), sender)); alice.command(Command::Track(proj_id.clone(), sender));