Browse Source

Introduce SimulationSnapshot

pull/975/head
Halil ibrahim Kalkan 8 years ago
parent
commit
ad2609aab8
  1. 12
      modules/client-simulation/src/Volo.ClientSimulation.Web/Pages/ClientSimulation/SimulationArea.cshtml
  2. 6
      modules/client-simulation/src/Volo.ClientSimulation.Web/Pages/ClientSimulation/SimulationArea.cshtml.cs
  3. 33
      modules/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/Client.cs
  4. 8
      modules/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/IClient.cs
  5. 41
      modules/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Scenarios/Scenario.cs
  6. 9
      modules/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Scenarios/ScenarioStep.cs
  7. 106
      modules/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Simulation.cs
  8. 13
      modules/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Snapshot/ClientSnapshot.cs
  9. 15
      modules/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Snapshot/ScenarioSnapshot.cs
  10. 10
      modules/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Snapshot/ScenarioStepSnapshot.cs
  11. 13
      modules/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Snapshot/SimulationSnapshot.cs

12
modules/client-simulation/src/Volo.ClientSimulation.Web/Pages/ClientSimulation/SimulationArea.cshtml

@ -8,18 +8,18 @@
@model Volo.ClientSimulation.Pages.ClientSimulation.SimulationAreaModel @model Volo.ClientSimulation.Pages.ClientSimulation.SimulationAreaModel
<abp-alert alert-type="Primary"> <abp-alert alert-type="Primary">
<form class="d-inline" id="StartButtonForm" method="post" asp-page-handler="Start" data-ajaxForm="true"> <form class="d-inline" id="StartButtonForm" method="post" asp-page-handler="Start" data-ajaxForm="true">
<abp-button button-type="Primary" type="submit" disabled="@(Model.Simulation.State != SimulationState.Stopped)">Start</abp-button> <abp-button button-type="Primary" type="submit" disabled="@(Model.Snapshot.State != SimulationState.Stopped)">Start</abp-button>
</form> </form>
<form class="d-inline" id="StopButtonForm" method="post" asp-page-handler="Stop" data-ajaxForm="true"> <form class="d-inline" id="StopButtonForm" method="post" asp-page-handler="Stop" data-ajaxForm="true">
<abp-button button-type="Primary" type="submit" disabled="@(Model.Simulation.State != SimulationState.Started)">Stop</abp-button> <abp-button button-type="Primary" type="submit" disabled="@(Model.Snapshot.State != SimulationState.Started)">Stop</abp-button>
</form> </form>
<span class="ml-3"> <span class="ml-3">
@Model.Simulation.State @Model.Snapshot.State
</span> </span>
</abp-alert> </abp-alert>
<abp-card class="mt-3"> <abp-card class="mt-3">
<abp-card-body> <abp-card-body>
@foreach (var client in Model.Simulation.Clients) @foreach (var client in Model.Snapshot.Clients)
{ {
<span class="simulation-client simulation-client-@client.State.ToString().ToLowerInvariant()"> <span class="simulation-client simulation-client-@client.State.ToString().ToLowerInvariant()">
<span class="simulation-client-icon"> <span class="simulation-client-icon">
@ -37,12 +37,12 @@
} }
</span> </span>
<span class="simulation-client-scenario"> <span class="simulation-client-scenario">
@client.Scenario.GetDisplayText() @client.Scenario.DisplayText
</span> </span>
<span class="simulation-client-scenario-current-step"> <span class="simulation-client-scenario-current-step">
@if (client.State != ClientState.Stopped) @if (client.State != ClientState.Stopped)
{ {
<text>| @client.Scenario.CurrentStep.GetDisplayText()</text> <text>| @client.Scenario.CurrentStep.DisplayText</text>
} }
</span> </span>
</span> </span>

6
modules/client-simulation/src/Volo.ClientSimulation.Web/Pages/ClientSimulation/SimulationArea.cshtml.cs

