Command execution, CreateContainer command WIP
This commit is contained in:
13
src/Core/FileTime.Core.Timeline/CommandRunnerContext.cs
Normal file
13
src/Core/FileTime.Core.Timeline/CommandRunnerContext.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
34
src/Core/FileTime.Core.Timeline/LocalCommandExecutor.cs
Normal file
34
src/Core/FileTime.Core.Timeline/LocalCommandExecutor.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user