/* * 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); } } }