299 lines
9.4 KiB
C#
299 lines
9.4 KiB
C#
using Microsoft.AspNetCore.SignalR;
|
|
using RobotNet.Script.Shares;
|
|
using RobotNet.ScriptManager.Helpers;
|
|
using RobotNet.ScriptManager.Hubs;
|
|
using RobotNet.ScriptManager.Models;
|
|
using System.Diagnostics;
|
|
|
|
namespace RobotNet.ScriptManager.Services;
|
|
|
|
public class ScriptStateManager(ScriptTaskManager taskManager,
|
|
ScriptMissionManager missionManager,
|
|
ScriptGlobalsManager globalsManager,
|
|
ScriptConnectionManager connectionManager,
|
|
IHubContext<ProcessorHub> processorHubContext,
|
|
IHubContext<HMIHub> hmiHubContext,
|
|
IHubContext<ConsoleHub> consoleHubContext,
|
|
ILogger<ScriptStateManager> logger) : LoopService(500)
|
|
{
|
|
public string StateMesssage { get; private set; } = "";
|
|
public ProcessorState State { get; private set; } = ProcessorState.Idle;
|
|
public ProcessorRequest Request { get; private set; } = ProcessorRequest.None;
|
|
private readonly ConsoleLog consoleLog = new(consoleHubContext, logger);
|
|
|
|
private readonly Mutex mutex = new();
|
|
private CancellationTokenSource? runningCancellation;
|
|
|
|
public bool Build(ref string message)
|
|
{
|
|
bool result = false;
|
|
|
|
if (mutex.WaitOne(1000))
|
|
{
|
|
if (Request != ProcessorRequest.None)
|
|
{
|
|
message = $"Không thể thực hiện build vì Processor đang thực hiện {Request}";
|
|
}
|
|
else if (State == ProcessorState.Running)
|
|
{
|
|
message = "Không thể thực hiện build vì Processor đang Running}";
|
|
}
|
|
else
|
|
{
|
|
result = true;
|
|
SetRequest(ProcessorRequest.Build);
|
|
}
|
|
|
|
mutex.ReleaseMutex();
|
|
}
|
|
else
|
|
{
|
|
message = "Không thể thực hiện build vì request timeout";
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public bool Run(ref string message)
|
|
{
|
|
bool result = false;
|
|
|
|
if (mutex.WaitOne(1000))
|
|
{
|
|
if (Request != ProcessorRequest.None)
|
|
{
|
|
message = $"Không thể thực hiện run vì Processor đang thực hiện {Request}";
|
|
}
|
|
else if (State != ProcessorState.Ready)
|
|
{
|
|
message = $"Không thể thực hiện run vì Processor đang ở trạng thái {State}, không phải Ready";
|
|
}
|
|
else
|
|
{
|
|
result = true;
|
|
SetRequest(ProcessorRequest.Run);
|
|
}
|
|
|
|
mutex.ReleaseMutex();
|
|
}
|
|
else
|
|
{
|
|
message = "Không thể thực hiện run vì request timeout";
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public bool Stop(ref string message)
|
|
{
|
|
bool result = false;
|
|
|
|
if (mutex.WaitOne(1000))
|
|
{
|
|
if (Request != ProcessorRequest.None)
|
|
{
|
|
message = $"Không thể thực hiện stop vì Processor đang thực hiện {Request}";
|
|
}
|
|
else if (State != ProcessorState.Running)
|
|
{
|
|
message = $"Không thể thực hiện stop vì Processor đang ở trạng thái {State}, không phải Running";
|
|
}
|
|
else
|
|
{
|
|
result = true;
|
|
SetRequest(ProcessorRequest.Stop);
|
|
}
|
|
|
|
mutex.ReleaseMutex();
|
|
}
|
|
else
|
|
{
|
|
message = "Không thể thực hiện stop vì request timeout";
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public bool Reset(ref string message)
|
|
{
|
|
bool result = false;
|
|
|
|
if (mutex.WaitOne(1000))
|
|
{
|
|
if (Request != ProcessorRequest.None)
|
|
{
|
|
message = $"Không thể thực hiện reset vì Processor đang thực hiện {Request}";
|
|
}
|
|
else if (State != ProcessorState.Ready && State != ProcessorState.Error && State != ProcessorState.BuildError && State != ProcessorState.Idle)
|
|
{
|
|
message = $"Không thể thực hiện reset vì Processor đang ở trạng thái {State}, không phải Ready hoặc Error hoặc BuildError";
|
|
}
|
|
else
|
|
{
|
|
result = true;
|
|
SetRequest(ProcessorRequest.Reset);
|
|
}
|
|
|
|
mutex.ReleaseMutex();
|
|
}
|
|
else
|
|
{
|
|
message = "Không thể thực hiện reset vì request timeout";
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private void SetRequest(ProcessorRequest request)
|
|
{
|
|
if (Request == request) return;
|
|
|
|
Request = request;
|
|
_ = Task.Factory.StartNew(async () =>
|
|
{
|
|
await processorHubContext.Clients.All.SendAsync("RequestChanged", Request);
|
|
await hmiHubContext.Clients.All.SendAsync("RequestChanged", Request);
|
|
});
|
|
}
|
|
|
|
private void SetState(ProcessorState state)
|
|
{
|
|
if (State == state) return;
|
|
|
|
State = state;
|
|
_ = Task.Factory.StartNew(async () =>
|
|
{
|
|
await processorHubContext.Clients.All.SendAsync("StateChanged", State);
|
|
await hmiHubContext.Clients.All.SendAsync("StateChanged", State);
|
|
});
|
|
}
|
|
|
|
protected override async Task BeforExecuteAsync(CancellationToken cancellationToken)
|
|
{
|
|
missionManager.ResetMissionDb();
|
|
SetRequest(ProcessorRequest.Build);
|
|
await base.BeforExecuteAsync(cancellationToken);
|
|
}
|
|
|
|
protected override void Execute(CancellationToken stoppingToken)
|
|
{
|
|
switch (State)
|
|
{
|
|
case ProcessorState.Idle:
|
|
case ProcessorState.BuildError:
|
|
case ProcessorState.Error:
|
|
if (Request == ProcessorRequest.Build)
|
|
{
|
|
SetState(ProcessorState.Building);
|
|
SetRequest(ProcessorRequest.None);
|
|
BuildHandler();
|
|
}
|
|
else if (Request == ProcessorRequest.Reset)
|
|
{
|
|
missionManager.Reset();
|
|
taskManager.Reset();
|
|
connectionManager.Reset();
|
|
SetState(ProcessorState.Idle);
|
|
SetRequest(ProcessorRequest.None);
|
|
}
|
|
break;
|
|
case ProcessorState.Ready:
|
|
if (Request == ProcessorRequest.Build)
|
|
{
|
|
SetState(ProcessorState.Building);
|
|
SetRequest(ProcessorRequest.None);
|
|
BuildHandler();
|
|
}
|
|
else if (Request == ProcessorRequest.Run)
|
|
{
|
|
SetState(ProcessorState.Running);
|
|
SetRequest(ProcessorRequest.None);
|
|
RunHandler();
|
|
}
|
|
else if (Request == ProcessorRequest.Reset)
|
|
{
|
|
missionManager.Reset();
|
|
taskManager.Reset();
|
|
connectionManager.Reset();
|
|
SetState(ProcessorState.Idle);
|
|
SetRequest(ProcessorRequest.None);
|
|
}
|
|
break;
|
|
case ProcessorState.Running:
|
|
if (Request == ProcessorRequest.Stop)
|
|
{
|
|
connectionManager.Reset();
|
|
SetState(ProcessorState.Stopping);
|
|
SetRequest(ProcessorRequest.None);
|
|
StopHandler();
|
|
}
|
|
break;
|
|
case ProcessorState.Building:
|
|
case ProcessorState.Stopping:
|
|
case ProcessorState.Starting:
|
|
default:
|
|
SetRequest(ProcessorRequest.None);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void BuildHandler()
|
|
{
|
|
_ = Task.Factory.StartNew(() =>
|
|
{
|
|
consoleLog.LogInfo($"Start build all scripts");
|
|
var watch = new Stopwatch();
|
|
watch.Start();
|
|
var code = ScriptConfiguration.GetScriptCode();
|
|
|
|
string error = string.Empty;
|
|
try
|
|
{
|
|
if (CSharpSyntaxHelper.VerifyScript(code, out error, out var variables, out var tasks, out var missions))
|
|
{
|
|
globalsManager.LoadVariables(variables);
|
|
taskManager.LoadTasks(tasks);
|
|
missionManager.LoadMissions(missions);
|
|
watch.Stop();
|
|
consoleLog.LogInfo($"Build all scripts successfully in {watch.ElapsedMilliseconds} ms");
|
|
SetState(ProcessorState.Ready);
|
|
return;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
error = ex.ToString();
|
|
}
|
|
|
|
watch.Stop();
|
|
SetState(ProcessorState.BuildError);
|
|
consoleLog.LogError(error);
|
|
|
|
});
|
|
}
|
|
|
|
private void RunHandler()
|
|
{
|
|
_ = Task.Factory.StartNew(() =>
|
|
{
|
|
runningCancellation = new();
|
|
taskManager.StartAll(runningCancellation.Token);
|
|
missionManager.Start(runningCancellation.Token);
|
|
SetState(ProcessorState.Running);
|
|
|
|
});
|
|
}
|
|
|
|
private void StopHandler()
|
|
{
|
|
_ = Task.Factory.StartNew(() =>
|
|
{
|
|
runningCancellation?.Cancel();
|
|
taskManager.StopAll();
|
|
missionManager.Stop();
|
|
SetState(ProcessorState.Ready);
|
|
});
|
|
}
|
|
|
|
}
|