diff --git a/appveyor.yml b/appveyor.yml index 1772705..7c4dc3f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,22 +1,17 @@ # gitversion will change the version number version: x-{build} -# branches to build for: - - branches: + branches: only: - master - environment: + environment: git_token: - secure: NeX5NCOUXsCLc1UjTJjqB9F02FZ8Wq0VsxqTXC8kBdyK6zjxjebrf/9Da2sY1Kql + secure: NeX5NCOUXsCLc1UjTJjqB9F02FZ8Wq0VsxqTXC8kBdyK6zjxjebrf/9Da2sY1Kql snk_secret: - secure: 5QzEIgiDqTIrZruPaIQIvTlNMl5BZ7TGEps7ALyBfHE= -- - branches: - except: - - gh-pages + secure: 5QzEIgiDqTIrZruPaIQIvTlNMl5BZ7TGEps7ALyBfHE= configuration: Release os: Visual Studio 2017 diff --git a/src/Block.cs b/src/Block.cs index 3291523..dd8b71f 100644 --- a/src/Block.cs +++ b/src/Block.cs @@ -10,23 +10,13 @@ namespace Ipfs.Api /// public class Block : IDataBlock { - byte[] dataBytes; + long? size; /// public Cid Id { get; set; } /// - public byte[] DataBytes - { - get - { - return dataBytes; - } - set - { - dataBytes = value; - } - } + public byte[] DataBytes { get; set; } /// public Stream DataStream @@ -35,7 +25,25 @@ public Stream DataStream { return new MemoryStream(DataBytes, false); } - } + } + + /// + public long Size + { + get + { + if (size.HasValue) + { + return size.Value; + } + return DataBytes.Length; + } + set + { + size = value; + } + } + } } diff --git a/src/ConnectedPeer.cs b/src/ConnectedPeer.cs deleted file mode 100644 index ff8e593..0000000 --- a/src/ConnectedPeer.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Ipfs.Api -{ - /// - /// A that is connected to the local peer node. - /// - public class ConnectedPeer : Peer - { - /// - /// The that the peer is connected on. - /// - /// - /// The MultiAddress contains the IPFS , such as - /// /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ. - /// - public MultiAddress ConnectedAddress { get; set; } - - /// - /// The round-trip time it takes to get data from a peer. - /// - public TimeSpan Latency { get; set; } - } -} diff --git a/src/CoreApi/BitswapApi.cs b/src/CoreApi/BitswapApi.cs new file mode 100644 index 0000000..3859c96 --- /dev/null +++ b/src/CoreApi/BitswapApi.cs @@ -0,0 +1,26 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Ipfs.CoreApi; +using System.IO; + +namespace Ipfs.Api +{ + + class BitswapApi : IBitswapApi + { + IpfsClient ipfs; + + internal BitswapApi(IpfsClient ipfs) + { + this.ipfs = ipfs; + } + } + +} diff --git a/src/CoreApi/BlockApi.cs b/src/CoreApi/BlockApi.cs index 599c3e2..358041c 100644 --- a/src/CoreApi/BlockApi.cs +++ b/src/CoreApi/BlockApi.cs @@ -7,50 +7,13 @@ using System.Text; using System.Threading; using System.Threading.Tasks; - +using Ipfs.CoreApi; +using System.IO; + namespace Ipfs.Api { - /// - /// Information about a raw IPFS Block. - /// - /// - public class BlockInfo - { - /// - /// The of the block. - /// - /// - /// The unique ID of the block. - /// - public Cid Id { get; set; } - - /// - /// The serialised size (in bytes) of the block. - /// - public long Size { get; set; } - } - - /// - /// Manages the raw IPFS blocks. - /// - /// - /// An IPFS Block is a byte sequence that represents an IPFS Object - /// (i.e. serialized byte buffers). It is useful to talk about them as "blocks" in Bitswap - /// and other things that do not care about what is being stored. - /// - /// It is also possible to store arbitrary stuff using ipfs block put/get as the API - /// does not check for proper IPFS Object formatting. - /// - /// - /// This may be very good or bad, we haven't decided yet 😄 - /// - /// - /// This API is accessed via the property. - /// - /// - /// Block API - public class BlockApi + class BlockApi : IBlockApi { IpfsClient ipfs; @@ -59,16 +22,7 @@ internal BlockApi(IpfsClient ipfs) this.ipfs = ipfs; } - /// - /// Gets a raw IPFS block. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - /// - /// The of the block. - /// - public async Task GetAsync(Cid id, CancellationToken cancel = default(CancellationToken)) // TODO CID support + public async Task GetAsync(Cid id, CancellationToken cancel = default(CancellationToken)) // TODO CID support { var data = await ipfs.DownloadBytesAsync("block/get", cancel, id); return new Block @@ -78,89 +32,63 @@ internal BlockApi(IpfsClient ipfs) }; } - /// - /// Stores a byte array as a raw IPFS block. - /// - /// - /// The byte array to send to the IPFS network. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - public async Task PutAsync(byte[] data, CancellationToken cancel = default(CancellationToken)) + public async Task PutAsync( + byte[] data, + string contentType = Cid.DefaultContentType, + string multiHash = MultiHash.DefaultAlgorithmName, + CancellationToken cancel = default(CancellationToken)) { - var json = await ipfs.UploadAsync("block/put", cancel, data); + var options = new List(); + if (multiHash != MultiHash.DefaultAlgorithmName || contentType != Cid.DefaultContentType) + { + options.Add($"mhtype={multiHash}"); + options.Add($"format={contentType}"); + } + var json = await ipfs.UploadAsync("block/put", cancel, data, options.ToArray()); var info = JObject.Parse(json); - return new Block - { - DataBytes = data, - Id = (string)info["Key"] - }; + return (string)info["Key"]; } - /// - /// Stores a raw IPFS block. - /// - /// - /// The to send to the IPFS network. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - public Task PutAsync(Block block, CancellationToken cancel = default(CancellationToken)) + public async Task PutAsync( + Stream data, + string contentType = Cid.DefaultContentType, + string multiHash = MultiHash.DefaultAlgorithmName, + CancellationToken cancel = default(CancellationToken)) { - return PutAsync(block.DataBytes, cancel); + var options = new List(); + if (multiHash != MultiHash.DefaultAlgorithmName || contentType != Cid.DefaultContentType) + { + options.Add($"mhtype={multiHash}"); + options.Add($"format={contentType}"); + } + var json = await ipfs.UploadAsync("block/put", cancel, data, options.ToArray()); + var info = JObject.Parse(json); + return (string)info["Key"]; } - /// - /// Information on a raw IPFS block. - /// - /// - /// The of the block. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - public async Task StatAsync(Cid id, CancellationToken cancel = default(CancellationToken)) + public async Task StatAsync(Cid id, CancellationToken cancel = default(CancellationToken)) { var json = await ipfs.DoCommandAsync("block/stat", cancel, id); var info = JObject.Parse(json); - return new BlockInfo + return new Block { Size = (long)info["Size"], Id = (string)info["Key"] }; } - /// - /// Remove a raw IPFS block. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - /// - /// The of the block. - /// - /// - /// If true do not raise exception when does not - /// exist. Default value is false. - /// - /// - /// The awaited Task will return the deleted or - /// if the hash does not exist and - /// is true. - /// - public async Task RemoveAsync(Cid id, bool ignoreNonexistent = false, CancellationToken cancel = default(CancellationToken)) // TODO CID support + public async Task RemoveAsync(Cid id, bool ignoreNonexistent = false, CancellationToken cancel = default(CancellationToken)) // TODO CID support { var json = await ipfs.DoCommandAsync("block/rm", cancel, id, "force=" + ignoreNonexistent.ToString().ToLowerInvariant()); if (json.Length == 0) - return ""; + return null; var result = JObject.Parse(json); var error = (string)result["Error"]; if (error != null) throw new HttpRequestException(error); - return (string)result["Hash"]; - } + return (Cid)(string)result["Hash"]; + } + } } diff --git a/src/CoreApi/ConfigApi.cs b/src/CoreApi/ConfigApi.cs index 7e597c9..1763766 100644 --- a/src/CoreApi/ConfigApi.cs +++ b/src/CoreApi/ConfigApi.cs @@ -6,22 +6,12 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Ipfs.CoreApi; namespace Ipfs.Api { - /// - /// Manages the IPFS Configuration. - /// - /// - /// This API is accessed via the property. - /// - /// Configuration values are JSON. Json.NET - /// is used to represent JSON. - /// - /// - /// Config API - public class ConfigApi + class ConfigApi : IConfigApi { IpfsClient ipfs; @@ -30,36 +20,12 @@ internal ConfigApi(IpfsClient ipfs) this.ipfs = ipfs; } - /// - /// Gets the entire configuration. - /// - /// - /// A containing the configuration. - /// public async Task GetAsync(CancellationToken cancel = default(CancellationToken)) { var json = await ipfs.DoCommandAsync("config/show", cancel); return JObject.Parse(json); } - /// - /// Gets the value of a configuration key. - /// - /// - /// The key name, such as "Addresses.API". - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - /// - /// The value of the as . - /// - /// - /// When the does not exist. - /// - /// - /// Keys are case sensistive. - /// public async Task GetAsync(string key, CancellationToken cancel = default(CancellationToken)) { var json = await ipfs.DoCommandAsync("config", cancel, key); @@ -67,36 +33,12 @@ internal ConfigApi(IpfsClient ipfs) return r["Value"]; } - /// - /// Adds or replaces a configuration value. - /// - /// - /// The key name, such as "Addresses.API". - /// - /// - /// The new value of the . - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// public async Task SetAsync(string key, string value, CancellationToken cancel = default(CancellationToken)) { var _ = await ipfs.DoCommandAsync("config", cancel, key, "arg=" + value); return; } - /// - /// Adds or replaces a configuration value. - /// - /// - /// The key name, such as "Addresses.API". - /// - /// - /// The new JSON value of the . - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// public async Task SetAsync(string key, JToken value, CancellationToken cancel = default(CancellationToken)) { var _ = await ipfs.DoCommandAsync("config", cancel, @@ -106,13 +48,6 @@ internal ConfigApi(IpfsClient ipfs) return; } - /// - /// Replaces the entire configuration. - /// - /// - /// - /// Not Yet Implemented. - /// public Task ReplaceAsync(JObject config) { throw new NotImplementedException(); diff --git a/src/CoreApi/DagApi.cs b/src/CoreApi/DagApi.cs index 71860fb..f576509 100644 --- a/src/CoreApi/DagApi.cs +++ b/src/CoreApi/DagApi.cs @@ -8,27 +8,13 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Ipfs.CoreApi; namespace Ipfs.Api { - /// - /// Manages the Directed Acrylic Graph. - /// - /// - /// - /// The Dag API seems to be a work in progress. There are no tests nor implemtations - /// of it. All methods throw . - /// - /// - /// This API is accessed via the property. - /// - /// - /// DAG API - public class DagApi + class DagApi : IDagApi { - static ILog log = LogManager.GetLogger(); - IpfsClient ipfs; internal DagApi(IpfsClient ipfs) @@ -36,21 +22,15 @@ internal DagApi(IpfsClient ipfs) this.ipfs = ipfs; } - /// - /// TODO - /// - public Task PutAsync(DagNode node, string multicodec, string hashAlgorithm = MultiHash.DefaultAlgorithmName, CancellationToken cancel = default(CancellationToken)) + + public Task PutAsync(ILinkedNode data, string contentType, string multiHash = MultiHash.DefaultAlgorithmName, CancellationToken cancel = default(CancellationToken)) { throw new NotImplementedException(); } - /// - /// TODO - /// - public Task GetAsync(string cid, CancellationToken cancel = default(CancellationToken)) + Task IDagApi.GetAsync(string path, CancellationToken cancel) { throw new NotImplementedException(); } - } } diff --git a/src/CoreApi/DhtApi.cs b/src/CoreApi/DhtApi.cs index e8627aa..09e6c1f 100644 --- a/src/CoreApi/DhtApi.cs +++ b/src/CoreApi/DhtApi.cs @@ -8,22 +8,12 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Ipfs.CoreApi; namespace Ipfs.Api { - /// - /// Manages the Distributed Hash Table. - /// - /// - /// The DHT is a place to store, not the value, but pointers to peers who have - /// the actual value. - /// - /// This API is accessed via the property. - /// - /// - /// Dht API - public class DhtApi + class DhtApi : IDhtApi { static ILog log = LogManager.GetLogger(); @@ -34,32 +24,11 @@ internal DhtApi(IpfsClient ipfs) this.ipfs = ipfs; } - /// - /// Information about an IPFS peer. - /// - /// - /// The ID of the IPFS peer. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// public Task FindPeerAsync(MultiHash id, CancellationToken cancel = default(CancellationToken)) { return ipfs.IdAsync(id, cancel); } - /// - /// Find the providers for content that is addressed by a hash. - /// - /// - /// The of the content. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - /// - /// A sequence of IPFS . - /// public async Task> FindProvidersAsync(Cid id, CancellationToken cancel = default(CancellationToken)) { var stream = await ipfs.PostDownloadAsync("dht/findprovs", cancel, id); diff --git a/src/CoreApi/FileSystemApi.cs b/src/CoreApi/FileSystemApi.cs index aed420b..15ac581 100644 --- a/src/CoreApi/FileSystemApi.cs +++ b/src/CoreApi/FileSystemApi.cs @@ -8,20 +8,12 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Ipfs.CoreApi; namespace Ipfs.Api { - /// - /// Manages the files/directories in IPFS. - /// - /// - /// - /// This API is accessed via the property. - /// - /// - /// Files API - public class FileSystemApi + class FileSystemApi : IFileSystemApi { static ILog log = LogManager.GetLogger(); @@ -34,14 +26,7 @@ internal FileSystemApi(IpfsClient ipfs) this.emptyFolder = new Lazy(() => ipfs.Object.NewDirectoryAsync().Result); } - /// - /// Add a file to the interplanetary file system. - /// - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - public async Task AddFileAsync(string path, CancellationToken cancel = default(CancellationToken)) + public async Task AddFileAsync(string path, CancellationToken cancel = default(CancellationToken)) { using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { @@ -50,30 +35,15 @@ internal FileSystemApi(IpfsClient ipfs) } } - /// - /// Add some text to the interplanetary file system. - /// - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - public Task AddTextAsync(string text, CancellationToken cancel = default(CancellationToken)) + public Task AddTextAsync(string text, CancellationToken cancel = default(CancellationToken)) { return AddAsync(new MemoryStream(Encoding.UTF8.GetBytes(text), false), "", cancel); } - /// - /// Add a to interplanetary file system. - /// - /// - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - public async Task AddAsync(Stream stream, string name = "", CancellationToken cancel = default(CancellationToken)) + public async Task AddAsync(Stream stream, string name = "", CancellationToken cancel = default(CancellationToken)) { var json = await ipfs.UploadAsync("add", cancel, stream); - var r = JObject.Parse(json); + var r = JObject.Parse(json); var fsn = new FileSystemNode { Id = (string)r["Hash"], @@ -83,23 +53,11 @@ internal FileSystemApi(IpfsClient ipfs) IpfsClient = ipfs }; if (log.IsDebugEnabled) - log.Debug("added " + fsn.Id + " " + fsn.Name); - return fsn; + log.Debug("added " + fsn.Id + " " + fsn.Name); + return fsn; } - /// - /// Add a directory and its files to the interplanetary file system. - /// - /// - /// The path to directory. - /// - /// - /// true to add sub-folders. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - public async Task AddDirectoryAsync(string path, bool recursive = true, CancellationToken cancel = default(CancellationToken)) + public async Task AddDirectoryAsync(string path, bool recursive = true, CancellationToken cancel = default(CancellationToken)) { // Add the files and sub-directories. path = Path.GetFullPath(path); @@ -187,7 +145,7 @@ internal FileSystemApi(IpfsClient ipfs) /// Is used to stop the task. When cancelled, the is raised. /// /// - public async Task ListFileAsync(string path, CancellationToken cancel = default(CancellationToken)) + public async Task ListFileAsync(string path, CancellationToken cancel = default(CancellationToken)) { var json = await ipfs.DoCommandAsync("file/ls", cancel, path); var r = JObject.Parse(json); diff --git a/src/CoreApi/GenericApi.cs b/src/CoreApi/GenericApi.cs index 4e46cdf..76dd4af 100644 --- a/src/CoreApi/GenericApi.cs +++ b/src/CoreApi/GenericApi.cs @@ -7,32 +7,19 @@ using System.Net; using System.Threading.Tasks; using System.Threading; +using Ipfs.CoreApi; namespace Ipfs.Api { - public partial class IpfsClient + public partial class IpfsClient : IGenericApi { - /// - /// Information about an IPFS peer. - /// - /// - /// The id of the IPFS peer. If not specified (e.g. null), then the local - /// peer is used. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - /// - /// Information on the peer node. - /// + /// public Task IdAsync(MultiHash peer = null, CancellationToken cancel = default(CancellationToken)) { return DoCommandAsync("id", cancel, peer?.ToString()); } - /// - /// Get the version information of the API server. - /// + /// public Task> VersionAsync(CancellationToken cancel = default(CancellationToken)) { return DoCommandAsync>("version", cancel); diff --git a/src/CoreApi/KeyApi.cs b/src/CoreApi/KeyApi.cs index b93d169..126fb6f 100644 --- a/src/CoreApi/KeyApi.cs +++ b/src/CoreApi/KeyApi.cs @@ -8,46 +8,22 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Ipfs.CoreApi; +using System.Security; namespace Ipfs.Api { - - /// - /// Manages asymmetric keys. - /// - /// - /// - /// The Key API is work in progress! There be dragons here. - /// - /// - /// This API is accessed via the property. - /// - /// - /// Key API - public class KeyApi + class KeyApi : IKeyApi { - static ILog log = LogManager.GetLogger(); - /// /// Information about a local key. /// - public class KeyInfo + public class KeyInfo : IKey { - /// - /// Unique identifier. - /// - /// - /// The of the key's public key. - /// + /// public MultiHash Id { get; set; } - /// - /// The locally assigned name to the key. - /// - /// - /// The name is only unique within the local peer node. The - /// is universally unique. - /// + /// public string Name { get; set; } /// @@ -64,25 +40,7 @@ internal KeyApi(IpfsClient ipfs) this.ipfs = ipfs; } - /// - /// Creates a new key. - /// - /// - /// The local name of the key. - /// - /// - /// The type of key to create; "rsa" or "ed25519". - /// - /// - /// The size, in bits, of the key. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - /// - /// The information on the newly created key. - /// - public async Task CreateAsync(string name, string keyType, int size, CancellationToken cancel = default(CancellationToken)) + public async Task CreateAsync(string name, string keyType, int size, CancellationToken cancel = default(CancellationToken)) { return await ipfs.DoCommandAsync("key/gen", cancel, name, @@ -90,16 +48,7 @@ internal KeyApi(IpfsClient ipfs) $"size={size}"); } - /// - /// List all the keys. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - /// - /// A sequence of IPFS keys. - /// - public async Task> ListAsync(CancellationToken cancel = default(CancellationToken)) + public async Task> ListAsync(CancellationToken cancel = default(CancellationToken)) { var json = await ipfs.DoCommandAsync("key/list", cancel, null, "l=true"); var keys = (JArray)(JObject.Parse(json)["Keys"]); @@ -111,19 +60,7 @@ internal KeyApi(IpfsClient ipfs) }); } - /// - /// Delete the specified key. - /// - /// - /// The local name of the key. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - /// - /// A sequence of IPFS keys that were deleted. - /// - public async Task> RemoveAsync(string name, CancellationToken cancel = default(CancellationToken)) + public async Task RemoveAsync(string name, CancellationToken cancel = default(CancellationToken)) { var json = await ipfs.DoCommandAsync("key/rm", cancel, name); var keys = (JArray)(JObject.Parse(json)["Keys"]); @@ -132,7 +69,23 @@ internal KeyApi(IpfsClient ipfs) { Id = (string)k["Id"], Name = (string)k["Name"] - }); + }) + .First(); + } + + public Task RenameAsync(string oldName, string newName, CancellationToken cancel = default(CancellationToken)) + { + throw new NotImplementedException(); + } + + public Task Export(string name, SecureString password, CancellationToken cancel = default(CancellationToken)) + { + throw new NotImplementedException(); + } + + public Task Import(string name, string pem, SecureString password = null, CancellationToken cancel = default(CancellationToken)) + { + throw new NotImplementedException(); } } } diff --git a/src/CoreApi/NameApi.cs b/src/CoreApi/NameApi.cs new file mode 100644 index 0000000..d75359d --- /dev/null +++ b/src/CoreApi/NameApi.cs @@ -0,0 +1,35 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Ipfs.CoreApi; +using System.IO; + +namespace Ipfs.Api +{ + + class NameApi : INameApi + { + IpfsClient ipfs; + + internal NameApi(IpfsClient ipfs) + { + this.ipfs = ipfs; + } + + public Task PublishAsync(string path, bool resolve = true, string key = "self", TimeSpan? lifetime = null, CancellationToken cancel = default(CancellationToken)) + { + throw new NotImplementedException(); + } + + public Task ResolveAsync(string name, bool recursive = false, bool nocache = false, CancellationToken cancel = default(CancellationToken)) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/CoreApi/ObjectApi.cs b/src/CoreApi/ObjectApi.cs index 395efd2..d964da2 100644 --- a/src/CoreApi/ObjectApi.cs +++ b/src/CoreApi/ObjectApi.cs @@ -8,20 +8,12 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Ipfs.CoreApi; namespace Ipfs.Api { - /// - /// Manages the Directed Acrylic Graph. - /// - /// - /// - /// This API is accessed via the property. - /// - /// - /// Object API - public class ObjectApi + class ObjectApi : IObjectApi { static ILog log = LogManager.GetLogger(); @@ -63,29 +55,11 @@ internal ObjectApi(IpfsClient ipfs) this.ipfs = ipfs; } - /// - /// Creates a new file directory in IPFS. - /// - /// - /// - /// Equivalent to NewAsync("unixfs-dir"). - /// public Task NewDirectoryAsync(CancellationToken cancel = default(CancellationToken)) { return NewAsync("unixfs-dir", cancel); } - /// - /// Create a new MerkleDAG node, using a specific layout. - /// - /// null or "unixfs-dir". - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - /// - /// - /// Caveat: So far, only UnixFS object layouts are supported. - /// public async Task NewAsync(string template = null, CancellationToken cancel = default(CancellationToken)) { var json = await ipfs.DoCommandAsync("object/new", cancel, template); @@ -93,80 +67,28 @@ internal ObjectApi(IpfsClient ipfs) return await GetAsync(hash); } - /// - /// Fetch a MerkleDAG node. - /// - /// - /// The to the node. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - /// public async Task GetAsync(Cid id, CancellationToken cancel = default(CancellationToken)) { var json = await ipfs.DoCommandAsync("object/get", cancel, id); return GetDagFromJson(json); } - /// - /// Store a MerkleDAG node. - /// - /// - /// The opaque data, can be null. - /// - /// - /// The links to other nodes. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// public Task PutAsync(byte[] data, IEnumerable links = null, CancellationToken cancel = default(CancellationToken)) { return PutAsync(new DagNode(data, links), cancel); } - /// - /// Store a MerkleDAG node. - /// - /// A merkle dag - /// - /// Is used to stop the task. When cancelled, the is raised. - /// public async Task PutAsync(DagNode node, CancellationToken cancel = default(CancellationToken)) { var json = await ipfs.UploadAsync("object/put", cancel, node.ToArray(), "inputenc=protobuf"); return node; } - /// - /// Get the data of a MerkleDAG node. - /// - /// - /// The of the node. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - /// - /// - /// The caller must dispose the returned . - /// public Task DataAsync(Cid id, CancellationToken cancel = default(CancellationToken)) { return ipfs.DownloadAsync("object/data", cancel, id); } - /// - /// Get the links of a MerkleDAG node. - /// - /// - /// The id of the node. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - /// A sequence of links public async Task> LinksAsync(Cid id, CancellationToken cancel = default(CancellationToken)) { var json = await ipfs.DoCommandAsync("object/links", cancel, id); diff --git a/src/CoreApi/PinApi.cs b/src/CoreApi/PinApi.cs index 0253638..4570e45 100644 --- a/src/CoreApi/PinApi.cs +++ b/src/CoreApi/PinApi.cs @@ -6,21 +6,12 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Ipfs.CoreApi; namespace Ipfs.Api { - /// - /// Manages pinned objects (local stored and permanent). - /// - /// - /// This API is accessed via the property. - /// - /// Pinned objects are locally stored and never garbage collected. - /// - /// - /// Pin API - public class PinApi + class PinApi : IPinApi { IpfsClient ipfs; @@ -29,75 +20,29 @@ internal PinApi(IpfsClient ipfs) this.ipfs = ipfs; } - /// - /// Adds an IPFS object to the pinset and also stores it to the IPFS repo. pinset is the set of hashes currently pinned (not gc'able). - /// - /// - /// A path to an existing object, such as "QmXarR6rgkQ2fDSHjSY5nM2kuCXKYGViky5nohtwgF65Ec/about" - /// or "QmZTR5bcpQD7cFgTorqxZDYaew1Wqgfbd2ud9QqGPAkK2V" - /// - /// - /// true to recursively pin links of object; otherwise, false to only pin - /// the specified object. Default is true. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - public async Task AddAsync(string path, bool recursive = true, CancellationToken cancel = default(CancellationToken)) + public async Task> AddAsync(string path, bool recursive = true, CancellationToken cancel = default(CancellationToken)) { var opts = "recursive=" + recursive.ToString().ToLowerInvariant(); var json = await ipfs.DoCommandAsync("pin/add", cancel, path, opts); return ((JArray)JObject.Parse(json)["Pins"]) - .Select(p => new PinnedObject { Id = (string)p }) - .ToArray(); + .Select(p => (Cid)(string)p); } - /// - /// List all the objects pinned to local storage. - /// - /// - /// The type of pinned objects to return. - /// Defaults to . - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - public async Task ListAsync(PinMode mode = PinMode.All, CancellationToken cancel = default(CancellationToken)) + public async Task> ListAsync(CancellationToken cancel = default(CancellationToken)) { - var filter = "type=" + mode.ToString().ToLowerInvariant(); - var json = await ipfs.DoCommandAsync("pin/ls", cancel, null, filter); + var json = await ipfs.DoCommandAsync("pin/ls", cancel); var keys = (JObject)(JObject.Parse(json)["Keys"]); return keys .Properties() - .Select(p => new PinnedObject - { - Id = p.Name, - Mode = (PinMode)Enum.Parse(typeof(PinMode), (string)keys[p.Name]["Type"], true) - }) - .ToArray(); + .Select(p => (Cid)p.Name); } - /// - /// Unpin an object. - /// - /// - /// A path to an existing object, such as "QmXarR6rgkQ2fDSHjSY5nM2kuCXKYGViky5nohtwgF65Ec/about" - /// or "QmZTR5bcpQD7cFgTorqxZDYaew1Wqgfbd2ud9QqGPAkK2V" - /// - /// - /// true to recursively unpin links of object; otherwise, false to only unpin - /// the specified object. Default is true. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - public async Task RemoveAsync(string path, bool recursive = true, CancellationToken cancel = default(CancellationToken)) + public async Task> RemoveAsync(Cid id, bool recursive = true, CancellationToken cancel = default(CancellationToken)) { var opts = "recursive=" + recursive.ToString().ToLowerInvariant(); - var json = await ipfs.DoCommandAsync("pin/rm", cancel, path, opts); + var json = await ipfs.DoCommandAsync("pin/rm", cancel, id, opts); return ((JArray)JObject.Parse(json)["Pins"]) - .Select(p => new PinnedObject { Id = (string)p }) - .ToArray(); + .Select(p => (Cid)(string)p); } } diff --git a/src/CoreApi/PubSubApi.cs b/src/CoreApi/PubSubApi.cs index c2e3803..4e891c7 100644 --- a/src/CoreApi/PubSubApi.cs +++ b/src/CoreApi/PubSubApi.cs @@ -8,26 +8,12 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Ipfs.CoreApi; namespace Ipfs.Api { - /// - /// Allows you to publish messages to a given topic, and also to - /// subscribe to new messages on a given topic. - /// - /// - /// This API is accessed via the property. - /// - /// This is an experimental feature. It is not intended in its current state - /// to be used in a production environment. - /// - /// - /// To use, the daemon must be run with '--enable-pubsub-experiment'. - /// - /// - /// PUBSUB API - public class PubSubApi + class PubSubApi : IPubSubApi { static ILog log = LogManager.GetLogger(); @@ -38,15 +24,6 @@ internal PubSubApi(IpfsClient ipfs) this.ipfs = ipfs; } - /// - /// Get the subscribed topics. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - /// - /// A sequence of for each topic. - /// public async Task> SubscribedTopicsAsync(CancellationToken cancel = default(CancellationToken)) { var json = await ipfs.DoCommandAsync("pubsub/ls", cancel); @@ -56,39 +33,15 @@ internal PubSubApi(IpfsClient ipfs) return strings.Select(s => (string)s); } - /// - /// Get the peers that are pubsubing with us. - /// - /// - /// When specified, only peers pubsubing on the topic are returned. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - /// - /// A sequence of for each peer ID. - /// - public async Task> PeersAsync(string topic = null, CancellationToken cancel = default(CancellationToken)) + public async Task> PeersAsync(string topic = null, CancellationToken cancel = default(CancellationToken)) { var json = await ipfs.DoCommandAsync("pubsub/peers", cancel, topic); var result = JObject.Parse(json); var strings = result["Strings"] as JArray; - if (strings == null) return new string[0]; - return strings.Select(s => (string)s); + if (strings == null) return new Peer[0]; + return strings.Select(s => new Peer { Id = (string)s } ); } - /// - /// Publish a message to a given topic. - /// - /// - /// The topic name. - /// - /// - /// The message to publish. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// public async Task Publish(string topic, string message, CancellationToken cancel = default(CancellationToken)) { // Avoid seqno bug in go-floodsub, see https://github.com/libp2p/go-floodsub/issues/52 @@ -98,26 +51,7 @@ internal PubSubApi(IpfsClient ipfs) return; } - /// - /// Subscribe to messages on a given topic. - /// - /// - /// The topic name. - /// - /// - /// The action to perform when a is received. - /// - /// - /// Is used to stop the topic listener. When cancelled, the - /// is NOT raised. - /// - /// - /// After the topic listener is register with the IPFS server. - /// - /// - /// The is invoked on the topic listener thread. - /// - public async Task Subscribe(string topic, Action handler, CancellationToken cancellationToken) + public async Task Subscribe(string topic, Action handler, CancellationToken cancellationToken) { var messageStream = await ipfs.PostDownloadAsync("pubsub/sub", cancellationToken, topic); var sr = new StreamReader(messageStream); diff --git a/src/CoreApi/SwarmApi.cs b/src/CoreApi/SwarmApi.cs index 3ee1c67..9c4f722 100644 --- a/src/CoreApi/SwarmApi.cs +++ b/src/CoreApi/SwarmApi.cs @@ -8,21 +8,12 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Ipfs.CoreApi; namespace Ipfs.Api { - /// - /// Manages the swarm of peers. - /// - /// - /// The swarm is a sequence of peer nodes. - /// - /// This API is accessed via the property. - /// - /// - /// Swarm API - public class SwarmApi + class SwarmApi : ISwarmApi { IpfsClient ipfs; @@ -31,13 +22,6 @@ internal SwarmApi(IpfsClient ipfs) this.ipfs = ipfs; } - /// - /// Get the peers in the current swarm. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - /// A sequence of peer nodes. public async Task> AddressesAsync(CancellationToken cancel = default(CancellationToken)) { var json = await ipfs.DoCommandAsync("swarm/addrs", cancel); @@ -50,16 +34,7 @@ internal SwarmApi(IpfsClient ipfs) }); } - /// - /// Get the peers that are connected to this node. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// - /// - /// A sequence of Connected Peers. - /// - public async Task> PeersAsync(CancellationToken cancel = default(CancellationToken)) + public async Task> PeersAsync(CancellationToken cancel = default(CancellationToken)) { var json = await ipfs.DoCommandAsync("swarm/peers", cancel, null, "verbose=true"); var result = JObject.Parse(json); @@ -73,7 +48,7 @@ internal SwarmApi(IpfsClient ipfs) { var parts = ((string)s).Split(' '); var address = new MultiAddress(parts[0]); - return new ConnectedPeer + return new Peer { Id = address.Protocols.First(p => p.Name == "ipfs").Value, ConnectedAddress = parts[0], @@ -86,7 +61,7 @@ internal SwarmApi(IpfsClient ipfs) var peers = (JArray)result["Peers"]; if (peers != null) { - return peers.Select(p => new ConnectedPeer + return peers.Select(p => new Peer { Id = (string)p["Peer"], ConnectedAddress = new MultiAddress((string)p["Addr"] + "/ipfs/" + (string)p["Peer"]), @@ -118,31 +93,11 @@ TimeSpan ParseLatency(string latency) throw new FormatException(String.Format("Invalid latency unit '{0}'.", latency)); } - /// - /// Connect to a peer. - /// - /// - /// An ipfs , such as - /// /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// public async Task ConnectAsync(MultiAddress address, CancellationToken cancel = default(CancellationToken)) { await ipfs.DoCommandAsync("swarm/connect", cancel, address.ToString()); } - /// - /// Disconnect from a peer. - /// - /// - /// An ipfs , such as - /// /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ. - /// - /// - /// Is used to stop the task. When cancelled, the is raised. - /// public async Task DisconnectAsync(MultiAddress address, CancellationToken cancel = default(CancellationToken)) { await ipfs.DoCommandAsync("swarm/disconnect", cancel, address.ToString()); diff --git a/src/FileSystemLink.cs b/src/FileSystemLink.cs index bc9e3c2..3089d5e 100644 --- a/src/FileSystemLink.cs +++ b/src/FileSystemLink.cs @@ -4,7 +4,7 @@ namespace Ipfs.Api /// /// A link to another file system node in IPFS. /// - public class FileSystemLink : IMerkleLink + public class FileSystemLink : IFileSystemLink { /// public string Name { get; set; } @@ -15,13 +15,7 @@ public class FileSystemLink : IMerkleLink /// public long Size { get; set; } - /// - /// Determines if the link is a directory (folder). - /// - /// - /// true if the link is a directory; Otherwise false, - /// the link is some type of a file. - /// + /// public bool IsDirectory { get; set; } } } diff --git a/src/FileSystemNode.cs b/src/FileSystemNode.cs index d8f190a..168a105 100644 --- a/src/FileSystemNode.cs +++ b/src/FileSystemNode.cs @@ -8,10 +8,10 @@ namespace Ipfs.Api { /// - public class FileSystemNode : IMerkleNode + public class FileSystemNode : IFileSystemNode { IpfsClient ipfsClient; - IEnumerable links; + IEnumerable links; long? size; bool? isDirectory; @@ -37,11 +37,12 @@ public Stream DataStream return IpfsClient.FileSystem.ReadFileAsync(Id).Result; } } + /// public Cid Id { get; set; } /// - public IEnumerable Links { + public IEnumerable Links { get { if (links == null) GetInfo(); @@ -99,15 +100,18 @@ public bool IsDirectory public string Name { get; set; } /// - public FileSystemLink ToLink(string name = null) + public IFileSystemLink ToLink(string name = "") { - return new FileSystemLink + var link = new FileSystemLink { - Name = name ?? Name, + Name = string.IsNullOrWhiteSpace(name) ? Name : name, Id = Id, Size = Size, IsDirectory = IsDirectory }; + Console.WriteLine("my name " + Name); + Console.WriteLine("link name " + link.Name); + return link; } internal IpfsClient IpfsClient diff --git a/src/IpfsApi.csproj b/src/IpfsApi.csproj index a886030..5f84cf6 100644 --- a/src/IpfsApi.csproj +++ b/src/IpfsApi.csproj @@ -18,21 +18,19 @@ Provides .Net client access to the InterPlanetary File System. false - © 2015-2017 Richard Schneider + © 2015-2018 Richard Schneider ipfs peer-to-peer distributed file-system True https://github.com/richardschneider/net-ipfs-api/blob/master/LICENSE https://github.com/richardschneider/net-ipfs-api https://github.com/ipfs/logo/blob/master/platform-icons/osx-menu-bar.png - - + - + - diff --git a/src/IpfsClient.cs b/src/IpfsClient.cs index ba6cf7c..c90af5b 100644 --- a/src/IpfsClient.cs +++ b/src/IpfsClient.cs @@ -11,6 +11,7 @@ using System.Net; using System.Net.Http.Headers; using System.Threading; +using Ipfs.CoreApi; namespace Ipfs.Api { @@ -26,7 +27,7 @@ namespace Ipfs.Api /// IpfsClient is thread safe, only one instance is required /// by the application. /// - public partial class IpfsClient + public partial class IpfsClient : ICoreApi { static ILog log = LogManager.GetLogger(typeof(IpfsClient)); static object safe = new object(); @@ -59,7 +60,8 @@ public IpfsClient() var version = typeof(IpfsClient).GetTypeInfo().Assembly.GetName().Version; UserAgent = string.Format("net-ipfs/{0}.{1}", version.Major, version.Minor); TrustedPeers = new TrustedPeerCollection(this); - PinnedObjects = new PinnedCollection(this); + + Bitswap = new BitswapApi(this); Block = new BlockApi(this); Config = new ConfigApi(this); Pin = new PinApi(this); @@ -70,6 +72,8 @@ public IpfsClient() FileSystem = new FileSystemApi(this); PubSub = new PubSubApi(this); Key = new KeyApi(this); + Generic = this; + Name = new NameApi(this); } /// @@ -108,63 +112,44 @@ public IpfsClient(string host) /// public TrustedPeerCollection TrustedPeers { get; private set; } - /// - /// The list of objects that are permanently stored on the local host. - /// - /// - /// This is equilivent to ipfs pin ls. - /// - public PinnedCollection PinnedObjects { get; private set; } + /// + public IBitswapApi Bitswap { get; private set; } - /// - /// Provides access to the Block API. - /// - public BlockApi Block { get; private set; } + /// + public IGenericApi Generic { get; private set; } - /// - /// Provides access to the Config API. - /// - public ConfigApi Config { get; private set; } + /// + public INameApi Name { get; private set; } - /// - /// Provides access to the Pin API. - /// - public PinApi Pin { get; private set; } + /// + public IBlockApi Block { get; private set; } - /// - /// Provides access to the DAG API. - /// - public DagApi Dag { get; private set; } + /// + public IConfigApi Config { get; private set; } - /// - /// Provides access to the Distributed Hash Table API. - /// - public DhtApi Dht { get; private set; } + /// + public IPinApi Pin { get; private set; } - /// - /// Provides access to the Swarm API. - /// - public SwarmApi Swarm { get; private set; } + /// + public IDagApi Dag { get; private set; } - /// - /// Provides access to the Object API. - /// - public ObjectApi Object { get; private set; } + /// + public IDhtApi Dht { get; private set; } - /// - /// Provides access to the File System API. - /// - public FileSystemApi FileSystem { get; private set; } + /// + public ISwarmApi Swarm { get; private set; } - /// - /// Provides access to the PubSub API. - /// - public PubSubApi PubSub { get; private set; } + /// + public IObjectApi Object { get; private set; } - /// - /// Provides access to the Key API. - /// - public KeyApi Key { get; private set; } + /// + public IFileSystemApi FileSystem { get; private set; } + + /// + public IPubSubApi PubSub { get; private set; } + + /// + public IKeyApi Key { get; private set; } Uri BuildCommand(string command, string arg = null, params string[] options) { diff --git a/src/MerkleNode.cs b/src/MerkleNode.cs index 0cce5a0..c95066a 100644 --- a/src/MerkleNode.cs +++ b/src/MerkleNode.cs @@ -11,17 +11,12 @@ namespace Ipfs.Api /// The IPFS MerkleDag is the datastructure at the heart of IPFS. It is an acyclic directed graph whose edges are hashes. /// /// - /// Initially an MerkleNode is just constructed with its Cid. Its other properties are lazily loaded. + /// Initially an MerkleNode is just constructed with its Cid. /// public class MerkleNode : IMerkleNode, IEquatable { - bool hasObjectStats; bool hasBlockStats; long blockSize; - long cumulativeSize; - long dataSize; - long linksSize; - long linksCount; string name; IEnumerable links; IpfsClient ipfsClient; @@ -54,7 +49,7 @@ public MerkleNode(Cid id, string name = null) public MerkleNode(string path, string name = null) { if (string.IsNullOrWhiteSpace(path)) - throw new ArgumentNullException("payh"); + throw new ArgumentNullException("path"); if (path.StartsWith("/ipfs/")) path = path.Substring(6); @@ -119,29 +114,16 @@ public long BlockSize } } - /// - /// Size of the Links segment. - /// - public long LinksSize + /// + /// + public long Size { get { - GetObjectStats(); - return linksSize; + return BlockSize; } } - /// - /// TODO - /// - public long LinksCount - { - get - { - GetObjectStats(); - return linksCount; - } - } /// public IEnumerable Links @@ -157,30 +139,6 @@ public IEnumerable Links } } - /// - /// Size of the Data segment. - /// - public long DataSize - { - get - { - GetObjectStats(); - return dataSize; - } - } - - /// - /// Cumulative size of object and its references. - /// - public long CumulativeSize - { - get - { - GetObjectStats(); - return cumulativeSize; - } - } - /// public byte[] DataBytes { @@ -205,30 +163,6 @@ public IMerkleLink ToLink(string name = null) return new DagLink(name ?? Name, Id, BlockSize); } - /// - /// Get object statistics about the node, ipfs object stat hash - /// - /// - /// The object stats include the block stats. - /// - void GetObjectStats() - { - if (hasObjectStats) - return; - - var stats = IpfsClient.Object.StatAsync(Id).Result; - blockSize = stats.BlockSize; - cumulativeSize = stats.CumulativeSize; - dataSize = stats.DataSize; - linksSize = stats.LinksSize; - linksCount = stats.NumLinks; - if (linksCount == 0) - links = new DagLink[0]; - - hasObjectStats = true; - hasBlockStats = true; - } - /// /// Get block statistics about the node, ipfs block stat key /// diff --git a/src/PinMode.cs b/src/PinMode.cs deleted file mode 100644 index 4036569..0000000 --- a/src/PinMode.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Ipfs.Api -{ - /// - /// The method used to pin an IPFS object. - /// - [Flags] - public enum PinMode - { - /// - /// Pin the specific object, and indirectly pin all its decendants - /// - Recursive = 1, - - /// - /// Pin the specific object. - /// - Direct = 2, - - /// - /// Pinned indirectly by an ancestor (like a refcount) - /// - Indirect = 4, - - /// - /// All - /// - All = 7 - } -} diff --git a/src/PinnedCollection .cs b/src/PinnedCollection .cs deleted file mode 100644 index b0fb33c..0000000 --- a/src/PinnedCollection .cs +++ /dev/null @@ -1,181 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.IO; -using System.Net; -using Newtonsoft.Json.Linq; - -namespace Ipfs.Api -{ - /// - /// A list of pinned object. - /// - /// - /// This is the list of objects that are permanently stored on the local host. - /// ipfs pin command. - /// - /// - /// A series of . - /// - public class PinnedCollection : ICollection - { - IpfsClient ipfs; - PinnedObject[] pins; - - internal PinnedCollection(IpfsClient ipfs) - { - this.ipfs = ipfs; - } - - PinnedObject[] Pins - { - get - { - if (pins == null) - { - Refresh(); - } - return pins; - } - } - - /// - public void Add(PinnedObject obj) - { - if (obj == null) - throw new ArgumentNullException(); - var _ = ipfs.Pin.AddAsync(obj.Id, obj.Mode == PinMode.Recursive).Result; - pins = null; - } - - /// - /// Pin an object. - /// - /// - /// The of the object. - /// - /// - /// True to also pin the object's links; False to just pin the object. Defaults to true. - /// - /// - /// Equivalent to ipfs pin add id. - /// - public void Add(Cid id, bool recursive = true) - { - Add(new PinnedObject - { - Id = id, - Mode = recursive ? PinMode.Recursive : PinMode.Direct - }); - } - - /// - /// Remove all the trusted peers. - /// - /// - /// Equivalent to ipfs bootstrap rm --all. - /// - public void Clear() - { - throw new NotImplementedException(); - } - - /// - public bool Contains(PinnedObject item) - { - return Pins.Contains(item); - } - - /// - /// Determines if the collection contains a - /// with the specified id. - /// - /// - /// - public bool Contains(Cid id) - { - return Pins.Any(pin => pin.Id == id); - } - - /// - public void CopyTo(PinnedObject[] array, int index) - { - Pins.CopyTo(array, index); - } - - /// - public int Count - { - get - { - return Pins.Length; - } - } - - /// - public bool IsReadOnly - { - get { return false; } - } - - /// - /// Remove the pinned object. - /// - /// - /// Equivalent to ipfs pin rm id. - /// - public bool Remove(PinnedObject obj) - { - if (obj == null) - throw new ArgumentNullException(); - - var unpins = ipfs.Pin.RemoveAsync(obj.Id, obj.Mode == PinMode.Recursive).Result; - pins = null; - return unpins.Any(p => p.Id == obj.Id); - } - - /// - /// Unpin an object. - /// - /// - /// The of the object. - /// - /// - /// True to also unpin the object's links; False to just unpin the object. Defaults to true. - /// - /// - /// Equivalent to ipfs pin rm id. - /// - public bool Remove(Cid id, bool recursive = true) - { - return Remove(new PinnedObject - { - Id = id, - Mode = recursive ? PinMode.Recursive : PinMode.Direct - }); - } - - /// - public IEnumerator GetEnumerator() - { - return ((IEnumerable) Pins).GetEnumerator(); - } - - /// - IEnumerator IEnumerable.GetEnumerator() - { - return Pins.GetEnumerator(); - } - - /// - /// Ask IPFS for the pinned objects. - /// - public void Refresh() - { - pins = ipfs.Pin.ListAsync().Result; - } - } -} diff --git a/src/PinnedObject.cs b/src/PinnedObject.cs deleted file mode 100644 index 2f801af..0000000 --- a/src/PinnedObject.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Ipfs.Api -{ - /// - /// An IPFS object that is permanently stored on the local host. - /// - public class PinnedObject - { - /// - /// The of the object. - /// - public Cid Id { get; set; } - - /// - /// The method used to pin the object. - /// - public PinMode Mode { get; set; } - - /// - public override string ToString() - { - return Id + " " + Mode.ToString(); - } - - } -} diff --git a/src/PublishedMessage.cs b/src/PublishedMessage.cs index 8208227..6df6e3b 100644 --- a/src/PublishedMessage.cs +++ b/src/PublishedMessage.cs @@ -13,7 +13,7 @@ namespace Ipfs.Api /// /// The is used to publish and subsribe to a message. /// - public class PublishedMessage + public class PublishedMessage : IPublishedMessage { /// /// Creates a new instance of from the @@ -32,38 +32,19 @@ public PublishedMessage(string json) this.Topics = topics.Select(t => (string)t); } - /// - /// The sender of the message. - /// - /// - /// This is the peer ID of the node that sent the message. - /// - public string Sender { get; private set; } + /// + public Peer Sender { get; private set; } - /// - /// The topics of the message. - /// + /// public IEnumerable Topics { get; private set; } - /// - /// The sequence number of the message. - /// + /// public byte[] SequenceNumber { get; private set; } - /// - /// Contents as a byte array. - /// - /// - /// The contents as a sequence of bytes. - /// + /// public byte[] DataBytes { get; private set; } - /// - /// Contents as a stream of bytes. - /// - /// - /// The contents as a stream of bytes. - /// + /// public Stream DataStream { get @@ -72,6 +53,11 @@ public Stream DataStream } } + /// + public long Size + { + get { return DataBytes.Length; } + } /// /// Contents as a string. /// @@ -85,5 +71,8 @@ public string DataString return Encoding.UTF8.GetString(DataBytes); } } + + /// + public Cid Id => throw new NotImplementedException(); } } diff --git a/test/CoreApi/BlockApiTest.cs b/test/CoreApi/BlockApiTest.cs index 7dc6319..cdb41f2 100644 --- a/test/CoreApi/BlockApiTest.cs +++ b/test/CoreApi/BlockApiTest.cs @@ -1,74 +1,127 @@ -using Ipfs.Api; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using System.Text; -using System.Threading.Tasks; - -namespace Ipfs.Api -{ - - [TestClass] - public class BlockApiTest - { - IpfsClient ipfs = TestFixture.Ipfs; - string id = "QmPv52ekjS75L4JmHpXVeuJ5uX2ecSfSZo88NSyxwA3rAQ"; - byte[] blob = Encoding.UTF8.GetBytes("blorb"); - - [TestMethod] - public void Put_Bytes() - { - var block = ipfs.Block.PutAsync(blob).Result; - Assert.AreEqual(id, (string)block.Id); - CollectionAssert.AreEqual(blob, block.DataBytes); - } - - [TestMethod] - public void Put_Block() - { - var block1 = new Block { DataBytes = blob }; - var block2 = ipfs.Block.PutAsync(block1).Result; - Assert.AreEqual(id, (string)block2.Id); - CollectionAssert.AreEqual(blob, block2.DataBytes); - } - - [TestMethod] - public void Get() - { - var _ = ipfs.Block.PutAsync(blob).Result; - var block = ipfs.Block.GetAsync(id).Result; - Assert.AreEqual(id, (string)block.Id); - CollectionAssert.AreEqual(blob, block.DataBytes); - } - - [TestMethod] - public void Stat() - { - var _ = ipfs.Block.PutAsync(blob).Result; - var info = ipfs.Block.StatAsync(id).Result; - Assert.AreEqual(id, (string)info.Id); - Assert.AreEqual(5, info.Size); - } - - [TestMethod] - public async Task Remove() - { - var _ = ipfs.Block.PutAsync(blob).Result; - var removed = await ipfs.Block.RemoveAsync(id); - Assert.AreEqual(id, removed); - } - - [TestMethod] - public void Remove_Unknown() - { - ExceptionAssert.Throws(() => { var _ = ipfs.Block.RemoveAsync("QmPv52ekjS75L4JmHpXVeuJ5uX2ecSfSZo88NSyxwA3rFF").Result; }); - } - - [TestMethod] - public async Task Remove_Unknown_OK() - { - var removed = await ipfs.Block.RemoveAsync("QmPv52ekjS75L4JmHpXVeuJ5uX2ecSfSZo88NSyxwA3rFF", true); - Assert.AreEqual("", removed); - } - - } -} +using Ipfs.Api; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.IO; +using System.Text; +using System.Threading.Tasks; + +namespace Ipfs.Api +{ + + [TestClass] + public class BlockApiTest + { + IpfsClient ipfs = TestFixture.Ipfs; + string id = "QmPv52ekjS75L4JmHpXVeuJ5uX2ecSfSZo88NSyxwA3rAQ"; + byte[] blob = Encoding.UTF8.GetBytes("blorb"); + + [TestMethod] + public void Put_Bytes() + { + var cid = ipfs.Block.PutAsync(blob).Result; + Assert.AreEqual(id, (string)cid); + + var data = ipfs.Block.GetAsync(cid).Result; + Assert.AreEqual(blob.Length, data.Size); + CollectionAssert.AreEqual(blob, data.DataBytes); + } + + [TestMethod] + public void Put_Bytes_ContentType() + { + var cid = ipfs.Block.PutAsync(blob, contentType: "raw").Result; + Assert.AreEqual("zb2rhYDhWhxyHN6HFAKGvHnLogYfnk9KvzBUZvCg7sYhS22N8", (string)cid); + + var data = ipfs.Block.GetAsync(cid).Result; + Assert.AreEqual(blob.Length, data.Size); + CollectionAssert.AreEqual(blob, data.DataBytes); + } + + [TestMethod] + public void Put_Bytes_Hash() + { + var cid = ipfs.Block.PutAsync(blob, "raw", "sha2-512").Result; + Assert.AreEqual("zB7NCfbtX9WqFowgroqE19J841VESUhLc1enF7faMSMhTPMR4M3kWq7rS2AfCvdHeZ3RdfoSM45q7svoMQmw2NDD37z9F", (string)cid); + + var data = ipfs.Block.GetAsync(cid).Result; + Assert.AreEqual(blob.Length, data.Size); + CollectionAssert.AreEqual(blob, data.DataBytes); + } + + [TestMethod] + public void Put_Stream() + { + var cid = ipfs.Block.PutAsync(new MemoryStream(blob)).Result; + Assert.AreEqual(id, (string)cid); + + var data = ipfs.Block.GetAsync(cid).Result; + Assert.AreEqual(blob.Length, data.Size); + CollectionAssert.AreEqual(blob, data.DataBytes); + } + + [TestMethod] + public void Put_Stream_ContentType() + { + var cid = ipfs.Block.PutAsync(new MemoryStream(blob), contentType: "raw").Result; + Assert.AreEqual("zb2rhYDhWhxyHN6HFAKGvHnLogYfnk9KvzBUZvCg7sYhS22N8", (string)cid); + + var data = ipfs.Block.GetAsync(cid).Result; + Assert.AreEqual(blob.Length, data.Size); + CollectionAssert.AreEqual(blob, data.DataBytes); + } + + [TestMethod] + public void Put_Stream_Hash() + { + var cid = ipfs.Block.PutAsync(new MemoryStream(blob), "raw", "sha2-512").Result; + Assert.AreEqual("zB7NCfbtX9WqFowgroqE19J841VESUhLc1enF7faMSMhTPMR4M3kWq7rS2AfCvdHeZ3RdfoSM45q7svoMQmw2NDD37z9F", (string)cid); + + var data = ipfs.Block.GetAsync(cid).Result; + Assert.AreEqual(blob.Length, data.Size); + CollectionAssert.AreEqual(blob, data.DataBytes); + } + + [TestMethod] + public void Get() + { + var _ = ipfs.Block.PutAsync(blob).Result; + var block = ipfs.Block.GetAsync(id).Result; + Assert.AreEqual(id, (string)block.Id); + CollectionAssert.AreEqual(blob, block.DataBytes); + var blob1 = new byte[blob.Length]; + block.DataStream.Read(blob1, 0, blob1.Length); + CollectionAssert.AreEqual(blob, blob1); + } + + [TestMethod] + public void Stat() + { + var _ = ipfs.Block.PutAsync(blob).Result; + var info = ipfs.Block.StatAsync(id).Result; + Assert.AreEqual(id, (string)info.Id); + Assert.AreEqual(5, info.Size); + } + + [TestMethod] + public async Task Remove() + { + var _ = ipfs.Block.PutAsync(blob).Result; + var cid = await ipfs.Block.RemoveAsync(id); + Assert.AreEqual(id, (string)cid); + } + + [TestMethod] + public void Remove_Unknown() + { + ExceptionAssert.Throws(() => { var _ = ipfs.Block.RemoveAsync("QmPv52ekjS75L4JmHpXVeuJ5uX2ecSfSZo88NSyxwA3rFF").Result; }); + } + + [TestMethod] + public async Task Remove_Unknown_OK() + { + var cid = await ipfs.Block.RemoveAsync("QmPv52ekjS75L4JmHpXVeuJ5uX2ecSfSZo88NSyxwA3rFF", true); + Assert.AreEqual(null, cid); + } + + } +} diff --git a/test/CoreApi/KeyApiTest.cs b/test/CoreApi/KeyApiTest.cs index 02582ce..3b5e4ae 100644 --- a/test/CoreApi/KeyApiTest.cs +++ b/test/CoreApi/KeyApiTest.cs @@ -65,8 +65,7 @@ public async Task Remove_Key() var clone = keys.Single(k => k.Name == name); Assert.IsNotNull(clone); - var removedKeys = await ipfs.Key.RemoveAsync(name); - var removed = removedKeys.Single(k => k.Name == name); + var removed = await ipfs.Key.RemoveAsync(name); Assert.IsNotNull(removed); Assert.AreEqual(key.Name, removed.Name); Assert.AreEqual(key.Id, removed.Id); diff --git a/test/CoreApi/ObjectApiTest.cs b/test/CoreApi/ObjectApiTest.cs index ccd32ab..4219f9e 100644 --- a/test/CoreApi/ObjectApiTest.cs +++ b/test/CoreApi/ObjectApiTest.cs @@ -91,6 +91,7 @@ public async Task Links() Assert.AreEqual(beta.Links.First().Size, links.First().Size); } +#if falses [TestMethod] public async Task Stat() { @@ -107,6 +108,7 @@ public async Task Stat() Assert.AreEqual(11, info.DataSize); Assert.AreEqual(77, info.CumulativeSize); } +#endif [TestMethod] public async Task Get_Nonexistent() diff --git a/test/CoreApi/PinApiTest.cs b/test/CoreApi/PinApiTest.cs index 0c27581..54879ba 100644 --- a/test/CoreApi/PinApiTest.cs +++ b/test/CoreApi/PinApiTest.cs @@ -18,16 +18,7 @@ public void List() var ipfs = TestFixture.Ipfs; var pins = ipfs.Pin.ListAsync().Result; Assert.IsNotNull(pins); - Assert.IsTrue(pins.Length > 0); - } - - [TestMethod] - public async Task List_Filtered() - { - var ipfs = TestFixture.Ipfs; - var all = await ipfs.Pin.ListAsync(); - var some = await ipfs.Pin.ListAsync(PinMode.Direct); - Assert.AreNotEqual(all.Length, some.Length); + Assert.IsTrue(pins.Count() > 0); } [TestMethod] @@ -38,14 +29,14 @@ public async Task Add_Remove() var id = result.Id; var pins = await ipfs.Pin.AddAsync(id); - Assert.IsTrue(pins.Any(pin => pin.Id == id)); + Assert.IsTrue(pins.Any(pin => pin == id)); var all = await ipfs.Pin.ListAsync(); - Assert.IsTrue(all.Any(pin => pin.Id == id)); + Assert.IsTrue(all.Any(pin => pin == id)); pins = await ipfs.Pin.RemoveAsync(id); - Assert.IsTrue(pins.Any(pin => pin.Id == id)); + Assert.IsTrue(pins.Any(pin => pin == id)); all = await ipfs.Pin.ListAsync(); - Assert.IsFalse(all.Any(pin => pin.Id == id)); + Assert.IsFalse(all.Any(pin => pin == id)); } } diff --git a/test/CoreApi/PubSubApiTest.cs b/test/CoreApi/PubSubApiTest.cs index 52f8d49..4426c6a 100644 --- a/test/CoreApi/PubSubApiTest.cs +++ b/test/CoreApi/PubSubApiTest.cs @@ -130,7 +130,7 @@ public async Task Multiple_Subscribe_Mutiple_Messages() var ipfs = TestFixture.Ipfs; var topic = "net-ipfs-api-test-" + Guid.NewGuid().ToString(); var cs = new CancellationTokenSource(); - Action processMessage = (msg) => + Action processMessage = (msg) => { Interlocked.Increment(ref messageCount); }; diff --git a/test/MerkleNodeTest.cs b/test/MerkleNodeTest.cs index d739c47..dcc2134 100644 --- a/test/MerkleNodeTest.cs +++ b/test/MerkleNodeTest.cs @@ -42,25 +42,6 @@ public void NullHash() ExceptionAssert.Throws(() => new MerkleNode((Cid)null)); } - [TestMethod] - public void Stats() - { - var node = new MerkleNode(IpfsInfo); - Assert.AreEqual(309, node.BlockSize); - Assert.AreEqual(307, node.LinksSize); - Assert.AreEqual(6, node.LinksCount); - Assert.AreEqual(2, node.DataSize); - Assert.AreEqual(6345, node.CumulativeSize); - } - - [TestMethod] - public void Links_and_LinksCount() - { - var node = new MerkleNode(IpfsInfo); - Assert.AreEqual(6, node.LinksCount); - Assert.AreEqual(6, node.Links.Count()); - } - [TestMethod] public void FromALink() { diff --git a/test/PinnedObjectTest.cs b/test/PinnedObjectTest.cs deleted file mode 100644 index 7552576..0000000 --- a/test/PinnedObjectTest.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Ipfs.Api; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using System.Linq; - -namespace Ipfs.Api -{ - - [TestClass] - public class PinnedObjectTest - { - - [TestMethod] - public void Stringify() - { - var pin = new PinnedObject - { - Id = "QmStfpa7ppKPSsdnazBy3Q5QH4zNzGLcpWV88otjVSV7SY", - Mode = PinMode.Recursive - }; - Assert.AreEqual("QmStfpa7ppKPSsdnazBy3Q5QH4zNzGLcpWV88otjVSV7SY Recursive", pin.ToString()); - } - - } -} diff --git a/test/PinnedObjectsTest.cs b/test/PinnedObjectsTest.cs deleted file mode 100644 index ed78624..0000000 --- a/test/PinnedObjectsTest.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Ipfs.Api; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using System.Linq; - -namespace Ipfs.Api -{ - - public partial class IpfsClientTest - { - - [TestMethod] - public void Pin_List() - { - var ipfs = TestFixture.Ipfs; - Assert.IsNotNull(ipfs.PinnedObjects); - Assert.IsTrue(ipfs.PinnedObjects.Count > 0); - } - - [TestMethod] - public void Pin_Add_Remove() - { - var ipfs = TestFixture.Ipfs; - var result = ipfs.FileSystem.AddTextAsync("I am pinned").Result; - var id = result.Id; - - ipfs.PinnedObjects.Add(id); - Assert.IsTrue(ipfs.PinnedObjects.Contains(id)); - - ipfs.PinnedObjects.Remove(id); - Assert.IsFalse(ipfs.PinnedObjects.Contains(id)); - } - - - } -}