Add binary media manifest metadata
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Jibo.Cloud.Application.Abstractions;
|
using Jibo.Cloud.Application.Abstractions;
|
||||||
using Jibo.Cloud.Domain.Models;
|
using Jibo.Cloud.Domain.Models;
|
||||||
@@ -343,10 +344,15 @@ public sealed class JiboCloudProtocolService(ICloudStateStore stateStore, IMedia
|
|||||||
var meta = ReadObject(body, "meta") ?? new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase);
|
var meta = ReadObject(body, "meta") ?? new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase);
|
||||||
var contentType = ReadHeader(envelope, "Content-Type") ?? "application/octet-stream";
|
var contentType = ReadHeader(envelope, "Content-Type") ?? "application/octet-stream";
|
||||||
meta["contentType"] = contentType;
|
meta["contentType"] = contentType;
|
||||||
|
var bodyBytes = string.IsNullOrWhiteSpace(envelope.BodyText)
|
||||||
|
? []
|
||||||
|
: Encoding.UTF8.GetBytes(envelope.BodyText);
|
||||||
|
meta["contentLength"] = bodyBytes.Length;
|
||||||
|
meta["contentSha256"] = Convert.ToHexString(SHA256.HashData(bodyBytes)).ToLowerInvariant();
|
||||||
if (!string.IsNullOrWhiteSpace(envelope.BodyText)) meta["bodyText"] = envelope.BodyText;
|
if (!string.IsNullOrWhiteSpace(envelope.BodyText)) meta["bodyText"] = envelope.BodyText;
|
||||||
|
|
||||||
_mediaContentStore.StoreAsync(path, contentType,
|
_mediaContentStore.StoreAsync(path, contentType,
|
||||||
string.IsNullOrWhiteSpace(envelope.BodyText) ? [] : Encoding.UTF8.GetBytes(envelope.BodyText),
|
bodyBytes,
|
||||||
meta as IReadOnlyDictionary<string, object?>, CancellationToken.None).GetAwaiter().GetResult();
|
meta as IReadOnlyDictionary<string, object?>, CancellationToken.None).GetAwaiter().GetResult();
|
||||||
|
|
||||||
return ProtocolDispatchResult.Ok(
|
return ProtocolDispatchResult.Ok(
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using Azure.Storage.Blobs;
|
using Azure.Storage.Blobs;
|
||||||
using Jibo.Cloud.Application.Abstractions;
|
using Jibo.Cloud.Application.Abstractions;
|
||||||
|
|
||||||
@@ -31,11 +32,17 @@ internal sealed class AzureBlobMediaContentStore : IMediaContentStore
|
|||||||
var metaBlob = _containerClient.GetBlobClient($"{relative}.json");
|
var metaBlob = _containerClient.GetBlobClient($"{relative}.json");
|
||||||
await _containerClient.CreateIfNotExistsAsync(cancellationToken: cancellationToken);
|
await _containerClient.CreateIfNotExistsAsync(cancellationToken: cancellationToken);
|
||||||
await contentBlob.UploadAsync(new MemoryStream(content), true, cancellationToken);
|
await contentBlob.UploadAsync(new MemoryStream(content), true, cancellationToken);
|
||||||
|
var manifestMeta = meta is null
|
||||||
|
? new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
: new Dictionary<string, object?>(meta, StringComparer.OrdinalIgnoreCase);
|
||||||
|
manifestMeta["contentLength"] = content.Length;
|
||||||
|
manifestMeta["contentSha256"] = Convert.ToHexString(SHA256.HashData(content)).ToLowerInvariant();
|
||||||
|
manifestMeta["storedUtc"] = DateTimeOffset.UtcNow;
|
||||||
var payload = JsonSerializer.Serialize(new
|
var payload = JsonSerializer.Serialize(new
|
||||||
{
|
{
|
||||||
path,
|
path,
|
||||||
contentType,
|
contentType,
|
||||||
meta
|
meta = manifestMeta
|
||||||
}, JsonOptions);
|
}, JsonOptions);
|
||||||
await metaBlob.UploadAsync(BinaryData.FromString(payload), true, cancellationToken);
|
await metaBlob.UploadAsync(BinaryData.FromString(payload), true, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using Jibo.Cloud.Application.Abstractions;
|
using Jibo.Cloud.Application.Abstractions;
|
||||||
|
|
||||||
namespace Jibo.Cloud.Infrastructure.Media;
|
namespace Jibo.Cloud.Infrastructure.Media;
|
||||||
@@ -29,11 +30,17 @@ internal sealed class FileMediaContentStore : IMediaContentStore
|
|||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(contentPath)!);
|
Directory.CreateDirectory(Path.GetDirectoryName(contentPath)!);
|
||||||
await File.WriteAllBytesAsync(contentPath, content, cancellationToken);
|
await File.WriteAllBytesAsync(contentPath, content, cancellationToken);
|
||||||
|
var manifestMeta = meta is null
|
||||||
|
? new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
: new Dictionary<string, object?>(meta, StringComparer.OrdinalIgnoreCase);
|
||||||
|
manifestMeta["contentLength"] = content.Length;
|
||||||
|
manifestMeta["contentSha256"] = Convert.ToHexString(SHA256.HashData(content)).ToLowerInvariant();
|
||||||
|
manifestMeta["storedUtc"] = DateTimeOffset.UtcNow;
|
||||||
var payload = new
|
var payload = new
|
||||||
{
|
{
|
||||||
path,
|
path,
|
||||||
contentType,
|
contentType,
|
||||||
meta
|
meta = manifestMeta
|
||||||
};
|
};
|
||||||
await File.WriteAllTextAsync(metaPath, JsonSerializer.Serialize(payload, JsonOptions), cancellationToken);
|
await File.WriteAllTextAsync(metaPath, JsonSerializer.Serialize(payload, JsonOptions), cancellationToken);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Jibo.Cloud.Application.Services;
|
using Jibo.Cloud.Application.Services;
|
||||||
using Jibo.Cloud.Domain.Models;
|
using Jibo.Cloud.Domain.Models;
|
||||||
@@ -420,6 +422,46 @@ public sealed class JiboCloudProtocolServiceTests
|
|||||||
Assert.Equal("binary-photo-placeholder", mediaGet.BodyText);
|
Assert.Equal("binary-photo-placeholder", mediaGet.BodyText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MediaCreate_WritesBinaryManifestMetadataForSync()
|
||||||
|
{
|
||||||
|
var directoryPath = Path.Combine(Path.GetTempPath(), "OpenJibo.Media.Tests", Guid.NewGuid().ToString("N"));
|
||||||
|
var service = new JiboCloudProtocolService(new InMemoryCloudStateStore(),
|
||||||
|
new FileMediaContentStore(directoryPath));
|
||||||
|
const string bodyText = "binary-photo-placeholder";
|
||||||
|
|
||||||
|
var result = await service.DispatchAsync(new ProtocolEnvelope
|
||||||
|
{
|
||||||
|
HostName = "api.jibo.com",
|
||||||
|
Method = "POST",
|
||||||
|
ServicePrefix = "Media_20160725",
|
||||||
|
Operation = "Create",
|
||||||
|
Headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
["Content-Type"] = "image/jpeg",
|
||||||
|
["x-path"] = "photo-blob-manifest",
|
||||||
|
["x-type"] = "image"
|
||||||
|
},
|
||||||
|
BodyText = bodyText
|
||||||
|
});
|
||||||
|
|
||||||
|
using var createdPayload = JsonDocument.Parse(result.BodyText);
|
||||||
|
var meta = createdPayload.RootElement.GetProperty("meta");
|
||||||
|
Assert.Equal(bodyText.Length, meta.GetProperty("contentLength").GetInt32());
|
||||||
|
Assert.Equal(
|
||||||
|
Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(bodyText))).ToLowerInvariant(),
|
||||||
|
meta.GetProperty("contentSha256").GetString());
|
||||||
|
|
||||||
|
var metaPath = Path.Combine(directoryPath, "photo-blob-manifest.json");
|
||||||
|
using var manifest = JsonDocument.Parse(await File.ReadAllTextAsync(metaPath));
|
||||||
|
var manifestMeta = manifest.RootElement.GetProperty("meta");
|
||||||
|
Assert.Equal(bodyText.Length, manifestMeta.GetProperty("contentLength").GetInt32());
|
||||||
|
Assert.Equal(
|
||||||
|
Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(bodyText))).ToLowerInvariant(),
|
||||||
|
manifestMeta.GetProperty("contentSha256").GetString());
|
||||||
|
Assert.True(manifestMeta.TryGetProperty("storedUtc", out _));
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task KeyCreateSymmetricKey_ReturnsKeyPayload()
|
public async Task KeyCreateSymmetricKey_ReturnsKeyPayload()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user