Fixed method of access game modules.
Added some documentation. Changed data persistence structure. General naming changes. Updated tests appropriately.
This commit is contained in:
parent
c7fadd8166
commit
f402b8b7f2
@ -55,7 +55,6 @@ namespace GameServiceWarden.Core.Games
|
||||
}
|
||||
|
||||
throw new FormatException($"\"{path}\" is corrupted. Could not find value for: {key}.");
|
||||
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetAllServiceInfoPaths()
|
||||
|
@ -25,14 +25,18 @@ namespace GameServiceWarden.Core.Games
|
||||
private volatile ServiceState state;
|
||||
private readonly IGameService service;
|
||||
private readonly string assemblyName;
|
||||
private readonly string moduleName;
|
||||
|
||||
/// <summary>
|
||||
/// Name of module this service uses.
|
||||
/// </summary>
|
||||
public string ModuleName { get; private set; }
|
||||
private readonly IReadOnlyDictionary<string, IGameConfigurable> configurables;
|
||||
private bool disposed;
|
||||
|
||||
public GameServiceInfo(IGameService service, string moduleName, string assemblyName)
|
||||
{
|
||||
this.service = service ?? throw new ArgumentNullException("service");
|
||||
this.moduleName = moduleName ?? throw new ArgumentNullException("moduleName");
|
||||
this.ModuleName = moduleName ?? throw new ArgumentNullException("moduleName");
|
||||
this.assemblyName = assemblyName ?? throw new ArgumentNullException("assemblyName");
|
||||
this.service.StateChangeEvent += OnServiceStateChange;
|
||||
|
||||
@ -121,12 +125,6 @@ namespace GameServiceWarden.Core.Games
|
||||
}
|
||||
}
|
||||
|
||||
/// <returns>The name of the module this service uses.</returns>
|
||||
public string GetModuleName()
|
||||
{
|
||||
return moduleName;
|
||||
}
|
||||
|
||||
/// <returns>The name of assembly this module is contained in.</returns>
|
||||
public string GetAssemblyName()
|
||||
{
|
||||
|
@ -8,22 +8,24 @@ namespace GameServiceWarden.Core.Games
|
||||
{
|
||||
public class GameServiceManager
|
||||
{
|
||||
private readonly IDictionary<string, GameServiceInfo> running;
|
||||
private readonly IPersistentDictionary<GameServiceInfo> services;
|
||||
private readonly IReadOnlyPersistentDictionary<IGameServiceModule> modules;
|
||||
private readonly IReadOnlyPersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>> modules;
|
||||
|
||||
public GameServiceManager(IPersistentDictionary<GameServiceInfo> services, IReadOnlyPersistentDictionary<IGameServiceModule> modules)
|
||||
public GameServiceManager(IPersistentDictionary<GameServiceInfo> services, IReadOnlyPersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>> modules)
|
||||
{
|
||||
this.services = services;
|
||||
this.modules = modules;
|
||||
this.running = new Dictionary<string, GameServiceInfo>();
|
||||
}
|
||||
|
||||
public void CreateService(string serviceName, string assemblyName, string moduleName)
|
||||
{
|
||||
string moduleID = ToModuleID(assemblyName, moduleName);
|
||||
if (!modules.ContainsKey(moduleID)) throw new KeyNotFoundException($"No module registered from \"{assemblyName}\" named \"{moduleName}\".");
|
||||
if (!this.modules.ContainsKey(assemblyName)) throw new KeyNotFoundException($"No file \"{assemblyName}\" found.");
|
||||
IReadOnlyDictionary<string, IGameServiceModule> modules = this.modules[assemblyName];
|
||||
if (services.ContainsKey(serviceName)) throw new ArgumentException($"Service of Name \"{serviceName}\" already exists.");
|
||||
|
||||
services.Add(serviceName, new GameServiceInfo(modules[moduleID].InstantiateGameService(services.GetPathForKey(serviceName), true), moduleName, assemblyName));
|
||||
services.Add(serviceName, new GameServiceInfo(modules[moduleName].InstantiateGameService(services.GetPathForKey(serviceName), true), moduleName, assemblyName));
|
||||
}
|
||||
|
||||
public void DeleteService(string serviceName)
|
||||
@ -75,30 +77,29 @@ namespace GameServiceWarden.Core.Games
|
||||
public void StartService(string serviceName)
|
||||
{
|
||||
if (!services.ContainsKey(serviceName)) throw new KeyNotFoundException($"Service under name \"{serviceName}\" not found.");
|
||||
services[serviceName].Start();
|
||||
if (running.ContainsKey(serviceName)) throw new InvalidOperationException($"Service under name \"{serviceName}\" is already running.");
|
||||
running.Add(serviceName, services[serviceName]);
|
||||
running[serviceName].Start();
|
||||
}
|
||||
|
||||
public void StopService(string serviceName)
|
||||
{
|
||||
if (!services.ContainsKey(serviceName)) throw new KeyNotFoundException($"Service under name \"{serviceName}\" not found.");
|
||||
services[serviceName].Stop();
|
||||
if (!running.ContainsKey(serviceName)) throw new InvalidOperationException($"Service under name \"{serviceName}\" is not running.");
|
||||
running[serviceName].Stop();
|
||||
services[serviceName] = running[serviceName];
|
||||
running.Remove(serviceName);
|
||||
}
|
||||
|
||||
public void ExecuteCommand(string serviceName, string command)
|
||||
{
|
||||
if (!services.ContainsKey(serviceName)) throw new KeyNotFoundException($"Service under name \"{serviceName}\" not found.");
|
||||
services[serviceName].ExecuteCommand(command);
|
||||
if (!running.ContainsKey(serviceName)) throw new InvalidOperationException($"Service under name \"{serviceName}\" is not running.");
|
||||
running[serviceName].ExecuteCommand(command);
|
||||
}
|
||||
|
||||
public Stream GetServiceConsoleStream(string serviceName)
|
||||
{
|
||||
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;
|
||||
if (!running.ContainsKey(serviceName)) throw new InvalidOperationException($"Service under name \"{serviceName}\" is not running.");
|
||||
return running[serviceName].ServiceConsoleStream;
|
||||
}
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ using GameServiceWarden.ModuleAPI;
|
||||
|
||||
namespace GameServiceWarden.Core.Games.Modules
|
||||
{
|
||||
public class GameModuleLoader //Gateway
|
||||
public class GameServiceModuleLoader //Gateway
|
||||
{
|
||||
/// <summary>
|
||||
/// Loads an extension module.
|
@ -0,0 +1,128 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using GameServiceWarden.Core.Games.Modules;
|
||||
using GameServiceWarden.ModuleAPI;
|
||||
|
||||
namespace GameServiceWarden.Core.Persistence
|
||||
{
|
||||
public class GameServiceModuleDictionary : IReadOnlyPersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>>
|
||||
{
|
||||
private readonly string mapDirectory;
|
||||
|
||||
private readonly GameServiceModuleLoader loader = new GameServiceModuleLoader();
|
||||
|
||||
public GameServiceModuleDictionary(string mapDirectory)
|
||||
{
|
||||
this.mapDirectory = mapDirectory;
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<string, IGameServiceModule> this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!ContainsKey(key)) throw new KeyNotFoundException($"Key \"{key}\" not found.");
|
||||
Dictionary<string, IGameServiceModule> res = new Dictionary<string, IGameServiceModule>();
|
||||
IEnumerable<IGameServiceModule> modules = loader.LoadModules(GetPathForKey(key));
|
||||
foreach (IGameServiceModule module in modules)
|
||||
{
|
||||
res.Add(module.Name, module);
|
||||
}
|
||||
return new ReadOnlyDictionary<string, IGameServiceModule>(res);
|
||||
}
|
||||
}
|
||||
|
||||
public string MapDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
return mapDirectory;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<string> Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
IEnumerable<string> files = Directory.EnumerateFiles(mapDirectory);
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (Path.GetExtension(file).ToLower().Equals("dll"))
|
||||
{
|
||||
yield return Path.GetFileName(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IReadOnlyDictionary<string, IGameServiceModule>> Values
|
||||
{
|
||||
get
|
||||
{
|
||||
IEnumerable<string> keys = Keys;
|
||||
foreach (string key in keys)
|
||||
{
|
||||
yield return this[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
int count = 0;
|
||||
IEnumerable<string> files = Directory.EnumerateFiles(mapDirectory);
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (Path.GetExtension(file).ToLower().Equals("dll"))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
string path = GetPathForKey(key);
|
||||
return File.Exists(path) && Path.GetExtension(path).ToLower().Equals("dll");
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<string, IReadOnlyDictionary<string, IGameServiceModule>>> GetEnumerator()
|
||||
{
|
||||
IEnumerable<string> keys = Keys;
|
||||
foreach (string key in keys)
|
||||
{
|
||||
yield return new KeyValuePair<string, IReadOnlyDictionary<string, IGameServiceModule>>(key, this[key]);
|
||||
}
|
||||
}
|
||||
|
||||
public string GetPathForKey(string key)
|
||||
{
|
||||
return mapDirectory + Path.DirectorySeparatorChar + key;
|
||||
}
|
||||
|
||||
public bool TryGetValue(string key, [MaybeNullWhen(false)] out IReadOnlyDictionary<string, IGameServiceModule> value)
|
||||
{
|
||||
try
|
||||
{
|
||||
value = this[key];
|
||||
return true;
|
||||
}
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
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<V> : IPersistentDictionary<V>, ICollection<KeyValuePair<string, V>>
|
||||
{
|
||||
private readonly string mapDirectory;
|
||||
private readonly IPersistentDictionaryWriter<V> writer;
|
||||
private readonly IPersistentDictionaryReader<V> reader;
|
||||
private readonly GeneralReadOnlyPersistentDictionary<V> readDictionary;
|
||||
|
||||
public GeneralPersistentDictionary(string mapDirectory, IPersistentDictionaryReader<V> reader, IPersistentDictionaryWriter<V> writer)
|
||||
{
|
||||
this.mapDirectory = mapDirectory ?? throw new ArgumentNullException("mapDirectory");
|
||||
this.reader = reader ?? throw new ArgumentNullException("reader");
|
||||
this.readDictionary = new GeneralReadOnlyPersistentDictionary<V>(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<string> Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
IEnumerable<string> keys = Directory.EnumerateFileSystemEntries(mapDirectory);
|
||||
List<string> res = new List<string>();
|
||||
foreach (string key in keys)
|
||||
{
|
||||
if (reader.IsValidValue(GetPathForKey(key))) res.Add(key);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<V> Values
|
||||
{
|
||||
get
|
||||
{
|
||||
IEnumerable<string> keys = Keys;
|
||||
List<V> res = new List<V>();
|
||||
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<KeyValuePair<string,V>>.Add(KeyValuePair<string, V> item)
|
||||
{
|
||||
Add(item.Key, item.Value);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
IEnumerable<string> keys = Keys;
|
||||
foreach (string key in keys)
|
||||
{
|
||||
string path = GetPathForKey(key);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
Directory.Delete(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<string, V>>.Contains(KeyValuePair<string, V> 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<string, V>[] 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<KeyValuePair<string, V>> pairs = GetEnumerator();
|
||||
for (int i = arrayIndex; i < array.Length; i++)
|
||||
{
|
||||
if (!pairs.MoveNext()) return;
|
||||
array[i] = pairs.Current;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<string, V>> GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable<KeyValuePair<string, V>>) 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<string, V> 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
|
||||
namespace GameServiceWarden.Core.Persistence
|
||||
{
|
||||
public class GeneralReadOnlyPersistentDictionary<V> : IReadOnlyPersistentDictionary<V>, IReadOnlyCollection<KeyValuePair<string, V>>
|
||||
{
|
||||
private readonly string mapDirectory;
|
||||
public string MapDirectory { get { return mapDirectory; } }
|
||||
private IPersistentDictionaryReader<V> reader;
|
||||
|
||||
public GeneralReadOnlyPersistentDictionary(string mapDirectory, IPersistentDictionaryReader<V> reader)
|
||||
{
|
||||
this.mapDirectory = mapDirectory;
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
public V this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
return reader.Read(GetPathForKey(key));
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<string> Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
IEnumerable<string> 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<V> Values
|
||||
{
|
||||
get
|
||||
{
|
||||
IEnumerable<string> keys = Directory.EnumerateFileSystemEntries(mapDirectory);
|
||||
foreach (string key in keys)
|
||||
{
|
||||
yield return reader.Read(GetPathForKey(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
int count = 0;
|
||||
IEnumerable<string> 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<KeyValuePair<string, V>> GetEnumerator()
|
||||
{
|
||||
IEnumerable<string> keys = Keys;
|
||||
List<KeyValuePair<string, V>> pairs = new List<KeyValuePair<string, V>>();
|
||||
foreach (string key in keys)
|
||||
{
|
||||
pairs.Add(new KeyValuePair<string, V>(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();
|
||||
}
|
||||
}
|
||||
}
|
@ -4,7 +4,16 @@ namespace GameServiceWarden.Core.Persistence
|
||||
{
|
||||
public interface IPersistentDictionary<V> : IDictionary<string, V>
|
||||
{
|
||||
/// <summary>
|
||||
/// The directory for this dictionary to use.
|
||||
/// </summary>
|
||||
string MapDirectory { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The path to the data representing a specific key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key to get the path for.</param>
|
||||
/// <returns>A <see cref="string"/> representing the key.</returns>
|
||||
string GetPathForKey(string key);
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
namespace GameServiceWarden.Core.Persistence
|
||||
{
|
||||
public interface IPersistentDictionaryReader<V>
|
||||
{
|
||||
V Read(string path);
|
||||
bool IsValidValue(string path);
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
namespace GameServiceWarden.Core.Persistence
|
||||
{
|
||||
public interface IPersistentDictionaryWriter<V>
|
||||
{
|
||||
void Write(string path, V value);
|
||||
}
|
||||
}
|
@ -4,7 +4,16 @@ namespace GameServiceWarden.Core.Persistence
|
||||
{
|
||||
public interface IReadOnlyPersistentDictionary<V> : IReadOnlyDictionary<string, V>
|
||||
{
|
||||
/// <summary>
|
||||
/// The directory for this dictionary to use.
|
||||
/// </summary>
|
||||
string MapDirectory { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The path to the data representing a specific key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key to get the path for.</param>
|
||||
/// <returns>A <see cref="string"/> representing the key.</returns>
|
||||
string GetPathForKey(string key);
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<mxfile host="65bd71144e" modified="2020-12-29T18:25:57.297Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Code/1.52.1 Chrome/83.0.4103.122 Electron/9.3.5 Safari/537.36" etag="YsJOF2puyTwjZNHuS3ue" version="13.10.0" type="embed" pages="2">
|
||||
<mxfile host="65bd71144e" pages="2">
|
||||
<diagram id="LHR7ubqCPd17_LyHkaH9" name="Structure">
|
||||
<mxGraphModel dx="1298" dy="740" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<mxGraphModel dx="1113" dy="480" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
@ -18,7 +18,7 @@
|
||||
<mxCell id="dmd0HlDYcxYugIlahWj0-7" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;sketch=1;" parent="dmd0HlDYcxYugIlahWj0-5" vertex="1">
|
||||
<mxGeometry y="166" width="401" height="8" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="dmd0HlDYcxYugIlahWj0-8" value="+ Start(): void + Stop(): void + GetConfigurableOptions(): ISet<string> + SetConfigurableValue(configurationName: string, value: string): bool + GetConfigurableValue(configurationName: string): string + GetServiceState(): ServiceState + getModuleName(): string + GetassemblyName(): string + SetServiceName(name: string): void // Implemented as property + GetServiceName(): string // Implemented as property + GetServiceConsoleStream(): Stream // Implemented as property - OnServiceStateChange(curr: ServiceState, prev: ServiceState): void # Dispose(disposing: bool): void + Dispose(): voide" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;sketch=1;" parent="dmd0HlDYcxYugIlahWj0-5" vertex="1">
|
||||
<mxCell id="dmd0HlDYcxYugIlahWj0-8" value="+ Start(): void + Stop(): void + GetConfigurableOptions(): ISet<string> + SetConfigurableValue(configurationName: string, value: string): bool + GetConfigurableValue(configurationName: string): string + GetServiceState(): ServiceState + getModuleName(): string //Implemented as property + GetassemblyName(): string + SetServiceName(name: string): void // Implemented as property + GetServiceName(): string // Implemented as property + GetServiceConsoleStream(): Stream // Implemented as property - OnServiceStateChange(curr: ServiceState, prev: ServiceState): void # Dispose(disposing: bool): void + Dispose(): voide" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;sketch=1;" parent="dmd0HlDYcxYugIlahWj0-5" vertex="1">
|
||||
<mxGeometry y="174" width="401" height="212" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="dmd0HlDYcxYugIlahWj0-9" value="«interface»<br><span>IDisposable</span>" style="html=1;sketch=1;" parent="1" vertex="1">
|
||||
@ -43,18 +43,18 @@
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="dmd0HlDYcxYugIlahWj0-11" value="GameServiceManager" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;sketch=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="697" y="640" width="531" height="300" as="geometry">
|
||||
<mxGeometry x="669.5" y="640" width="561" height="300" as="geometry">
|
||||
<mxRectangle x="25" y="490" width="120" height="26" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="dmd0HlDYcxYugIlahWj0-12" value="- serviceDir: string - services: IDictionary<string, Service> - modules: IReadOnlyDictionary<string, Dictionary<string, IGameServiceModule>>" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;sketch=1;" parent="dmd0HlDYcxYugIlahWj0-11" vertex="1">
|
||||
<mxGeometry y="26" width="531" height="54" as="geometry"/>
|
||||
<mxCell id="dmd0HlDYcxYugIlahWj0-12" value="- services: IPersistentDictionary<GameServiceInfo> - modules: IReadOnlyPersistentDictionary<string, IReadOnlyDictionary<string, IGameServiceModule>> - running: IDictionary<string, GameServiceInfo>" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;sketch=1;" parent="dmd0HlDYcxYugIlahWj0-11" vertex="1">
|
||||
<mxGeometry y="26" width="561" height="54" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="dmd0HlDYcxYugIlahWj0-13" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;sketch=1;" parent="dmd0HlDYcxYugIlahWj0-11" vertex="1">
|
||||
<mxGeometry y="80" width="531" height="8" as="geometry"/>
|
||||
<mxGeometry y="80" width="561" height="8" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="dmd0HlDYcxYugIlahWj0-14" value="+ CreateService(serviceName: string, assemblyName: string, moduleName: string): void + DeleteService(serviceName: string): void + GetModuleIDs(): IEnumerable<string> + GetServiceNames(): IReadOnlyCollection<string> + GetServiceOptions(serviceName: string): IEnumerable<string> + GetServiceOptionsValue(serviceName: string): IEnumerable<string> + SetServiceOptionValue(serviceName: string, optionName: string, string: value): bool + GetServiceState(serviceName: string): ServiceState + StartService(serviceName: string): void + StopService(serviceName: string): void + ExecuteCommand(serviceName: string, command: string): void + GetServiceConsoleStream(): Stream + ExecuteServiceAction(serviceAction: serviceAction): void - ToModuleID(assemblyName: string, moduleName: string): string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;sketch=1;" parent="dmd0HlDYcxYugIlahWj0-11" vertex="1">
|
||||
<mxGeometry y="88" width="531" height="212" as="geometry"/>
|
||||
<mxCell id="dmd0HlDYcxYugIlahWj0-14" value="+ CreateService(serviceName: string, assemblyName: string, moduleName: string): void + DeleteService(serviceName: string): void + GetModuleNames(): IEnumerable<string> + GetServiceNames(): IReadOnlyCollection<string> + GetServiceOptions(serviceName: string): IEnumerable<string> + GetServiceOptionValue(serviceName: string, optionName: string): IEnumerable<string> + SetServiceOptionValue(serviceName: string, optionName: string, string: value): bool + GetServiceState(serviceName: string): ServiceState + StartService(serviceName: string): void + StopService(serviceName: string): void + ExecuteCommand(serviceName: string, command: string): void + GetServiceConsoleStream(): Stream + ExecuteServiceAction(serviceAction: serviceAction): void" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;sketch=1;" parent="dmd0HlDYcxYugIlahWj0-11" vertex="1">
|
||||
<mxGeometry y="88" width="561" height="212" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="dmd0HlDYcxYugIlahWj0-38" value="<<Interface>> ITextCommand" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=40;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;sketch=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="1285" y="138" width="181" height="114" as="geometry"/>
|
||||
@ -176,7 +176,12 @@
|
||||
<mxGeometry y="26" width="160" height="8" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="SI3d9EEbteElKQB4Ic5T-5" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;endArrow=open;endFill=0;sketch=1;" parent="1" source="zFFzFwxISwJASp9ezwbr-1" target="fdKXkHfjRXYybK0fejAG-9" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="495" y="660"/>
|
||||
<mxPoint x="407" y="660"/>
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="zFFzFwxISwJASp9ezwbr-1" value="<<Interface>> IGameServiceOutputMonitor" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=40;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;sketch=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="355" y="464" width="280" height="74" as="geometry"/>
|
||||
@ -209,348 +214,348 @@
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="gj0qHRc3eh050ABAey3g" name="Data-Flow">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGraphModel dx="1216" dy="740" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<root>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="jVG6p58vlRYGO9X4wXeX-0"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="jVG6p58vlRYGO9X4wXeX-1" parent="jVG6p58vlRYGO9X4wXeX-0"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="28FAlPysTx9DMYvLwa-2-21" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.3333333333333333;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;endArrow=open;endFill=0;fillColor=#1ba1e2;strokeColor=#006EAF;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="jVG6p58vlRYGO9X4wXeX-2" target="jVG6p58vlRYGO9X4wXeX-3" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="jVG6p58vlRYGO9X4wXeX-2" value="Actor" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" vertex="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry x="10" y="300" width="30" height="60" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="jVG6p58vlRYGO9X4wXeX-12" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;endArrow=open;endFill=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;fillColor=#1ba1e2;strokeColor=#006EAF;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="jVG6p58vlRYGO9X4wXeX-3" target="jVG6p58vlRYGO9X4wXeX-4" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="28FAlPysTx9DMYvLwa-2-22" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;entryX=0.75;entryY=0.1;entryDx=0;entryDy=0;entryPerimeter=0;endArrow=open;endFill=0;fillColor=#1ba1e2;strokeColor=#006EAF;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="jVG6p58vlRYGO9X4wXeX-3" target="jVG6p58vlRYGO9X4wXeX-2" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="345FJoVc2gbAayMsQlD7-0" value="Use" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;dashed=1;endArrow=open;endFill=0;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="jVG6p58vlRYGO9X4wXeX-3" target="jVG6p58vlRYGO9X4wXeX-4" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="345FJoVc2gbAayMsQlD7-6" value="Use" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=0;exitDx=0;exitDy=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;dashed=1;endArrow=open;endFill=0;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="jVG6p58vlRYGO9X4wXeX-3" target="28FAlPysTx9DMYvLwa-2-7" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="jVG6p58vlRYGO9X4wXeX-3" value="Console View" style="whiteSpace=wrap;html=1;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" vertex="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry x="80" y="300" width="120" height="60" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="jVG6p58vlRYGO9X4wXeX-13" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;endArrow=open;endFill=0;fillColor=#1ba1e2;strokeColor=#006EAF;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="jVG6p58vlRYGO9X4wXeX-4" target="jVG6p58vlRYGO9X4wXeX-5" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="345FJoVc2gbAayMsQlD7-2" value="Use" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.75;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;dashed=1;endArrow=open;endFill=0;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="jVG6p58vlRYGO9X4wXeX-4" target="jVG6p58vlRYGO9X4wXeX-5" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="jVG6p58vlRYGO9X4wXeX-4" value="string command (request)" style="whiteSpace=wrap;html=1;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" vertex="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry x="260" y="482.5" width="120" height="60" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="jVG6p58vlRYGO9X4wXeX-8" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;dashed=1;endArrow=block;endFill=0;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="jVG6p58vlRYGO9X4wXeX-5" target="jVG6p58vlRYGO9X4wXeX-7" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="28FAlPysTx9DMYvLwa-2-3" value="Use" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;endArrow=open;endFill=0;dashed=1;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="jVG6p58vlRYGO9X4wXeX-5" target="jVG6p58vlRYGO9X4wXeX-7" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-18" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;endArrow=open;endFill=0;strokeColor=#006EAF;fillColor=#1ba1e2;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="jVG6p58vlRYGO9X4wXeX-5" target="jVG6p58vlRYGO9X4wXeX-9" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="jVG6p58vlRYGO9X4wXeX-5" value="MainController" style="whiteSpace=wrap;html=1;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" vertex="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry x="420" y="482.5" width="120" height="60" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="jVG6p58vlRYGO9X4wXeX-6" value="http://www.plainionist.net/Implementing-Clean-Architecture-Controller-Presenter/" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" vertex="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry y="840" width="480" height="20" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="jVG6p58vlRYGO9X4wXeX-7" value="&lt;&lt;Interface&gt;&gt;<br>ICommand" style="whiteSpace=wrap;html=1;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" vertex="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry x="420" y="372.5" width="120" height="60" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="jVG6p58vlRYGO9X4wXeX-10" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;dashed=1;endArrow=block;endFill=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="jVG6p58vlRYGO9X4wXeX-9" target="jVG6p58vlRYGO9X4wXeX-7" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-8" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.25;entryDx=0;entryDy=0;endArrow=open;endFill=0;strokeColor=#006EAF;fillColor=#1ba1e2;exitX=1;exitY=0.5;exitDx=0;exitDy=0;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="jVG6p58vlRYGO9X4wXeX-9" target="UY-EM7-1ECCvWtENr50b-1" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxPoint x="809.9999999999998" y="512.5000000000002" as="sourcePoint"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxGeometry>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="345FJoVc2gbAayMsQlD7-3" value="Use" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;dashed=1;endArrow=open;endFill=0;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="jVG6p58vlRYGO9X4wXeX-9" target="UY-EM7-1ECCvWtENr50b-2" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="345FJoVc2gbAayMsQlD7-4" value="Use" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.75;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;dashed=1;endArrow=open;endFill=0;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="jVG6p58vlRYGO9X4wXeX-9" target="UY-EM7-1ECCvWtENr50b-1" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="jVG6p58vlRYGO9X4wXeX-9" value="ServiceController" style="whiteSpace=wrap;html=1;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" vertex="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry x="575" y="482.5" width="120" height="60" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-4" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=none;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="28FAlPysTx9DMYvLwa-2-1" target="UY-EM7-1ECCvWtENr50b-2" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-5" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;dashed=1;endArrow=block;endFill=0;strokeColor=#f0f0f0;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="28FAlPysTx9DMYvLwa-2-1" target="UY-EM7-1ECCvWtENr50b-2" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-7" value="Use" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1.008;entryY=0.625;entryDx=0;entryDy=0;entryPerimeter=0;endArrow=open;endFill=0;strokeColor=#f0f0f0;dashed=1;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="28FAlPysTx9DMYvLwa-2-1" target="UY-EM7-1ECCvWtENr50b-1" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<Array as="points">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxPoint x="960" y="338"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxPoint x="960" y="580"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</Array>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxGeometry>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-16" value="Use" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=open;endFill=0;dashed=1;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="28FAlPysTx9DMYvLwa-2-1" target="UY-EM7-1ECCvWtENr50b-11" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="345FJoVc2gbAayMsQlD7-7" value="Use" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;dashed=1;endArrow=open;endFill=0;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="28FAlPysTx9DMYvLwa-2-1" target="UY-EM7-1ECCvWtENr50b-10" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<Array as="points">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxPoint x="960" y="338"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxPoint x="960" y="83"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</Array>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxGeometry>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="28FAlPysTx9DMYvLwa-2-1" value="ServiceManager" style="whiteSpace=wrap;html=1;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" vertex="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry x="800" y="307.5" width="120" height="60" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="28FAlPysTx9DMYvLwa-2-9" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;endArrow=open;endFill=0;fillColor=#1ba1e2;strokeColor=#006EAF;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="28FAlPysTx9DMYvLwa-2-5" target="tM_Gde3HH8YiZ2frBV5J-0" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-12" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;endArrow=block;endFill=0;strokeColor=#f0f0f0;dashed=1;exitX=1;exitY=0.75;exitDx=0;exitDy=0;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="28FAlPysTx9DMYvLwa-2-5" target="UY-EM7-1ECCvWtENr50b-11" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-13" value="Use" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.75;entryDx=0;entryDy=0;endArrow=open;endFill=0;strokeColor=#f0f0f0;dashed=1;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="28FAlPysTx9DMYvLwa-2-5" target="UY-EM7-1ECCvWtENr50b-10" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="tM_Gde3HH8YiZ2frBV5J-3" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;dashed=1;endArrow=block;endFill=0;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="28FAlPysTx9DMYvLwa-2-5" target="tM_Gde3HH8YiZ2frBV5J-1" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="28FAlPysTx9DMYvLwa-2-5" value="ServicePresenter" style="whiteSpace=wrap;html=1;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" vertex="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry x="575" y="122.5" width="120" height="60" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="28FAlPysTx9DMYvLwa-2-8" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;endArrow=open;endFill=0;fillColor=#1ba1e2;strokeColor=#006EAF;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="28FAlPysTx9DMYvLwa-2-7" target="jVG6p58vlRYGO9X4wXeX-3" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="tM_Gde3HH8YiZ2frBV5J-5" value="Use" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;dashed=1;endArrow=open;endFill=0;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="28FAlPysTx9DMYvLwa-2-7" target="tM_Gde3HH8YiZ2frBV5J-0" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="28FAlPysTx9DMYvLwa-2-7" value="String Output" style="whiteSpace=wrap;html=1;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" vertex="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry x="260" y="122.5" width="120" height="60" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-1" value="ServiceAction &lt;DS&gt;" style="whiteSpace=wrap;html=1;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" vertex="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry x="800" y="542.5" width="120" height="60" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-6" value="Use" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;endArrow=open;endFill=0;strokeColor=#f0f0f0;dashed=1;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="UY-EM7-1ECCvWtENr50b-2" target="UY-EM7-1ECCvWtENr50b-1" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-20" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=1;entryY=0.75;entryDx=0;entryDy=0;endArrow=open;endFill=0;strokeColor=#006EAF;fillColor=#1ba1e2;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="UY-EM7-1ECCvWtENr50b-1" target="28FAlPysTx9DMYvLwa-2-1" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-2" value="&lt;&lt;Interface&gt;&gt;<br>IServiceManipulator" style="whiteSpace=wrap;html=1;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" vertex="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry x="800" y="432.5" width="120" height="60" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-22" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;endArrow=open;endFill=0;strokeColor=#006EAF;fillColor=#1ba1e2;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="UY-EM7-1ECCvWtENr50b-10" target="28FAlPysTx9DMYvLwa-2-5" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-10" value="ServicesResult &lt;DS&gt;" style="whiteSpace=wrap;html=1;fillColor=none;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" vertex="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry x="800" y="67.5" width="120" height="60" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-14" value="Use" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=open;endFill=0;strokeColor=#f0f0f0;dashed=1;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="UY-EM7-1ECCvWtENr50b-11" target="UY-EM7-1ECCvWtENr50b-10" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-21" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=1;entryY=0.75;entryDx=0;entryDy=0;endArrow=open;endFill=0;strokeColor=#006EAF;fillColor=#1ba1e2;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="28FAlPysTx9DMYvLwa-2-1" target="UY-EM7-1ECCvWtENr50b-10" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-11" value="&lt;&lt;Interface&gt;&gt;<br>IServicesMonitor" style="whiteSpace=wrap;html=1;fillColor=none;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" vertex="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry x="800" y="167.5" width="120" height="60" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-70" value="" style="line;strokeWidth=2;direction=south;html=1;fillColor=none;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" vertex="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry x="220" y="50" width="10" height="570" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-71" value="" style="line;strokeWidth=2;direction=south;html=1;fillColor=none;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" vertex="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry x="760" y="50" width="10" height="570" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="UY-EM7-1ECCvWtENr50b-73" value="Page 191 (Chapter 22) of Clean Architecture" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" vertex="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry y="870" width="480" height="20" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="tM_Gde3HH8YiZ2frBV5J-2" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;dashed=1;endArrow=block;endFill=0;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="tM_Gde3HH8YiZ2frBV5J-0" target="tM_Gde3HH8YiZ2frBV5J-1" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="tM_Gde3HH8YiZ2frBV5J-4" value="Use" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;dashed=1;endArrow=open;endFill=0;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" source="tM_Gde3HH8YiZ2frBV5J-0" target="tM_Gde3HH8YiZ2frBV5J-1" edge="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="tM_Gde3HH8YiZ2frBV5J-0" value="MainPresenter" style="html=1;dashed=0;whitespace=wrap;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" vertex="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry x="420" y="122.5" width="110" height="60" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxCell id="tM_Gde3HH8YiZ2frBV5J-1" value="&lt;&lt;Interface&gt;&gt;<br>IConsoleOutput" style="html=1;dashed=0;whitespace=wrap;sketch=1;" parent="jVG6p58vlRYGO9X4wXeX-1" vertex="1">
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
<mxGeometry x="420" y="20" width="110" height="50" as="geometry"/>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxCell>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</root>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</mxGraphModel>
|
||||

 
 



|
||||

 
 
 
 
 
 







|
||||
</diagram>
|
||||
</mxfile>
|
@ -7,7 +7,7 @@ using Xunit;
|
||||
namespace GameServiceWarden.Core.Tests.Modules.Games
|
||||
{
|
||||
// Testing convention from: https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices
|
||||
// Fakes are generic test objects,
|
||||
// fakes are generic test objects,
|
||||
// mocks are the objects being asserted upon,
|
||||
// stubs are objects used as part of the test.
|
||||
public class GameServiceInfoTest
|
||||
@ -63,7 +63,7 @@ namespace GameServiceWarden.Core.Tests.Modules.Games
|
||||
//When
|
||||
serviceInfo.SetConfigurableValue(stubConfigurable.OptionName, "success");
|
||||
//Then
|
||||
Assert.Equal<string>("success", serviceInfo.GetConfigurableValue(stubConfigurable.OptionName));
|
||||
Assert.True("success".Equals(serviceInfo.GetConfigurableValue(stubConfigurable.OptionName)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -98,7 +98,7 @@ namespace GameServiceWarden.Core.Tests.Modules.Games
|
||||
IGameService stubService = new FakeGameService();
|
||||
GameServiceInfo serviceInfo = new GameServiceInfo(stubService, MODULE_NAME, "FakeAssembly");
|
||||
//Then
|
||||
Assert.Equal(MODULE_NAME, serviceInfo.GetModuleName());
|
||||
Assert.Equal(MODULE_NAME, serviceInfo.ModuleName);
|
||||
serviceInfo.Dispose();
|
||||
}
|
||||
|
||||
@ -124,7 +124,7 @@ namespace GameServiceWarden.Core.Tests.Modules.Games
|
||||
//When
|
||||
serviceInfo.ServiceName = SERVICE_NAME;
|
||||
//Then
|
||||
Assert.Equal(SERVICE_NAME, serviceInfo.ServiceName);
|
||||
Assert.True(SERVICE_NAME.Equals(serviceInfo.ServiceName));
|
||||
serviceInfo.Dispose();
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using GameServiceWarden.Core.Games;
|
||||
using GameServiceWarden.ModuleAPI;
|
||||
@ -14,12 +16,14 @@ namespace GameServiceWarden.Core.Tests.Modules.Games
|
||||
//Given
|
||||
const string ASSEMBLY_NAME = "FakeAssembly";
|
||||
const string FAKE_SERVICE_NAME = "FakeService";
|
||||
FakePersistentDictionary<IGameServiceModule> stubPersistentModuleDictionary = new FakePersistentDictionary<IGameServiceModule>();
|
||||
FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>> stubPersistentModuleDictionary = new FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>>();
|
||||
FakePersistentDictionary<GameServiceInfo> stubPersistentServiceDictionary = new FakePersistentDictionary<GameServiceInfo>();
|
||||
GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary);
|
||||
Dictionary<string, IGameServiceModule> stubAssemblyModulesDictionary = new Dictionary<string, IGameServiceModule>();
|
||||
IGameServiceModule stubGameServiceModule = new FakeGameServiceModule();
|
||||
stubAssemblyModulesDictionary.Add(stubGameServiceModule.Name, stubGameServiceModule);
|
||||
stubPersistentModuleDictionary.Add(ASSEMBLY_NAME, stubAssemblyModulesDictionary);
|
||||
//When
|
||||
stubPersistentModuleDictionary.Add(ASSEMBLY_NAME + Path.DirectorySeparatorChar + stubGameServiceModule.Name, stubGameServiceModule);
|
||||
serviceManager.CreateService(FAKE_SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name);
|
||||
//Then
|
||||
Assert.Contains<string>(FAKE_SERVICE_NAME, serviceManager.GetServiceNames());
|
||||
@ -31,12 +35,14 @@ namespace GameServiceWarden.Core.Tests.Modules.Games
|
||||
//Given
|
||||
const string ASSEMBLY_NAME = "FakeAssembly";
|
||||
const string FAKE_SERVICE_NAME = "FakeService";
|
||||
FakePersistentDictionary<IGameServiceModule> stubPersistentModuleDictionary = new FakePersistentDictionary<IGameServiceModule>();
|
||||
FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>> stubPersistentModuleDictionary = new FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>>();
|
||||
FakePersistentDictionary<GameServiceInfo> stubPersistentServiceDictionary = new FakePersistentDictionary<GameServiceInfo>();
|
||||
GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary);
|
||||
Dictionary<string, IGameServiceModule> stubAssemblyModulesDictionary = new Dictionary<string, IGameServiceModule>();
|
||||
IGameServiceModule stubGameServiceModule = new FakeGameServiceModule();
|
||||
stubAssemblyModulesDictionary.Add(stubGameServiceModule.Name, stubGameServiceModule);
|
||||
stubPersistentModuleDictionary.Add(ASSEMBLY_NAME, stubAssemblyModulesDictionary);
|
||||
//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
|
||||
@ -49,12 +55,14 @@ namespace GameServiceWarden.Core.Tests.Modules.Games
|
||||
//Given
|
||||
const string ASSEMBLY_NAME = "FakeAssembly";
|
||||
const string FAKE_SERVICE_PREFIX = "FakeService_";
|
||||
FakePersistentDictionary<IGameServiceModule> stubPersistentModuleDictionary = new FakePersistentDictionary<IGameServiceModule>();
|
||||
FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>> stubPersistentModuleDictionary = new FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>>();
|
||||
FakePersistentDictionary<GameServiceInfo> stubPersistentServiceDictionary = new FakePersistentDictionary<GameServiceInfo>();
|
||||
GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary);
|
||||
Dictionary<string, IGameServiceModule> stubAssemblyModulesDictionary = new Dictionary<string, IGameServiceModule>();
|
||||
IGameServiceModule stubGameServiceModule = new FakeGameServiceModule();
|
||||
stubAssemblyModulesDictionary.Add(stubGameServiceModule.Name, stubGameServiceModule);
|
||||
stubPersistentModuleDictionary.Add(ASSEMBLY_NAME, stubAssemblyModulesDictionary);
|
||||
//When
|
||||
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);
|
||||
@ -71,42 +79,45 @@ namespace GameServiceWarden.Core.Tests.Modules.Games
|
||||
{
|
||||
//Given
|
||||
const string ASSEMBLY_NAME = "FakeAssembly";
|
||||
const string SERVICE_NAME = "FakeService";
|
||||
FakePersistentDictionary<IGameServiceModule> stubPersistentModuleDictionary = new FakePersistentDictionary<IGameServiceModule>();
|
||||
const string FAKE_SERVICE_NAME = "FakeService";
|
||||
FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>> stubPersistentModuleDictionary = new FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>>();
|
||||
FakePersistentDictionary<GameServiceInfo> stubPersistentServiceDictionary = new FakePersistentDictionary<GameServiceInfo>();
|
||||
GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary);
|
||||
Dictionary<string, IGameServiceModule> stubAssemblyModulesDictionary = new Dictionary<string, IGameServiceModule>();
|
||||
IGameServiceModule stubGameServiceModule = new FakeGameServiceModule(
|
||||
new FakeGameConfigurable("A"),
|
||||
new FakeGameConfigurable("B"),
|
||||
new FakeGameConfigurable("C")
|
||||
);
|
||||
stubAssemblyModulesDictionary.Add(stubGameServiceModule.Name, stubGameServiceModule);
|
||||
stubPersistentModuleDictionary.Add(ASSEMBLY_NAME, stubAssemblyModulesDictionary);
|
||||
//When
|
||||
stubPersistentModuleDictionary.Add(ASSEMBLY_NAME + Path.DirectorySeparatorChar + stubGameServiceModule.Name, stubGameServiceModule);
|
||||
serviceManager.CreateService(SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name);
|
||||
serviceManager.CreateService(FAKE_SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name);
|
||||
//Then
|
||||
Assert.Contains<string>("A", serviceManager.GetServiceOptions(SERVICE_NAME));
|
||||
Assert.Contains<string>("B", serviceManager.GetServiceOptions(SERVICE_NAME));
|
||||
Assert.Contains<string>("C", serviceManager.GetServiceOptions(SERVICE_NAME));
|
||||
Assert.Contains<string>("A", serviceManager.GetServiceOptions(FAKE_SERVICE_NAME));
|
||||
Assert.Contains<string>("B", serviceManager.GetServiceOptions(FAKE_SERVICE_NAME));
|
||||
Assert.Contains<string>("C", serviceManager.GetServiceOptions(FAKE_SERVICE_NAME));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetandGetServiceOptionValue_OneOption_OptionChanged()
|
||||
{
|
||||
//Given
|
||||
const string ASSEMBLY_NAME = "FakeAssembly";
|
||||
const string SERVICE_NAME = "FakeService";
|
||||
FakePersistentDictionary<IGameServiceModule> stubPersistentModuleDictionary = new FakePersistentDictionary<IGameServiceModule>();
|
||||
const string FAKE_SERVICE_NAME = "FakeService";
|
||||
FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>> stubPersistentModuleDictionary = new FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>>();
|
||||
FakePersistentDictionary<GameServiceInfo> stubPersistentServiceDictionary = new FakePersistentDictionary<GameServiceInfo>();
|
||||
GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary);
|
||||
Dictionary<string, IGameServiceModule> stubAssemblyModulesDictionary = new Dictionary<string, IGameServiceModule>();
|
||||
IGameServiceModule stubGameServiceModule = new FakeGameServiceModule(
|
||||
new FakeGameConfigurable("A")
|
||||
);
|
||||
stubAssemblyModulesDictionary.Add(stubGameServiceModule.Name, stubGameServiceModule);
|
||||
stubPersistentModuleDictionary.Add(ASSEMBLY_NAME, stubAssemblyModulesDictionary);
|
||||
//When
|
||||
stubPersistentModuleDictionary.Add(ASSEMBLY_NAME + Path.DirectorySeparatorChar + stubGameServiceModule.Name, stubGameServiceModule);
|
||||
serviceManager.CreateService(SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name);
|
||||
serviceManager.SetServiceOptionValue(SERVICE_NAME, "A", "Test");
|
||||
serviceManager.CreateService(FAKE_SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name);
|
||||
serviceManager.SetServiceOptionValue(FAKE_SERVICE_NAME, "A", "Test");
|
||||
//Then
|
||||
Assert.Equal<string>("Test", serviceManager.GetServiceOptionValue(SERVICE_NAME, "A"));
|
||||
Assert.True("Test".Equals(serviceManager.GetServiceOptionValue(FAKE_SERVICE_NAME, "A")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -114,16 +125,18 @@ namespace GameServiceWarden.Core.Tests.Modules.Games
|
||||
{
|
||||
//Given
|
||||
const string ASSEMBLY_NAME = "FakeAssembly";
|
||||
const string SERVICE_NAME = "FakeService";
|
||||
FakePersistentDictionary<IGameServiceModule> stubPersistentModuleDictionary = new FakePersistentDictionary<IGameServiceModule>();
|
||||
const string FAKE_SERVICE_NAME = "FakeService";
|
||||
FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>> stubPersistentModuleDictionary = new FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>>();
|
||||
FakePersistentDictionary<GameServiceInfo> stubPersistentServiceDictionary = new FakePersistentDictionary<GameServiceInfo>();
|
||||
GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary);
|
||||
Dictionary<string, IGameServiceModule> stubAssemblyModulesDictionary = new Dictionary<string, IGameServiceModule>();
|
||||
IGameServiceModule stubGameServiceModule = new FakeGameServiceModule();
|
||||
stubAssemblyModulesDictionary.Add(stubGameServiceModule.Name, stubGameServiceModule);
|
||||
stubPersistentModuleDictionary.Add(ASSEMBLY_NAME, stubAssemblyModulesDictionary);
|
||||
//When
|
||||
stubPersistentModuleDictionary.Add(ASSEMBLY_NAME + Path.DirectorySeparatorChar + stubGameServiceModule.Name, stubGameServiceModule);
|
||||
serviceManager.CreateService(SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name);
|
||||
serviceManager.CreateService(FAKE_SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name);
|
||||
//Then
|
||||
Assert.Equal<ServiceState>(ServiceState.Stopped, serviceManager.GetServiceState(SERVICE_NAME));
|
||||
Assert.Equal<ServiceState>(ServiceState.Stopped, serviceManager.GetServiceState(FAKE_SERVICE_NAME));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -131,17 +144,19 @@ namespace GameServiceWarden.Core.Tests.Modules.Games
|
||||
{
|
||||
//Given
|
||||
const string ASSEMBLY_NAME = "FakeAssembly";
|
||||
const string SERVICE_NAME = "FakeService";
|
||||
FakePersistentDictionary<IGameServiceModule> stubPersistentModuleDictionary = new FakePersistentDictionary<IGameServiceModule>();
|
||||
const string FAKE_SERVICE_NAME = "FakeService";
|
||||
FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>> stubPersistentModuleDictionary = new FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>>();
|
||||
FakePersistentDictionary<GameServiceInfo> stubPersistentServiceDictionary = new FakePersistentDictionary<GameServiceInfo>();
|
||||
GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary);
|
||||
Dictionary<string, IGameServiceModule> stubAssemblyModulesDictionary = new Dictionary<string, IGameServiceModule>();
|
||||
IGameServiceModule stubGameServiceModule = new FakeGameServiceModule();
|
||||
stubAssemblyModulesDictionary.Add(stubGameServiceModule.Name, stubGameServiceModule);
|
||||
stubPersistentModuleDictionary.Add(ASSEMBLY_NAME, stubAssemblyModulesDictionary);
|
||||
//When
|
||||
stubPersistentModuleDictionary.Add(ASSEMBLY_NAME + Path.DirectorySeparatorChar + stubGameServiceModule.Name, stubGameServiceModule);
|
||||
serviceManager.CreateService(SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name);
|
||||
serviceManager.StartService(SERVICE_NAME);
|
||||
serviceManager.CreateService(FAKE_SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name);
|
||||
serviceManager.StartService(FAKE_SERVICE_NAME);
|
||||
//Then
|
||||
Assert.Equal<ServiceState>(ServiceState.Running, serviceManager.GetServiceState(SERVICE_NAME));
|
||||
Assert.Equal<ServiceState>(ServiceState.Running, serviceManager.GetServiceState(FAKE_SERVICE_NAME));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -149,17 +164,19 @@ namespace GameServiceWarden.Core.Tests.Modules.Games
|
||||
{
|
||||
//Given
|
||||
const string ASSEMBLY_NAME = "FakeAssembly";
|
||||
const string SERVICE_NAME = "FakeService";
|
||||
FakePersistentDictionary<IGameServiceModule> stubPersistentModuleDictionary = new FakePersistentDictionary<IGameServiceModule>();
|
||||
const string FAKE_SERVICE_NAME = "FakeService";
|
||||
FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>> stubPersistentModuleDictionary = new FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>>();
|
||||
FakePersistentDictionary<GameServiceInfo> stubPersistentServiceDictionary = new FakePersistentDictionary<GameServiceInfo>();
|
||||
GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary);
|
||||
Dictionary<string, IGameServiceModule> stubAssemblyModulesDictionary = new Dictionary<string, IGameServiceModule>();
|
||||
IGameServiceModule stubGameServiceModule = new FakeGameServiceModule();
|
||||
stubAssemblyModulesDictionary.Add(stubGameServiceModule.Name, stubGameServiceModule);
|
||||
stubPersistentModuleDictionary.Add(ASSEMBLY_NAME, stubAssemblyModulesDictionary);
|
||||
//When
|
||||
stubPersistentModuleDictionary.Add(ASSEMBLY_NAME + Path.DirectorySeparatorChar + stubGameServiceModule.Name, stubGameServiceModule);
|
||||
serviceManager.CreateService(SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name);
|
||||
serviceManager.StartService(SERVICE_NAME);
|
||||
serviceManager.CreateService(FAKE_SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name);
|
||||
serviceManager.StartService(FAKE_SERVICE_NAME);
|
||||
//Then
|
||||
Assert.Equal<ServiceState>(ServiceState.Running, serviceManager.GetServiceState(SERVICE_NAME));
|
||||
Assert.Equal<ServiceState>(ServiceState.Running, serviceManager.GetServiceState(FAKE_SERVICE_NAME));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -167,18 +184,20 @@ namespace GameServiceWarden.Core.Tests.Modules.Games
|
||||
{
|
||||
//Given
|
||||
const string ASSEMBLY_NAME = "FakeAssembly";
|
||||
const string SERVICE_NAME = "FakeService";
|
||||
FakePersistentDictionary<IGameServiceModule> stubPersistentModuleDictionary = new FakePersistentDictionary<IGameServiceModule>();
|
||||
const string FAKE_SERVICE_NAME = "FakeService";
|
||||
FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>> stubPersistentModuleDictionary = new FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>>();
|
||||
FakePersistentDictionary<GameServiceInfo> stubPersistentServiceDictionary = new FakePersistentDictionary<GameServiceInfo>();
|
||||
GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary);
|
||||
Dictionary<string, IGameServiceModule> stubAssemblyModulesDictionary = new Dictionary<string, IGameServiceModule>();
|
||||
IGameServiceModule stubGameServiceModule = new FakeGameServiceModule();
|
||||
stubAssemblyModulesDictionary.Add(stubGameServiceModule.Name, stubGameServiceModule);
|
||||
stubPersistentModuleDictionary.Add(ASSEMBLY_NAME, stubAssemblyModulesDictionary);
|
||||
//When
|
||||
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);
|
||||
serviceManager.CreateService(FAKE_SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name);
|
||||
serviceManager.StartService(FAKE_SERVICE_NAME);
|
||||
serviceManager.StopService(FAKE_SERVICE_NAME);
|
||||
//Then
|
||||
Assert.Equal<ServiceState>(ServiceState.Stopped, serviceManager.GetServiceState(SERVICE_NAME));
|
||||
Assert.Equal<ServiceState>(ServiceState.Stopped, serviceManager.GetServiceState(FAKE_SERVICE_NAME));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -186,22 +205,24 @@ namespace GameServiceWarden.Core.Tests.Modules.Games
|
||||
{
|
||||
//Given
|
||||
const string ASSEMBLY_NAME = "FakeAssembly";
|
||||
const string SERVICE_NAME = "FakeService";
|
||||
FakePersistentDictionary<IGameServiceModule> stubPersistentModuleDictionary = new FakePersistentDictionary<IGameServiceModule>();
|
||||
const string FAKE_SERVICE_NAME = "FakeService";
|
||||
FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>> stubPersistentModuleDictionary = new FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>>();
|
||||
FakePersistentDictionary<GameServiceInfo> stubPersistentServiceDictionary = new FakePersistentDictionary<GameServiceInfo>();
|
||||
GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary);
|
||||
Dictionary<string, IGameServiceModule> stubAssemblyModulesDictionary = new Dictionary<string, IGameServiceModule>();
|
||||
IGameServiceModule stubGameServiceModule = new FakeGameServiceModule();
|
||||
stubAssemblyModulesDictionary.Add(stubGameServiceModule.Name, stubGameServiceModule);
|
||||
stubPersistentModuleDictionary.Add(ASSEMBLY_NAME, stubAssemblyModulesDictionary);
|
||||
//When
|
||||
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");
|
||||
serviceManager.CreateService(FAKE_SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name);
|
||||
serviceManager.StartService(FAKE_SERVICE_NAME);
|
||||
serviceManager.ExecuteCommand(FAKE_SERVICE_NAME, "Test");
|
||||
//Then
|
||||
Stream stream = serviceManager.GetServiceConsoleStream(SERVICE_NAME);
|
||||
Stream stream = serviceManager.GetServiceConsoleStream(FAKE_SERVICE_NAME);
|
||||
stream.Position = 0;
|
||||
using (StreamReader reader = new StreamReader(stream))
|
||||
{
|
||||
Assert.Equal<string>("Test", reader.ReadLine());
|
||||
Assert.True("Test".Equals(reader.ReadLine()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,16 +231,22 @@ namespace GameServiceWarden.Core.Tests.Modules.Games
|
||||
{
|
||||
//Given
|
||||
const string ASSEMBLY_NAME = "FakeAssembly";
|
||||
const string SERVICE_NAME = "FakeService";
|
||||
FakePersistentDictionary<IGameServiceModule> stubPersistentModuleDictionary = new FakePersistentDictionary<IGameServiceModule>();
|
||||
const string FAKE_SERVICE_NAME = "FakeService";
|
||||
FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>> stubPersistentModuleDictionary = new FakePersistentDictionary<IReadOnlyDictionary<string, IGameServiceModule>>();
|
||||
FakePersistentDictionary<GameServiceInfo> stubPersistentServiceDictionary = new FakePersistentDictionary<GameServiceInfo>();
|
||||
GameServiceManager serviceManager = new GameServiceManager(stubPersistentServiceDictionary, stubPersistentModuleDictionary);
|
||||
Dictionary<string, IGameServiceModule> stubAssemblyModulesDictionary = new Dictionary<string, IGameServiceModule>();
|
||||
IGameServiceModule stubGameServiceModule = new FakeGameServiceModule();
|
||||
stubAssemblyModulesDictionary.Add(stubGameServiceModule.Name, stubGameServiceModule);
|
||||
stubPersistentModuleDictionary.Add(ASSEMBLY_NAME, stubAssemblyModulesDictionary);
|
||||
//When
|
||||
stubPersistentModuleDictionary.Add(ASSEMBLY_NAME + Path.DirectorySeparatorChar + stubGameServiceModule.Name, stubGameServiceModule);
|
||||
serviceManager.CreateService(SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name);
|
||||
serviceManager.CreateService(FAKE_SERVICE_NAME, ASSEMBLY_NAME, stubGameServiceModule.Name);
|
||||
//Then
|
||||
Assert.Null(serviceManager.GetServiceConsoleStream(SERVICE_NAME));
|
||||
Action action = delegate()
|
||||
{
|
||||
serviceManager.GetServiceConsoleStream(FAKE_SERVICE_NAME);
|
||||
};
|
||||
Assert.Throws<InvalidOperationException>(action);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user