ipns: Implement.

This commit is contained in:
David Craven 2019-03-04 13:19:37 +01:00
parent 3cde9980ae
commit 20b1b6c78c
No known key found for this signature in database
GPG Key ID: DF438712EA50DBB1
9 changed files with 788 additions and 0 deletions

1
Cargo.lock generated
View File

@ -804,6 +804,7 @@ dependencies = [
name = "ipfs"
version = "0.1.0"
dependencies = [
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"cbor 0.4.1 (git+https://github.com/dvc94ch/rust-cbor?branch=read-data-item)",
"cid 0.3.0 (git+https://github.com/dvc94ch/rust-cid?branch=implement-hash)",
"env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -5,6 +5,7 @@ authors = ["David Craven <david@craven.ch>"]
edition = "2018"
[dependencies]
byteorder = "*"
cbor = "*"
cid = "*"
env_logger = "*"

View File

@ -0,0 +1,27 @@
#![feature(async_await, await_macro, futures_api)]
use ipfs::{Ipfs, IpfsOptions, PeerId, TestTypes};
fn main() {
let options = IpfsOptions::<TestTypes>::default();
env_logger::Builder::new().parse(&options.ipfs_log).init();
let mut ipfs = Ipfs::new(options);
tokio::run_async(async move {
// Start daemon and initialize repo
let fut = ipfs.start_daemon().unwrap();
tokio::spawn_async(fut);
await!(ipfs.init_repo()).unwrap();
await!(ipfs.open_repo()).unwrap();
// Create a Block
let ipfs_path = await!(ipfs.put_dag("block v0".into())).unwrap();
// Publish a Block
let ipns_path = await!(ipfs.publish_ipns(&PeerId::random(), &ipfs_path)).unwrap();
// Resolve a Block
let new_ipfs_path = await!(ipfs.resolve_ipns(&ipns_path)).unwrap();
assert_eq!(ipfs_path, new_ipfs_path);
ipfs.exit_daemon();
});
}

View File

@ -2,3 +2,4 @@
protoc --rust_out src/bitswap src/bitswap/bitswap_pb.proto
protoc --rust_out src/ipld/formats/pb src/ipld/formats/pb/dag_pb.proto
protoc --rust_out src/ipns src/ipns/ipns_pb.proto

125
src/ipns/entry.rs Normal file
View File

@ -0,0 +1,125 @@
use crate::error::Error;
use crate::ipns::ipns_pb as proto;
use crate::path::IpfsPath;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use libp2p::core::PublicKey;
use libp2p::secio::SecioKeyPair;
use protobuf::{self, ProtobufError, Message as ProtobufMessage};
use std::time::{Duration, SystemTime};
#[derive(Clone, Debug, PartialEq)]
pub struct IpnsEntry {
value: String,
seq: u64,
validity: SystemTime,
public_key: PublicKey,
signature: Vec<u8>,
}
impl IpnsEntry {
pub fn new(value: String, seq: u64, ttl: Duration, key: &SecioKeyPair) -> Self {
let validity = SystemTime::now() + ttl;
let public_key = key.to_public_key();
let signature = IpnsEntry::sign(&validity, &value, &key);
IpnsEntry {
value,
seq,
validity,
public_key,
signature,
}
}
pub fn seq(&self) -> u64 {
self.seq
}
pub fn from_path(path: &IpfsPath, seq: u64, key: &SecioKeyPair) -> Self {
let value = path.to_string();
// TODO what is a reasonable default?
let ttl = Duration::new(1, 0);
IpnsEntry::new(value, seq, ttl, key)
}
fn sign(_validity: &SystemTime, _value: &String, _key: &SecioKeyPair) -> Vec<u8> {
// TODO
Vec::new()
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut proto = proto::IpnsEntry::new();
proto.set_value(self.value.as_bytes().to_vec());
proto.set_sequence(self.seq);
let nanos = self.validity
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_nanos();
let mut validity = vec![];
validity.write_u64::<BigEndian>(nanos as u64).unwrap();
proto.set_validityType(proto::IpnsEntry_ValidityType::EOL);
proto.set_validity(validity);
proto.set_signature(self.signature.clone());
proto.set_pubKey(self.public_key.clone().into_protobuf_encoding());
proto
.write_to_bytes()
.expect("there is no situation in which the protobuf message can be invalid")
}
pub fn from_bytes(bytes: &Vec<u8>) -> Result<Self, ProtobufError> {
let proto: proto::IpnsEntry = protobuf::parse_from_bytes(bytes)?;
let value = String::from_utf8_lossy(proto.get_value()).to_string();
let public_key = PublicKey::from_protobuf_encoding(proto.get_pubKey())?;
let nanos = proto.get_validity().read_u64::<BigEndian>()?;
let validity = SystemTime::UNIX_EPOCH + Duration::from_nanos(nanos);
let ipns = IpnsEntry {
value,
seq: proto.get_sequence(),
validity,
signature: proto.get_signature().to_vec(),
public_key,
};
Ok(ipns)
}
pub fn is_valid(&self) -> bool {
// TODO
true
}
pub fn resolve(&self) -> Result<IpfsPath, Error> {
IpfsPath::from_str(&self.value)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_valid() {
let value = "/ipfs/".into();
let duration = Duration::new(1, 0);
let key = SecioKeyPair::ed25519_generated().unwrap();
let ipns = IpnsEntry::new(value, 0, duration, &key);
assert!(ipns.is_valid());
}
#[test]
fn test_to_from_bytes() {
let value = "/ipfs/".into();
let duration = Duration::new(1, 0);
let key = SecioKeyPair::ed25519_generated().unwrap();
let ipns = IpnsEntry::new(value, 0, duration, &key);
let bytes = ipns.to_bytes();
let ipns2 = IpnsEntry::from_bytes(&bytes).unwrap();
assert_eq!(ipns, ipns2);
}
#[test]
fn test_from_path() {
let key = SecioKeyPair::ed25519_generated().unwrap();
let path = IpfsPath::from_str("/ipfs/QmUJPTFZnR2CPGAzmfdYPghgrFtYFB6pf1BqMvqfiPDam8").unwrap();
let ipns = IpnsEntry::from_path(&path, 0, &key);
assert_eq!(path, ipns.resolve().unwrap());
}
}

19
src/ipns/ipns_pb.proto Normal file
View File

@ -0,0 +1,19 @@
syntax = "proto3";
message IpnsEntry {
enum ValidityType {
EOL = 0; // setting an EOL says "this record is valid until..."
}
bytes value = 1; // required
bytes signature = 2; // required
ValidityType validityType = 3;
bytes validity = 4;
uint64 sequence = 5;
uint64 ttl = 6;
// in order for nodes to properly validate a record upon receipt, they
// need the public key associated with it. For old RSA keys, its easiest
// if we just send this as part of the record itself. For newer ed25519
// keys, the public key can be embedded in the peerID, making this field
// unnecessary.
bytes pubKey = 7;
}

530
src/ipns/ipns_pb.rs Normal file
View File

@ -0,0 +1,530 @@
// This file is generated by rust-protobuf 2.0.2. Do not edit
// @generated
// https://github.com/Manishearth/rust-clippy/issues/702
#![allow(unknown_lints)]
#![allow(clippy)]
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(box_pointers)]
#![allow(dead_code)]
#![allow(missing_docs)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(trivial_casts)]
#![allow(unsafe_code)]
#![allow(unused_imports)]
#![allow(unused_results)]
use protobuf::Message as Message_imported_for_functions;
use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions;
#[derive(PartialEq,Clone,Default)]
pub struct IpnsEntry {
// message fields
pub value: ::std::vec::Vec<u8>,
pub signature: ::std::vec::Vec<u8>,
pub validityType: IpnsEntry_ValidityType,
pub validity: ::std::vec::Vec<u8>,
pub sequence: u64,
pub ttl: u64,
pub pubKey: ::std::vec::Vec<u8>,
// special fields
unknown_fields: ::protobuf::UnknownFields,
cached_size: ::protobuf::CachedSize,
}
impl IpnsEntry {
pub fn new() -> IpnsEntry {
::std::default::Default::default()
}
// bytes value = 1;
pub fn clear_value(&mut self) {
self.value.clear();
}
// Param is passed by value, moved
pub fn set_value(&mut self, v: ::std::vec::Vec<u8>) {
self.value = v;
}
// Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first.
pub fn mut_value(&mut self) -> &mut ::std::vec::Vec<u8> {
&mut self.value
}
// Take field
pub fn take_value(&mut self) -> ::std::vec::Vec<u8> {
::std::mem::replace(&mut self.value, ::std::vec::Vec::new())
}
pub fn get_value(&self) -> &[u8] {
&self.value
}
// bytes signature = 2;
pub fn clear_signature(&mut self) {
self.signature.clear();
}
// Param is passed by value, moved
pub fn set_signature(&mut self, v: ::std::vec::Vec<u8>) {
self.signature = v;
}
// Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first.
pub fn mut_signature(&mut self) -> &mut ::std::vec::Vec<u8> {
&mut self.signature
}
// Take field
pub fn take_signature(&mut self) -> ::std::vec::Vec<u8> {
::std::mem::replace(&mut self.signature, ::std::vec::Vec::new())
}
pub fn get_signature(&self) -> &[u8] {
&self.signature
}
// .IpnsEntry.ValidityType validityType = 3;
pub fn clear_validityType(&mut self) {
self.validityType = IpnsEntry_ValidityType::EOL;
}
// Param is passed by value, moved
pub fn set_validityType(&mut self, v: IpnsEntry_ValidityType) {
self.validityType = v;
}
pub fn get_validityType(&self) -> IpnsEntry_ValidityType {
self.validityType
}
// bytes validity = 4;
pub fn clear_validity(&mut self) {
self.validity.clear();
}
// Param is passed by value, moved
pub fn set_validity(&mut self, v: ::std::vec::Vec<u8>) {
self.validity = v;
}
// Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first.
pub fn mut_validity(&mut self) -> &mut ::std::vec::Vec<u8> {
&mut self.validity
}
// Take field
pub fn take_validity(&mut self) -> ::std::vec::Vec<u8> {
::std::mem::replace(&mut self.validity, ::std::vec::Vec::new())
}
pub fn get_validity(&self) -> &[u8] {
&self.validity
}
// uint64 sequence = 5;
pub fn clear_sequence(&mut self) {
self.sequence = 0;
}
// Param is passed by value, moved
pub fn set_sequence(&mut self, v: u64) {
self.sequence = v;
}
pub fn get_sequence(&self) -> u64 {
self.sequence
}
// uint64 ttl = 6;
pub fn clear_ttl(&mut self) {
self.ttl = 0;
}
// Param is passed by value, moved
pub fn set_ttl(&mut self, v: u64) {
self.ttl = v;
}
pub fn get_ttl(&self) -> u64 {
self.ttl
}
// bytes pubKey = 7;
pub fn clear_pubKey(&mut self) {
self.pubKey.clear();
}
// Param is passed by value, moved
pub fn set_pubKey(&mut self, v: ::std::vec::Vec<u8>) {
self.pubKey = v;
}
// Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first.
pub fn mut_pubKey(&mut self) -> &mut ::std::vec::Vec<u8> {
&mut self.pubKey
}
// Take field
pub fn take_pubKey(&mut self) -> ::std::vec::Vec<u8> {
::std::mem::replace(&mut self.pubKey, ::std::vec::Vec::new())
}
pub fn get_pubKey(&self) -> &[u8] {
&self.pubKey
}
}
impl ::protobuf::Message for IpnsEntry {
fn is_initialized(&self) -> bool {
true
}
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> {
while !is.eof()? {
let (field_number, wire_type) = is.read_tag_unpack()?;
match field_number {
1 => {
::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.value)?;
},
2 => {
::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.signature)?;
},
3 => {
::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.validityType, 3, &mut self.unknown_fields)?
},
4 => {
::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.validity)?;
},
5 => {
if wire_type != ::protobuf::wire_format::WireTypeVarint {
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
}
let tmp = is.read_uint64()?;
self.sequence = tmp;
},
6 => {
if wire_type != ::protobuf::wire_format::WireTypeVarint {
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
}
let tmp = is.read_uint64()?;
self.ttl = tmp;
},
7 => {
::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.pubKey)?;
},
_ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
},
};
}
::std::result::Result::Ok(())
}
// Compute sizes of nested messages
#[allow(unused_variables)]
fn compute_size(&self) -> u32 {
let mut my_size = 0;
if !self.value.is_empty() {
my_size += ::protobuf::rt::bytes_size(1, &self.value);
}
if !self.signature.is_empty() {
my_size += ::protobuf::rt::bytes_size(2, &self.signature);
}
if self.validityType != IpnsEntry_ValidityType::EOL {
my_size += ::protobuf::rt::enum_size(3, self.validityType);
}
if !self.validity.is_empty() {
my_size += ::protobuf::rt::bytes_size(4, &self.validity);
}
if self.sequence != 0 {
my_size += ::protobuf::rt::value_size(5, self.sequence, ::protobuf::wire_format::WireTypeVarint);
}
if self.ttl != 0 {
my_size += ::protobuf::rt::value_size(6, self.ttl, ::protobuf::wire_format::WireTypeVarint);
}
if !self.pubKey.is_empty() {
my_size += ::protobuf::rt::bytes_size(7, &self.pubKey);
}
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
self.cached_size.set(my_size);
my_size
}
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> {
if !self.value.is_empty() {
os.write_bytes(1, &self.value)?;
}
if !self.signature.is_empty() {
os.write_bytes(2, &self.signature)?;
}
if self.validityType != IpnsEntry_ValidityType::EOL {
os.write_enum(3, self.validityType.value())?;
}
if !self.validity.is_empty() {
os.write_bytes(4, &self.validity)?;
}
if self.sequence != 0 {
os.write_uint64(5, self.sequence)?;
}
if self.ttl != 0 {
os.write_uint64(6, self.ttl)?;
}
if !self.pubKey.is_empty() {
os.write_bytes(7, &self.pubKey)?;
}
os.write_unknown_fields(self.get_unknown_fields())?;
::std::result::Result::Ok(())
}
fn get_cached_size(&self) -> u32 {
self.cached_size.get()
}
fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
&self.unknown_fields
}
fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
&mut self.unknown_fields
}
fn as_any(&self) -> &::std::any::Any {
self as &::std::any::Any
}
fn as_any_mut(&mut self) -> &mut ::std::any::Any {
self as &mut ::std::any::Any
}
fn into_any(self: Box<Self>) -> ::std::boxed::Box<::std::any::Any> {
self
}
fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
Self::descriptor_static()
}
fn new() -> IpnsEntry {
IpnsEntry::new()
}
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy {
lock: ::protobuf::lazy::ONCE_INIT,
ptr: 0 as *const ::protobuf::reflect::MessageDescriptor,
};
unsafe {
descriptor.get(|| {
let mut fields = ::std::vec::Vec::new();
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>(
"value",
|m: &IpnsEntry| { &m.value },
|m: &mut IpnsEntry| { &mut m.value },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>(
"signature",
|m: &IpnsEntry| { &m.signature },
|m: &mut IpnsEntry| { &mut m.signature },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<IpnsEntry_ValidityType>>(
"validityType",
|m: &IpnsEntry| { &m.validityType },
|m: &mut IpnsEntry| { &mut m.validityType },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>(
"validity",
|m: &IpnsEntry| { &m.validity },
|m: &mut IpnsEntry| { &mut m.validity },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>(
"sequence",
|m: &IpnsEntry| { &m.sequence },
|m: &mut IpnsEntry| { &mut m.sequence },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>(
"ttl",
|m: &IpnsEntry| { &m.ttl },
|m: &mut IpnsEntry| { &mut m.ttl },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>(
"pubKey",
|m: &IpnsEntry| { &m.pubKey },
|m: &mut IpnsEntry| { &mut m.pubKey },
));
::protobuf::reflect::MessageDescriptor::new::<IpnsEntry>(
"IpnsEntry",
fields,
file_descriptor_proto()
)
})
}
}
fn default_instance() -> &'static IpnsEntry {
static mut instance: ::protobuf::lazy::Lazy<IpnsEntry> = ::protobuf::lazy::Lazy {
lock: ::protobuf::lazy::ONCE_INIT,
ptr: 0 as *const IpnsEntry,
};
unsafe {
instance.get(IpnsEntry::new)
}
}
}
impl ::protobuf::Clear for IpnsEntry {
fn clear(&mut self) {
self.clear_value();
self.clear_signature();
self.clear_validityType();
self.clear_validity();
self.clear_sequence();
self.clear_ttl();
self.clear_pubKey();
self.unknown_fields.clear();
}
}
impl ::std::fmt::Debug for IpnsEntry {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for IpnsEntry {
fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef {
::protobuf::reflect::ProtobufValueRef::Message(self)
}
}
#[derive(Clone,PartialEq,Eq,Debug,Hash)]
pub enum IpnsEntry_ValidityType {
EOL = 0,
}
impl ::protobuf::ProtobufEnum for IpnsEntry_ValidityType {
fn value(&self) -> i32 {
*self as i32
}
fn from_i32(value: i32) -> ::std::option::Option<IpnsEntry_ValidityType> {
match value {
0 => ::std::option::Option::Some(IpnsEntry_ValidityType::EOL),
_ => ::std::option::Option::None
}
}
fn values() -> &'static [Self] {
static values: &'static [IpnsEntry_ValidityType] = &[
IpnsEntry_ValidityType::EOL,
];
values
}
fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy {
lock: ::protobuf::lazy::ONCE_INIT,
ptr: 0 as *const ::protobuf::reflect::EnumDescriptor,
};
unsafe {
descriptor.get(|| {
::protobuf::reflect::EnumDescriptor::new("IpnsEntry_ValidityType", file_descriptor_proto())
})
}
}
}
impl ::std::marker::Copy for IpnsEntry_ValidityType {
}
impl ::std::default::Default for IpnsEntry_ValidityType {
fn default() -> Self {
IpnsEntry_ValidityType::EOL
}
}
impl ::protobuf::reflect::ProtobufValue for IpnsEntry_ValidityType {
fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef {
::protobuf::reflect::ProtobufValueRef::Enum(self.descriptor())
}
}
static file_descriptor_proto_data: &'static [u8] = b"\
\n\x16src/ipns/ipns_pb.proto\"\xf7\x01\n\tIpnsEntry\x12\x14\n\x05value\
\x18\x01\x20\x01(\x0cR\x05value\x12\x1c\n\tsignature\x18\x02\x20\x01(\
\x0cR\tsignature\x12;\n\x0cvalidityType\x18\x03\x20\x01(\x0e2\x17.IpnsEn\
try.ValidityTypeR\x0cvalidityType\x12\x1a\n\x08validity\x18\x04\x20\x01(\
\x0cR\x08validity\x12\x1a\n\x08sequence\x18\x05\x20\x01(\x04R\x08sequenc\
e\x12\x10\n\x03ttl\x18\x06\x20\x01(\x04R\x03ttl\x12\x16\n\x06pubKey\x18\
\x07\x20\x01(\x0cR\x06pubKey\"\x17\n\x0cValidityType\x12\x07\n\x03EOL\
\x10\0J\xd9\x07\n\x06\x12\x04\0\0\x12\x01\n\x08\n\x01\x0c\x12\x03\0\0\
\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x12\x01\n\n\n\x03\x04\0\x01\x12\x03\
\x02\x08\x11\n\x0c\n\x04\x04\0\x04\0\x12\x04\x03\x02\x05\x03\n\x0c\n\x05\
\x04\0\x04\0\x01\x12\x03\x03\x07\x13\nD\n\x06\x04\0\x04\0\x02\0\x12\x03\
\x04\x04\x0c\"5\x20setting\x20an\x20EOL\x20says\x20\"this\x20record\x20i\
s\x20valid\x20until...\"\n\n\x0e\n\x07\x04\0\x04\0\x02\0\x01\x12\x03\x04\
\x04\x07\n\x0e\n\x07\x04\0\x04\0\x02\0\x02\x12\x03\x04\n\x0b\n\x17\n\x04\
\x04\0\x02\0\x12\x03\x06\x02\x12\"\n\x20required\n\n\r\n\x05\x04\0\x02\0\
\x04\x12\x04\x06\x02\x05\x03\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x06\x02\
\x07\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x06\x08\r\n\x0c\n\x05\x04\0\x02\
\0\x03\x12\x03\x06\x10\x11\n\x17\n\x04\x04\0\x02\x01\x12\x03\x07\x02\x16\
\"\n\x20required\n\n\r\n\x05\x04\0\x02\x01\x04\x12\x04\x07\x02\x06\x12\n\
\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x07\x02\x07\n\x0c\n\x05\x04\0\x02\
\x01\x01\x12\x03\x07\x08\x11\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x07\
\x14\x15\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x08\x02\x20\n\r\n\x05\x04\0\
\x02\x02\x04\x12\x04\x08\x02\x07\x16\n\x0c\n\x05\x04\0\x02\x02\x06\x12\
\x03\x08\x02\x0e\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x08\x0f\x1b\n\x0c\
\n\x05\x04\0\x02\x02\x03\x12\x03\x08\x1e\x1f\n\x0b\n\x04\x04\0\x02\x03\
\x12\x03\t\x02\x15\n\r\n\x05\x04\0\x02\x03\x04\x12\x04\t\x02\x08\x20\n\
\x0c\n\x05\x04\0\x02\x03\x05\x12\x03\t\x02\x07\n\x0c\n\x05\x04\0\x02\x03\
\x01\x12\x03\t\x08\x10\n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\t\x13\x14\n\
\x0b\n\x04\x04\0\x02\x04\x12\x03\n\x02\x16\n\r\n\x05\x04\0\x02\x04\x04\
\x12\x04\n\x02\t\x15\n\x0c\n\x05\x04\0\x02\x04\x05\x12\x03\n\x02\x08\n\
\x0c\n\x05\x04\0\x02\x04\x01\x12\x03\n\t\x11\n\x0c\n\x05\x04\0\x02\x04\
\x03\x12\x03\n\x14\x15\n\x0b\n\x04\x04\0\x02\x05\x12\x03\x0b\x02\x11\n\r\
\n\x05\x04\0\x02\x05\x04\x12\x04\x0b\x02\n\x16\n\x0c\n\x05\x04\0\x02\x05\
\x05\x12\x03\x0b\x02\x08\n\x0c\n\x05\x04\0\x02\x05\x01\x12\x03\x0b\t\x0c\
\n\x0c\n\x05\x04\0\x02\x05\x03\x12\x03\x0b\x0f\x10\n\xb5\x02\n\x04\x04\0\
\x02\x06\x12\x03\x11\x02\x13\x1a\xa7\x02\x20in\x20order\x20for\x20nodes\
\x20to\x20properly\x20validate\x20a\x20record\x20upon\x20receipt,\x20the\
y\n\x20need\x20the\x20public\x20key\x20associated\x20with\x20it.\x20For\
\x20old\x20RSA\x20keys,\x20its\x20easiest\n\x20if\x20we\x20just\x20send\
\x20this\x20as\x20part\x20of\x20the\x20record\x20itself.\x20For\x20newer\
\x20ed25519\n\x20keys,\x20the\x20public\x20key\x20can\x20be\x20embedded\
\x20in\x20the\x20peerID,\x20making\x20this\x20field\n\x20unnecessary.\n\
\n\r\n\x05\x04\0\x02\x06\x04\x12\x04\x11\x02\x0b\x11\n\x0c\n\x05\x04\0\
\x02\x06\x05\x12\x03\x11\x02\x07\n\x0c\n\x05\x04\0\x02\x06\x01\x12\x03\
\x11\x08\x0e\n\x0c\n\x05\x04\0\x02\x06\x03\x12\x03\x11\x11\x12b\x06proto\
3\
";
static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy {
lock: ::protobuf::lazy::ONCE_INIT,
ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto,
};
fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto {
::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap()
}
pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto {
unsafe {
file_descriptor_proto_lazy.get(|| {
parse_descriptor_proto()
})
}
}

