using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using GameServiceWarden.Core.Module; using GameServiceWarden.ModuleFramework; using System.Collections.ObjectModel; namespace GameServiceWarden.Core.Persistence { public class ServiceDescriptorPersistence : IPersistent> { private readonly string mapDirectory; private const string EXTENSION = ".sin"; public ServiceDescriptorPersistence(string mapDirectory) { this.mapDirectory = mapDirectory; } public IReadOnlyDictionary this[string key] { set { SaveService(key, value[ServiceDescriptor.ASSEMBLY_PROPERTY], value[ServiceDescriptor.MODULE_PROPERTY]); } get { if (!ContainsKey(key)) throw new KeyNotFoundException(); Dictionary info = new Dictionary(); info[ServiceDescriptor.ASSEMBLY_PROPERTY] = GetServiceInfoValue(key, ServiceDescriptor.ASSEMBLY_PROPERTY); info[ServiceDescriptor.MODULE_PROPERTY] = GetServiceInfoValue(key, ServiceDescriptor.MODULE_PROPERTY); return new ReadOnlyDictionary(info); } } public string MapDirectory { get { return mapDirectory; } } public int Count { get { return Directory.GetFiles(mapDirectory).Length; } } public IEnumerable> Values { get { IEnumerable keys = Keys; List> res = new List>(); foreach (string key in keys) { res.Add(this[key]); } return res; } } public IEnumerable Keys { get { IEnumerable keys = Directory.EnumerateDirectories(mapDirectory); List res = new List(); foreach (string key in keys) { res.Add(Path.GetDirectoryName(key)); } return res; } } public void AddToPersistence(string key, IReadOnlyDictionary value) { if (key == null) throw new ArgumentNullException(); if (ContainsKey(key)) throw new ArgumentException(); this[key] = value; } public void Clear() { IEnumerable directories = Keys; foreach (string directory in directories) { Directory.Delete(directory); } } public bool ContainsKey(string key) { return Directory.Exists(GetPathForKey(key)); } public IEnumerator>> GetEnumerator() { IEnumerable keys = Keys; List>> result = new List>>(); foreach (string key in keys) { result.Add(new KeyValuePair>(key, this[key])); } return result.GetEnumerator(); } public string GetPathForKey(string key) { return Path.Combine(mapDirectory, key); } public bool Delete(string key) { if (!ContainsKey(key)) return false; try { Directory.Delete(GetPathForKey(key)); } catch (System.Exception) { return false; throw; } return true; } public bool TryLoadValue(string key, [MaybeNullWhen(false)] out IReadOnlyDictionary value) { try { value = this[key]; } catch (KeyNotFoundException) { value = null; return false; } return true; } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public void SaveService(string key, string assemblyName, string moduleName) { if (key == null) throw new ArgumentNullException("key"); if (assemblyName == null) throw new ArgumentNullException("assemblyName"); if (moduleName == null) throw new ArgumentNullException("moduleName"); string serviceInfoPath = GetPathForKey(key); Directory.CreateDirectory(serviceInfoPath); using (StreamWriter writer = File.CreateText(Path.Combine(serviceInfoPath, key + EXTENSION))) { writer.WriteLine($"{ServiceDescriptor.ASSEMBLY_PROPERTY}: {assemblyName}"); writer.WriteLine($"{ServiceDescriptor.MODULE_PROPERTY}: {moduleName}"); } } private string GetServiceInfoValue(string key, string value) { string path = GetPathForKey(key); IEnumerable lines = File.ReadAllLines(Path.Combine(path, key + EXTENSION)); foreach (string line in lines) { if (line.StartsWith($"{value}: ")) { return line.Substring(value.Length + 2); } } throw new FormatException($"\"{path}\" is corrupted. Could not find value for: {value}."); } } }