@ -1,12 +1,15 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.RazorPages;
using Volo.ClientSimulation.Snapshot;
namespace Volo.ClientSimulation.Pages.ClientSimulation namespace Volo.ClientSimulation.Pages.ClientSimulation
{ {
public class SimulationAreaModel : PageModel public class SimulationAreaModel : PageModel
{ {
public Simulation Simulation { get; } public SimulationSnapshot Snapshot { get; private set; }
protected Simulation Simulation { get; }
public SimulationAreaModel(Simulation simulation) public SimulationAreaModel(Simulation simulation)
{ {
@ -15,6 +18,7 @@ namespace Volo.ClientSimulation.Pages.ClientSimulation
public Task OnGetAsync() public Task OnGetAsync()
{ {
Snapshot = Simulation.CreateSnapshot();
return Task.CompletedTask; return Task.CompletedTask;
} }

33
modules/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/Client.cs

@ -1,13 +1,17 @@
using System.Threading; using System;
using System.Threading;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading; using Volo.Abp.Threading;
using Volo.ClientSimulation.Scenarios; using Volo.ClientSimulation.Scenarios;
using Volo.ClientSimulation.Snapshot;
namespace Volo.ClientSimulation.Clients namespace Volo.ClientSimulation.Clients
{ {
public class Client : IClient, ITransientDependency public class Client : IClient, ITransientDependency
{ {
public event EventHandler Stopped;
public Scenario Scenario { get; private set; } public Scenario Scenario { get; private set; }
public ClientState State public ClientState State
@ -23,7 +27,15 @@ namespace Volo.ClientSimulation.Clients
public void Initialize(Scenario scenario) public void Initialize(Scenario scenario)
{ {
Scenario = scenario; lock (SyncLock)
{
if (State != ClientState.Stopped)
{
throw new UserFriendlyException($"Client should be stopped to be able to initialize it. Current state is '{State}'.");
}
Scenario = scenario;
}
} }
public void Start() public void Start()
@ -37,6 +49,7 @@ namespace Volo.ClientSimulation.Clients
State = ClientState.Running; State = ClientState.Running;
Scenario.Reset();
_thread = new Thread(Run); _thread = new Thread(Run);
_thread.Start(); _thread.Start();
} }
@ -55,10 +68,20 @@ namespace Volo.ClientSimulation.Clients
} }
} }
private void Run() public ClientSnapshot CreateSnapshot()
{ {
Scenario.Reset(); lock (SyncLock)
{
return new ClientSnapshot
{
State = State,
Scenario = Scenario.CreateSnapshot()
};
}
}
private void Run()
{
while (true) while (true)
{ {
lock (SyncLock) lock (SyncLock)
@ -66,6 +89,8 @@ namespace Volo.ClientSimulation.Clients
if (State != ClientState.Running) if (State != ClientState.Running)
{ {
State = ClientState.Stopped; State = ClientState.Stopped;
_thread = null;
Stopped.InvokeSafely(this);
break; break;
} }
} }

8
modules/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Clients/IClient.cs

@ -1,9 +1,13 @@
using Volo.ClientSimulation.Scenarios; using System;
using Volo.ClientSimulation.Scenarios;
using Volo.ClientSimulation.Snapshot;
namespace Volo.ClientSimulation.Clients namespace Volo.ClientSimulation.Clients
{ {
public interface IClient public interface IClient
{ {
event EventHandler Stopped;
Scenario Scenario { get; } Scenario Scenario { get; }
ClientState State { get; } ClientState State { get; }
@ -13,5 +17,7 @@ namespace Volo.ClientSimulation.Clients
void Start(); void Start();
void Stop(); void Stop();
ClientSnapshot CreateSnapshot();
} }
} }

41
modules/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Scenarios/Scenario.cs

@ -1,29 +1,30 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.ClientSimulation.Snapshot;
namespace Volo.ClientSimulation.Scenarios namespace Volo.ClientSimulation.Scenarios
{ {
public abstract class Scenario : ITransientDependency public abstract class Scenario : ITransientDependency
{ {
public IReadOnlyList<ScenarioStep> Steps => StepList.ToImmutableList(); protected List<ScenarioStep> Steps { get; }
protected List<ScenarioStep> StepList { get; }
public ScenarioStep CurrentStep protected ScenarioStep CurrentStep
{ {
get get
{ {
CheckStepCount(); CheckStepCount();
return StepList[CurrentStepIndex]; return Steps[CurrentStepIndex];
} }
} }
public int CurrentStepIndex { get; protected set; }
protected int CurrentStepIndex { get; set; }
protected Scenario() protected Scenario()
{ {
StepList = new List<ScenarioStep>(); Steps = new List<ScenarioStep>();
} }
public virtual string GetDisplayText() public virtual string GetDisplayText()
@ -37,11 +38,11 @@ namespace Volo.ClientSimulation.Scenarios
{ {
CheckStepCount(); CheckStepCount();
await StepList[CurrentStepIndex].RunAsync(); await Steps[CurrentStepIndex].RunAsync();
CurrentStepIndex++; CurrentStepIndex++;
if (CurrentStepIndex >= StepList.Count) if (CurrentStepIndex >= Steps.Count)
{ {
CurrentStepIndex = 0; CurrentStepIndex = 0;
} }
@ -52,19 +53,29 @@ namespace Volo.ClientSimulation.Scenarios
CurrentStepIndex = 0; CurrentStepIndex = 0;
} }
public ScenarioSnapshot CreateSnapshot()
{
return new ScenarioSnapshot
{
DisplayText = GetDisplayText(),
Steps = Steps.Select(s => s.CreateSnapshot()).ToList(),
CurrentStep = CurrentStep.CreateSnapshot()
};
}
protected void AddStep(ScenarioStep step)
{
Steps.Add(step);
}
private void CheckStepCount() private void CheckStepCount()
{ {
if (StepList.Count <= 0) if (Steps.Count <= 0)
{ {
throw new ApplicationException( throw new ApplicationException(
$"No Steps added to the scenario '{GetDisplayText()}'" $"No Steps added to the scenario '{GetDisplayText()}'"
); );
} }
} }
protected void AddStep(ScenarioStep step)
{
StepList.Add(step);
}
} }
} }

9
modules/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Scenarios/ScenarioStep.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.ClientSimulation.Snapshot;
namespace Volo.ClientSimulation.Scenarios namespace Volo.ClientSimulation.Scenarios
{ {
@ -46,5 +47,13 @@ namespace Volo.ClientSimulation.Scenarios
.Name .Name
.RemovePostFix(nameof(ScenarioStep)); .RemovePostFix(nameof(ScenarioStep));
} }
public ScenarioStepSnapshot CreateSnapshot()
{
return new ScenarioStepSnapshot
{
DisplayText = GetDisplayText()
};
}
} }
} }

106
modules/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Simulation.cs

@ -1,23 +1,29 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.ClientSimulation.Clients; using Volo.ClientSimulation.Clients;
using Volo.ClientSimulation.Scenarios; using Volo.ClientSimulation.Scenarios;
using Volo.ClientSimulation.Snapshot;
namespace Volo.ClientSimulation namespace Volo.ClientSimulation
{ {
public class Simulation : ISingletonDependency, IDisposable public class Simulation : ISingletonDependency, IDisposable
{ {
public ILogger<Simulation> Logger { get; set; }
public SimulationState State { get; private set; } public SimulationState State { get; private set; }
public List<IClient> Clients { get; } public List<IClient> Clients { get; }
protected ClientSimulationOptions Options { get; } protected ClientSimulationOptions Options { get; }
protected IServiceScopeFactory ServiceScopeFactory { get; }
protected IServiceScope ServiceScope { get; } protected IServiceScope ServiceScope { get; private set; }
protected readonly object SyncObj = new object(); protected readonly object SyncObj = new object();
@ -25,27 +31,15 @@ namespace Volo.ClientSimulation
IServiceScopeFactory serviceScopeFactory, IServiceScopeFactory serviceScopeFactory,
IOptions<ClientSimulationOptions> options) IOptions<ClientSimulationOptions> options)
{ {
ServiceScopeFactory = serviceScopeFactory;
Options = options.Value; Options = options.Value;
ServiceScope = serviceScopeFactory.CreateScope();
Clients = new List<IClient>(); Logger = NullLogger<Simulation>.Instance;
foreach (var scenarioConfiguration in Options.Scenarios) Clients = new List<IClient>();
{
for (int i = 0; i < scenarioConfiguration.ClientCount; i++)
{
var scenario = (Scenario) ServiceScope.ServiceProvider.GetRequiredService(
scenarioConfiguration.ScenarioType
);
var client = ServiceScope.ServiceProvider.GetRequiredService<IClient>();
client.Initialize(scenario);
Clients.Add(client);
}
}
} }
public void Start() public virtual void Start()
{ {
lock (SyncObj) lock (SyncObj)
{ {
@ -56,16 +50,42 @@ namespace Volo.ClientSimulation
State = SimulationState.Starting; State = SimulationState.Starting;
foreach (var client in Clients) try
{ {
client.Start(); DisposeResources();
ServiceScope = ServiceScopeFactory.CreateScope();
foreach (var scenarioConfiguration in Options.Scenarios)
{
for (int i = 0; i < scenarioConfiguration.ClientCount; i++)
{
var scenario = (Scenario)ServiceScope.ServiceProvider.GetRequiredService(
scenarioConfiguration.ScenarioType
);
var client = ServiceScope.ServiceProvider.GetRequiredService<IClient>();
client.Stopped += Client_OnStopped;
client.Initialize(scenario);
Clients.Add(client);
}
}
foreach (var client in Clients)
{
client.Start();
}
State = SimulationState.Started;
}
catch(Exception ex)
{
Logger.LogException(ex);
State = SimulationState.Stopped;
} }
State = SimulationState.Started;
} }
} }
public void Stop() public virtual void Stop()
{ {
lock (SyncObj) lock (SyncObj)
{ {
@ -80,14 +100,48 @@ namespace Volo.ClientSimulation
{ {
client.Stop(); client.Stop();
} }
}
}
State = SimulationState.Stopped; public virtual SimulationSnapshot CreateSnapshot()
{
lock (SyncObj)
{
return new SimulationSnapshot
{
State = State,
Clients = Clients
.Select(c => c.CreateSnapshot())
.ToList()
};
}
}
public virtual void Dispose()
{
DisposeResources();
}
protected virtual void Client_OnStopped(object sender, EventArgs e)
{
lock (SyncObj)
{
if (Clients.All(c => c.State == ClientState.Stopped))
{
OnStopped();
}
} }
} }
public void Dispose() private void OnStopped()
{
State = SimulationState.Stopped;
}
private void DisposeResources()
{ {
ServiceScope.Dispose(); Clients.Clear();
ServiceScope?.Dispose();
} }
} }
} }

13
modules/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Snapshot/ClientSnapshot.cs

@ -0,0 +1,13 @@
using System;
using Volo.ClientSimulation.Clients;
namespace Volo.ClientSimulation.Snapshot
{
[Serializable]
public class ClientSnapshot
{
public ClientState State { get; set; }
public ScenarioSnapshot Scenario { get; set; }
}
}

15
modules/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Snapshot/ScenarioSnapshot.cs

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
namespace Volo.ClientSimulation.Snapshot
{
[Serializable]
public class ScenarioSnapshot
{
public string DisplayText { get; set; }
public List<ScenarioStepSnapshot> Steps { get; set; }
public ScenarioStepSnapshot CurrentStep { get; set; }
}
}

10
modules/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Snapshot/ScenarioStepSnapshot.cs

@ -0,0 +1,10 @@
using System;
namespace Volo.ClientSimulation.Snapshot
{
[Serializable]
public class ScenarioStepSnapshot
{
public string DisplayText { get; set; }
}
}

13
modules/client-simulation/src/Volo.ClientSimulation/Volo/ClientSimulation/Snapshot/SimulationSnapshot.cs

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
namespace Volo.ClientSimulation.Snapshot
{
[Serializable]
public class SimulationSnapshot
{
public SimulationState State { get; set; }
public List<ClientSnapshot> Clients { get; set; }
}
}
Loading…
Cancel
Save