57
src/ipns/mod.rs Normal file
View File

@ -0,0 +1,57 @@
#![allow(dead_code)]
use crate::error::Error;
use crate::path::{IpfsPath, PathRoot};
use crate::repo::{Repo, RepoTypes};
use libp2p::PeerId;
use std::future::Future;
mod ipns_pb;
mod entry;
pub struct Ipns<Types: RepoTypes> {
repo: Repo<Types>,
}
impl<Types: RepoTypes> Ipns<Types> {
pub fn new(repo: Repo<Types>) -> Self {
Ipns {
repo
}
}
/// Resolves a ipns path to an ipld path.
pub fn resolve(&self, path: &IpfsPath) ->
impl Future<Output=Result<IpfsPath, Error>>
{
let repo = self.repo.clone();
let path = path.to_owned();
async move {
if path.root().is_ipns() {
Ok(await!(repo.get_ipns(path.root().peer_id()?))??)
} else {
Ok(path)
}
}
}
/// Publishes an ipld path.
pub fn publish(&self, key: &PeerId, path: &IpfsPath) ->
impl Future<Output=Result<IpfsPath, Error>>
{
let future = self.repo.put_ipns(key, path);
let key = key.to_owned();
let mut path = path.to_owned();
async move {
await!(future)?;
path.set_root(PathRoot::Ipns(key));
Ok(path)
}
}
/// Cancel an ipns path.
pub fn cancel(&self, key: &PeerId) ->
impl Future<Output=Result<(), Error>>
{
self.repo.remove_ipns(key)
}
}

