From 3948223b522a578adca44d13b15084c9ac52136f Mon Sep 17 00:00:00 2001 From: Halil ibrahim Kalkan Date: Sat, 6 Apr 2019 22:21:11 +0300 Subject: [PATCH] Added scenario concept --- .../Volo.Abp.Core/Volo/Abp/RandomHelper.cs | 2 +- .../Pages/Index.cshtml | 8 +- .../Pages/SimulationArea.cshtml | 7 +- .../Pages/SimulationArea.css | 5 + .../Pages/SimulationArea.min.css | 1 + .../Pages/SimulationArea.scss | 6 + .../Volo.ClientSimulation.Web.csproj | 8 ++ .../compilerconfig.json | 6 + .../compilerconfig.json.defaults | 63 +++++++++ .../ClientSimulationModule.cs | 10 +- .../ClientSimulationOptions.cs | 15 +++ .../Volo/ClientSimulation/Clients/Client.cs | 46 +++++-- .../Volo/ClientSimulation/Clients/IClient.cs | 3 + .../Clients/IClientFactory.cs | 20 +++ .../Clients/IDisposableClientHandler.cs | 24 ++++ .../ClientSimulation/Scenarios/Scenario.cs | 122 ++++++++++++++++++ .../Volo/ClientSimulation/Simulation.cs | 37 +++--- 17 files changed, 347 insertions(+), 36 deletions(-) create mode 100644 utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/SimulationArea.css create mode 100644 utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/SimulationArea.min.css create mode 100644 utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/SimulationArea.scss create mode 100644 utils/client-simulation/src/Volo.ClientSimulation.Web/compilerconfig.json create mode 100644 utils/client-simulation/src/Volo.ClientSimulation.Web/compilerconfig.json.defaults create mode 100644 utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/ClientSimulationOptions.cs create mode 100644 utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/IClientFactory.cs create mode 100644 utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/IDisposableClientHandler.cs create mode 100644 utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Scenarios/Scenario.cs diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/RandomHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/RandomHelper.cs index 97992ad27d..361173387e 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/RandomHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/RandomHelper.cs @@ -77,7 +77,7 @@ namespace Volo.Abp /// /// Type of the objects /// List of object to select a random one - public static T GetRandomOf([NotNull] IList list) + public static T GetRandomOfList([NotNull] IList list) { Check.NotNullOrEmpty(list, nameof(list)); diff --git a/utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/Index.cshtml b/utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/Index.cshtml index 59a0e0e435..48292e6dd0 100644 --- a/utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/Index.cshtml +++ b/utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/Index.cshtml @@ -1,7 +1,11 @@ @page @model Volo.ClientSimulation.Web.Pages.IndexModel -@section scripts - { +@section styles { + + + +} +@section scripts { diff --git a/utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/SimulationArea.cshtml b/utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/SimulationArea.cshtml index 97dca18d7e..fb97b9be73 100644 --- a/utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/SimulationArea.cshtml +++ b/utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/SimulationArea.cshtml @@ -17,6 +17,11 @@ - Active client count: @Model.Simulation.ActiveClients.Count + @foreach (var clientHandler in Model.Simulation.ActiveClients) + { + + [@clientHandler.Client.State] @clientHandler.Client.Scenario.GetDisplayText(): @clientHandler.Client.Scenario.CurrentStep.GetDisplayText() + + } \ No newline at end of file diff --git a/utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/SimulationArea.css b/utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/SimulationArea.css new file mode 100644 index 0000000000..30cd9cb44e --- /dev/null +++ b/utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/SimulationArea.css @@ -0,0 +1,5 @@ +.simulation-client { + border: 1px solid #008000; + background-color: #d6ffce; + margin: 3px; + padding: 5px; } diff --git a/utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/SimulationArea.min.css b/utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/SimulationArea.min.css new file mode 100644 index 0000000000..b5120f66b5 --- /dev/null +++ b/utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/SimulationArea.min.css @@ -0,0 +1 @@ +.simulation-client{border:1px solid #008000;background-color:#d6ffce;margin:3px;padding:5px;} \ No newline at end of file diff --git a/utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/SimulationArea.scss b/utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/SimulationArea.scss new file mode 100644 index 0000000000..b43f39c08f --- /dev/null +++ b/utils/client-simulation/src/Volo.ClientSimulation.Web/Pages/SimulationArea.scss @@ -0,0 +1,6 @@ +.simulation-client { + border: 1px solid #008000; + background-color: #d6ffce; + margin: 3px; + padding: 5px; +} diff --git a/utils/client-simulation/src/Volo.ClientSimulation.Web/Volo.ClientSimulation.Web.csproj b/utils/client-simulation/src/Volo.ClientSimulation.Web/Volo.ClientSimulation.Web.csproj index d654badfe3..1de5b06cf0 100644 --- a/utils/client-simulation/src/Volo.ClientSimulation.Web/Volo.ClientSimulation.Web.csproj +++ b/utils/client-simulation/src/Volo.ClientSimulation.Web/Volo.ClientSimulation.Web.csproj @@ -24,4 +24,12 @@ + + + + + + + + diff --git a/utils/client-simulation/src/Volo.ClientSimulation.Web/compilerconfig.json b/utils/client-simulation/src/Volo.ClientSimulation.Web/compilerconfig.json new file mode 100644 index 0000000000..d3e2a7ea96 --- /dev/null +++ b/utils/client-simulation/src/Volo.ClientSimulation.Web/compilerconfig.json @@ -0,0 +1,6 @@ +[ + { + "outputFile": "Pages/SimulationArea.css", + "inputFile": "Pages/SimulationArea.scss" + } +] \ No newline at end of file diff --git a/utils/client-simulation/src/Volo.ClientSimulation.Web/compilerconfig.json.defaults b/utils/client-simulation/src/Volo.ClientSimulation.Web/compilerconfig.json.defaults new file mode 100644 index 0000000000..b3519312c4 --- /dev/null +++ b/utils/client-simulation/src/Volo.ClientSimulation.Web/compilerconfig.json.defaults @@ -0,0 +1,63 @@ +{ + "compilers": { + "less": { + "autoPrefix": "", + "cssComb": "none", + "ieCompat": true, + "strictMath": false, + "strictUnits": false, + "relativeUrls": true, + "rootPath": "", + "sourceMapRoot": "", + "sourceMapBasePath": "", + "sourceMap": false + }, + "sass": { + "autoPrefix": "", + "includePath": "", + "indentType": "space", + "indentWidth": 2, + "outputStyle": "nested", + "Precision": 5, + "relativeUrls": true, + "sourceMapRoot": "", + "lineFeed": "", + "sourceMap": false + }, + "stylus": { + "sourceMap": false + }, + "babel": { + "sourceMap": false + }, + "coffeescript": { + "bare": false, + "runtimeMode": "node", + "sourceMap": false + }, + "handlebars": { + "root": "", + "noBOM": false, + "name": "", + "namespace": "", + "knownHelpersOnly": false, + "forcePartial": false, + "knownHelpers": [], + "commonjs": "", + "amd": false, + "sourceMap": false + } + }, + "minifiers": { + "css": { + "enabled": true, + "termSemicolons": true, + "gzip": false + }, + "javascript": { + "enabled": true, + "termSemicolons": true, + "gzip": false + } + } +} \ No newline at end of file diff --git a/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/ClientSimulationModule.cs b/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/ClientSimulationModule.cs index 5bf3380a8a..28f79b1ba3 100644 --- a/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/ClientSimulationModule.cs +++ b/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/ClientSimulationModule.cs @@ -1,5 +1,6 @@ using Volo.Abp.Http.Client.IdentityModel; using Volo.Abp.Modularity; +using Volo.ClientSimulation.Scenarios; namespace Volo.ClientSimulation { @@ -8,6 +9,13 @@ namespace Volo.ClientSimulation )] public class ClientSimulationModule : AbpModule { - + public override void ConfigureServices(ServiceConfigurationContext context) + { + //TODO: Temporary add a DemoScenario, remove later + Configure(options => + { + options.Scenarios.Add(new DemoScenario()); + }); + } } } diff --git a/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/ClientSimulationOptions.cs b/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/ClientSimulationOptions.cs new file mode 100644 index 0000000000..8de165fd2b --- /dev/null +++ b/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/ClientSimulationOptions.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using Volo.ClientSimulation.Scenarios; + +namespace Volo.ClientSimulation +{ + public class ClientSimulationOptions + { + public List Scenarios { get; } + + public ClientSimulationOptions() + { + Scenarios = new List(); + } + } +} diff --git a/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/Client.cs b/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/Client.cs index a9df1fd974..059c8b8ae5 100644 --- a/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/Client.cs +++ b/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/Client.cs @@ -1,45 +1,65 @@ using System; using System.Threading; -using Volo.Abp.DependencyInjection; +using Volo.ClientSimulation.Scenarios; namespace Volo.ClientSimulation.Clients { - public class Client : IClient, ITransientDependency + public class Client : IClient { + public IScenario Scenario { get; } + public event EventHandler Stopped; - public ClientState State { get; private set; } + public ClientState State + { + get => _state; + private set => _state = value; + } + private volatile ClientState _state; private Thread _thread; - public Client() + protected readonly object SyncLock = new object(); + + public Client(IScenario scenario) { - + Scenario = scenario; } public void Start() { - if (State != ClientState.Stopped) + lock (SyncLock) { - throw new ApplicationException("State is not stopped. It is " + State); - } + if (State != ClientState.Stopped) + { + throw new ApplicationException("State is not stopped. It is " + State); + } - State = ClientState.Running; + State = ClientState.Running; - _thread = new Thread(Run); - _thread.Start(); + _thread = new Thread(Run); + _thread.Start(); + } } public void Stop() { - State = ClientState.Stopping; + lock (SyncLock) + { + if (State != ClientState.Running) + { + return; + } + + State = ClientState.Stopping; + } } private void Run() { while (State == ClientState.Running) { - Thread.Sleep(1); + Scenario.Proceed(); } State = ClientState.Stopped; diff --git a/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/IClient.cs b/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/IClient.cs index 869645392c..d056123c07 100644 --- a/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/IClient.cs +++ b/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/IClient.cs @@ -1,9 +1,12 @@ using System; +using Volo.ClientSimulation.Scenarios; namespace Volo.ClientSimulation.Clients { public interface IClient { + IScenario Scenario { get; } + event EventHandler Stopped; ClientState State { get; } diff --git a/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/IClientFactory.cs b/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/IClientFactory.cs new file mode 100644 index 0000000000..0fd4d64849 --- /dev/null +++ b/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/IClientFactory.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using System.Text; +using Volo.Abp.DependencyInjection; +using Volo.ClientSimulation.Scenarios; + +namespace Volo.ClientSimulation.Clients +{ + public interface IClientFactory + { + IDisposableClientHandler Create(IScenario scenario); + } + + public class DefaultClientFactory : IClientFactory, ISingletonDependency + { + public IDisposableClientHandler Create(IScenario scenario) + { + return new DisposableClientHandler(new Client(scenario)); + } + } +} diff --git a/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/IDisposableClientHandler.cs b/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/IDisposableClientHandler.cs new file mode 100644 index 0000000000..7d9799823e --- /dev/null +++ b/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/IDisposableClientHandler.cs @@ -0,0 +1,24 @@ +using System; + +namespace Volo.ClientSimulation.Clients +{ + public interface IDisposableClientHandler : IDisposable + { + IClient Client { get; } + } + + public class DisposableClientHandler : IDisposableClientHandler + { + public IClient Client { get; } + + public DisposableClientHandler(IClient client) + { + Client = client; + } + + public virtual void Dispose() + { + + } + } +} \ No newline at end of file diff --git a/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Scenarios/Scenario.cs b/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Scenarios/Scenario.cs new file mode 100644 index 0000000000..48170ee6c5 --- /dev/null +++ b/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Scenarios/Scenario.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Text; +using System.Threading; + +namespace Volo.ClientSimulation.Scenarios +{ + public abstract class Scenario : IScenario + { + public IReadOnlyList Steps => StepList.ToImmutableList(); + protected List StepList { get; } + + public IScenarioStep CurrentStep + { + get + { + CheckStepCount(); + return StepList[CurrentStepIndex]; + } + } + public int CurrentStepIndex { get; protected set; } + + protected Scenario() + { + StepList = new List(); + } + + public virtual string GetDisplayText() + { + return GetType() + .Name + .RemovePostFix(nameof(Scenario)); + } + + public virtual void Proceed() + { + CheckStepCount(); + + StepList[CurrentStepIndex].Run(); + + CurrentStepIndex++; + + if (CurrentStepIndex >= StepList.Count) + { + CurrentStepIndex = 0; + } + } + + private void CheckStepCount() + { + if (StepList.Count <= 0) + { + throw new ApplicationException( + $"No Steps defined for the scenario '{GetDisplayText()}'" + ); + } + } + + protected void AddStep(IScenarioStep step) + { + StepList.Add(step); + } + } + + public interface IScenario + { + IReadOnlyList Steps { get; } + + IScenarioStep CurrentStep { get; } + + int CurrentStepIndex { get; } + + string GetDisplayText(); + + void Proceed(); + } + + public interface IScenarioStep + { + void Run(); + + string GetDisplayText(); + } + + public abstract class ScenarioStep : IScenarioStep + { + public abstract void Run(); + + public virtual string GetDisplayText() + { + return GetType() + .Name + .RemovePostFix(nameof(ScenarioStep)); + } + } + + public class DemoScenario : Scenario + { + public DemoScenario() + { + AddStep(new SleepScenarioStep()); + AddStep(new SleepScenarioStep(3000)); + AddStep(new SleepScenarioStep()); + } + } + + public class SleepScenarioStep : ScenarioStep + { + public int Duration { get; } + + public SleepScenarioStep(int duration = 1000) + { + Duration = duration; + } + + public override void Run() + { + Thread.Sleep(Duration); + } + } +} diff --git a/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Simulation.cs b/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Simulation.cs index 314eb6318f..b266ea9c7c 100644 --- a/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Simulation.cs +++ b/utils/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Simulation.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp; using Volo.Abp.DependencyInjection; using Volo.ClientSimulation.Clients; namespace Volo.ClientSimulation { - public class Simulation : ISingletonDependency, IDisposable + public class Simulation : ISingletonDependency { public GlobalOptions GlobalOptions { get; } @@ -14,17 +15,21 @@ namespace Volo.ClientSimulation public SimulationState State { get; private set; } - public List ActiveClients { get; } + public List ActiveClients { get; } - private readonly IServiceScope _serviceScope; + protected IClientFactory ClientFactory { get; } + + protected ClientSimulationOptions Options { get; } public Simulation( - GlobalOptions globalOptions, - IServiceScopeFactory serviceScopeFactory) + GlobalOptions globalOptions, + IClientFactory clientFactory, + IOptions options) { - _serviceScope = serviceScopeFactory.CreateScope(); GlobalOptions = globalOptions; - ActiveClients = new List(); + ClientFactory = clientFactory; + Options = options.Value; + ActiveClients = new List(); } public void Start() @@ -39,13 +44,14 @@ namespace Volo.ClientSimulation for (int i = 0; i < CurrentOptions.MaxClientCount; i++) { - ActiveClients.Add(_serviceScope.ServiceProvider.GetRequiredService()); + var selectedScenario = RandomHelper.GetRandomOfList(Options.Scenarios); + ActiveClients.Add(ClientFactory.Create(selectedScenario)); } foreach (var activeClient in ActiveClients) { - activeClient.Stopped += ActiveClientOnStopped; - activeClient.Start(); + activeClient.Client.Stopped += ActiveClientOnStopped; + activeClient.Client.Start(); } } @@ -60,7 +66,7 @@ namespace Volo.ClientSimulation { foreach (var activeClient in ActiveClients) { - activeClient.Stop(); + activeClient.Client.Stop(); } } @@ -73,13 +79,8 @@ namespace Volo.ClientSimulation lock (ActiveClients) { - ActiveClients.Remove(client); + ActiveClients.RemoveAll(c => c.Client == client); } } - - public void Dispose() - { - _serviceScope.Dispose(); - } } }