Command execution, CreateContainer command WIP

This commit is contained in:
2022-05-23 18:12:22 +02:00
parent 6b3a8f7127
commit d4bd9d3ba1
29 changed files with 499 additions and 26 deletions

View File

@@ -0,0 +1,13 @@
using FileTime.Core.Command;
namespace FileTime.Core.Timeline;
public class CommandRunnerContext
{
public ICommand Command { get; }
public CommandRunnerContext(ICommand command)
{
Command = command;
}
}

View File

@@ -1,6 +1,165 @@
using DynamicData;
using FileTime.Core.Command;
using Microsoft.Extensions.DependencyInjection;
namespace FileTime.Core.Timeline;
public class CommandScheduler : ICommandScheduler
{
private readonly IServiceProvider _serviceProvider;
private readonly SourceList<ParallelCommands> _commandsToRun = new();
private readonly List<ICommandExecutor> _commandExecutors = new();
private readonly object _guard = new();
private bool _enableRunning = true;
private bool _resourceIsInUse;
public bool EnableRunning
{
get
{
bool result = true;
RunWithLock(() => result = _enableRunning);
return result;
}
set { RunWithLock(() => _enableRunning = value); }
}
public CommandScheduler(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
var localExecutor = serviceProvider.GetRequiredService<ILocalCommandExecutor>();
localExecutor.CommandFinished += LocalExecutorOnCommandFinished;
_commandExecutors.Add(localExecutor);
}
public async Task AddCommand(ICommand command, int? batchId = null, bool toNewBatch = false)
{
await RunWithLockAsync(async () =>
{
ParallelCommands batchToAdd;
if (_commandsToRun.Count == 0)
{
batchToAdd = new ParallelCommands(PointInTime.CreateEmpty());
_commandsToRun.Add(batchToAdd);
}
else if (toNewBatch)
{
batchToAdd = new ParallelCommands(_commandsToRun.Items.Last().Result);
_commandsToRun.Add(batchToAdd);
}
else if (batchId != null && _commandsToRun.Items.First(b => b.Id == batchId) is { } parallelCommands)
{
batchToAdd = parallelCommands;
}
else
{
batchToAdd = _commandsToRun.Items.First();
}
await batchToAdd.AddCommand(command);
await RefreshCommands();
ExecuteCommands();
/*if (_commandRunners.Count == 0)
{
StartCommandRunner();
}
await UpdateReadOnlyCommands();*/
});
}
private void ExecuteCommands()
{
if (!_enableRunning) return;
var parallelCommandsToExecute = _commandsToRun.Items.FirstOrDefault();
if (parallelCommandsToExecute is null ||
parallelCommandsToExecute.Commands.All(c => c.ExecutionState != ExecutionState.Waiting)) return;
var commandsToExecute = parallelCommandsToExecute.Commands;
foreach (var commandToExecute in commandsToExecute)
{
if (commandToExecute.ExecutionState != ExecutionState.Waiting) continue;
var commandExecutor = GetCommandExecutor();
commandExecutor.ExecuteCommand(commandToExecute.Command);
commandToExecute.ExecutionState = ExecutionState.Running;
}
}
private ICommandExecutor GetCommandExecutor()
{
//TODO
return _commandExecutors[0];
}
private void LocalExecutorOnCommandFinished(object? sender, ICommand command)
{
var parallelCommandsToExecute = _commandsToRun.Items.FirstOrDefault();
if (parallelCommandsToExecute is null) return;
var state = parallelCommandsToExecute.Commands.FirstOrDefault(c => c.Command == command);
if (state is null) return;
state.ExecutionState = ExecutionState.Finished;
}
private async Task RefreshCommands()
{
var currentTime = PointInTime.CreateEmpty();
foreach (var batch in _commandsToRun.Items)
{
currentTime = await batch.RefreshResult(currentTime);
}
}
private void RunWithLock(Action action) => Task.Run(async () => await RunWithLockAsync(action)).Wait();
private async Task RunWithLockAsync(Action action)
{
await RunWithLockAsync(() =>
{
action();
return Task.CompletedTask;
});
}
private async Task RunWithLockAsync(Func<Task> func)
{
while (true)
{
lock (_guard)
{
if (!_resourceIsInUse)
{
_resourceIsInUse = true;
break;
}
}
await Task.Delay(1);
}
try
{
await func();
}
finally
{
lock (_guard)
{
_resourceIsInUse = false;
}
}
}
}

View File

@@ -0,0 +1,34 @@
using FileTime.Core.Command;
namespace FileTime.Core.Timeline;
public class LocalCommandExecutor : ILocalCommandExecutor
{
private readonly ICommandRunner _commandRunner;
public event EventHandler<ICommand> CommandFinished;
public LocalCommandExecutor(ICommandRunner commandRunner)
{
_commandRunner = commandRunner;
}
public void ExecuteCommand(ICommand command)
{
var context = new CommandRunnerContext(command);
var thread = new Thread(new ParameterizedThreadStart(RunCommand));
thread.Start(context);
}
private async void RunCommand(object? contextObj)
{
if (contextObj is not CommandRunnerContext context)
throw new ArgumentException($"Parameter must be of type {typeof(CommandRunnerContext)}");
try
{
await _commandRunner.RunCommandAsync(context.Command);
}
catch(Exception ex){}
CommandFinished.Invoke(this, context.Command);
}
}