View File

@ -8,6 +8,7 @@
#[macro_use] extern crate failure;
#[macro_use] extern crate log;
use futures::prelude::*;
pub use libp2p::PeerId;
use std::marker::PhantomData;
use std::path::PathBuf;
use std::pin::Pin;
@ -21,6 +22,7 @@ mod config;
pub mod error;
mod future;
pub mod ipld;
pub mod ipns;
pub mod p2p;
pub mod path;
pub mod repo;
@ -31,6 +33,7 @@ use self::config::ConfigFile;
pub use self::error::Error;
use self::ipld::IpldDag;
pub use self::ipld::Ipld;
use self::ipns::Ipns;
pub use self::p2p::SwarmTypes;
use self::p2p::{create_swarm, SwarmOptions, TSwarm};
pub use self::path::IpfsPath;
@ -124,6 +127,7 @@ pub struct Ipfs<Types: IpfsTypes> {
repo: Repo<Types>,
repo_events: Option<Receiver<RepoEvent>>,
dag: IpldDag<Types>,
ipns: Ipns<Types>,
swarm: Option<TSwarm<Types>>,
exit_events: Vec<Sender<IpfsEvent>>,
}
@ -140,10 +144,12 @@ impl<Types: IpfsTypes> Ipfs<Types> {
let swarm_options = SwarmOptions::<Types>::from(&options);
let swarm = create_swarm(swarm_options, repo.clone());
let dag = IpldDag::new(repo.clone());
let ipns = Ipns::new(repo.clone());
Ipfs {
repo,
dag,
ipns,
repo_events: Some(repo_events),
swarm: Some(swarm),
exit_events: Vec::default(),
@ -200,6 +206,27 @@ impl<Types: IpfsTypes> Ipfs<Types> {
File::get_unixfs_v1(&self.dag, path)
}
/// Resolves a ipns path to an ipld path.
pub fn resolve_ipns(&self, path: &IpfsPath) ->
impl Future<Output=Result<IpfsPath, Error>>
{
self.ipns.resolve(path)
}
/// Publishes an ipld path.
pub fn publish_ipns(&self, key: &PeerId, path: &IpfsPath) ->
impl Future<Output=Result<IpfsPath, Error>>
{
self.ipns.publish(key, path)
}
/// Cancel an ipns path.
pub fn cancel_ipns(&self, key: &PeerId) ->
impl Future<Output=Result<(), Error>>
{
self.ipns.cancel(key)
}
/// Start daemon.
pub fn start_daemon(&mut self) -> Option<IpfsFuture<Types>> {
self.repo_events.take().map(|repo_events|{