From 0dd597ee4ed88f2d460ae1b041208cf48fdc22eb Mon Sep 17 00:00:00 2001 From: chrisbell Date: Thu, 29 Jan 2026 15:55:25 -0600 Subject: [PATCH] Adding Async methods to verious services --- SzCore/Defaults/DefaultLocalFileManager.cs | 53 +++-- SzCore/ISzDatabaseHandler.cs | 7 +- SzCore/ISzFileManager.cs | 20 +- SzCore/SzDataHandler.cs | 252 ++++++--------------- SzCore/SzEvaluator.cs | 10 +- 5 files changed, 121 insertions(+), 221 deletions(-) diff --git a/SzCore/Defaults/DefaultLocalFileManager.cs b/SzCore/Defaults/DefaultLocalFileManager.cs index ffa103b..523f75c 100644 --- a/SzCore/Defaults/DefaultLocalFileManager.cs +++ b/SzCore/Defaults/DefaultLocalFileManager.cs @@ -13,48 +13,69 @@ public class DefaultLocalFileManager : ISzFileManager Directory.CreateDirectory(TemplatesPath); } + #region Synchronous Methods public bool SaveFile(string path, string fileContent) { try { - var dir = Path.GetDirectoryName(path); - if (dir is null) return false; - Directory.CreateDirectory(dir); - + PrepareDirectory(path); File.WriteAllText(path, fileContent); return true; } catch (Exception e) { - Console.WriteLine($"Error saving file: {e.Message}"); + SZ.Logger.LogError($"Error saving file: {e.Message}"); return false; } } public string? LoadFile(string path) { - try - { - return File.ReadAllText(path); - } - catch (Exception e) - { - Console.WriteLine($"Error loading file: {e.Message}"); - return null; - } + try { return File.ReadAllText(path); } + catch { return null; } } public bool DeleteFile(string path) + { + try { File.Delete(path); return true; } + catch { return false; } + } + #endregion + + #region Asynchronous Methods + public async Task SaveFileAsync(string path, string fileContent, CancellationToken ct = default) { try { - File.Delete(path); + PrepareDirectory(path); + // Use the native async File I/O + await File.WriteAllTextAsync(path, fileContent, ct); return true; } catch (Exception e) { - SZ.Logger.LogError("LocalFileManager: Could not delete file. " + e.Message); + SZ.Logger.LogError($"Error saving file async: {e.Message}"); return false; } } + + public async Task LoadFileAsync(string path, CancellationToken ct = default) + { + try + { + if (!File.Exists(path)) return null; + return await File.ReadAllTextAsync(path, ct); + } + catch { return null; } + } + #endregion + + private void PrepareDirectory(string filePath) + { + var dir = Path.GetDirectoryName(filePath); + if (dir != null && !Directory.Exists(dir)) + { + Directory.CreateDirectory(dir); + } + } } \ No newline at end of file diff --git a/SzCore/ISzDatabaseHandler.cs b/SzCore/ISzDatabaseHandler.cs index 7e52f70..19d5658 100644 --- a/SzCore/ISzDatabaseHandler.cs +++ b/SzCore/ISzDatabaseHandler.cs @@ -7,9 +7,6 @@ public interface ISzDatabaseHandler public bool InternetAllowed { get; set; } public Dictionary SzDbUrls { get; set; } - public Task TryRetrieveDatasetAsync(Guid uuid); - public Task TryRetrieveTemplateAsync(Guid uuid); - - public SzDataset? TryRetrieveDataset(Guid uuid); - public ISzTemplate? TryRetrieveTemplate(Guid uuid); + public Task TryRetrieveDatasetAsync(Guid uuid, CancellationToken ct = default); + public Task TryRetrieveTemplateAsync(Guid uuid, CancellationToken ct = default); } \ No newline at end of file diff --git a/SzCore/ISzFileManager.cs b/SzCore/ISzFileManager.cs index 9e631c5..6f2c5c7 100644 --- a/SzCore/ISzFileManager.cs +++ b/SzCore/ISzFileManager.cs @@ -1,15 +1,15 @@ -using System.Security.Cryptography.X509Certificates; -using SzCore.DataObjects; - namespace SzCore; public interface ISzFileManager { - public string DataPath {get;} - public string DatasetsPath {get;} - public string TemplatesPath {get;} + string DataPath { get; } + string DatasetsPath { get; } + string TemplatesPath { get; } - public bool SaveFile(string path, string fileContent); - public string? LoadFile(string path); - public bool DeleteFile(string path); -} + bool SaveFile(string path, string fileContent); + string? LoadFile(string path); + bool DeleteFile(string path); + + Task SaveFileAsync(string path, string fileContent, CancellationToken ct = default); + Task LoadFileAsync(string path, CancellationToken ct = default); +} \ No newline at end of file diff --git a/SzCore/SzDataHandler.cs b/SzCore/SzDataHandler.cs index 15bd42b..f64ee2c 100644 --- a/SzCore/SzDataHandler.cs +++ b/SzCore/SzDataHandler.cs @@ -1,14 +1,13 @@ -using System.ComponentModel.Design; using SzCore.DataObjects; namespace SzCore; public class SzDataHandler { - private Dictionary _loadedDatasets = []; - private Dictionary _loadedTemplates = []; + private readonly Dictionary _loadedDatasets = []; + private readonly Dictionary _loadedTemplates = []; - public SzDataHandler(){} + public SzDataHandler() { } private void ClearCache() { @@ -16,13 +15,14 @@ public class SzDataHandler _loadedTemplates.Clear(); } - #region Datasets - public SzResult SaveDataset(SzDataset dataset) + #region Datasets (Async) + public async Task> SaveDatasetAsync(SzDataset dataset, CancellationToken ct = default) { var datasetPath = Path.Combine(SZ.LocalFileManager.DatasetsPath, dataset.Id, "dataset.json"); try { - var success = SZ.LocalFileManager.SaveFile(datasetPath, SZ.Parser.SerializeDatasetToJson(dataset)); + var json = SZ.Parser.SerializeDatasetToJson(dataset); + var success = await SZ.LocalFileManager.SaveFileAsync(datasetPath, json, ct); return success ? SzResult.Success(true) : SzResult.Failure("Failed to write dataset file."); } catch (Exception e) @@ -32,53 +32,47 @@ public class SzDataHandler } } - public SzResult DeleteDataset(string datasetId) - { - try - { - Directory.Delete(Path.Combine(SZ.LocalFileManager.DatasetsPath, datasetId), true); - return SzResult.Success(true); - } - catch (Exception e) - { - SZ.Logger.LogError($"Could not delete Dataset with id '{datasetId}': {e.Message}"); - return SzResult.Failure(e.Message); - } - } - - public SzResult LoadDataset(string datasetId) + public async Task> LoadDatasetAsync(string datasetId, CancellationToken ct = default) { if (_loadedDatasets.TryGetValue(datasetId, out SzDataset? value)) - { return SzResult.Success(value); - } - var datasetPath = Path.Combine(SZ.LocalFileManager.DataPath, "datasets", datasetId, "dataset.json"); + var datasetPath = Path.Combine(SZ.LocalFileManager.DatasetsPath, datasetId, "dataset.json"); - var json = SZ.LocalFileManager.LoadFile(datasetPath); + var json = await SZ.LocalFileManager.LoadFileAsync(datasetPath, ct); if (json is null) - { - SZ.Logger.LogWarning($"Could not load dataset with ID '{datasetId}'"); - return SzResult.Failure($"Could not find dataset file for ID '{datasetId}'"); - } + return SzResult.Failure($"Could not find dataset file for ID '{datasetId}'"); var parsedDataset = SZ.Parser.DeserializeDataset(json); if (parsedDataset is null) - { - SZ.Logger.LogWarning($"Could not load dataset with ID '{datasetId}'"); - return SzResult.Failure($"Failed to parse dataset JSON for ID '{datasetId}'"); - } + return SzResult.Failure($"Failed to parse dataset JSON for ID '{datasetId}'"); - _loadedDatasets.Add(parsedDataset.Id, parsedDataset); + _loadedDatasets.TryAdd(parsedDataset.Id, parsedDataset); return SzResult.Success(parsedDataset); } - public SzResult CreateDataset(string name, string templateId, string? id = null, Guid? templateUuid = null) + public async Task> DeleteDatasetAsync(string datasetId) { - if (string.IsNullOrEmpty(name)) - return SzResult.Failure("Dataset name cannot be empty."); + return await Task.Run(() => { + try + { + var path = Path.Combine(SZ.LocalFileManager.DatasetsPath, datasetId); + if (Directory.Exists(path)) Directory.Delete(path, true); + _loadedDatasets.Remove(datasetId); + return SzResult.Success(true); + } + catch (Exception e) + { + return SzResult.Failure(e.Message); + } + }); + } - var templateResult = LoadTemplate(templateId); + public async Task> CreateDatasetAsync(string name, string templateId, string? id = null, Guid? templateUuid = null) + { + if (string.IsNullOrEmpty(name)) return SzResult.Failure("Name empty."); + + var templateResult = await LoadTemplateAsync(templateId); if (!templateResult.IsSuccess || templateResult.Value is null) return SzResult.Failure($"Template '{templateId}' not found."); @@ -91,76 +85,49 @@ public class SzDataHandler DataObjectType = templateResult.Value.DataObjectType, Uuid = Guid.NewGuid() }; - - return SzResult.Success(newDataset); } #endregion - #region Templates - public SzResult SaveTemplate(ISzTemplate template) + #region Templates (Async) + public async Task> SaveTemplateAsync(ISzTemplate template, CancellationToken ct = default) { var templatePath = Path.Combine(SZ.LocalFileManager.TemplatesPath, template.Id, "template.json"); try { - var success = SZ.LocalFileManager.SaveFile(templatePath, SZ.Parser.SerializeTemplateToJson(template)); + var json = SZ.Parser.SerializeTemplateToJson(template); + var success = await SZ.LocalFileManager.SaveFileAsync(templatePath, json, ct); return success ? SzResult.Success(true) : SzResult.Failure("Failed to write template file."); } catch (Exception e) { - SZ.Logger.LogError("Error saving template: " + e.Message); return SzResult.Failure(e.Message); } } - public SzResult DeleteTemplate(string templateId) - { - try - { - Directory.Delete(Path.Combine(SZ.LocalFileManager.TemplatesPath, templateId), true); - return SzResult.Success(true); - } - catch (Exception e) - { - SZ.Logger.LogError($"Could not delete Template with id '{templateId}': {e.Message}"); - return SzResult.Failure(e.Message); - } - } - - public SzResult LoadTemplate(string templateId) where T : ISzTemplate + public async Task> LoadTemplateAsync(string templateId, CancellationToken ct = default) where T : ISzTemplate { if (_loadedTemplates.TryGetValue(templateId, out ISzTemplate? cachedTemplate)) - { return SzResult.Success((T)cachedTemplate); - } - var templatePah = Path.Combine(SZ.LocalFileManager.TemplatesPath, templateId, "template.json"); + var path = Path.Combine(SZ.LocalFileManager.TemplatesPath, templateId, "template.json"); + var json = await SZ.LocalFileManager.LoadFileAsync(path, ct); - var json = SZ.LocalFileManager.LoadFile(templatePah); - if (json is null) - { - SZ.Logger.LogWarning($"Could not load template with ID '{templateId}'"); - return SzResult.Failure($"Could not find template file for ID '{templateId}'"); - } + if (json is null) return SzResult.Failure($"Template '{templateId}' not found."); - var parsedTemplate = SZ.Parser.DeserializeTemplate(json); - if (parsedTemplate is null) - { - SZ.Logger.LogWarning($"Could not load template with ID '{templateId}'"); - return SzResult.Failure($"Failed to parse template JSON for ID '{templateId}'"); - } + var parsed = SZ.Parser.DeserializeTemplate(json); + if (parsed is null) return SzResult.Failure("Parse error."); - _loadedTemplates.TryAdd(parsedTemplate.Id, parsedTemplate); - - return SzResult.Success(parsedTemplate); + _loadedTemplates.TryAdd(parsed.Id, parsed); + return SzResult.Success(parsed); } + #endregion + #region Synchronous Logic + // These remain synchronous because they are purely in-memory operations. public SzResult CreateDataObjectTemplate(string name, string dataObjectType, string? id = null, string? description = null, List? fields = null) { - if (string.IsNullOrEmpty(name)) return SzResult.Failure("Name cannot be empty."); - if (string.IsNullOrEmpty(dataObjectType)) return SzResult.Failure("DataObjectType cannot be empty."); - var newTemplate = new SzDataObjectTemplate() { Name = name, @@ -170,48 +137,27 @@ public class SzDataHandler Description = description ?? "" }; - if (fields is null) return SzResult.Success(newTemplate); - foreach (var field in fields) + if (fields != null) { - newTemplate.TemplateFields.Add(field.Id, field); + foreach (var field in fields) newTemplate.TemplateFields.TryAdd(field.Id, field); } return SzResult.Success(newTemplate); } - #endregion - #region Other - public SzResult CreateTemplateField(string id, SzFieldType fieldType, bool isList = false, string? defaultValue = null, bool isSpecialType = false, string? specialTypeValue = null) + public SzResult CreateDataObject(SzDataObjectTemplate template, string name, string? id = null) { - if (string.IsNullOrEmpty(id)) return SzResult.Failure("ID cannot be empty."); - - var newField = new SzTemplateField() + var dataObject = new SzDataObject() { - Id = id, - FieldType = fieldType, - IsList = isList, - IsSpecialType = isSpecialType, - DefaultValue = defaultValue ?? "", - SpecialTypeValue = specialTypeValue ?? "" + Name = name, + Id = id ?? name.ToLower().Replace(" ", "-").Trim() }; - return SzResult.Success(newField); - } - - public SzResult CreateField(string id, SzFieldType fieldType, bool isList = false, string? value = null) - { - if (string.IsNullOrEmpty(id)) - return SzResult.Failure("Could not create field, the id parameter was empty"); + var fieldsResult = CreateFieldsFromTemplate(template); + if (!fieldsResult.IsSuccess) return SzResult.Failure(fieldsResult.Error); - var newField = new SzField() - { - Id = id, - FieldType = fieldType, - IsList = isList, - Value = value ?? "" - }; - - return SzResult.Success(newField); + dataObject.Fields = fieldsResult.Value!; + return SzResult.Success(dataObject); } public SzResult> CreateFieldsFromTemplate(ISzTemplate template) @@ -219,87 +165,23 @@ public class SzDataHandler var fields = new Dictionary(); foreach (var tempField in template.TemplateFields.Values) { - var newField = CreateField(tempField.Id, tempField.FieldType, tempField.IsList); - if (!newField.IsSuccess || newField.Value is null) - return SzResult>.Failure($"Could not create field: {newField.Error}"); - fields.Add(newField.Value.Id, newField.Value); + fields.Add(tempField.Id, new SzField { Id = tempField.Id, FieldType = tempField.FieldType, IsList = tempField.IsList }); } - return SzResult>.Success(fields); } - - public SzResult CreateDataObject(SzDataObjectTemplate template, string name, string? id = null) - { - if (string.IsNullOrEmpty(name)) - return SzResult.Failure("Could not create object, name was empty"); - - var dataObject = new SzDataObject() - { - Name = name, - Id = id ?? name.ToLower().Replace(" ", "-").Trim() - }; - - var createFieldsResult = CreateFieldsFromTemplate(template); - if (!createFieldsResult.IsSuccess || createFieldsResult.Value is null) - return SzResult.Failure($"Could not create data object's fields: {createFieldsResult.Error}"); - dataObject.Fields = createFieldsResult.Value; - - return SzResult.Success(dataObject); - } #endregion - #region Tests - private void LoadAllDatasets() + #region Bulk Operations + public async Task LoadAllDatasetsAsync(CancellationToken ct = default) { _loadedDatasets.Clear(); - if (!Directory.Exists(SZ.LocalFileManager.DatasetsPath)) + if (!Directory.Exists(SZ.LocalFileManager.DatasetsPath)) return; + + var dirs = Directory.GetDirectories(SZ.LocalFileManager.DatasetsPath); + foreach (var dir in dirs) { - throw new Exception("Could not load datasets, the dataset directory does not exist."); - } - - foreach (var dir in Directory.GetDirectories(SZ.LocalFileManager.DatasetsPath)) - { - var datasetFilePath = Path.Combine(dir, "dataset.json"); - if (!File.Exists(datasetFilePath)) continue; - - var datasetJson = SZ.LocalFileManager.LoadFile(datasetFilePath); - if (datasetJson == null) continue; - - var parsedDataset = SZ.Parser.DeserializeDataset(datasetJson); - if (parsedDataset == null) - { - SZ.Logger.LogWarning($"Parse error: Could not parse file {datasetFilePath} as an SzDataset"); - continue; - } - - _loadedDatasets.Add(parsedDataset.Id, parsedDataset); - } - } - - private void LoadAllTemplates() - { - _loadedTemplates.Clear(); - if (!Directory.Exists(SZ.LocalFileManager.TemplatesPath)) - { - throw new Exception("Could not load templates, the template directory does not exist."); - } - - foreach (var dir in Directory.GetDirectories(SZ.LocalFileManager.TemplatesPath)) - { - var templateFilePath = Path.Combine(dir, "template.json"); - if (!File.Exists(templateFilePath)) continue; - - var templateJson = SZ.LocalFileManager.LoadFile(templateFilePath); - if (templateJson == null) continue; - - var parsedTemplate = SZ.Parser.DeserializeTemplate(templateJson); - if (parsedTemplate == null) - { - SZ.Logger.LogWarning($"Parse error: Could not parse file {templateFilePath} as an ISzTemplate"); - continue; - } - - _loadedTemplates.Add(parsedTemplate.Id, parsedTemplate); + var id = Path.GetFileName(dir); + await LoadDatasetAsync(id, ct); } } #endregion diff --git a/SzCore/SzEvaluator.cs b/SzCore/SzEvaluator.cs index b18cd69..7493e2b 100644 --- a/SzCore/SzEvaluator.cs +++ b/SzCore/SzEvaluator.cs @@ -6,17 +6,17 @@ namespace SzCore; public class SzEvaluator { - - public SzResult EvaluateDataset(SzDataset dataset) + public async Task> EvaluateDatasetAsync(SzDataset dataset, CancellationToken ct = default) { var errors = new StringBuilder(); - var template = SZ.DataHandler.LoadTemplate(dataset.DataObjectTemplateId); - if (!template.IsSuccess || template.Value is null) return SzResult.Failure($"Template with id {dataset.DataObjectTemplateId} for Dataset ID {dataset.Id} could not be loaded"); + var templateResult = await SZ.DataHandler.LoadTemplateAsync(dataset.DataObjectTemplateId, ct); + if (!templateResult.IsSuccess || templateResult.Value is null) + return SzResult.Failure($"Template with id {dataset.DataObjectTemplateId} for Dataset ID {dataset.Id} could not be loaded: {templateResult.Error}"); foreach (var dataObject in dataset.DataObjects.Values) { - var evalResult = EvaluateDataObject(dataObject, template.Value); + var evalResult = EvaluateDataObject(dataObject, templateResult.Value); if (!evalResult.IsSuccess) errors.Append(evalResult.Error); }