From 9a535f125522407e8e0a70d4e4b60de6e01ef3cd Mon Sep 17 00:00:00 2001 From: Krivoshchekov Artem Date: Thu, 8 Aug 2024 14:06:13 -0300 Subject: [PATCH 1/5] DoAddCommand in progress --- .gitignore | 4 + src/IpfsClient.cs | 87 ++++++++++++++++------ test/CoreApi/FileSystemApiTest.cs | 119 ++++++++++++++++++------------ test/IpfsHttpClientTests.csproj | 2 +- 4 files changed, 144 insertions(+), 68 deletions(-) diff --git a/.gitignore b/.gitignore index f03d425..6573a85 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,10 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. +# Ide + +.idea + # User-specific files *.suo *.user diff --git a/src/IpfsClient.cs b/src/IpfsClient.cs index 62b1c1c..5d8db9e 100644 --- a/src/IpfsClient.cs +++ b/src/IpfsClient.cs @@ -10,6 +10,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using System.Web; namespace Ipfs.Http { @@ -59,7 +60,8 @@ public IpfsClient() var assembly = typeof(IpfsClient).GetTypeInfo().Assembly; var version = assembly.GetName().Version; - UserAgent = string.Format("{0}/{1}.{2}.{3}", assembly.GetName().Name, version.Major, version.Minor, version.Revision); + UserAgent = string.Format("{0}/{1}.{2}.{3}", assembly.GetName().Name, version.Major, version.Minor, + version.Revision); TrustedPeers = new TrustedPeerCollection(this); Bootstrap = new BootstrapApi(this); @@ -229,7 +231,7 @@ HttpClient Api() if (HttpMessageHandler is HttpClientHandler handler && handler.SupportsAutomaticDecompression) { handler.AutomaticDecompression = DecompressionMethods.GZip - | DecompressionMethods.Deflate; + | DecompressionMethods.Deflate; } api = new HttpClient(HttpMessageHandler) @@ -241,6 +243,7 @@ HttpClient Api() } } } + return api; } @@ -271,7 +274,8 @@ HttpClient Api() /// /// When the IPFS server indicates an error. /// - public async Task DoCommandAsync(string command, CancellationToken cancel, string arg = null, params string[] options) + public async Task DoCommandAsync(string command, CancellationToken cancel, string arg = null, + params string[] options) { var url = BuildCommand(command, arg, options); @@ -284,6 +288,34 @@ public async Task DoCommandAsync(string command, CancellationToken cance } } + /// + /// Executes /api/v0/add command + /// See details here - https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-add + /// + /// FileSystem path + /// Cancellation token + /// Args + /// Options + /// Response + public async Task DoAddCommand(string path, CancellationToken cancel, string arg = null, + params string[] options) + { + var url = BuildCommand("add", arg, options); + + var content = new MultipartFormDataContent(); + + content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") + { + Name = "\"file\"", + FileName = $"\"{HttpUtility.UrlEncode(path)}\"" + }; + + content.Headers.ContentType = new MediaTypeHeaderValue("application/x-directory"); + content.Add(new StringContent(path), "path"); + + return await DoCommandAsync(url, content, cancel); + } + internal Task DoCommandAsync(Uri url, byte[] bytes, CancellationToken cancel) { return DoCommandAsync(url, new ByteArrayContent(bytes), cancel); @@ -299,13 +331,14 @@ internal Task DoCommandAsync(Uri url, string str, CancellationToken cancel) return DoCommandAsync(url, new StringContent(str), cancel); } - internal async Task DoCommandAsync(Uri url, HttpContent content, CancellationToken cancel) + internal async Task DoCommandAsync(Uri url, HttpContent content, CancellationToken cancel) { - using (var response = await Api().PostAsync(url, new MultipartFormDataContent { { content, "\"file\"" } }, cancel)) - { - await ThrowOnErrorAsync(response); - var body = await response.Content.ReadAsStringAsync(); - } + using var response = + await Api().PostAsync(url, new MultipartFormDataContent {{content, "\"file\""}}, cancel); + + await ThrowOnErrorAsync(response); + var body = await response.Content.ReadAsStringAsync(); + return body; } @@ -339,7 +372,8 @@ internal async Task DoCommandAsync(Uri url, HttpContent content, CancellationTok /// /// When the IPFS server indicates an error. /// - public async Task DoCommandAsync(string command, CancellationToken cancel, string arg = null, params string[] options) + public async Task DoCommandAsync(string command, CancellationToken cancel, string arg = null, + params string[] options) { var json = await DoCommandAsync(command, cancel, arg, options); return JsonConvert.DeserializeObject(json); @@ -367,7 +401,8 @@ public async Task DoCommandAsync(string command, CancellationToken cancel, /// /// When the IPFS server indicates an error. /// - public async Task PostDownloadAsync(string command, CancellationToken cancel, string arg = null, params string[] options) + public async Task PostDownloadAsync(string command, CancellationToken cancel, string arg = null, + params string[] options) { var url = BuildCommand(command, arg, options); @@ -402,7 +437,8 @@ public async Task PostDownloadAsync(string command, CancellationToken ca /// /// When the IPFS server indicates an error. /// - public async Task DownloadAsync(string command, CancellationToken cancel, string arg = null, params string[] options) + public async Task DownloadAsync(string command, CancellationToken cancel, string arg = null, + params string[] options) { var url = BuildCommand(command, arg, options); @@ -435,7 +471,8 @@ public async Task DownloadAsync(string command, CancellationToken cancel /// /// When the IPFS server indicates an error. /// - public async Task DownloadBytesAsync(string command, CancellationToken cancel, string arg = null, params string[] options) + public async Task DownloadBytesAsync(string command, CancellationToken cancel, string arg = null, + params string[] options) { var url = BuildCommand(command, arg, options); @@ -473,7 +510,8 @@ public async Task DownloadBytesAsync(string command, CancellationToken c /// /// When the IPFS server indicates an error. /// - public async Task UploadAsync(string command, CancellationToken cancel, Stream data, string name, params string[] options) + public async Task UploadAsync(string command, CancellationToken cancel, Stream data, string name, + params string[] options) { var content = new MultipartFormDataContent(); var streamContent = new StreamContent(data); @@ -495,6 +533,7 @@ public async Task UploadAsync(string command, CancellationToken cancel, return json; } } + /// /// Perform an IPFS API command that /// requires uploading of a "file". @@ -523,7 +562,8 @@ public async Task UploadAsync(string command, CancellationToken cancel, /// /// When the IPFS server indicates an error. /// - public async Task Upload2Async(string command, CancellationToken cancel, Stream data, string name, params string[] options) + public async Task Upload2Async(string command, CancellationToken cancel, Stream data, string name, + params string[] options) { var content = new MultipartFormDataContent(); var streamContent = new StreamContent(data); @@ -543,7 +583,8 @@ public async Task Upload2Async(string command, CancellationToken cancel, /// /// TODO /// - public async Task UploadAsync(string command, CancellationToken cancel, byte[] data, params string[] options) + public async Task UploadAsync(string command, CancellationToken cancel, byte[] data, + params string[] options) { var content = new MultipartFormDataContent(); var streamContent = new ByteArrayContent(data); @@ -593,17 +634,21 @@ async Task ThrowOnErrorAsync(HttpResponseMessage response) try { var res = JsonConvert.DeserializeObject(body); - message = (string)res.Message; + message = (string) res.Message; + } + catch + { } - catch { } throw new HttpRequestException(message); } /// - public IAsyncEnumerable Ping(MultiHash peer, int count = 10, CancellationToken cancel = new CancellationToken()) => Generic.Ping(peer, count, cancel); + public IAsyncEnumerable Ping(MultiHash peer, int count = 10, + CancellationToken cancel = new CancellationToken()) => Generic.Ping(peer, count, cancel); /// - public IAsyncEnumerable Ping(MultiAddress address, int count = 10, CancellationToken cancel = new CancellationToken()) => Generic.Ping(address, count, cancel); + public IAsyncEnumerable Ping(MultiAddress address, int count = 10, + CancellationToken cancel = new CancellationToken()) => Generic.Ping(address, count, cancel); } -} +} \ No newline at end of file diff --git a/test/CoreApi/FileSystemApiTest.cs b/test/CoreApi/FileSystemApiTest.cs index 6df79cb..25096e4 100644 --- a/test/CoreApi/FileSystemApiTest.cs +++ b/test/CoreApi/FileSystemApiTest.cs @@ -3,7 +3,6 @@ using System; using System.IO; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; @@ -17,7 +16,7 @@ public void AddText() { var ipfs = TestFixture.Ipfs; var result = ipfs.FileSystem.AddTextAsync("hello world").Result; - Assert.AreEqual("Qmf412jQZiuVUtdgnB36FXFX7xg5V6KEbSJ4dpQuhkLyfD", (string)result.Id); + Assert.AreEqual("Qmf412jQZiuVUtdgnB36FXFX7xg5V6KEbSJ4dpQuhkLyfD", (string) result.Id); } [TestMethod] @@ -38,7 +37,7 @@ public void AddFile() { var ipfs = TestFixture.Ipfs; var result = ipfs.FileSystem.AddFileAsync(path).Result; - Assert.AreEqual("Qmf412jQZiuVUtdgnB36FXFX7xg5V6KEbSJ4dpQuhkLyfD", (string)result.Id); + Assert.AreEqual("Qmf412jQZiuVUtdgnB36FXFX7xg5V6KEbSJ4dpQuhkLyfD", (string) result.Id); Assert.AreEqual(0, result.Links.Count()); } finally @@ -51,7 +50,7 @@ public void AddFile() public void Read_With_Offset() { var ipfs = TestFixture.Ipfs; - var indata = new MemoryStream(new byte[] { 10, 20, 30 }); + var indata = new MemoryStream(new byte[] {10, 20, 30}); var node = ipfs.FileSystem.AddAsync(indata).Result; using (var outdata = ipfs.FileSystem.ReadFileAsync(node.Id, offset: 1).Result) { @@ -65,7 +64,7 @@ public void Read_With_Offset() public void Read_With_Offset_Length_1() { var ipfs = TestFixture.Ipfs; - var indata = new MemoryStream(new byte[] { 10, 20, 30 }); + var indata = new MemoryStream(new byte[] {10, 20, 30}); var node = ipfs.FileSystem.AddAsync(indata).Result; using (var outdata = ipfs.FileSystem.ReadFileAsync(node.Id, offset: 1, count: 1).Result) { @@ -78,7 +77,7 @@ public void Read_With_Offset_Length_1() public void Read_With_Offset_Length_2() { var ipfs = TestFixture.Ipfs; - var indata = new MemoryStream(new byte[] { 10, 20, 30 }); + var indata = new MemoryStream(new byte[] {10, 20, 30}); var node = ipfs.FileSystem.AddAsync(indata).Result; using (var outdata = ipfs.FileSystem.ReadFileAsync(node.Id, offset: 1, count: 2).Result) { @@ -92,8 +91,8 @@ public void Read_With_Offset_Length_2() public void Add_NoPin() { var ipfs = TestFixture.Ipfs; - var data = new MemoryStream(new byte[] { 11, 22, 33 }); - var options = new AddFileOptions { Pin = false }; + var data = new MemoryStream(new byte[] {11, 22, 33}); + var options = new AddFileOptions {Pin = false}; var node = ipfs.FileSystem.AddAsync(data, "", options).Result; var pins = ipfs.Pin.ListAsync().Result; Assert.IsFalse(pins.Any(pin => pin == node.Id)); @@ -103,7 +102,7 @@ public void Add_NoPin() public async Task Add_Wrap() { var path = "hello.txt"; - File.WriteAllText(path, "hello world"); + await File.WriteAllTextAsync(path, "hello world"); try { var ipfs = TestFixture.Ipfs; @@ -112,11 +111,11 @@ public async Task Add_Wrap() Wrap = true }; var node = await ipfs.FileSystem.AddFileAsync(path, options); - Assert.AreEqual("QmNxvA5bwvPGgMXbmtyhxA1cKFdvQXnsGnZLCGor3AzYxJ", (string)node.Id); + Assert.AreEqual("QmNxvA5bwvPGgMXbmtyhxA1cKFdvQXnsGnZLCGor3AzYxJ", (string) node.Id); Assert.AreEqual(true, node.IsDirectory); Assert.AreEqual(1, node.Links.Count()); Assert.AreEqual("hello.txt", node.Links.First().Name); - Assert.AreEqual("Qmf412jQZiuVUtdgnB36FXFX7xg5V6KEbSJ4dpQuhkLyfD", (string)node.Links.First().Id); + Assert.AreEqual("Qmf412jQZiuVUtdgnB36FXFX7xg5V6KEbSJ4dpQuhkLyfD", (string) node.Links.First().Id); } finally { @@ -134,15 +133,15 @@ public async Task Add_SizeChunking() }; options.Pin = true; var node = await ipfs.FileSystem.AddTextAsync("hello world", options); - Assert.AreEqual("QmVVZXWrYzATQdsKWM4knbuH5dgHFmrRqW3nJfDgdWrBjn", (string)node.Id); + Assert.AreEqual("QmVVZXWrYzATQdsKWM4knbuH5dgHFmrRqW3nJfDgdWrBjn", (string) node.Id); Assert.AreEqual(false, node.IsDirectory); var links = (await ipfs.Object.LinksAsync(node.Id)).ToArray(); Assert.AreEqual(4, links.Length); - Assert.AreEqual("QmevnC4UDUWzJYAQtUSQw4ekUdqDqwcKothjcobE7byeb6", (string)links[0].Id); - Assert.AreEqual("QmTdBogNFkzUTSnEBQkWzJfQoiWbckLrTFVDHFRKFf6dcN", (string)links[1].Id); - Assert.AreEqual("QmPdmF1n4di6UwsLgW96qtTXUsPkCLN4LycjEUdH9977d6", (string)links[2].Id); - Assert.AreEqual("QmXh5UucsqF8XXM8UYQK9fHXsthSEfi78kewr8ttpPaLRE", (string)links[3].Id); + Assert.AreEqual("QmevnC4UDUWzJYAQtUSQw4ekUdqDqwcKothjcobE7byeb6", (string) links[0].Id); + Assert.AreEqual("QmTdBogNFkzUTSnEBQkWzJfQoiWbckLrTFVDHFRKFf6dcN", (string) links[1].Id); + Assert.AreEqual("QmPdmF1n4di6UwsLgW96qtTXUsPkCLN4LycjEUdH9977d6", (string) links[2].Id); + Assert.AreEqual("QmXh5UucsqF8XXM8UYQK9fHXsthSEfi78kewr8ttpPaLRE", (string) links[3].Id); var text = await ipfs.FileSystem.ReadAllTextAsync(node.Id); Assert.AreEqual("hello world", text); @@ -157,7 +156,7 @@ public async Task Add_Raw() RawLeaves = true }; var node = await ipfs.FileSystem.AddTextAsync("hello world", options); - Assert.AreEqual("bafkreifzjut3te2nhyekklss27nh3k72ysco7y32koao5eei66wof36n5e", (string)node.Id); + Assert.AreEqual("bafkreifzjut3te2nhyekklss27nh3k72ysco7y32koao5eei66wof36n5e", (string) node.Id); Assert.AreEqual(11, node.Size); var text = await ipfs.FileSystem.ReadAllTextAsync(node.Id); @@ -174,20 +173,49 @@ public async Task Add_RawAndChunked() ChunkSize = 3 }; var node = await ipfs.FileSystem.AddTextAsync("hello world", options); - Assert.AreEqual("QmUuooB6zEhMmMaBvMhsMaUzar5gs5KwtVSFqG4C1Qhyhs", (string)node.Id); + Assert.AreEqual("QmUuooB6zEhMmMaBvMhsMaUzar5gs5KwtVSFqG4C1Qhyhs", (string) node.Id); Assert.AreEqual(false, node.IsDirectory); var links = (await ipfs.Object.LinksAsync(node.Id)).ToArray(); Assert.AreEqual(4, links.Length); - Assert.AreEqual("bafkreigwvapses57f56cfow5xvoua4yowigpwcz5otqqzk3bpcbbjswowe", (string)links[0].Id); - Assert.AreEqual("bafkreiew3cvfrp2ijn4qokcp5fqtoknnmr6azhzxovn6b3ruguhoubkm54", (string)links[1].Id); - Assert.AreEqual("bafkreibsybcn72tquh2l5zpim2bba4d2kfwcbpzuspdyv2breaq5efo7tq", (string)links[2].Id); - Assert.AreEqual("bafkreihfuch72plvbhdg46lef3n5zwhnrcjgtjywjryyv7ffieyedccchu", (string)links[3].Id); + Assert.AreEqual("bafkreigwvapses57f56cfow5xvoua4yowigpwcz5otqqzk3bpcbbjswowe", (string) links[0].Id); + Assert.AreEqual("bafkreiew3cvfrp2ijn4qokcp5fqtoknnmr6azhzxovn6b3ruguhoubkm54", (string) links[1].Id); + Assert.AreEqual("bafkreibsybcn72tquh2l5zpim2bba4d2kfwcbpzuspdyv2breaq5efo7tq", (string) links[2].Id); + Assert.AreEqual("bafkreihfuch72plvbhdg46lef3n5zwhnrcjgtjywjryyv7ffieyedccchu", (string) links[3].Id); var text = await ipfs.FileSystem.ReadAllTextAsync(node.Id); Assert.AreEqual("hello world", text); } + [TestMethod] + public async Task DoAddCommand() + { + var ipfs = TestFixture.Ipfs; + var temp = MakeTemp(); + + try + { + var response = await ipfs.DoAddCommand(temp, CancellationToken.None); + + // Assert.IsTrue(dir.IsDirectory); + // + // var files = dir.Links.ToArray(); + // Assert.AreEqual(2, files.Length); + // Assert.AreEqual("alpha.txt", files[0].Name); + // Assert.AreEqual("beta.txt", files[1].Name); + // + // Assert.AreEqual("alpha", ipfs.FileSystem.ReadAllTextAsync(files[0].Id).Result); + // Assert.AreEqual("beta", ipfs.FileSystem.ReadAllTextAsync(files[1].Id).Result); + // + // Assert.AreEqual("alpha", ipfs.FileSystem.ReadAllTextAsync(dir.Id + "/alpha.txt").Result); + // Assert.AreEqual("beta", ipfs.FileSystem.ReadAllTextAsync(dir.Id + "/beta.txt").Result); + } + finally + { + DeleteTemp(temp); + } + } + [TestMethod] public void AddDirectory() { @@ -261,17 +289,17 @@ public void AddDirectoryRecursive() } } - [TestMethod] - public async Task GetTar_EmptyDirectory() - { - var ipfs = TestFixture.Ipfs; - var temp = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); - Directory.CreateDirectory(temp); - try - { - var dir = ipfs.FileSystem.AddDirectoryAsync(temp, true).Result; - var dirid = dir.Id.Encode(); - + [TestMethod] + public async Task GetTar_EmptyDirectory() + { + var ipfs = TestFixture.Ipfs; + var temp = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + Directory.CreateDirectory(temp); + try + { + var dir = ipfs.FileSystem.AddDirectoryAsync(temp, true).Result; + var dirid = dir.Id.Encode(); + using (var tar = await ipfs.FileSystem.GetAsync(dir.Id)) { var buffer = new byte[3 * 512]; @@ -282,13 +310,14 @@ public async Task GetTar_EmptyDirectory() Assert.IsTrue(n > 0); offset += n; } + Assert.AreEqual(-1, tar.ReadByte()); - } - } - finally - { - DeleteTemp(temp); - } + } + } + finally + { + DeleteTemp(temp); + } } @@ -303,13 +332,10 @@ public async Task AddFile_WithProgress() var bytesTransferred = 0UL; var options = new AddFileOptions { - Progress = new Progress(t => - { - bytesTransferred += t.Bytes; - }) + Progress = new Progress(t => { bytesTransferred += t.Bytes; }) }; var result = await ipfs.FileSystem.AddFileAsync(path, options); - Assert.AreEqual("Qmf412jQZiuVUtdgnB36FXFX7xg5V6KEbSJ4dpQuhkLyfD", (string)result.Id); + Assert.AreEqual("Qmf412jQZiuVUtdgnB36FXFX7xg5V6KEbSJ4dpQuhkLyfD", (string) result.Id); // Progress reports get posted on another synchronisation context. var stop = DateTime.Now.AddSeconds(3); @@ -319,6 +345,7 @@ public async Task AddFile_WithProgress() break; await Task.Delay(10); } + Assert.AreEqual(11UL, bytesTransferred); } finally @@ -339,7 +366,7 @@ void DeleteTemp(string temp) catch (Exception) { Thread.Sleep(1); - continue; // most likely anti-virus is reading a file + continue; // most likely anti-virus is reading a file } } } @@ -360,4 +387,4 @@ string MakeTemp() return temp; } } -} +} \ No newline at end of file diff --git a/test/IpfsHttpClientTests.csproj b/test/IpfsHttpClientTests.csproj index 707f186..cb3eea0 100644 --- a/test/IpfsHttpClientTests.csproj +++ b/test/IpfsHttpClientTests.csproj @@ -1,11 +1,11 @@  - net6.0 false full Ipfs.Http + net8.0 From 1770acdb4543660f055e5e19a041f059cce3a8b9 Mon Sep 17 00:00:00 2001 From: Krivoshchekov Artem Date: Sat, 10 Aug 2024 21:05:11 -0300 Subject: [PATCH 2/5] doAddCommand implemented + covered with tests --- src/IpfsClient.cs | 61 +++++++++++++++++++++++++------ src/IpfsFIle.cs | 29 +++++++++++++++ src/IpfsHttpClient.csproj | 2 +- test/CoreApi/FileSystemApiTest.cs | 33 +++++++++-------- 4 files changed, 97 insertions(+), 28 deletions(-) create mode 100644 src/IpfsFIle.cs diff --git a/src/IpfsClient.cs b/src/IpfsClient.cs index 5d8db9e..17f3f54 100644 --- a/src/IpfsClient.cs +++ b/src/IpfsClient.cs @@ -1,8 +1,7 @@ -using Ipfs.CoreApi; -using Newtonsoft.Json; -using System; +using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; @@ -10,7 +9,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; -using System.Web; +using Ipfs.CoreApi; +using Newtonsoft.Json; namespace Ipfs.Http { @@ -297,23 +297,60 @@ public async Task DoCommandAsync(string command, CancellationToken cance /// Args /// Options /// Response - public async Task DoAddCommand(string path, CancellationToken cancel, string arg = null, + public async Task> DoAddCommand( + string path, + CancellationToken cancel, + string arg = null, params string[] options) { var url = BuildCommand("add", arg, options); + var dirInfo = new DirectoryInfo(Path.GetFullPath(path)); + + if (!dirInfo.Exists) + { + throw new Exception("Directory does not exists"); + } + + var upperLevelFolder = dirInfo.Parent?.FullName ?? Path.GetFullPath(path); + + string GetFileName(string cPath) + { + var relativePath = Path.GetRelativePath(upperLevelFolder, cPath); + return $"{Uri.EscapeDataString(relativePath)}"; + } + + ByteArrayContent addFile(FileInfo cFile) + { + var content = new ByteArrayContent(File.ReadAllBytes(cFile.FullName)); + content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") + { + Name = "file", + FileName = GetFileName(cFile.FullName) + }; + content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); + return content; + } + var content = new MultipartFormDataContent(); - content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") + foreach (var file in dirInfo.EnumerateFiles()) { - Name = "\"file\"", - FileName = $"\"{HttpUtility.UrlEncode(path)}\"" - }; + content.Add(addFile(file)); + } + + using var response = await Api().PostAsync(url, content, cancel); + await ThrowOnErrorAsync(response); + + var strBody = await response.Content.ReadAsStringAsync(); - content.Headers.ContentType = new MediaTypeHeaderValue("application/x-directory"); - content.Add(new StringContent(path), "path"); + var result = strBody + .Split("\n") + .Where(x => !string.IsNullOrWhiteSpace(x)) + .Select(JsonConvert.DeserializeObject) + .ToList(); - return await DoCommandAsync(url, content, cancel); + return result; } internal Task DoCommandAsync(Uri url, byte[] bytes, CancellationToken cancel) diff --git a/src/IpfsFIle.cs b/src/IpfsFIle.cs new file mode 100644 index 0000000..74edd31 --- /dev/null +++ b/src/IpfsFIle.cs @@ -0,0 +1,29 @@ +using System.Runtime.Serialization; + +namespace Ipfs.Http; + +/// +/// AddResponse +/// {"Name":"var","Hash":"QmPypQtsKqpUC6QzufU1ZfaPw6Kj4eN459aBMzbcfdnPAN","Size":"288"} +/// +[DataContract] +public class IpfsFile +{ + /// + /// Name + /// + [DataMember(Name = "Name")] + public string Name { get; set; } + + /// + /// Hash + /// + [DataMember(Name = "Hash")] + public string Hash { get; set; } + + /// + /// Size + /// + [DataMember(Name = "Size")] + public string Size { get; set; } +} \ No newline at end of file diff --git a/src/IpfsHttpClient.csproj b/src/IpfsHttpClient.csproj index 82bef48..e898917 100644 --- a/src/IpfsHttpClient.csproj +++ b/src/IpfsHttpClient.csproj @@ -1,7 +1,6 @@  - netstandard2.0 IpfsShipyard.Ipfs.Http.Client Ipfs.Http bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml @@ -27,6 +26,7 @@ True https://github.com/ipfs-shipyard/net-ipfs-http-client icon.png + netstandard2.1 diff --git a/test/CoreApi/FileSystemApiTest.cs b/test/CoreApi/FileSystemApiTest.cs index 25096e4..57a6762 100644 --- a/test/CoreApi/FileSystemApiTest.cs +++ b/test/CoreApi/FileSystemApiTest.cs @@ -188,27 +188,30 @@ public async Task Add_RawAndChunked() } [TestMethod] - public async Task DoAddCommand() + public void DoAddCommand() { var ipfs = TestFixture.Ipfs; var temp = MakeTemp(); try { - var response = await ipfs.DoAddCommand(temp, CancellationToken.None); - - // Assert.IsTrue(dir.IsDirectory); - // - // var files = dir.Links.ToArray(); - // Assert.AreEqual(2, files.Length); - // Assert.AreEqual("alpha.txt", files[0].Name); - // Assert.AreEqual("beta.txt", files[1].Name); - // - // Assert.AreEqual("alpha", ipfs.FileSystem.ReadAllTextAsync(files[0].Id).Result); - // Assert.AreEqual("beta", ipfs.FileSystem.ReadAllTextAsync(files[1].Id).Result); - // - // Assert.AreEqual("alpha", ipfs.FileSystem.ReadAllTextAsync(dir.Id + "/alpha.txt").Result); - // Assert.AreEqual("beta", ipfs.FileSystem.ReadAllTextAsync(dir.Id + "/beta.txt").Result); + var response = ipfs.DoAddCommand( + temp, + CancellationToken.None + ).Result.ToList(); + + Assert.AreEqual(3, response.Count(), "Expected 3 files to be added"); + + var parentDir = new DirectoryInfo(temp); + + if (parentDir == null) + { + throw new Exception("Parent directory is null"); + } + + Assert.AreEqual(Path.Join(parentDir.Name, "alpha.txt"), response[0].Name); + Assert.AreEqual(Path.Join(parentDir.Name, "beta.txt"), response[1].Name); + Assert.AreEqual(parentDir.Name, response[2].Name); } finally { From 8a049d93a53fe53a41ff9e6e63fb96a855919063 Mon Sep 17 00:00:00 2001 From: Krivoshchekov Artem Date: Sat, 10 Aug 2024 22:28:25 -0300 Subject: [PATCH 3/5] netstandard2.0 --- src/IpfsClient.cs | 7 +++++-- src/IpfsHttpClient.csproj | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/IpfsClient.cs b/src/IpfsClient.cs index 17f3f54..08c65b5 100644 --- a/src/IpfsClient.cs +++ b/src/IpfsClient.cs @@ -316,7 +316,10 @@ public async Task> DoAddCommand( string GetFileName(string cPath) { - var relativePath = Path.GetRelativePath(upperLevelFolder, cPath); + // var relativePath = Path.GetRelativePath(upperLevelFolder, cPath); + // var relativePath = Path.join(upperLevelFolder, cPath); + + var relativePath = cPath.Replace(upperLevelFolder, ""); return $"{Uri.EscapeDataString(relativePath)}"; } @@ -345,7 +348,7 @@ ByteArrayContent addFile(FileInfo cFile) var strBody = await response.Content.ReadAsStringAsync(); var result = strBody - .Split("\n") + .Split('\n') .Where(x => !string.IsNullOrWhiteSpace(x)) .Select(JsonConvert.DeserializeObject) .ToList(); diff --git a/src/IpfsHttpClient.csproj b/src/IpfsHttpClient.csproj index e898917..cbdafc3 100644 --- a/src/IpfsHttpClient.csproj +++ b/src/IpfsHttpClient.csproj @@ -26,7 +26,7 @@ True https://github.com/ipfs-shipyard/net-ipfs-http-client icon.png - netstandard2.1 + netstandard2.0 From 771e45e400205d38daa2c0b2c05469288b86a6cc Mon Sep 17 00:00:00 2001 From: Krivoshchekov Artem Date: Sat, 10 Aug 2024 23:01:45 -0300 Subject: [PATCH 4/5] published to nuget --- .gitignore | 1 + src/DreadIpfsHttpClient.nuspec | 31 +++++++++++++++++++++++++++++++ src/IpfsHttpClient.csproj | 5 +++++ src/Makefile | 5 +++++ 4 files changed, 42 insertions(+) create mode 100644 src/DreadIpfsHttpClient.nuspec create mode 100644 src/Makefile diff --git a/.gitignore b/.gitignore index 6573a85..c8e9b2b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ # Ide .idea +.env # User-specific files *.suo diff --git a/src/DreadIpfsHttpClient.nuspec b/src/DreadIpfsHttpClient.nuspec new file mode 100644 index 0000000..aab5931 --- /dev/null +++ b/src/DreadIpfsHttpClient.nuspec @@ -0,0 +1,31 @@ + + + + DreadIpfsHttpClient + 0.5.0 + IpfsHttpClient + docs\README.md + DreadfulBot + false + MIT + + https://github.com/DreadfulBot/net-ipfs-http-client + IpfsClient with some improvements + Folder upload function fixed + DreadfulBot + ipfs files nft blockchain liberation + + + + + + + + + + + + + + + diff --git a/src/IpfsHttpClient.csproj b/src/IpfsHttpClient.csproj index cbdafc3..00fe509 100644 --- a/src/IpfsHttpClient.csproj +++ b/src/IpfsHttpClient.csproj @@ -6,6 +6,7 @@ bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml full true + README.md 0.5.0 @@ -71,6 +72,10 @@ The obsolete IFileSystemApi.ListFileAsync was removed due to prior deprecation a Added missing IFileSystemApi.ListAsync. Doesn't fully replace the removed IFileSystemApi.ListFileAsync, but is a step in the right direction. See https://github.com/ipfs/kubo/issues/7493#issuecomment-2016563729. + + + + diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..c2d06de --- /dev/null +++ b/src/Makefile @@ -0,0 +1,5 @@ +include .env +nuget-push: + nuget push bin/Release/$(PACKAGE_NAME).$(VERSION).nupkg -Source https://api.nuget.org/v3/index.json -ApiKey $(NUGET_API_KEY) +nuget-pack: + nuget pack $(PACKAGE_NAME).nuspec -Version $(VERSION) -Properties Configuration=Release -OutputDirectory bin/Release From 05041fb53c999745b3d24843f5f155bc4ea1f83a Mon Sep 17 00:00:00 2001 From: Krivoshchekov Artem Date: Sat, 10 Aug 2024 23:14:32 -0300 Subject: [PATCH 5/5] refactor --- src/IpfsFIle.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/IpfsFIle.cs b/src/IpfsFIle.cs index 74edd31..02ccf7e 100644 --- a/src/IpfsFIle.cs +++ b/src/IpfsFIle.cs @@ -3,8 +3,7 @@ namespace Ipfs.Http; /// -/// AddResponse -/// {"Name":"var","Hash":"QmPypQtsKqpUC6QzufU1ZfaPw6Kj4eN459aBMzbcfdnPAN","Size":"288"} +/// IpfsFile /// [DataContract] public class IpfsFile