node: Rename `ProjId` -> `Id`
Remove `UserId` type. Signed-off-by: Alexis Sellier <self@cloudhead.io>
This commit is contained in:
parent
c80ba01ed9
commit
927f062dc9
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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> {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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(())
|
||||||
|
|
|
||||||
|
|
@ -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 {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue