using Disco.Plugins.ServiceTracker.Models; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace Disco.Plugins.ServiceTracker.Services { /// /// JSON file-based data store for ServiceTracker metadata. /// Stores ticket extensions and configuration in the plugin data directory. /// public class ServiceTrackerDataStore { private readonly string _dataDirectory; private readonly string _ticketsPath; private readonly string _configPath; private static readonly object _lock = new object(); public ServiceTrackerDataStore(string pluginDataDirectory) { _dataDirectory = pluginDataDirectory; _ticketsPath = Path.Combine(_dataDirectory, "tickets.json"); _configPath = Path.Combine(_dataDirectory, "config.json"); if (!Directory.Exists(_dataDirectory)) Directory.CreateDirectory(_dataDirectory); } // --- Configuration --- public ServiceTrackerConfig LoadConfig() { lock (_lock) { if (!File.Exists(_configPath)) { var defaultConfig = ServiceTrackerConfig.CreateDefault(); SaveConfig(defaultConfig); return defaultConfig; } var json = File.ReadAllText(_configPath); return JsonConvert.DeserializeObject(json) ?? ServiceTrackerConfig.CreateDefault(); } } public void SaveConfig(ServiceTrackerConfig config) { lock (_lock) { var json = JsonConvert.SerializeObject(config, Formatting.Indented); File.WriteAllText(_configPath, json); } } // --- Tickets --- public List LoadAllTickets() { lock (_lock) { if (!File.Exists(_ticketsPath)) return new List(); var json = File.ReadAllText(_ticketsPath); return JsonConvert.DeserializeObject>(json) ?? new List(); } } public ServiceTicket GetTicket(int jobId) { return LoadAllTickets().FirstOrDefault(t => t.JobId == jobId); } public void SaveTicket(ServiceTicket ticket) { lock (_lock) { var tickets = LoadAllTicketsUnsafe(); var existing = tickets.FindIndex(t => t.JobId == ticket.JobId); ticket.LastModifiedDate = DateTime.Now; if (existing >= 0) tickets[existing] = ticket; else tickets.Add(ticket); SaveAllTicketsUnsafe(tickets); } } public void DeleteTicket(int jobId) { lock (_lock) { var tickets = LoadAllTicketsUnsafe(); tickets.RemoveAll(t => t.JobId == jobId); SaveAllTicketsUnsafe(tickets); } } public void AddNote(int jobId, TicketNote note) { lock (_lock) { var tickets = LoadAllTicketsUnsafe(); var ticket = tickets.FirstOrDefault(t => t.JobId == jobId); if (ticket != null) { if (ticket.Notes == null) ticket.Notes = new List(); ticket.Notes.Add(note); ticket.LastModifiedDate = DateTime.Now; SaveAllTicketsUnsafe(tickets); } } } // Internal methods (caller must hold lock) private List LoadAllTicketsUnsafe() { if (!File.Exists(_ticketsPath)) return new List(); var json = File.ReadAllText(_ticketsPath); return JsonConvert.DeserializeObject>(json) ?? new List(); } private void SaveAllTicketsUnsafe(List tickets) { var json = JsonConvert.SerializeObject(tickets, Formatting.Indented); File.WriteAllText(_ticketsPath, json); } } }