diff --git a/src/GameServiceWarden.Core/Games/GameServiceAction.cs b/src/GameServiceWarden.Core/Games/GameServiceAction.cs new file mode 100644 index 0000000..d5b507a --- /dev/null +++ b/src/GameServiceWarden.Core/Games/GameServiceAction.cs @@ -0,0 +1,13 @@ +using GameServiceWarden.ModuleAPI; + +namespace GameServiceWarden.Core.Games +{ + public struct ServiceAction + { + public string AssemblyName { get; set; } + public string ModuleName { get; set; } + public string ServiceName { get; set; } + public IGameServiceModule Module { get; set; } + public GameServiceActions Action { get; set; } + } +} \ No newline at end of file diff --git a/src/GameServiceWarden.Core/Games/GameServiceActions.cs b/src/GameServiceWarden.Core/Games/GameServiceActions.cs new file mode 100644 index 0000000..5885a7d --- /dev/null +++ b/src/GameServiceWarden.Core/Games/GameServiceActions.cs @@ -0,0 +1,16 @@ +namespace GameServiceWarden.Core.Games +{ + public enum GameServiceActions + { + + Start, + Stop, + AddModule, + RemoveModule, + CreateService, + DeleteService, + ExecuteCommand, + SetServiceOption, + View + } +} \ No newline at end of file diff --git a/src/GameServiceWarden.Core/Games/GameServiceInfo.cs b/src/GameServiceWarden.Core/Games/GameServiceInfo.cs index 1bde81b..d711944 100644 --- a/src/GameServiceWarden.Core/Games/GameServiceInfo.cs +++ b/src/GameServiceWarden.Core/Games/GameServiceInfo.cs @@ -4,7 +4,6 @@ using System.Collections.ObjectModel; using System.Globalization; using System.IO; using System.Threading; -using GameServiceWarden.Core.Preferences; using GameServiceWarden.ModuleAPI; namespace GameServiceWarden.Core.Games diff --git a/src/GameServiceWarden.Core/Games/GameServiceManager.cs b/src/GameServiceWarden.Core/Games/GameServiceManager.cs index 4819061..8feb7e5 100644 --- a/src/GameServiceWarden.Core/Games/GameServiceManager.cs +++ b/src/GameServiceWarden.Core/Games/GameServiceManager.cs @@ -1,50 +1,29 @@ using System; using System.Collections.Generic; using System.IO; +using GameServiceWarden.Core.Persistence; using GameServiceWarden.ModuleAPI; namespace GameServiceWarden.Core.Games { public class GameServiceManager { - private readonly Dictionary services = new Dictionary(); - private readonly Dictionary> modules = new Dictionary>(); + private readonly IPersistentDictionary services; + private readonly IReadOnlyPersistentDictionary modules; - public void AddModule(string assemblyName, IGameServiceModule module) + public GameServiceManager(IPersistentDictionary services, IReadOnlyPersistentDictionary modules) { - if (!modules.ContainsKey(assemblyName)) modules.Add(assemblyName, new Dictionary()); - modules[assemblyName][module.Name] = module; - } - - public void RemoveModule(string assemblyName, string moduleName) - { - if (!modules.ContainsKey(assemblyName) || !modules[assemblyName].ContainsKey(moduleName)) throw new KeyNotFoundException($"No module registered from {assemblyName} named {moduleName}."); - modules[assemblyName].Remove(moduleName); - if (modules[assemblyName].Count == 0) modules.Remove(assemblyName); - } - - public IReadOnlyCollection GetAssemblyNames() - { - string[] names = new string[modules.Count]; - modules.Keys.CopyTo(names, 0); - return names; - } - - public IReadOnlyCollection GetModuleNames(string assembly) - { - if (!modules.ContainsKey(assembly)) throw new KeyNotFoundException($"No loaded assembly named \"{assembly}\"."); - string[] names = new string[modules.Count]; - modules[assembly].Keys.CopyTo(names, 0); - return names; - + this.services = services; + this.modules = modules; } public void CreateService(string serviceName, string assemblyName, string moduleName) { - if (!modules.ContainsKey(assemblyName) || !modules[assemblyName].ContainsKey(moduleName)) throw new KeyNotFoundException($"No module registered from \"{assemblyName}\" named \"{moduleName}\"."); + string moduleID = ToModuleID(assemblyName, moduleName); + if (!modules.ContainsKey(moduleID)) throw new KeyNotFoundException($"No module registered from \"{assemblyName}\" named \"{moduleName}\"."); if (services.ContainsKey(serviceName)) throw new ArgumentException($"Service of Name \"{serviceName}\" already exists."); - services.Add(serviceName, new GameServiceInfo(modules[assemblyName][moduleName].CreateGameService(), moduleName, assemblyName)); + services.Add(serviceName, new GameServiceInfo(modules[moduleID].InstantiateGameService(services.GetPathForKey(serviceName), true), moduleName, assemblyName)); } public void DeleteService(string serviceName) @@ -54,6 +33,11 @@ namespace GameServiceWarden.Core.Games services.Remove(serviceName); } + public IEnumerable GetModuleNames() + { + return modules.Keys; + } + public IReadOnlyCollection GetServiceNames() { string[] names = new string[services.Count]; @@ -68,13 +52,6 @@ namespace GameServiceWarden.Core.Games return serviceInfo.GetConfigurableOptions(); } - public bool SetServiceOptionValue(string serviceName, string optionName, string value) - { - if (!services.ContainsKey(serviceName)) throw new KeyNotFoundException($"Service under name \"{serviceName}\" not found."); - if (!services[serviceName].GetConfigurableOptions().Contains(optionName)) throw new KeyNotFoundException($"Option \"{optionName}\" for service \"{serviceName}\" not found."); - return services[serviceName].SetConfigurableValue(optionName, value); - } - public string GetServiceOptionValue(string serviceName, string optionName) { if (!services.ContainsKey(serviceName)) throw new KeyNotFoundException($"Service under name \"{serviceName}\" not found."); @@ -82,6 +59,13 @@ namespace GameServiceWarden.Core.Games return services[serviceName].GetConfigurableValue(optionName); } + public bool SetServiceOptionValue(string serviceName, string optionName, string value) + { + if (!services.ContainsKey(serviceName)) throw new KeyNotFoundException($"Service under name \"{serviceName}\" not found."); + if (!services[serviceName].GetConfigurableOptions().Contains(optionName)) throw new KeyNotFoundException($"Option \"{optionName}\" for service \"{serviceName}\" not found."); + return services[serviceName].SetConfigurableValue(optionName, value); + } + public ServiceState GetServiceState(string serviceName) { if (!services.ContainsKey(serviceName)) throw new KeyNotFoundException($"Service under name \"{serviceName}\" not found."); @@ -111,5 +95,10 @@ namespace GameServiceWarden.Core.Games if (!services.ContainsKey(serviceName)) throw new KeyNotFoundException($"Service under name \"{serviceName}\" not found."); return services[serviceName].ServiceConsoleStream; } + + private string ToModuleID(string assemblyName, string moduleName) + { + return assemblyName + Path.DirectorySeparatorChar + moduleName; + } } } \ No newline at end of file diff --git a/src/GameServiceWarden.Core/Games/IGameServiceActionExecuter.cs b/src/GameServiceWarden.Core/Games/IGameServiceActionExecuter.cs new file mode 100644 index 0000000..f74d27a --- /dev/null +++ b/src/GameServiceWarden.Core/Games/IGameServiceActionExecuter.cs @@ -0,0 +1,7 @@ +namespace GameServiceWarden.Core.Games +{ + public interface IGameServiceExecutioner + { + void ExecuteAction(ServiceAction action); + } +} \ No newline at end of file diff --git a/src/GameServiceWarden.Core/Persistence/GeneralPersistentDictionary.cs b/src/GameServiceWarden.Core/Persistence/GeneralPersistentDictionary.cs new file mode 100644 index 0000000..08cf87a --- /dev/null +++ b/src/GameServiceWarden.Core/Persistence/GeneralPersistentDictionary.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +namespace GameServiceWarden.Core.Persistence +{ + public class GeneralPersistentDictionary : IPersistentDictionary, ICollection> + { + private readonly string mapDirectory; + private readonly IPersistentDictionaryWriter writer; + private readonly IPersistentDictionaryReader reader; + private readonly GeneralReadOnlyPersistentDictionary readDictionary; + + public GeneralPersistentDictionary(string mapDirectory, IPersistentDictionaryReader reader, IPersistentDictionaryWriter writer) + { + this.mapDirectory = mapDirectory ?? throw new ArgumentNullException("mapDirectory"); + this.reader = reader ?? throw new ArgumentNullException("reader"); + this.readDictionary = new GeneralReadOnlyPersistentDictionary(this.mapDirectory, reader); + this.writer = writer ?? throw new ArgumentNullException("writer"); + } + + public V this[string key] { get { return readDictionary[key]; } set { writer.Write(GetPathForKey(key), value); } } + + public ICollection Keys + { + get + { + IEnumerable keys = Directory.EnumerateFileSystemEntries(mapDirectory); + List res = new List(); + foreach (string key in keys) + { + if (reader.IsValidValue(GetPathForKey(key))) res.Add(key); + } + return res; + } + } + + public ICollection Values + { + get + { + IEnumerable keys = Keys; + List res = new List(); + foreach (string key in keys) + { + res.Add(reader.Read(GetPathForKey(key))); + } + return res; + } + } + + public int Count {get { return readDictionary.Count; } } + + public bool IsReadOnly {get { return false; } } + + public string MapDirectory { get { return mapDirectory; } } + + public void Add(string key, V value) + { + string path = GetPathForKey(key); + if (key == null) throw new ArgumentNullException("key"); + if (File.Exists(path) || Directory.Exists(path)) + { + if (reader.IsValidValue(path)) throw new ArgumentException($"Key \"{key}\" already exists."); + throw new ArgumentException($"Corrupt item at \"{path}\" associated with key \"{key}\"."); + } + writer.Write(GetPathForKey(key), value); + } + + void ICollection>.Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + + public void Clear() + { + IEnumerable keys = Keys; + foreach (string key in keys) + { + string path = GetPathForKey(key); + if (File.Exists(path)) + { + File.Delete(path); + } + else + { + Directory.Delete(path); + } + } + } + + bool ICollection>.Contains(KeyValuePair item) + { + string path = GetPathForKey(item.Key); + return ContainsKey(item.Key) && readDictionary[item.Key].Equals(item.Value); + } + + public bool ContainsKey(string key) + { + return readDictionary.ContainsKey(key); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + if (array == null) throw new ArgumentNullException("array"); + if (arrayIndex < 0) throw new ArgumentOutOfRangeException("arrayIndex"); + if (array.Length - arrayIndex < Count) throw new ArgumentException($"The number of elements in this dictionary ({Count}) is greater than the space from arrayIndex to the end of the array ({array.Length - arrayIndex})."); + IEnumerator> pairs = GetEnumerator(); + for (int i = arrayIndex; i < array.Length; i++) + { + if (!pairs.MoveNext()) return; + array[i] = pairs.Current; + } + } + + public IEnumerator> GetEnumerator() + { + return ((IEnumerable>) readDictionary).GetEnumerator(); + } + + public bool Remove(string key) + { + if (key == null) throw new ArgumentNullException("key"); + + if (!ContainsKey(key)) return false; + string path = GetPathForKey(key); + if (Directory.Exists(path)) + { + Directory.Delete(path); + return true; + } + File.Delete(path); + return true; + } + + public bool Remove(KeyValuePair item) + { + return Remove(item.Key); + } + + public bool TryGetValue(string key, [MaybeNullWhen(false)] out V value) + { + return readDictionary.TryGetValue(key, out value); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable) readDictionary).GetEnumerator(); + } + + public string GetPathForKey(string key) + { + return mapDirectory + Path.DirectorySeparatorChar + key; + } + } +} \ No newline at end of file diff --git a/src/GameServiceWarden.Core/Persistence/GeneralReadOnlyPersistentDictionary.cs b/src/GameServiceWarden.Core/Persistence/GeneralReadOnlyPersistentDictionary.cs new file mode 100644 index 0000000..0fe957f --- /dev/null +++ b/src/GameServiceWarden.Core/Persistence/GeneralReadOnlyPersistentDictionary.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +namespace GameServiceWarden.Core.Persistence +{ + public class GeneralReadOnlyPersistentDictionary : IReadOnlyPersistentDictionary, IReadOnlyCollection> + { + private readonly string mapDirectory; + public string MapDirectory { get { return mapDirectory; } } + private IPersistentDictionaryReader reader; + + public GeneralReadOnlyPersistentDictionary(string mapDirectory, IPersistentDictionaryReader reader) + { + this.mapDirectory = mapDirectory; + this.reader = reader; + } + + public V this[string key] + { + get + { + return reader.Read(GetPathForKey(key)); + } + } + + public IEnumerable Keys + { + get + { + IEnumerable keys = Directory.EnumerateFileSystemEntries(mapDirectory); + foreach (string key in keys) + { + string path = GetPathForKey(key); + if ((File.Exists(path) || Directory.Exists(path)) && reader.IsValidValue(path)) yield return key; + } + } + } + + public IEnumerable Values + { + get + { + IEnumerable keys = Directory.EnumerateFileSystemEntries(mapDirectory); + foreach (string key in keys) + { + yield return reader.Read(GetPathForKey(key)); + } + } + } + + public int Count + { + get + { + int count = 0; + IEnumerable keys = Directory.EnumerateFileSystemEntries(mapDirectory); + foreach (string key in keys) + { + string path = GetPathForKey(key); + if ((File.Exists(path) || Directory.Exists(path)) && reader.IsValidValue(path)) count++; + } + return count; + } + } + + public bool ContainsKey(string key) + { + if (key == null) throw new ArgumentNullException(key); + string path = GetPathForKey(key); + return (File.Exists(path) || Directory.Exists(path)) && reader.IsValidValue(path); + } + + public IEnumerator> GetEnumerator() + { + IEnumerable keys = Keys; + List> pairs = new List>(); + foreach (string key in keys) + { + pairs.Add(new KeyValuePair(key, this[key])); + } + return pairs.GetEnumerator(); + } + + public bool TryGetValue(string key, [MaybeNullWhen(false)] out V value) + { + string path = GetPathForKey(key); + if (!File.Exists(path) || !Directory.Exists(path) || !reader.IsValidValue(path)) + { + value = default(V); + return false; + } + value = reader.Read(path); + return true; + } + + public string GetPathForKey(string key) + { + return mapDirectory + Path.DirectorySeparatorChar + key; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/src/GameServiceWarden.Core/Persistence/IPersistentDictionary.cs b/src/GameServiceWarden.Core/Persistence/IPersistentDictionary.cs new file mode 100644 index 0000000..f8f449f --- /dev/null +++ b/src/GameServiceWarden.Core/Persistence/IPersistentDictionary.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace GameServiceWarden.Core.Persistence +{ + public interface IPersistentDictionary : IDictionary + { + string MapDirectory { get; } + string GetPathForKey(string key); + } +} \ No newline at end of file diff --git a/src/GameServiceWarden.Core/Persistence/IPersistentDictionaryReader.cs b/src/GameServiceWarden.Core/Persistence/IPersistentDictionaryReader.cs new file mode 100644 index 0000000..5a33eff --- /dev/null +++ b/src/GameServiceWarden.Core/Persistence/IPersistentDictionaryReader.cs @@ -0,0 +1,8 @@ +namespace GameServiceWarden.Core.Persistence +{ + public interface IPersistentDictionaryReader + { + V Read(string path); + bool IsValidValue(string path); + } +} \ No newline at end of file diff --git a/src/GameServiceWarden.Core/Persistence/IPersistentDictionaryWriter.cs b/src/GameServiceWarden.Core/Persistence/IPersistentDictionaryWriter.cs new file mode 100644 index 0000000..b652510 --- /dev/null +++ b/src/GameServiceWarden.Core/Persistence/IPersistentDictionaryWriter.cs @@ -0,0 +1,7 @@ +namespace GameServiceWarden.Core.Persistence +{ + public interface IPersistentDictionaryWriter + { + void Write(string path, V value); + } +} \ No newline at end of file diff --git a/src/GameServiceWarden.Core/Persistence/IReadOnlyPersistentDictionary.cs b/src/GameServiceWarden.Core/Persistence/IReadOnlyPersistentDictionary.cs new file mode 100644 index 0000000..755d57f --- /dev/null +++ b/src/GameServiceWarden.Core/Persistence/IReadOnlyPersistentDictionary.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace GameServiceWarden.Core.Persistence +{ + public interface IReadOnlyPersistentDictionary : IReadOnlyDictionary + { + string MapDirectory { get; } + string GetPathForKey(string key); + } +} \ No newline at end of file diff --git a/src/GameServiceWarden.Core/Preferences/GeneralPreferences.cs b/src/GameServiceWarden.Core/Preferences/GeneralPreferences.cs deleted file mode 100644 index 051ea96..0000000 --- a/src/GameServiceWarden.Core/Preferences/GeneralPreferences.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.IO; -using System.Net; -using System.Reflection; -using System.Xml.Serialization; - -namespace GameServiceWarden.Core.Preferences -{ - [Serializable] - public class GeneralPreferences : IPersistable - { - //XML serialization invariants. - private readonly XmlSerializer xmlSerializer; - private readonly string APP_DATA_DIR; - - //Preferences stored. - public int Port = 8080; - public string ListeningIP = IPAddress.Any.ToString(); - public string ModuleDataPath; - - public GeneralPreferences() - { - APP_DATA_DIR = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "/" + Assembly.GetAssembly(GetType()).GetName().Name + "/"; - xmlSerializer = new XmlSerializer(GetType()); - - this.ModuleDataPath = APP_DATA_DIR + "modules/"; - Load(); - } - - public void Save() - { - using (FileStream writer = new FileStream(APP_DATA_DIR + GetType().Name + ".xml", FileMode.OpenOrCreate)) - { - xmlSerializer.Serialize(writer, this); - } - } - - public void Load() - { - using (FileStream reader = new FileStream(APP_DATA_DIR + GetType().Name + ".xml", FileMode.Open)) - { - xmlSerializer.Deserialize(reader); - } - } - } -} \ No newline at end of file diff --git a/src/GameServiceWarden.Core/Preferences/IPersistable.cs b/src/GameServiceWarden.Core/Preferences/IPersistable.cs deleted file mode 100644 index 0e660c5..0000000 --- a/src/GameServiceWarden.Core/Preferences/IPersistable.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace GameServiceWarden.Core.Preferences -{ - public interface IPersistable - { - public void Save(); - public void Load(); - } -} \ No newline at end of file diff --git a/src/GameServiceWarden.Core/UI/ConsoleView.cs b/src/GameServiceWarden.Core/UI/ConsoleView.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/GameServiceWarden.Core/UI/ITextCommand.cs b/src/GameServiceWarden.Core/UI/ITextCommand.cs new file mode 100644 index 0000000..9a0f3a8 --- /dev/null +++ b/src/GameServiceWarden.Core/UI/ITextCommand.cs @@ -0,0 +1,10 @@ +namespace GameServiceWarden.Core.UI +{ + public interface ITextCommand + { + string Prefix { get; } + string Help{ get; } + bool Validate(string input); + void Execute(string input); + } +} \ No newline at end of file diff --git a/src/GameServiceWarden.Core/UMLSketch.drawio b/src/GameServiceWarden.Core/UMLSketch.drawio index 239b4ba..4f72cc5 100644 --- a/src/GameServiceWarden.Core/UMLSketch.drawio +++ b/src/GameServiceWarden.Core/UMLSketch.drawio @@ -1,26 +1,28 @@ - + - + - + + + - + - + - + - + @@ -41,42 +43,18 @@ - + - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -108,7 +86,7 @@ - + @@ -125,32 +103,32 @@ - - + + - - + + - + - + - + - - + + - + @@ -177,7 +155,7 @@ - + @@ -219,360 +197,360 @@ - + - - + + - + - - - + + + - + - + - - - + + + - + - + - + - + - - - + + + - + - - - + + + - + - + - + - + - + - + - + - - - + + + - + - - - + + + - + - + - + - + - - - + + + - + - - - + + + - + - - - + + + - + - + - + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - + - + - + - + - + - + - + - + - + - + - + - - - + + + - + - - - + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - + + + - + - - - + + + - + - + - + - + - + - + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - + - + - + - + - + - + - - - + + + - + - + - + - + - - - + + + - + - + - + - + - + - + - + - - - + + + - + - + - + - + - + - + - + - - - + + + - + - - - + + + - + - - - + + + - + - + - + - + - + - + - + - + - + - + \ No newline at end of file diff --git a/src/GameServiceWarden.ModuleAPI/IGameServiceModule.cs b/src/GameServiceWarden.ModuleAPI/IGameServiceModule.cs index 05052d8..accb628 100644 --- a/src/GameServiceWarden.ModuleAPI/IGameServiceModule.cs +++ b/src/GameServiceWarden.ModuleAPI/IGameServiceModule.cs @@ -22,7 +22,9 @@ namespace GameServiceWarden.ModuleAPI /// /// Creates an instance of a the service to be used. /// + /// The workspace directory. All service required files should be stored here. Expect the directory to be created. + /// Whether or not this game service is new. That is, the workspace can be assumed empty. /// The responsible for the instance of the game service. - IGameService CreateGameService(); + IGameService InstantiateGameService(string workspace, bool clean); } } \ No newline at end of file diff --git a/tests/GameServiceWarden.Core.Tests/Modules/Games/FakeGameServiceModule.cs b/tests/GameServiceWarden.Core.Tests/Modules/Games/FakeGameServiceModule.cs index 689f9b2..c67a773 100644 --- a/tests/GameServiceWarden.Core.Tests/Modules/Games/FakeGameServiceModule.cs +++ b/tests/GameServiceWarden.Core.Tests/Modules/Games/FakeGameServiceModule.cs @@ -21,5 +21,10 @@ namespace GameServiceWarden.Core.Tests.Modules.Games { return new FakeGameService(configurables); } + + public IGameService InstantiateGameService(string workspace, bool clean) + { + return new FakeGameService(configurables); + } } } \ No newline at end of file diff --git a/tests/GameServiceWarden.Core.Tests/Modules/Games/FakePersistentDictionary.cs b/tests/GameServiceWarden.Core.Tests/Modules/Games/FakePersistentDictionary.cs new file mode 100644 index 0000000..4a2e40e --- /dev/null +++ b/tests/GameServiceWarden.Core.Tests/Modules/Games/FakePersistentDictionary.cs @@ -0,0 +1,88 @@ +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using GameServiceWarden.Core.Persistence; + +namespace GameServiceWarden.Core.Tests.Modules +{ + public class FakePersistentDictionary : IPersistentDictionary, IReadOnlyPersistentDictionary + { + private IDictionary backing = new Dictionary(); + public V this[string key] { get { return backing[key]; } set { backing[key] = value; } } + + public string MapDirectory { get { return "fake/directory/"; } } + + public ICollection Keys { get { return backing.Keys; } } + + public ICollection Values { get { return backing.Values; } } + + public int Count { get { return backing.Count; } } + + public bool IsReadOnly { get { return false; } } + + IEnumerable IReadOnlyDictionary.Keys { get { return backing.Keys; } } + + IEnumerable IReadOnlyDictionary.Values { get { return backing.Values; } } + + public void Add(string key, V value) + { + backing.Add(key, value); + } + + public void Add(KeyValuePair item) + { + backing.Add(item); + } + + public void Clear() + { + backing.Clear(); + } + + public bool Contains(KeyValuePair item) + { + return backing.Contains(item); + } + + public bool ContainsKey(string key) + { + return backing.ContainsKey(key); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + backing.CopyTo(array, arrayIndex); + } + + public IEnumerator> GetEnumerator() + { + return backing.GetEnumerator(); + } + + public string GetPathForKey(string key) + { + return MapDirectory + Path.DirectorySeparatorChar + key; + } + + public bool Remove(string key) + { + return backing.Remove(key); + } + + public bool Remove(KeyValuePair item) + { + return backing.Remove(item); + } + + public bool TryGetValue(string key, [MaybeNullWhen(false)] out V value) + { + return backing.TryGetValue(key, out value); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return backing.GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/tests/GameServiceWarden.Core.Tests/Modules/Games/GameServiceManagerTest.cs b/tests/GameServiceWarden.Core.Tests/Modules/Games/GameServiceManagerTest.cs index bae9e73..63fbff6 100644 --- a/tests/GameServiceWarden.Core.Tests/Modules/Games/GameServiceManagerTest.cs +++ b/tests/GameServiceWarden.Core.Tests/Modules/Games/GameServiceManagerTest.cs @@ -7,33 +7,6 @@ namespace GameServiceWarden.Core.Tests.Modules.Games { public class GameServiceManagerTest { - [Fact] - public void AddModule_NewManager_SuccessfulAddition() - { - //Given - const string ASSEMBLY_NAME = "FakeAssembly"; - GameServiceManager serviceManager = new GameServiceManager(); - IGameServiceModule stubGameServiceModule = new FakeGameServiceModule(); - //When - serviceManager.AddModule(ASSEMBLY_NAME, stubGameServiceModule); - //Then - Assert.Contains(ASSEMBLY_NAME, serviceManager.GetAssemblyNames()); - Assert.Contains(stubGameServiceModule.Name, serviceManager.GetModuleNames(ASSEMBLY_NAME)); - } - - [Fact] - public void RemoveModule_NewManager_SuccessfulRemoval() - { - //Given - const string ASSEMBLY_NAME = "FakeAssembly"; - GameServiceManager serviceManager = new GameServiceManager(); - IGameServiceModule stubGameServiceModule = new FakeGameServiceModule(); - //When - serviceManager.AddModule(ASSEMBLY_NAME, stubGameServiceModule); - serviceManager.RemoveModule(ASSEMBLY_NAME, stubGameServiceModule.Name); - //Then - Assert.DoesNotContain(ASSEMBLY_NAME, serviceManager.GetAssemblyNames()); - } [Fact] public void CreateService_NewManager_NewServiceCreated() @@ -41,11 +14,13 @@ namespace GameServiceWarden.Core.Tests.Modules.Games //Given const string ASSEMBLY_NAME = "FakeAssembly"; const string FAKE_SERVICE_NAME = "FakeService"; - GameServiceManager serviceManager = new GameServiceManager(); + FakePersistentDictionary stubPersistentModuleDictionary = new FakePersistentDictionary(); + FakePersistentDictionary stubPersistentServiceDictionary = new FakePersistentDictionary(); + GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary); IGameServiceModule stubGameServiceModule = new FakeGameServiceModule(); - serviceManager.AddModule(ASSEMBLY_NAME, stubGameServiceModule); //When - serviceManager.CreateService("FakeService", ASSEMBLY_NAME, stubGameServiceModule.Name); + stubPersistentModuleDictionary.Add(ASSEMBLY_NAME + Path.DirectorySeparatorChar + stubGameServiceModule.Name, stubGameServiceModule); + serviceManager.CreateService(FAKE_SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name); //Then Assert.Contains(FAKE_SERVICE_NAME, serviceManager.GetServiceNames()); } @@ -56,11 +31,13 @@ namespace GameServiceWarden.Core.Tests.Modules.Games //Given const string ASSEMBLY_NAME = "FakeAssembly"; const string FAKE_SERVICE_NAME = "FakeService"; - GameServiceManager serviceManager = new GameServiceManager(); + FakePersistentDictionary stubPersistentModuleDictionary = new FakePersistentDictionary(); + FakePersistentDictionary stubPersistentServiceDictionary = new FakePersistentDictionary(); + GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary); IGameServiceModule stubGameServiceModule = new FakeGameServiceModule(); - serviceManager.AddModule(ASSEMBLY_NAME, stubGameServiceModule); - serviceManager.CreateService(FAKE_SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name); //When + stubPersistentModuleDictionary.Add(ASSEMBLY_NAME + Path.DirectorySeparatorChar + stubGameServiceModule.Name, stubGameServiceModule); + serviceManager.CreateService(FAKE_SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name); serviceManager.DeleteService(FAKE_SERVICE_NAME); //Then Assert.DoesNotContain(FAKE_SERVICE_NAME, serviceManager.GetServiceNames()); @@ -72,10 +49,12 @@ namespace GameServiceWarden.Core.Tests.Modules.Games //Given const string ASSEMBLY_NAME = "FakeAssembly"; const string FAKE_SERVICE_PREFIX = "FakeService_"; - GameServiceManager serviceManager = new GameServiceManager(); + FakePersistentDictionary stubPersistentModuleDictionary = new FakePersistentDictionary(); + FakePersistentDictionary stubPersistentServiceDictionary = new FakePersistentDictionary(); + GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary); IGameServiceModule stubGameServiceModule = new FakeGameServiceModule(); //When - serviceManager.AddModule(ASSEMBLY_NAME, stubGameServiceModule); + stubPersistentModuleDictionary.Add(ASSEMBLY_NAME + Path.DirectorySeparatorChar + stubGameServiceModule.Name, stubGameServiceModule); for (int i = 0; i < 100; i++) { serviceManager.CreateService(FAKE_SERVICE_PREFIX + i, ASSEMBLY_NAME, stubGameServiceModule.Name); @@ -93,14 +72,16 @@ namespace GameServiceWarden.Core.Tests.Modules.Games //Given const string ASSEMBLY_NAME = "FakeAssembly"; const string SERVICE_NAME = "FakeService"; - GameServiceManager serviceManager = new GameServiceManager(); + FakePersistentDictionary stubPersistentModuleDictionary = new FakePersistentDictionary(); + FakePersistentDictionary stubPersistentServiceDictionary = new FakePersistentDictionary(); + GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary); IGameServiceModule stubGameServiceModule = new FakeGameServiceModule( new FakeGameConfigurable("A"), new FakeGameConfigurable("B"), new FakeGameConfigurable("C") ); //When - serviceManager.AddModule(ASSEMBLY_NAME, stubGameServiceModule); + stubPersistentModuleDictionary.Add(ASSEMBLY_NAME + Path.DirectorySeparatorChar + stubGameServiceModule.Name, stubGameServiceModule); serviceManager.CreateService(SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name); //Then Assert.Contains("A", serviceManager.GetServiceOptions(SERVICE_NAME)); @@ -114,12 +95,14 @@ namespace GameServiceWarden.Core.Tests.Modules.Games //Given const string ASSEMBLY_NAME = "FakeAssembly"; const string SERVICE_NAME = "FakeService"; - GameServiceManager serviceManager = new GameServiceManager(); + FakePersistentDictionary stubPersistentModuleDictionary = new FakePersistentDictionary(); + FakePersistentDictionary stubPersistentServiceDictionary = new FakePersistentDictionary(); + GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary); IGameServiceModule stubGameServiceModule = new FakeGameServiceModule( new FakeGameConfigurable("A") ); //When - serviceManager.AddModule(ASSEMBLY_NAME, stubGameServiceModule); + stubPersistentModuleDictionary.Add(ASSEMBLY_NAME + Path.DirectorySeparatorChar + stubGameServiceModule.Name, stubGameServiceModule); serviceManager.CreateService(SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name); serviceManager.SetServiceOptionValue(SERVICE_NAME, "A", "Test"); //Then @@ -132,10 +115,12 @@ namespace GameServiceWarden.Core.Tests.Modules.Games //Given const string ASSEMBLY_NAME = "FakeAssembly"; const string SERVICE_NAME = "FakeService"; - GameServiceManager serviceManager = new GameServiceManager(); + FakePersistentDictionary stubPersistentModuleDictionary = new FakePersistentDictionary(); + FakePersistentDictionary stubPersistentServiceDictionary = new FakePersistentDictionary(); + GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary); IGameServiceModule stubGameServiceModule = new FakeGameServiceModule(); //When - serviceManager.AddModule(ASSEMBLY_NAME, stubGameServiceModule); + stubPersistentModuleDictionary.Add(ASSEMBLY_NAME + Path.DirectorySeparatorChar + stubGameServiceModule.Name, stubGameServiceModule); serviceManager.CreateService(SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name); //Then Assert.Equal(ServiceState.Stopped, serviceManager.GetServiceState(SERVICE_NAME)); @@ -147,10 +132,12 @@ namespace GameServiceWarden.Core.Tests.Modules.Games //Given const string ASSEMBLY_NAME = "FakeAssembly"; const string SERVICE_NAME = "FakeService"; - GameServiceManager serviceManager = new GameServiceManager(); + FakePersistentDictionary stubPersistentModuleDictionary = new FakePersistentDictionary(); + FakePersistentDictionary stubPersistentServiceDictionary = new FakePersistentDictionary(); + GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary); IGameServiceModule stubGameServiceModule = new FakeGameServiceModule(); //When - serviceManager.AddModule(ASSEMBLY_NAME, stubGameServiceModule); + stubPersistentModuleDictionary.Add(ASSEMBLY_NAME + Path.DirectorySeparatorChar + stubGameServiceModule.Name, stubGameServiceModule); serviceManager.CreateService(SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name); serviceManager.StartService(SERVICE_NAME); //Then @@ -163,10 +150,12 @@ namespace GameServiceWarden.Core.Tests.Modules.Games //Given const string ASSEMBLY_NAME = "FakeAssembly"; const string SERVICE_NAME = "FakeService"; - GameServiceManager serviceManager = new GameServiceManager(); + FakePersistentDictionary stubPersistentModuleDictionary = new FakePersistentDictionary(); + FakePersistentDictionary stubPersistentServiceDictionary = new FakePersistentDictionary(); + GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary); IGameServiceModule stubGameServiceModule = new FakeGameServiceModule(); //When - serviceManager.AddModule(ASSEMBLY_NAME, stubGameServiceModule); + stubPersistentModuleDictionary.Add(ASSEMBLY_NAME + Path.DirectorySeparatorChar + stubGameServiceModule.Name, stubGameServiceModule); serviceManager.CreateService(SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name); serviceManager.StartService(SERVICE_NAME); //Then @@ -179,10 +168,12 @@ namespace GameServiceWarden.Core.Tests.Modules.Games //Given const string ASSEMBLY_NAME = "FakeAssembly"; const string SERVICE_NAME = "FakeService"; - GameServiceManager serviceManager = new GameServiceManager(); + FakePersistentDictionary stubPersistentModuleDictionary = new FakePersistentDictionary(); + FakePersistentDictionary stubPersistentServiceDictionary = new FakePersistentDictionary(); + GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary); IGameServiceModule stubGameServiceModule = new FakeGameServiceModule(); //When - serviceManager.AddModule(ASSEMBLY_NAME, stubGameServiceModule); + stubPersistentModuleDictionary.Add(ASSEMBLY_NAME + Path.DirectorySeparatorChar + stubGameServiceModule.Name, stubGameServiceModule); serviceManager.CreateService(SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name); serviceManager.StartService(SERVICE_NAME); serviceManager.StopService(SERVICE_NAME); @@ -196,10 +187,12 @@ namespace GameServiceWarden.Core.Tests.Modules.Games //Given const string ASSEMBLY_NAME = "FakeAssembly"; const string SERVICE_NAME = "FakeService"; - GameServiceManager serviceManager = new GameServiceManager(); + FakePersistentDictionary stubPersistentModuleDictionary = new FakePersistentDictionary(); + FakePersistentDictionary stubPersistentServiceDictionary = new FakePersistentDictionary(); + GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary); IGameServiceModule stubGameServiceModule = new FakeGameServiceModule(); //When - serviceManager.AddModule(ASSEMBLY_NAME, stubGameServiceModule); + stubPersistentModuleDictionary.Add(ASSEMBLY_NAME + Path.DirectorySeparatorChar + stubGameServiceModule.Name, stubGameServiceModule); serviceManager.CreateService(SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name); serviceManager.StartService(SERVICE_NAME); serviceManager.ExecuteCommand(SERVICE_NAME, "Test"); @@ -218,10 +211,12 @@ namespace GameServiceWarden.Core.Tests.Modules.Games //Given const string ASSEMBLY_NAME = "FakeAssembly"; const string SERVICE_NAME = "FakeService"; - GameServiceManager serviceManager = new GameServiceManager(); + FakePersistentDictionary stubPersistentModuleDictionary = new FakePersistentDictionary(); + FakePersistentDictionary stubPersistentServiceDictionary = new FakePersistentDictionary(); + GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary); IGameServiceModule stubGameServiceModule = new FakeGameServiceModule(); //When - serviceManager.AddModule(ASSEMBLY_NAME, stubGameServiceModule); + stubPersistentModuleDictionary.Add(ASSEMBLY_NAME + Path.DirectorySeparatorChar + stubGameServiceModule.Name, stubGameServiceModule); serviceManager.CreateService(SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name); //Then Assert.Null(serviceManager.GetServiceConsoleStream(SERVICE_NAME));