node: Move doc stuff to its own module
Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This commit is contained in:
parent
3e9a4eedae
commit
73d62de0cc
|
|
@ -1,22 +1,19 @@
|
||||||
use std::marker::PhantomData;
|
pub mod doc;
|
||||||
use std::ops::Deref;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::ops::Deref;
|
||||||
use std::{ffi::OsString, fmt, io, str::FromStr};
|
use std::path::PathBuf;
|
||||||
|
use std::{ffi::OsString, fmt, str::FromStr};
|
||||||
|
|
||||||
use nonempty::NonEmpty;
|
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
use radicle_git_ext::Oid;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::crypto::{self, Unverified, Verified};
|
use crate::crypto::{self, Verified};
|
||||||
use crate::hash;
|
use crate::hash;
|
||||||
use crate::serde_ext;
|
use crate::serde_ext;
|
||||||
use crate::storage::{BranchName, Remotes};
|
use crate::storage::Remotes;
|
||||||
|
|
||||||
pub use crypto::PublicKey;
|
pub use crypto::PublicKey;
|
||||||
|
pub use doc::{Delegate, Doc};
|
||||||
pub static IDENTITY_PATH: Lazy<&Path> = Lazy::new(|| Path::new("radicle.json"));
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum IdError {
|
pub enum IdError {
|
||||||
|
|
@ -170,193 +167,6 @@ pub struct Project {
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum DocError {
|
|
||||||
#[error("json: {0}")]
|
|
||||||
Json(#[from] serde_json::Error),
|
|
||||||
#[error("i/o: {0}")]
|
|
||||||
Io(#[from] io::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
||||||
pub struct Delegate {
|
|
||||||
pub name: String,
|
|
||||||
pub id: Did,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "kebab-case")]
|
|
||||||
pub struct Doc<V> {
|
|
||||||
pub name: String,
|
|
||||||
pub description: String,
|
|
||||||
pub default_branch: String,
|
|
||||||
pub version: u32,
|
|
||||||
pub parent: Option<Oid>,
|
|
||||||
pub delegates: NonEmpty<Delegate>,
|
|
||||||
pub threshold: usize,
|
|
||||||
|
|
||||||
verified: PhantomData<V>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Doc<Verified> {
|
|
||||||
pub fn write<W: io::Write>(&self, mut writer: W) -> Result<Id, DocError> {
|
|
||||||
let mut buf = Vec::new();
|
|
||||||
let mut ser =
|
|
||||||
serde_json::Serializer::with_formatter(&mut buf, olpc_cjson::CanonicalFormatter::new());
|
|
||||||
|
|
||||||
self.serialize(&mut ser)?;
|
|
||||||
|
|
||||||
let digest = hash::Digest::new(&buf);
|
|
||||||
let id = Id::from(digest);
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// version to disk to make it easier for users to edit.
|
|
||||||
writer.write_all(&buf)?;
|
|
||||||
|
|
||||||
Ok(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const MAX_STRING_LENGTH: usize = 255;
|
|
||||||
pub const MAX_DELEGATES: usize = 255;
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum DocVerificationError {
|
|
||||||
#[error("invalid name: {0}")]
|
|
||||||
Name(&'static str),
|
|
||||||
#[error("invalid description: {0}")]
|
|
||||||
Description(&'static str),
|
|
||||||
#[error("invalid default branch: {0}")]
|
|
||||||
DefaultBranch(&'static str),
|
|
||||||
#[error("invalid delegates: {0}")]
|
|
||||||
Delegates(&'static str),
|
|
||||||
#[error("invalid version `{0}`")]
|
|
||||||
Version(u32),
|
|
||||||
#[error("invalid parent: {0}")]
|
|
||||||
Parent(&'static str),
|
|
||||||
#[error("invalid threshold `{0}`: {1}")]
|
|
||||||
Threshold(usize, &'static str),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Doc<Unverified> {
|
|
||||||
pub fn initial(
|
|
||||||
name: String,
|
|
||||||
description: String,
|
|
||||||
default_branch: BranchName,
|
|
||||||
delegate: Delegate,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
default_branch,
|
|
||||||
version: 1,
|
|
||||||
parent: None,
|
|
||||||
delegates: NonEmpty::new(delegate),
|
|
||||||
threshold: 1,
|
|
||||||
verified: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(
|
|
||||||
name: String,
|
|
||||||
description: String,
|
|
||||||
default_branch: BranchName,
|
|
||||||
parent: Option<Oid>,
|
|
||||||
delegates: NonEmpty<Delegate>,
|
|
||||||
threshold: usize,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
default_branch,
|
|
||||||
version: 1,
|
|
||||||
parent,
|
|
||||||
delegates,
|
|
||||||
threshold,
|
|
||||||
verified: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_json(bytes: &[u8]) -> Result<Self, serde_json::Error> {
|
|
||||||
serde_json::from_slice(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn verified(self) -> Result<Doc<Verified>, DocVerificationError> {
|
|
||||||
if self.name.is_empty() {
|
|
||||||
return Err(DocVerificationError::Name("name cannot be empty"));
|
|
||||||
}
|
|
||||||
if self.name.len() > MAX_STRING_LENGTH {
|
|
||||||
return Err(DocVerificationError::Name("name cannot exceed 255 bytes"));
|
|
||||||
}
|
|
||||||
if self.description.len() > MAX_STRING_LENGTH {
|
|
||||||
return Err(DocVerificationError::Description(
|
|
||||||
"description cannot exceed 255 bytes",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if self.delegates.len() > MAX_DELEGATES {
|
|
||||||
return Err(DocVerificationError::Delegates(
|
|
||||||
"number of delegates cannot exceed 255",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if self
|
|
||||||
.delegates
|
|
||||||
.iter()
|
|
||||||
.any(|d| d.name.is_empty() || d.name.len() > MAX_STRING_LENGTH)
|
|
||||||
{
|
|
||||||
return Err(DocVerificationError::Delegates(
|
|
||||||
"delegate name must not be empty and must not exceed 255 bytes",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if self.delegates.is_empty() {
|
|
||||||
return Err(DocVerificationError::Delegates(
|
|
||||||
"delegate list cannot be empty",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if self.default_branch.is_empty() {
|
|
||||||
return Err(DocVerificationError::DefaultBranch(
|
|
||||||
"default branch cannot be empty",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if self.default_branch.len() > MAX_STRING_LENGTH {
|
|
||||||
return Err(DocVerificationError::DefaultBranch(
|
|
||||||
"default branch cannot exceed 255 bytes",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if let Some(parent) = self.parent {
|
|
||||||
if parent.is_zero() {
|
|
||||||
return Err(DocVerificationError::Parent("parent cannot be zero"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if self.version != 1 {
|
|
||||||
return Err(DocVerificationError::Version(self.version));
|
|
||||||
}
|
|
||||||
if self.threshold > self.delegates.len() {
|
|
||||||
return Err(DocVerificationError::Threshold(
|
|
||||||
self.threshold,
|
|
||||||
"threshold cannot exceed number of delegates",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if self.threshold == 0 {
|
|
||||||
return Err(DocVerificationError::Threshold(
|
|
||||||
self.threshold,
|
|
||||||
"threshold cannot be zero",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Doc {
|
|
||||||
name: self.name,
|
|
||||||
description: self.description,
|
|
||||||
delegates: self.delegates,
|
|
||||||
default_branch: self.default_branch,
|
|
||||||
parent: self.parent,
|
|
||||||
version: self.version,
|
|
||||||
threshold: self.threshold,
|
|
||||||
verified: PhantomData,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
@ -364,14 +174,6 @@ mod test {
|
||||||
use quickcheck_macros::quickcheck;
|
use quickcheck_macros::quickcheck;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[quickcheck]
|
|
||||||
fn prop_encode_decode(doc: Doc<Verified>) {
|
|
||||||
let mut bytes = Vec::new();
|
|
||||||
|
|
||||||
doc.write(&mut bytes).unwrap();
|
|
||||||
assert_eq!(Doc::from_json(&bytes).unwrap().verified().unwrap(), doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[quickcheck]
|
#[quickcheck]
|
||||||
fn prop_key_equality(a: PublicKey, b: PublicKey) {
|
fn prop_key_equality(a: PublicKey, b: PublicKey) {
|
||||||
assert_ne!(a, b);
|
assert_ne!(a, b);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,218 @@
|
||||||
|
use std::io;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use nonempty::NonEmpty;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use radicle_git_ext::Oid;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::crypto::{self, Unverified, Verified};
|
||||||
|
use crate::hash;
|
||||||
|
use crate::identity::{Did, Id};
|
||||||
|
use crate::storage::BranchName;
|
||||||
|
|
||||||
|
pub use crypto::PublicKey;
|
||||||
|
|
||||||
|
pub static PATH: Lazy<&Path> = Lazy::new(|| Path::new("radicle.json"));
|
||||||
|
pub const MAX_STRING_LENGTH: usize = 255;
|
||||||
|
pub const MAX_DELEGATES: usize = 255;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("json: {0}")]
|
||||||
|
Json(#[from] serde_json::Error),
|
||||||
|
#[error("i/o: {0}")]
|
||||||
|
Io(#[from] io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
pub struct Delegate {
|
||||||
|
pub name: String,
|
||||||
|
pub id: Did,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
pub struct Doc<V> {
|
||||||
|
pub name: String,
|
||||||
|
pub description: String,
|
||||||
|
pub default_branch: String,
|
||||||
|
pub version: u32,
|
||||||
|
pub parent: Option<Oid>,
|
||||||
|
pub delegates: NonEmpty<Delegate>,
|
||||||
|
pub threshold: usize,
|
||||||
|
|
||||||
|
verified: PhantomData<V>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Doc<Verified> {
|
||||||
|
pub fn write<W: io::Write>(&self, mut writer: W) -> Result<Id, Error> {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
let mut ser =
|
||||||
|
serde_json::Serializer::with_formatter(&mut buf, olpc_cjson::CanonicalFormatter::new());
|
||||||
|
|
||||||
|
self.serialize(&mut ser)?;
|
||||||
|
|
||||||
|
let digest = hash::Digest::new(&buf);
|
||||||
|
let id = Id::from(digest);
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// version to disk to make it easier for users to edit.
|
||||||
|
writer.write_all(&buf)?;
|
||||||
|
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum VerificationError {
|
||||||
|
#[error("invalid name: {0}")]
|
||||||
|
Name(&'static str),
|
||||||
|
#[error("invalid description: {0}")]
|
||||||
|
Description(&'static str),
|
||||||
|
#[error("invalid default branch: {0}")]
|
||||||
|
DefaultBranch(&'static str),
|
||||||
|
#[error("invalid delegates: {0}")]
|
||||||
|
Delegates(&'static str),
|
||||||
|
#[error("invalid version `{0}`")]
|
||||||
|
Version(u32),
|
||||||
|
#[error("invalid parent: {0}")]
|
||||||
|
Parent(&'static str),
|
||||||
|
#[error("invalid threshold `{0}`: {1}")]
|
||||||
|
Threshold(usize, &'static str),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Doc<Unverified> {
|
||||||
|
pub fn initial(
|
||||||
|
name: String,
|
||||||
|
description: String,
|
||||||
|
default_branch: BranchName,
|
||||||
|
delegate: Delegate,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
default_branch,
|
||||||
|
version: 1,
|
||||||
|
parent: None,
|
||||||
|
delegates: NonEmpty::new(delegate),
|
||||||
|
threshold: 1,
|
||||||
|
verified: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(
|
||||||
|
name: String,
|
||||||
|
description: String,
|
||||||
|
default_branch: BranchName,
|
||||||
|
parent: Option<Oid>,
|
||||||
|
delegates: NonEmpty<Delegate>,
|
||||||
|
threshold: usize,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
default_branch,
|
||||||
|
version: 1,
|
||||||
|
parent,
|
||||||
|
delegates,
|
||||||
|
threshold,
|
||||||
|
verified: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_json(bytes: &[u8]) -> Result<Self, serde_json::Error> {
|
||||||
|
serde_json::from_slice(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verified(self) -> Result<Doc<Verified>, VerificationError> {
|
||||||
|
if self.name.is_empty() {
|
||||||
|
return Err(VerificationError::Name("name cannot be empty"));
|
||||||
|
}
|
||||||
|
if self.name.len() > MAX_STRING_LENGTH {
|
||||||
|
return Err(VerificationError::Name("name cannot exceed 255 bytes"));
|
||||||
|
}
|
||||||
|
if self.description.len() > MAX_STRING_LENGTH {
|
||||||
|
return Err(VerificationError::Description(
|
||||||
|
"description cannot exceed 255 bytes",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if self.delegates.len() > MAX_DELEGATES {
|
||||||
|
return Err(VerificationError::Delegates(
|
||||||
|
"number of delegates cannot exceed 255",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if self
|
||||||
|
.delegates
|
||||||
|
.iter()
|
||||||
|
.any(|d| d.name.is_empty() || d.name.len() > MAX_STRING_LENGTH)
|
||||||
|
{
|
||||||
|
return Err(VerificationError::Delegates(
|
||||||
|
"delegate name must not be empty and must not exceed 255 bytes",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if self.delegates.is_empty() {
|
||||||
|
return Err(VerificationError::Delegates(
|
||||||
|
"delegate list cannot be empty",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if self.default_branch.is_empty() {
|
||||||
|
return Err(VerificationError::DefaultBranch(
|
||||||
|
"default branch cannot be empty",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if self.default_branch.len() > MAX_STRING_LENGTH {
|
||||||
|
return Err(VerificationError::DefaultBranch(
|
||||||
|
"default branch cannot exceed 255 bytes",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if let Some(parent) = self.parent {
|
||||||
|
if parent.is_zero() {
|
||||||
|
return Err(VerificationError::Parent("parent cannot be zero"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if self.version != 1 {
|
||||||
|
return Err(VerificationError::Version(self.version));
|
||||||
|
}
|
||||||
|
if self.threshold > self.delegates.len() {
|
||||||
|
return Err(VerificationError::Threshold(
|
||||||
|
self.threshold,
|
||||||
|
"threshold cannot exceed number of delegates",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if self.threshold == 0 {
|
||||||
|
return Err(VerificationError::Threshold(
|
||||||
|
self.threshold,
|
||||||
|
"threshold cannot be zero",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Doc {
|
||||||
|
name: self.name,
|
||||||
|
description: self.description,
|
||||||
|
delegates: self.delegates,
|
||||||
|
default_branch: self.default_branch,
|
||||||
|
parent: self.parent,
|
||||||
|
version: self.version,
|
||||||
|
threshold: self.threshold,
|
||||||
|
verified: PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use quickcheck_macros::quickcheck;
|
||||||
|
|
||||||
|
#[quickcheck]
|
||||||
|
fn prop_encode_decode(doc: Doc<Verified>) {
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
|
||||||
|
doc.write(&mut bytes).unwrap();
|
||||||
|
assert_eq!(Doc::from_json(&bytes).unwrap().verified().unwrap(), doc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,9 +16,9 @@ pub const REMOTE_NAME: &str = "rad";
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum InitError {
|
pub enum InitError {
|
||||||
#[error("doc: {0}")]
|
#[error("doc: {0}")]
|
||||||
Doc(#[from] identity::DocError),
|
Doc(#[from] identity::doc::Error),
|
||||||
#[error("doc: {0}")]
|
#[error("doc: {0}")]
|
||||||
DocVerification(#[from] identity::DocVerificationError),
|
DocVerification(#[from] identity::doc::VerificationError),
|
||||||
#[error("git: {0}")]
|
#[error("git: {0}")]
|
||||||
Git(#[from] git2::Error),
|
Git(#[from] git2::Error),
|
||||||
#[error("i/o: {0}")]
|
#[error("i/o: {0}")]
|
||||||
|
|
@ -56,7 +56,7 @@ pub fn init<'r, G: Signer, S: storage::WriteStorage<'r>>(
|
||||||
)
|
)
|
||||||
.verified()?;
|
.verified()?;
|
||||||
|
|
||||||
let filename = *identity::IDENTITY_PATH;
|
let filename = *identity::doc::PATH;
|
||||||
let mut doc_bytes = Vec::new();
|
let mut doc_bytes = Vec::new();
|
||||||
let id = doc.write(&mut doc_bytes)?;
|
let id = doc.write(&mut doc_bytes)?;
|
||||||
let project = storage.repository(&id)?;
|
let project = storage.repository(&id)?;
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ pub enum Error {
|
||||||
#[error("i/o: {0}")]
|
#[error("i/o: {0}")]
|
||||||
Io(#[from] io::Error),
|
Io(#[from] io::Error),
|
||||||
#[error("doc: {0}")]
|
#[error("doc: {0}")]
|
||||||
Doc(#[from] identity::DocError),
|
Doc(#[from] identity::doc::Error),
|
||||||
#[error("invalid repository head")]
|
#[error("invalid repository head")]
|
||||||
InvalidHead,
|
InvalidHead,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,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;
|
||||||
use crate::identity::{Id, Project};
|
use crate::identity::{Id, Project};
|
||||||
use crate::storage::refs;
|
use crate::storage::refs;
|
||||||
use crate::storage::refs::{Refs, SignedRefs};
|
use crate::storage::refs::{Refs, SignedRefs};
|
||||||
|
|
@ -263,7 +263,7 @@ impl Repository {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let doc = match self.blob_at(oid, Path::new(&*IDENTITY_PATH)) {
|
let doc = match self.blob_at(oid, Path::new(&*identity::doc::PATH)) {
|
||||||
Err(git::ext::Error::NotFound(_)) => return Ok(None),
|
Err(git::ext::Error::NotFound(_)) => return Ok(None),
|
||||||
Err(e) => return Err(e.into()),
|
Err(e) => return Err(e.into()),
|
||||||
Ok(doc) => doc,
|
Ok(doc) => doc,
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ use crate::crypto;
|
||||||
use crate::crypto::{PublicKey, SecretKey, Signer, Unverified, Verified};
|
use crate::crypto::{PublicKey, SecretKey, Signer, Unverified, Verified};
|
||||||
use crate::git;
|
use crate::git;
|
||||||
use crate::hash;
|
use crate::hash;
|
||||||
use crate::identity::{Delegate, Did, Doc, Id, Project};
|
use crate::identity::{doc::Delegate, doc::Doc, Did, Id, Project};
|
||||||
use crate::service::filter::{Filter, FILTER_SIZE};
|
use crate::service::filter::{Filter, FILTER_SIZE};
|
||||||
use crate::service::message::{
|
use crate::service::message::{
|
||||||
Address, Envelope, InventoryAnnouncement, Message, NodeAnnouncement, RefsAnnouncement,
|
Address, Envelope, InventoryAnnouncement, Message, NodeAnnouncement, RefsAnnouncement,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue