Move metadata to provider interface

This commit is contained in:
Kieran
2022-02-08 18:20:59 +00:00
parent 6d37b42d11
commit 3321e93478
7 changed files with 99 additions and 36 deletions

View File

@@ -7,9 +7,9 @@ namespace VoidCat.Controllers;
[Route("d")] [Route("d")]
public class DownloadController : Controller public class DownloadController : Controller
{ {
private readonly IFileStorage _storage; private readonly IFileStore _storage;
public DownloadController(IFileStorage storage) public DownloadController(IFileStore storage)
{ {
_storage = storage; _storage = storage;
} }

View File

@@ -10,9 +10,9 @@ namespace VoidCat.Controllers
[Route("upload")] [Route("upload")]
public class UploadController : Controller public class UploadController : Controller
{ {
private readonly IFileStorage _storage; private readonly IFileStore _storage;
public UploadController(IFileStorage storage) public UploadController(IFileStore storage)
{ {
_storage = storage; _storage = storage;
} }

View File

@@ -16,7 +16,8 @@ services.AddControllers().AddNewtonsoftJson();
services.AddMemoryCache(); services.AddMemoryCache();
services.AddScoped<IFileStorage, LocalDiskFileIngressFactory>(); services.AddScoped<IFileMetadataStore, LocalDiskFileMetadataStore>();
services.AddScoped<IFileStore, LocalDiskFileIngressFactory>();
services.AddScoped<IStatsCollector, InMemoryStatsCollector>(); services.AddScoped<IStatsCollector, InMemoryStatsCollector>();
var app = builder.Build(); var app = builder.Build();

View File

@@ -0,0 +1,12 @@
using VoidCat.Model;
namespace VoidCat.Services;
public interface IFileMetadataStore
{
Task<InternalVoidFile?> Get(Guid id);
Task Set(InternalVoidFile meta);
Task Update(VoidFile patch, Guid editSecret);
}

View File

@@ -2,7 +2,7 @@
namespace VoidCat.Services namespace VoidCat.Services
{ {
public interface IFileStorage public interface IFileStore
{ {
Task<VoidFile?> Get(Guid id); Task<VoidFile?> Get(Guid id);
@@ -11,5 +11,7 @@ namespace VoidCat.Services
Task Egress(Guid id, Stream outStream, CancellationToken cts); Task Egress(Guid id, Stream outStream, CancellationToken cts);
Task UpdateInfo(VoidFile patch, Guid editSecret); Task UpdateInfo(VoidFile patch, Guid editSecret);
IAsyncEnumerable<VoidFile> ListFiles();
} }
} }

View File

@@ -0,0 +1,55 @@
using Newtonsoft.Json;
using VoidCat.Model;
using VoidCat.Model.Exceptions;
namespace VoidCat.Services;
public class LocalDiskFileMetadataStore : IFileMetadataStore
{
private const string MetadataDir = "metadata";
private readonly VoidSettings _settings;
public LocalDiskFileMetadataStore(VoidSettings settings)
{
_settings = settings;
var metaPath = Path.Combine(_settings.DataDirectory, MetadataDir);
if (!Directory.Exists(metaPath))
{
Directory.CreateDirectory(metaPath);
}
}
public async Task<InternalVoidFile?> Get(Guid id)
{
var path = MapMeta(id);
if (!File.Exists(path)) throw new VoidFileNotFoundException(id);
var json = await File.ReadAllTextAsync(path);
return JsonConvert.DeserializeObject<InternalVoidFile>(json);
}
public Task Set(InternalVoidFile meta)
{
var path = MapMeta(meta.Id);
var json = JsonConvert.SerializeObject(meta);
return File.WriteAllTextAsync(path, json);
}
public async Task Update(VoidFile patch, Guid editSecret)
{
var oldMeta = await Get(patch.Id);
if (oldMeta?.EditSecret != editSecret)
{
throw new VoidNotAllowedException("Edit secret incorrect");
}
// only patch metadata
oldMeta.Metadata = patch.Metadata;
await Set(oldMeta);
}
private string MapMeta(Guid id) =>
Path.ChangeExtension(Path.Join(_settings.DataDirectory, MetadataDir, id.ToString()), ".json");
}

View File

@@ -1,19 +1,21 @@
using System.Buffers; using System.Buffers;
using Newtonsoft.Json;
using VoidCat.Model; using VoidCat.Model;
using VoidCat.Model.Exceptions; using VoidCat.Model.Exceptions;
namespace VoidCat.Services; namespace VoidCat.Services;
public class LocalDiskFileIngressFactory : IFileStorage public class LocalDiskFileIngressFactory : IFileStore
{ {
private readonly VoidSettings _settings; private readonly VoidSettings _settings;
private readonly IStatsCollector _stats; private readonly IStatsCollector _stats;
private readonly IFileMetadataStore _metadataStore;
public LocalDiskFileIngressFactory(VoidSettings settings, IStatsCollector stats) public LocalDiskFileIngressFactory(VoidSettings settings, IStatsCollector stats,
IFileMetadataStore metadataStore)
{ {
_settings = settings; _settings = settings;
_stats = stats; _stats = stats;
_metadataStore = metadataStore;
if (!Directory.Exists(_settings.DataDirectory)) if (!Directory.Exists(_settings.DataDirectory))
{ {
@@ -23,11 +25,7 @@ public class LocalDiskFileIngressFactory : IFileStorage
public async Task<VoidFile?> Get(Guid id) public async Task<VoidFile?> Get(Guid id)
{ {
var path = MapMeta(id); return await _metadataStore.Get(id);
if (!File.Exists(path)) throw new VoidFileNotFoundException(id);
var json = await File.ReadAllTextAsync(path);
return JsonConvert.DeserializeObject<VoidFile>(json);
} }
public async Task Egress(Guid id, Stream outStream, CancellationToken cts) public async Task Egress(Guid id, Stream outStream, CancellationToken cts)
@@ -70,35 +68,30 @@ public class LocalDiskFileIngressFactory : IFileStorage
EditSecret = Guid.NewGuid() EditSecret = Guid.NewGuid()
}; };
var mPath = MapMeta(id); await _metadataStore.Set(fm);
var json = JsonConvert.SerializeObject(fm);
await File.WriteAllTextAsync(mPath, json, cts);
return fm; return fm;
} }
public async Task UpdateInfo(VoidFile patch, Guid editSecret) public Task UpdateInfo(VoidFile patch, Guid editSecret)
{ {
var path = MapMeta(patch.Id); return _metadataStore.Update(patch, editSecret);
if (!File.Exists(path)) throw new VoidFileNotFoundException(patch.Id); }
var oldJson = await File.ReadAllTextAsync(path); public async IAsyncEnumerable<VoidFile> ListFiles()
var oldObj = JsonConvert.DeserializeObject<InternalVoidFile>(oldJson); {
foreach (var fe in Directory.EnumerateFiles(_settings.DataDirectory))
if (oldObj?.EditSecret != editSecret)
{ {
throw new VoidNotAllowedException("Edit secret incorrect"); var filename = Path.GetFileNameWithoutExtension(fe);
if (!Guid.TryParse(filename, out var id)) continue;
var meta = await _metadataStore.Get(id);
if (meta != default)
{
yield return meta;
}
} }
// only patch metadata
oldObj.Metadata = patch.Metadata;
var json = JsonConvert.SerializeObject(oldObj);
await File.WriteAllTextAsync(path, json);
} }
private string MapPath(Guid id) => private string MapPath(Guid id) =>
Path.Join(_settings.DataDirectory, id.ToString()); Path.Join(_settings.DataDirectory, id.ToString());
private string MapMeta(Guid id) =>
Path.ChangeExtension(MapPath(id), ".json");
} }