Skip to content

Commit

Permalink
Merge pull request #54 from Etherna/feature/BNET-106-swarm-path
Browse files Browse the repository at this point in the history
Feature/bnet 106 swarm path
  • Loading branch information
tmm360 authored Jul 8, 2024
2 parents 5fa542b + ce89e9d commit 686a704
Show file tree
Hide file tree
Showing 8 changed files with 293 additions and 53 deletions.
11 changes: 7 additions & 4 deletions src/BeeNet.Core/Models/SwarmAddress.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ namespace Etherna.BeeNet.Models
{
public readonly struct SwarmAddress : IEquatable<SwarmAddress>
{
// Consts.
public const char Separator = '/';

// Constructor.
public SwarmAddress(SwarmHash hash, string? path = null)
{
Expand All @@ -30,12 +33,12 @@ public SwarmAddress(string address)
ArgumentNullException.ThrowIfNull(address, nameof(address));

// Trim initial slash.
address = address.TrimStart('/');
address = address.TrimStart(Separator);

// Extract hash root.
var slashIndex = address.IndexOf('/', StringComparison.InvariantCulture);
var slashIndex = address.IndexOf(Separator, StringComparison.InvariantCulture);
var hash = slashIndex > 0 ? address[..slashIndex] : address;
var path = slashIndex > 0 ? address[slashIndex..] : "/";
var path = slashIndex > 0 ? address[slashIndex..] : Separator.ToString();

// Set hash and path.
Hash = new SwarmHash(hash);
Expand Down Expand Up @@ -72,6 +75,6 @@ public override int GetHashCode() => Hash.GetHashCode() ^

// Helpers.
internal static string NormalizePath(string? path) =>
'/' + (path ?? "").TrimStart('/');
Separator + (path ?? "").TrimStart(Separator);
}
}
24 changes: 20 additions & 4 deletions src/BeeNet.Core/Models/SwarmHash.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ namespace Etherna.BeeNet.Models
public SwarmHash(byte[] hash)
{
ArgumentNullException.ThrowIfNull(hash, nameof(hash));
if (hash.Length != HashSize)
if (!IsValidHash(hash))
throw new ArgumentOutOfRangeException(nameof(hash));

byteHash = hash;
Expand All @@ -40,7 +40,7 @@ public SwarmHash(byte[] hash)
public SwarmHash(string hash)
{
ArgumentNullException.ThrowIfNull(hash, nameof(hash));

try
{
byteHash = hash.HexToByteArray();
Expand All @@ -50,8 +50,8 @@ public SwarmHash(string hash)
throw new ArgumentException("Invalid hash", nameof(hash));
}

if (byteHash.Length != HashSize)
throw new ArgumentException("Invalid hash", nameof(hash));
if (!IsValidHash(byteHash))
throw new ArgumentOutOfRangeException(nameof(hash));
}

// Static properties.
Expand All @@ -70,6 +70,22 @@ public uint ToBucketId() =>
// Static methods.
public static SwarmHash FromByteArray(byte[] value) => new(value);
public static SwarmHash FromString(string value) => new(value);
public static bool IsValidHash(byte[] value)
{
ArgumentNullException.ThrowIfNull(value, nameof(value));
return value.Length == HashSize;
}
public static bool IsValidHash(string value)
{
try
{
return IsValidHash(value.HexToByteArray());
}
catch (FormatException)
{
return false;
}
}

// Operator methods.
public static bool operator ==(SwarmHash left, SwarmHash right) => left.Equals(right);
Expand Down
31 changes: 22 additions & 9 deletions src/BeeNet.Core/Models/SwarmUri.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,17 @@ public SwarmUri(SwarmHash? hash, string? path)
Hash = hash;
Path = hash != null ? SwarmAddress.NormalizePath(path) : path!;
}
public SwarmUri(string uri, bool isAbsolute)
public SwarmUri(string uri, UriKind uriKind)
{
ArgumentNullException.ThrowIfNull(uri, nameof(uri));

if (isAbsolute)
// Determine uri kind.
if (uriKind == UriKind.RelativeOrAbsolute)
uriKind = SwarmHash.IsValidHash(uri.Split(SwarmAddress.Separator)[0])
? UriKind.Absolute
: UriKind.Relative;

if (uriKind == UriKind.Absolute)
{
var address = new SwarmAddress(uri);
Hash = address.Hash;
Expand All @@ -49,9 +55,9 @@ public SwarmUri(string uri, bool isAbsolute)

// Properties.
public SwarmHash? Hash { get; }
public bool IsAbsolute => Hash.HasValue;
public bool IsRooted => IsAbsolute || System.IO.Path.IsPathRooted(Path);
public bool IsRooted => UriKind == UriKind.Absolute || System.IO.Path.IsPathRooted(Path);
public string Path { get; }
public UriKind UriKind => Hash.HasValue ? UriKind.Absolute : UriKind.Relative;

// Methods.
public bool Equals(SwarmUri other) =>
Expand All @@ -64,7 +70,7 @@ public override int GetHashCode() => Hash.GetHashCode() ^
(Path?.GetHashCode(StringComparison.InvariantCulture) ?? 0);

public override string ToString() =>
IsAbsolute ? new SwarmAddress(Hash!.Value, Path).ToString() : Path!;
UriKind == UriKind.Absolute ? new SwarmAddress(Hash!.Value, Path).ToString() : Path!;

public SwarmAddress ToSwarmAddress(SwarmAddress prefix)
{
Expand All @@ -79,10 +85,13 @@ public bool TryGetRelativeTo(SwarmUri relativeTo, out SwarmUri output)
if (relativeTo.Hash != Hash)
return false;

if (!Path.StartsWith(relativeTo.Path, StringComparison.InvariantCulture))
var dirs = Path.Split(SwarmAddress.Separator);
var relativeToDirs = relativeTo.Path.TrimEnd(SwarmAddress.Separator).Split(SwarmAddress.Separator);
if (dirs.Length < relativeToDirs.Length ||
!dirs[..relativeToDirs.Length].SequenceEqual(relativeToDirs))
return false;

output = new SwarmUri(null, Path[relativeTo.Path.Length..].TrimStart('/'));
output = new SwarmUri(null, string.Join(SwarmAddress.Separator, dirs[relativeToDirs.Length..]));
return true;
}

Expand All @@ -96,16 +105,19 @@ public static SwarmUri Combine(params SwarmUri[] uris)
var combined = uris[0];
foreach (var uri in uris.Skip(1))
{
if (uri.IsAbsolute)
if (uri.UriKind == UriKind.Absolute)
combined = uri;
else if (uri.IsRooted)
combined = new SwarmUri(combined.Hash, uri.Path);
else
combined = new SwarmUri(combined.Hash, string.Concat(combined.Path ?? "", uri.Path!));
combined = new SwarmUri(
combined.Hash,
(combined.Path ?? "").TrimEnd(SwarmAddress.Separator) + SwarmAddress.Separator + uri.Path);
}

return combined;
}
public static SwarmUri FromString(string value) => new(value, UriKind.RelativeOrAbsolute);
public static SwarmUri FromSwarmAddress(SwarmAddress value) => new(value.Hash, value.Path);
public static SwarmUri FromSwarmHash(SwarmHash value) => new(value, null);

Expand All @@ -114,6 +126,7 @@ public static SwarmUri Combine(params SwarmUri[] uris)
public static bool operator !=(SwarmUri left, SwarmUri right) => !(left == right);

// Implicit conversion operator methods.
public static implicit operator SwarmUri(string value) => new(value, UriKind.RelativeOrAbsolute);
public static implicit operator SwarmUri(SwarmAddress value) => new(value.Hash, value.Path);
public static implicit operator SwarmUri(SwarmHash value) => new(value, null);

Expand Down
2 changes: 1 addition & 1 deletion src/BeeNet.Util/Manifest/MantarayManifest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ namespace Etherna.BeeNet.Manifest
public class MantarayManifest : IReadOnlyMantarayManifest
{
// Consts.
public const string RootPath = "/";
public static readonly string RootPath = SwarmAddress.Separator.ToString();

// Fields.
private readonly Func<IHasherPipeline> hasherBuilder;
Expand Down
3 changes: 1 addition & 2 deletions src/BeeNet.Util/Manifest/MantarayNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ public class MantarayNode : IReadOnlyMantarayNode
{
// Consts.
public const int ForksIndexSize = 32;
public const char PathSeparator = '/';
public static readonly byte[] Version02Hash = new HashProvider().ComputeHash(
"mantaray:0.2"u8.ToArray()).Take(VersionHashSize).ToArray();
public const int VersionHashSize = 31;
Expand Down Expand Up @@ -231,7 +230,7 @@ private byte[] ToByteArray()

private void UpdateFlagIsWithPathSeparator(string path)
{
if (path.IndexOf(PathSeparator, StringComparison.InvariantCulture) > 0)
if (path.IndexOf(SwarmAddress.Separator, StringComparison.InvariantCulture) > 0)
SetNodeTypeFlag(NodeType.WithPathSeparator);
else
RemoveNodeTypeFlag(NodeType.WithPathSeparator);
Expand Down
8 changes: 4 additions & 4 deletions src/BeeNet.Util/Manifest/ReferencedMantarayNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ public async Task<IReadOnlyDictionary<string, string>> GetResourceMetadataAsync(
if (path.Length == 0)
{
//try to lookup for index document suffix
if (!_forks.TryGetValue('/', out var rootFork) ||
rootFork.Prefix != "/")
if (!_forks.TryGetValue(SwarmAddress.Separator, out var rootFork) ||
rootFork.Prefix != SwarmAddress.Separator.ToString())
throw new KeyNotFoundException($"Final path {path} can't be found");

if (!rootFork.Node.Metadata.TryGetValue(ManifestEntry.WebsiteIndexDocPathKey, out var suffix))
Expand Down Expand Up @@ -136,8 +136,8 @@ public async Task<SwarmHash> ResolveResourceHashAsync(string path)
return EntryHash.Value;

//try to lookup for index document suffix
if (!_forks.TryGetValue('/', out var rootFork) ||
rootFork.Prefix != "/")
if (!_forks.TryGetValue(SwarmAddress.Separator, out var rootFork) ||
rootFork.Prefix != SwarmAddress.Separator.ToString())
throw new KeyNotFoundException($"Final path {path} can't be found");

if (!rootFork.Node.Metadata.TryGetValue(ManifestEntry.WebsiteIndexDocPathKey, out var suffix))
Expand Down
2 changes: 1 addition & 1 deletion src/BeeNet.Util/Services/CalculatorService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public async Task<UploadEvaluationResult> EvaluateDirectoryUploadAsync(
IChunkStore? chunkStore = null)
{
// Checks.
if (indexFilename?.Contains('/', StringComparison.InvariantCulture) == true)
if (indexFilename?.Contains(SwarmAddress.Separator, StringComparison.InvariantCulture) == true)
throw new ArgumentException(
"Index document suffix must not include slash character",
nameof(indexFilename));
Expand Down
Loading

0 comments on commit 686a704

Please sign in to comment.