/*
* Copyright (c) 2023 Vaughn Nugent
*
* Library: CMNext
* Package: Content.Publishing.Blog.Admin
* File: StorageExtensions.cs
*
* CMNext is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* CMNext is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using VNLib.Utils.IO;
using VNLib.Net.Http;
using Content.Publishing.Blog.Admin.Model;
namespace Content.Publishing.Blog.Admin
{
internal static class StorageExtensions
{
///
/// Writes a file of the given content type to the given path in the given channel context.
///
///
/// The channel context to write the file in
/// The stream containing the file data to write to the storage layer
/// The relative path to the file within the context to write
/// The file content type
/// A token to cancel the operation
/// A task that completes when the file data has been written to the storage layer
public static Task SetObjectDataAsync(this ISimpleFilesystem storage, IChannelContext context, Stream data, string path, ContentType ct, CancellationToken cancellation)
{
return storage.WriteFileAsync($"{context.BaseDir}/{path}", data, HttpHelpers.GetContentTypeString(ct), cancellation);
}
///
/// Removes an item from a pauth scoped within the given channel context
///
///
/// The channel to scope the item into
/// The item path within the channel to delete
/// A token to cancel the operation
/// A task that completes when the deletion operation has completed
public static Task RemoveObjectAsync(this ISimpleFilesystem storage, IChannelContext context, string path, CancellationToken cancellation)
{
return storage.DeleteFileAsync($"{context.BaseDir}/{path}", cancellation);
}
///
/// Creates and loads a new with the file data from the given path
/// that resides in the given channel context
///
///
///
/// The channel context to get the file data from
/// The relative path inside the channel to load the database from
/// A token to cancel the operation
/// A task that resolves the new from file
public static Task> LoadDbAsync(this ISimpleFilesystem storage, IChannelContext context, string fileName, CancellationToken cancellation) where T : IRecord
{
return storage.LoadDbAsync($"{context.BaseDir}/{fileName}", cancellation);
}
///
/// Stores the given in the given channel context at the given file path
///
///
///
/// The channel context to write the database file inside
/// The path to the database file to overwrite
/// The database to capture the file data from
/// A token to cancel the operation
/// A task that completes when the database has been stored
public static Task StoreAsync(this ISimpleFilesystem storage, IChannelContext context, string fileName, IRecordDb store, CancellationToken cancellation)
{
return storage.StoreAsync($"{context.BaseDir}/{fileName}", store, cancellation);
}
///
/// Reads the file data from the given path that resides in the given channel context
/// and writes it to the given stream
///
///
/// The channel context to read the file from
/// The realtive path within the channel to the file
/// The stream to write the file data to from the storage layer
/// A token to cancel the operation
/// A task that resolves the number of bytes read into the output stream
public static Task ReadFileAsync(this ISimpleFilesystem storage, IChannelContext context, string fileName, Stream stream, CancellationToken cancellation)
{
return storage.ReadFileAsync($"{context.BaseDir}/{fileName}", stream, cancellation);
}
///
/// Gets the external file path for the given path that exists in the given channel context
///
///
/// The channel context that contains the item
/// The realtive path inside the channel to the item to get the path for
/// The full external path of the item
public static string GetExternalFilePath(this ISimpleFilesystem storage, IChannelContext context, string path)
{
return storage.GetExternalFilePath($"{context.BaseDir}/{path}");
}
///
/// Stores the at the given file path async
///
/// The record type
///
/// The database to store
/// The file path to store the record at
/// A token to cancel the operation
/// A task that completes when the operation has completed
public static async Task StoreAsync(this ISimpleFilesystem storage, string path, IRecordDb store, CancellationToken cancellation)
{
//Alloc ms to write records to
using VnMemoryStream ms = new();
//Write the records to the stream
store.Store(ms);
await storage.WriteFileAsync(path, ms, HttpHelpers.GetContentTypeString(ContentType.Json), cancellation);
}
///
/// Creates a new from the given object path and populates
/// it with records from the file
///
///
///
/// The path to the stored database file
/// A token to cancel the operation
/// The populated , if loading fails (file not found etc) the store will be returned empty
public static async Task> LoadDbAsync(this ISimpleFilesystem storage, string objPath, CancellationToken cancellation) where T : IRecord
{
//Create the db
IRecordDb db = JsonRecordDb.Create();
await storage.LoadDbAsync(objPath, db, cancellation);
return db;
}
///
/// Populates the given with records from the file at the given path
///
///
///
/// The path to the database file
/// The record database store ready to accept the database content
/// A token to cancel the operation
/// A task that completes when the database has been populated
public static async Task LoadDbAsync(this ISimpleFilesystem storage, string objPath, IRecordDb db, CancellationToken cancellation) where T : IRecord
{
//Mem stream to read the object into
using VnMemoryStream ms = new();
await storage.ReadFileAsync(objPath, ms, cancellation);
//Load the db from the stream
db.Load(ms);
}
}
}