diff --git a/IpfsCli/Commands/RepoCommand.cs b/IpfsCli/Commands/RepoCommand.cs new file mode 100644 index 00000000..b39e8728 --- /dev/null +++ b/IpfsCli/Commands/RepoCommand.cs @@ -0,0 +1,84 @@ +using Ipfs.Engine; +using McMaster.Extensions.CommandLineUtils; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Text; +using System.Threading.Tasks; + +namespace Ipfs.Cli +{ + [Command(Description = "Manage the IPFS repository")] + [Subcommand("gc", typeof(RepoGCCommand))] + [Subcommand("stat", typeof(RepoStatCommand))] + [Subcommand("verify", typeof(RepoVerifyCommand))] + [Subcommand("version", typeof(RepoVersionCommand))] + class RepoCommand : CommandBase + { + public Program Parent { get; set; } + + protected override Task OnExecute(CommandLineApplication app) + { + app.ShowHelp(); + return Task.FromResult(0); + } + } + + [Command(Description = "Perform a garbage collection sweep on the repo")] + class RepoGCCommand : CommandBase + { + RepoCommand Parent { get; set; } + + protected override async Task OnExecute(CommandLineApplication app) + { + var Program = Parent.Parent; + + await Program.CoreApi.BlockRepository.RemoveGarbageAsync(); + return 0; + } + } + + [Command(Description = "Verify all blocks in repo are not corrupted")] + class RepoVerifyCommand : CommandBase + { + RepoCommand Parent { get; set; } + + protected override async Task OnExecute(CommandLineApplication app) + { + var Program = Parent.Parent; + + await Program.CoreApi.BlockRepository.VerifyAsync(); + return 0; + } + } + + [Command(Description = "Repository information")] + class RepoStatCommand : CommandBase + { + RepoCommand Parent { get; set; } + + protected override async Task OnExecute(CommandLineApplication app) + { + var Program = Parent.Parent; + + var stats = await Program.CoreApi.BlockRepository.StatisticsAsync(); + return Program.Output(app, stats, null); + } + } + + [Command(Description = "Repository version")] + class RepoVersionCommand : CommandBase + { + RepoCommand Parent { get; set; } + + protected override async Task OnExecute(CommandLineApplication app) + { + var Program = Parent.Parent; + + var stats = await Program.CoreApi.BlockRepository.VersionAsync(); + return Program.Output(app, stats, null); + } + } + + +} diff --git a/IpfsCli/IpfsCli.csproj b/IpfsCli/IpfsCli.csproj index a55872e1..b306baa8 100644 --- a/IpfsCli/IpfsCli.csproj +++ b/IpfsCli/IpfsCli.csproj @@ -15,7 +15,7 @@ - + diff --git a/IpfsCli/Program.cs b/IpfsCli/Program.cs index bdffe6f3..c3b7a652 100644 --- a/IpfsCli/Program.cs +++ b/IpfsCli/Program.cs @@ -51,6 +51,7 @@ namespace Ipfs.Cli [Subcommand("update", typeof(UpdateCommand))] [Subcommand("bitswap", typeof(BitswapCommand))] [Subcommand("stats", typeof(StatsCommand))] + [Subcommand("repo", typeof(RepoCommand))] class Program : CommandBase { static bool debugging; diff --git a/IpfsServer/HttpApi/V0/BlockRepositoryController.cs b/IpfsServer/HttpApi/V0/BlockRepositoryController.cs new file mode 100644 index 00000000..e3a74f1b --- /dev/null +++ b/IpfsServer/HttpApi/V0/BlockRepositoryController.cs @@ -0,0 +1,72 @@ +using Ipfs.CoreApi; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Http; +using System.IO; + +namespace Ipfs.Server.HttpApi.V0 +{ + /// + /// A wrapped version number. + /// + public class VersionBlockRepositoryDto + { + /// + /// The version number. + /// + public string Version; + } + + /// + /// Manages all the blocks in teh repository. + /// + public class BlockRepositoryController : IpfsController + { + /// + /// Creates a new controller. + /// + public BlockRepositoryController(ICoreApi ipfs) : base(ipfs) { } + + /// + /// Garbage collection. + /// + [HttpGet, HttpPost, Route("repo/gc")] + public Task GarbageCollection() + { + return IpfsCore.BlockRepository.RemoveGarbageAsync(Cancel); + } + + /// + /// Get repository information. + /// + [HttpGet, HttpPost, Route("repo/stat")] + public Task Statistics() + { + return IpfsCore.BlockRepository.StatisticsAsync(Cancel); + } + + /// + /// Verify that the blocks are not corrupt. + /// + [HttpGet, HttpPost, Route("repo/verify")] + public Task Verify() + { + return IpfsCore.BlockRepository.VerifyAsync(Cancel); + } + + /// + /// Get repository information. + /// + [HttpGet, HttpPost, Route("repo/version")] + public async Task Version() + { + return new VersionBlockRepositoryDto + { + Version = await IpfsCore.BlockRepository.VersionAsync(Cancel) + }; + } + } +} diff --git a/IpfsServer/IpfsServer.csproj b/IpfsServer/IpfsServer.csproj index 9252fa89..f52f8ad6 100644 --- a/IpfsServer/IpfsServer.csproj +++ b/IpfsServer/IpfsServer.csproj @@ -13,7 +13,7 @@ - + diff --git a/doc/articles/core-api.md b/doc/articles/core-api.md index dcd60d83..9e930b17 100644 --- a/doc/articles/core-api.md +++ b/doc/articles/core-api.md @@ -17,6 +17,7 @@ Each IPFS feature has it's own interface. | ------- | ------- | | [Bitswap](xref:Ipfs.CoreApi.IBitswapApi) | Block trading between peers | | [Block](xref:Ipfs.CoreApi.IBlockApi) | Manages the blocks | +| [BlockRepository](xref:Ipfs.CoreApi.IBlockRepositoryApi) | Manages the repository for [blocks](xref:Ipfs.CoreApi.IBlockApi) | | [Bootstrap](xref:Ipfs.CoreApi.IBootstrapApi) | Trusted peers | | [Config](xref:Ipfs.CoreApi.IConfigApi) | Manages the configuration of the local peer | | [Dag](xref:Ipfs.CoreApi.IDagApi) | Manages the IPLD (linked data) Directed Acrylic Graph | diff --git a/src/CoreApi/BlockRepositoryApi.cs b/src/CoreApi/BlockRepositoryApi.cs new file mode 100644 index 00000000..0a4188af --- /dev/null +++ b/src/CoreApi/BlockRepositoryApi.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Ipfs.CoreApi; +using Newtonsoft.Json.Linq; +using System.Linq; +using System.Collections.Concurrent; +using PeerTalk; + +namespace Ipfs.Engine.CoreApi +{ + class BlockRepositoryApi : IBlockRepositoryApi + { + IpfsEngine ipfs; + + public BlockRepositoryApi(IpfsEngine ipfs) + { + this.ipfs = ipfs; + } + + public Task RemoveGarbageAsync(CancellationToken cancel = default(CancellationToken)) + { + throw new NotImplementedException(); + } + + public Task StatisticsAsync(CancellationToken cancel = default(CancellationToken)) + { + var data = new RepositoryData + { + RepoPath = Path.GetFullPath(ipfs.Options.Repository.Folder), + Version = "1", + StorageMax = 10000000000 // TODO: there is no storage max + }; + + GetDirStats(data.RepoPath, data, cancel); + + return Task.FromResult(data); + } + + public Task VerifyAsync(CancellationToken cancel = default(CancellationToken)) + { + throw new NotImplementedException(); + } + + public async Task VersionAsync(CancellationToken cancel = default(CancellationToken)) + { + var stats = await StatisticsAsync(cancel).ConfigureAwait(false); + return stats.Version; + } + + void GetDirStats(string path, RepositoryData data, CancellationToken cancel) + { + foreach (var file in Directory.EnumerateFiles(path)) + { + cancel.ThrowIfCancellationRequested(); + ++data.NumObjects; + data.RepoSize += (ulong)(new FileInfo(file).Length); + } + + foreach (var dir in Directory.EnumerateDirectories(path)) + { + cancel.ThrowIfCancellationRequested(); + GetDirStats(dir, data, cancel); + } + } + } +} diff --git a/src/CoreApi/StatsApi.cs b/src/CoreApi/StatsApi.cs index 3d07ecbb..46a471be 100644 --- a/src/CoreApi/StatsApi.cs +++ b/src/CoreApi/StatsApi.cs @@ -33,32 +33,7 @@ public StatsApi(IpfsEngine ipfs) public Task RepositoryAsync(CancellationToken cancel = default(CancellationToken)) { - var data = new RepositoryData - { - RepoPath = Path.GetFullPath(ipfs.Options.Repository.Folder), - Version = "1", - StorageMax = 0 // TODO: there is no storage max - }; - - GetDirStats(data.RepoPath, data, cancel); - - return Task.FromResult(data); - } - - void GetDirStats(string path, RepositoryData data, CancellationToken cancel) - { - foreach (var file in Directory.EnumerateFiles(path)) - { - cancel.ThrowIfCancellationRequested(); - ++data.NumObjects; - data.RepoSize += (ulong)(new FileInfo(file).Length); - } - - foreach (var dir in Directory.EnumerateDirectories(path)) - { - cancel.ThrowIfCancellationRequested(); - GetDirStats(dir, data, cancel); - } + return ipfs.BlockRepository.StatisticsAsync(cancel); } } } diff --git a/src/IpfsEngine.cs b/src/IpfsEngine.cs index 4a314795..492e5aef 100644 --- a/src/IpfsEngine.cs +++ b/src/IpfsEngine.cs @@ -101,6 +101,7 @@ void Init() // Init the core api inteface. Bitswap = new BitswapApi(this); Block = new BlockApi(this); + BlockRepository = new BlockRepositoryApi(this); Bootstrap = new BootstrapApi(this); Config = new ConfigApi(this); Dag = new DagApi(this); @@ -215,6 +216,9 @@ void Init() /// public IBlockApi Block { get; set; } + /// + public IBlockRepositoryApi BlockRepository { get; set; } + /// public IBootstrapApi Bootstrap { get; set; } diff --git a/src/IpfsEngine.csproj b/src/IpfsEngine.csproj index 2cc68cee..2f57cc5a 100644 --- a/src/IpfsEngine.csproj +++ b/src/IpfsEngine.csproj @@ -36,7 +36,7 @@ - + diff --git a/test/CoreApi/BlockRepositoryApiTest.cs b/test/CoreApi/BlockRepositoryApiTest.cs new file mode 100644 index 00000000..b537d186 --- /dev/null +++ b/test/CoreApi/BlockRepositoryApiTest.cs @@ -0,0 +1,32 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Ipfs.Engine +{ + + [TestClass] + public class BlockRepositoryApiTest + { + IpfsEngine ipfs = TestFixture.Ipfs; + + [TestMethod] + public void Exists() + { + Assert.IsNotNull(ipfs.BlockRepository); + } + + [TestMethod] + public async Task Stats() + { + var stats = await ipfs.BlockRepository.StatisticsAsync(); + var version = await ipfs.BlockRepository.VersionAsync(); + Assert.AreEqual(stats.Version, version); + } + + } +}