Skip to content

Commit

Permalink
Release 0.6.0. See release note or expand full commit message for det…
Browse files Browse the repository at this point in the history
…ails.

[Breaking]
Fixed WebRTC-Direct support added in Kubo 0.30.0.
Removed the Object API completely, since Kubo replaced it with the DAG API and no longer offers it.
Refactored the FileSystem API to:
  - Enable proper directory uploads via a new `AddAsync` method that takes File and Folder parts separately.
  - Bring `FileAddOptions` fully up-to-date with modern Kubo.
  - Remove `AddDirectoryAsync` (used missing Object API).
Updated several types to use one of int, long or ulong for Size matching the Kubo API.
MerkleNode no longer has a static internal IpfsClient, and several properties that performed async calls synchronously were adjusted or removed.
Block.DataBytes was removed as it was unused by any known interface or implementation.

[New]
Added FilestoreApi and the corresponding types.

[Improvements]
FilesystemApi.AddAsync now uses chunked transfer encoding, enabling uploading of very large files or groups of files.
  • Loading branch information
Arlodotexe committed Nov 21, 2024
1 parent d8b77d9 commit e43acf0
Show file tree
Hide file tree
Showing 23 changed files with 642 additions and 868 deletions.
14 changes: 5 additions & 9 deletions src/Block.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
using System.Runtime.Serialization;
using System.Runtime.Serialization;
using Newtonsoft.Json;

namespace Ipfs.Http
{
/// <inheritdoc />
[DataContract]
public class Block : IDataBlock
public record Block : IBlockStat
{
/// <summary>
/// The data of the block.
/// </summary>
public byte[] DataBytes { get; set; }

/// <inheritdoc />
[DataMember]
[JsonProperty("Key")]
public required Cid Id { get; set; }

/// <inheritdoc />
[DataMember]
public required long Size { get; set; }
public required int Size { get; set; }
}

}
128 changes: 63 additions & 65 deletions src/CoreApi/BlockApi.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using Ipfs.CoreApi;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

#nullable enable

namespace Ipfs.Http
{
class BlockApi : IBlockApi
Expand All @@ -17,92 +18,89 @@ internal BlockApi(IpfsClient ipfs)
this.ipfs = ipfs;
}

public async Task<byte[]> GetAsync(Cid id, CancellationToken cancel = default(CancellationToken))
public async Task<byte[]> GetAsync(Cid id, CancellationToken cancel = default)
{
return await ipfs.DownloadBytesAsync("block/get", cancel, id);
}

public async Task<Cid> PutAsync(
public async Task<IBlockStat> PutAsync(
byte[] data,
string contentType = Cid.DefaultContentType,
string multiHash = MultiHash.DefaultAlgorithmName,
string encoding = MultiBase.DefaultAlgorithmName,
bool pin = false,
CancellationToken cancel = default(CancellationToken))
string cidCodec = "raw",
MultiHash? hash = null,
bool? pin = null,
bool? allowBigBlock = null,
CancellationToken cancel = default)
{
var options = new List<string>();
if (multiHash != MultiHash.DefaultAlgorithmName ||
contentType != Cid.DefaultContentType ||
encoding != MultiBase.DefaultAlgorithmName)
{
options.Add($"mhtype={multiHash}");
options.Add($"format={contentType}");
options.Add($"cid-base={encoding}");
}
var json = await ipfs.UploadAsync("block/put", cancel, data, options.ToArray());
var info = JObject.Parse(json);
Cid cid = (string)info["Key"];

if (pin)
{
await ipfs.Pin.AddAsync(cid, recursive: false, cancel: cancel);
}

return cid;
using var stream = new MemoryStream(data);
return await PutAsync(stream, cidCodec, hash, pin, allowBigBlock, cancel);
}

public async Task<Cid> PutAsync(
public async Task<IBlockStat> PutAsync(
Stream data,
string contentType = Cid.DefaultContentType,
string multiHash = MultiHash.DefaultAlgorithmName,
string encoding = MultiBase.DefaultAlgorithmName,
bool pin = false,
CancellationToken cancel = default(CancellationToken))
string cidCodec = "raw",
MultiHash? hash = null,
bool? pin = null,
bool? allowBigBlock = null,
CancellationToken cancel = default)
{
var options = new List<string>();
if (multiHash != MultiHash.DefaultAlgorithmName ||
contentType != Cid.DefaultContentType ||
encoding != MultiBase.DefaultAlgorithmName)
{
options.Add($"mhtype={multiHash}");
options.Add($"format={contentType}");
options.Add($"cid-base={encoding}");
}
var json = await ipfs.UploadAsync("block/put", cancel, data, null, options.ToArray());
var info = JObject.Parse(json);
Cid cid = (string)info["Key"];

if (pin)
{
await ipfs.Pin.AddAsync(cid, recursive: false, cancel: cancel);
}
string[] options = [
$"cid-codec={cidCodec}"
];

return cid;
if (hash != null)
options = [.. options, $"mhtype={hash}", $"mhlen={hash.Algorithm.DigestSize}"];

if (pin != null)
options = [.. options, $"pin={pin.ToString().ToLowerInvariant()}"];

if (allowBigBlock != null)
options = [.. options, $"allow-big-block={allowBigBlock.ToString().ToLowerInvariant()}"];

var json = await ipfs.UploadAsync("block/put", cancel, data, null, options);
var res = JObject.Parse(json).ToObject<Block>();
if (res is null)
throw new InvalidDataException("The response did not contain a block.");

return res;
}

public async Task<IDataBlock> StatAsync(Cid id, CancellationToken cancel = default(CancellationToken))
public async Task<IBlockStat> StatAsync(Cid id, CancellationToken cancel = default)
{
var json = await ipfs.DoCommandAsync("block/stat", cancel, id);
var info = JObject.Parse(json);
return new Block
{
Size = (long)info["Size"],
Id = (string)info["Key"]
};

var parsed = JObject.Parse(json);
if (parsed is null)
throw new InvalidDataException("The response could not be parsed.");

var error = (string?)parsed["Error"];
if (error != null)
throw new HttpRequestException(error);

var res = parsed.ToObject<Block>();
if (res is null)
throw new InvalidDataException("The response could not be deserialized.");

return res;
}

public async Task<Cid> RemoveAsync(Cid id, bool ignoreNonexistent = false, CancellationToken cancel = default(CancellationToken))
public async Task<Cid> RemoveAsync(Cid id, bool ignoreNonexistent = false, CancellationToken cancel = default)
{
var json = await ipfs.DoCommandAsync("block/rm", cancel, id, "force=" + ignoreNonexistent.ToString().ToLowerInvariant());
if (json.Length == 0)
return null;
var result = JObject.Parse(json);
var error = (string)result["Error"];

var parsed = JObject.Parse(json);
if (parsed is null)
throw new InvalidDataException("The response could not be parsed.");

var error = (string?)parsed["Error"];
if (error != null)
throw new HttpRequestException(error);
return (Cid)(string)result["Hash"];
}

var cid = parsed["Hash"]?.ToObject<Cid>();
if (cid is null)
throw new InvalidDataException("The response could not be deserialized.");

return cid;
}
}

}
Loading

0 comments on commit e43acf0

Please sign in to comment.