using System.Text.Json; using Models; namespace Repository; public class JsonRepository : IRepository, IDisposable { private const string _appName = "Keychain"; private uint _autoIncrementedId; private readonly string _filePath; private List _cache; private bool _cacheAhead; public JsonRepository(string fileName) { string? xdgDataHome = Environment.GetEnvironmentVariable("XDG_DATA_HOME"); string dataHome; if (!string.IsNullOrEmpty(xdgDataHome)) { dataHome = Path.Combine(xdgDataHome, _appName); } else { dataHome = Path.Combine( Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local", "share"), _appName ); } _filePath = Path.Combine(dataHome, fileName); ReadAllFromFile(); var lastItem = _cache.OrderBy(item => item.ID).LastOrDefault(); _autoIncrementedId = lastItem != null ? lastItem.ID : 0; } private void ReadAllFromFile() { var items = new List(); if (File.Exists(_filePath)) { try { string json = File.ReadAllText(_filePath); items = JsonSerializer.Deserialize>(json) ?? new List(); } catch (JsonException e) { WriteToStdErr($"JSON error: {e.Message}"); } catch (IOException e) { WriteToStdErr($"File I/O error: {e.Message}"); } catch (Exception e) { WriteToStdErr($"Unexpected error: {e.Message}"); } } _cache = items; _cacheAhead = false; } public List GetAll() { return _cache; } public PasswordStore? Get(uint id) { try { return _cache.First(item => item.ID.Equals(id)); } catch (InvalidOperationException) { // Not found return null; } catch (Exception e) { WriteToStdErr($"Unexpected error: {e.Message}"); return null; } } public void Dispose() { if (_cacheAhead) { try { string json = JsonSerializer.Serialize(_cache); string? directory = Path.GetDirectoryName(_filePath); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory!); } File.WriteAllText(_filePath, json); } catch (IOException e) { WriteToStdErr($"File I/O error: {e.Message}"); } catch (Exception e) { WriteToStdErr($"Unexpected error: {e.Message}"); } ReadAllFromFile(); } } public void Edit(uint ID, PasswordStore newItem) { try { PasswordStore item = _cache.First(item => item.ID.Equals(ID)); item.DisplayName = newItem.DisplayName; item.IconName = newItem.IconName; item.Path = newItem.Path; _cacheAhead = true; } catch (InvalidOperationException) { WriteToStdErr($"Edit error: Item with ID {ID} not found."); } catch (Exception e) { WriteToStdErr($"Unexpected error: {e.Message}"); } } public void Create(PasswordStore item) { item.ID = ++_autoIncrementedId; _cache.Add(item); _cacheAhead = true; } public void Delete(PasswordStore item) { Delete(item.ID); } public void Delete(uint id) { try { var item = _cache.First(item => item.ID.Equals(id)); _cache.Remove(item); _cacheAhead = true; } catch (InvalidOperationException) { WriteToStdErr($"Delete error: Item with ID {id} not found."); } catch (Exception e) { WriteToStdErr($"Unexpected error: {e.Message}"); } } private void WriteToStdErr(string message) { using var sw = new StreamWriter(Console.OpenStandardError()); sw.WriteLine(message); } }