RobotApp/RobotApp/Services/Robot/Actions/RobotAction.cs
Đăng Nguyễn 99716cc414 update
2025-11-06 09:22:55 +07:00

202 lines
6.5 KiB
C#

using Grpc.Core;
using MudBlazor;
using RobotApp.Services.Exceptions;
using RobotApp.VDA5050.Factsheet;
using RobotApp.VDA5050.InstantAction;
using RobotApp.VDA5050.State;
using RobotApp.VDA5050.Type;
namespace RobotApp.Services.Robot.Actions;
public abstract class RobotAction(IServiceProvider serviceProvider) : IDisposable
{
public ActionType Type { get; private set; }
public string Id { get; private set; } = "";
public string Description { get; private set; } = "";
public BlockingType BlockingType { get; private set; }
public ActionParameter[] Parameters { get; private set; } = [];
public ActionStatus Status { get; protected set; } = ActionStatus.WAITING;
public string ResultDescription { get; set; } = "";
public bool IsCompleted => Status == ActionStatus.FINISHED || Status == ActionStatus.FAILED;
public ActionScopes ActionScope { get; set; }
private WatchTimerAsync<RobotAction>? ActionTimer;
private const int ActionInterval = 200;
protected IServiceProvider ServiceProvider = serviceProvider;
protected VDA5050.InstantAction.Action? Action;
protected IServiceScope? Scope;
protected Logger<RobotAction>? Logger;
protected AgvAction? AgvAction;
protected bool IsPaused = false;
protected ActionStatus HistoryStatus;
private bool IsCancelAction = false;
public bool Initialize(ActionScopes actionScope, VDA5050.InstantAction.Action action)
{
Status = ActionStatus.WAITING;
ActionScope = actionScope;
Action = action;
Initialize();
Id = Action.ActionId;
Description = Action.ActionDescription;
Status = ActionStatus.WAITING;
return true;
}
public void Start()
{
if (Status != ActionStatus.WAITING) return;
Scope ??= ServiceProvider.CreateScope();
Logger = Scope.ServiceProvider.GetRequiredService<Logger<RobotAction>>();
ActionTimer = new(ActionInterval, ActionHandler, Logger);
Status = ActionStatus.INITIALIZING;
ActionTimer.Start();
}
public void Pause()
{
HistoryStatus = Status;
Status = ActionStatus.PAUSED;
IsPaused = true;
}
public void Resume()
{
if (Status == ActionStatus.PAUSED) Status = ActionStatus.WAITING;
}
public void Cancel()
{
if (!IsCompleted) IsCancelAction = true;
if (Status == ActionStatus.WAITING) StopAction();
}
public async Task WaitAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested && !IsCompleted)
{
await Task.Delay(500, cancellationToken).ConfigureAwait(false);
}
}
public void Wait(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested && !IsCompleted)
{
Task.Delay(500, cancellationToken).Wait(cancellationToken);
}
}
protected virtual Task StartAction()
{
return Task.CompletedTask;
}
protected virtual Task StopAction()
{
Console.WriteLine($"StopAction {Type}");
Status = ActionStatus.FAILED;
ResultDescription = "Action bị hủy bỏ.";
return Task.CompletedTask;
}
protected virtual Task ExecuteAction()
{
return Task.CompletedTask;
}
protected virtual Task PauseAction()
{
return Task.CompletedTask;
}
protected virtual Task ResumeAction()
{
return Task.CompletedTask;
}
protected virtual void Initialize()
{
if (Action is null) throw new ActionException("Khởi tạo Action không tồn tại");
Scope ??= ServiceProvider.CreateScope();
var FactsheetService = Scope.ServiceProvider.GetRequiredService<RobotFactsheet>();
if (Enum.TryParse(Action.ActionType, out ActionType type)) Type = type;
else throw new ActionException($"ActionType {Action.ActionType} không hợp lệ.");
var actionStore = FactsheetService.GetAction(Type) ?? throw new ActionException($"ActionType {Action.ActionType} không được thiết kế.");
if (Enum.TryParse(Action.BlockingType, out BlockingType blockingType)) BlockingType = blockingType;
else throw new ActionException($"BlockingType {Action.BlockingType} không hợp lệ.");
if (!actionStore.BlockingTypes.Any(bt => bt == BlockingType.ToString())) throw new ActionException($"BlockingType {BlockingType} không được hỗ trợ cho action {Type}.");
if (!actionStore.ActionScopes.Any(sp => sp == ActionScope.ToString())) throw new ActionException($"ActionScope {ActionScope} không được hỗ trợ cho action {Type}.");
if (actionStore.ActionParameters.Length > 0)
{
foreach (var parameterStore in actionStore.ActionParameters)
{
if (!parameterStore.IsOptional)
{
if (!Action.ActionParameters.Any(a => a.Key == parameterStore.Key)) throw new ActionException($"Thiếu tham số bắt buộc '{parameterStore.Key}' cho action {Type}.");
}
}
Parameters = Action.ActionParameters;
}
AgvAction = actionStore;
}
private async Task ActionHandler()
{
try
{
if (IsCancelAction)
{
await StopAction();
}
else
{
if (Status == ActionStatus.INITIALIZING)
{
Logger?.Info($"Thực hiện action {Type}");
Status = ActionStatus.RUNNING;
await StartAction();
}
else if (Status == ActionStatus.RUNNING)
{
await ExecuteAction();
}
else if (Status == ActionStatus.PAUSED)
{
await PauseAction();
}
else if (Status == ActionStatus.WAITING && IsPaused)
{
await ResumeAction();
}
}
if (IsCompleted)
{
Dispose();
}
}
catch (Exception ex)
{
Logger?.Error($"Thực hiện action {Type} xảy ra lỗi: {ex.Message}");
Status = ActionStatus.FAILED;
ResultDescription = $"Thực hiện action {Type} xảy ra lỗi: {ex.Message}";
}
}
public void Dispose()
{
if (!IsCompleted) StopAction();
ActionTimer?.Dispose();
ActionTimer = null;
GC.SuppressFinalize(this);
}
}