using Microsoft.AspNetCore.SignalR; using RobotNet10.ScriptEngine.Shared; using RobotNet10.Shared; namespace RobotNet10.ScriptEngine.Hubs; /// /// SignalR hub for ScriptEngine management operations. /// /// /// Initializes a new instance of ScriptManagerHub. /// public class ScriptManagerHub(ScriptEngine _scriptEngine) : Hub { /// /// Gets the current state of the ScriptEngine. /// public Task GetState() { return Task.FromResult(_scriptEngine.State); } /// /// Builds scripts from all files. Only allowed when state is Idle or BuildError. /// public Task Build() { return Task.FromResult(_scriptEngine.Build()); } /// /// Starts the ScriptEngine. Only allowed when state is Ready. /// public Task Start() { return Task.FromResult(_scriptEngine.Start()); } /// /// Stops the ScriptEngine. Only allowed when state is Running. /// public Task Stop() { return Task.FromResult(_scriptEngine.Stop()); } /// /// Resets the ScriptEngine. Allowed from Idle, Ready, BuildError, Running, or Fault. /// public Task Reset() { return Task.FromResult(_scriptEngine.Reset()); } #region VariableManager Methods /// /// Gets all script variables. /// public Task GetScriptVariables() { return Task.FromResult(_scriptEngine.VariableManager.GetVariables().ToArray()); } /// /// Finds specific script variables by names. /// public Task FindScriptVariables(string[] names) { return Task.FromResult(_scriptEngine.VariableManager.GetVariables(names).ToArray()); } /// /// Sets the value of a script variable by name. /// public Task SetValue(string name, string value) { return Task.FromResult(_scriptEngine.VariableManager.SetValue(name, value)); } #endregion #region TaskManager Methods /// /// Gets all script tasks. /// public Task GetScriptTasks() { return Task.FromResult(_scriptEngine.TaskManager.GetScriptTasks()); } /// /// Finds specific script tasks by names. /// public Task FindScriptTasks(string[] names) { return Task.FromResult(_scriptEngine.TaskManager.FindScriptTasks(names)); } /// /// Enables a task (resumes if paused, starts if stopped). /// public Task EnableTask(string name) { return Task.FromResult(_scriptEngine.TaskManager.EnableTask(name)); } /// /// Disables a task (pauses if running). /// public Task DisableTask(string name) { return Task.FromResult(_scriptEngine.TaskManager.DisableTask(name)); } #endregion #region MissionManager Methods /// /// Gets all script missions. /// public Task GetScriptMissions() { return Task.FromResult(_scriptEngine.MissionManager.GetScriptMissions()); } /// /// Finds specific script missions by names. /// public Task FindScriptMissions(string[] names) { return Task.FromResult(_scriptEngine.MissionManager.FindScriptMissions(names)); } /// /// Creates a mission instance with parameters provided as a dictionary. /// /// The name of the mission model. /// Dictionary of parameter values keyed by parameter name (as strings). /// MessageResult containing the mission ID if successful. public async Task> CreateMission(string name, IDictionary args) { if (string.IsNullOrWhiteSpace(name)) return new MessageResult(false, default, "Mission name cannot be null or empty"); if (args == null) return new MessageResult(false, default, "Parameters cannot be null"); // Convert string dictionary to object dictionary var missionModel = _scriptEngine.MissionManager.GetMissionModel(name); if (missionModel == null) return new MessageResult(false, default, $"Mission model '{name}' not found"); var parameters = new Dictionary(); foreach (var paramModel in missionModel.Parameters) { // Skip CancellationToken parameters if (paramModel.Type == typeof(CancellationToken)) continue; if (args.TryGetValue(paramModel.Name, out var stringValue)) { try { object? convertedValue = null; if (!string.IsNullOrEmpty(stringValue) && stringValue != "null") { if (paramModel.Type == typeof(string)) { convertedValue = stringValue; } else if (paramModel.Type.IsEnum) { convertedValue = Enum.Parse(paramModel.Type, stringValue, true); } else { convertedValue = Convert.ChangeType(stringValue, paramModel.Type); } } parameters[paramModel.Name] = convertedValue; } catch (Exception ex) { var errorMessage = $"Failed to convert parameter '{paramModel.Name}' value '{stringValue}' to type '{paramModel.Type.Name}': {ex.Message}"; // Log error via ConsoleHubContext if available // Note: We don't have direct access to ConsoleHubContext here, but error is returned to client return new MessageResult(false, default, errorMessage); } } else { // Use default value if not provided parameters[paramModel.Name] = paramModel.DefaultValue; } } return await Task.FromResult(_scriptEngine.MissionManager.CreateMission(name, parameters)); } /// /// Cancels a running or paused mission. /// /// The ID of the mission instance to cancel. /// The reason for cancellation. /// True if the mission was canceled successfully, false otherwise. public Task CancelMission(Guid id, string reason) { var mission = _scriptEngine.MissionManager.GetMission(id); if (mission == null) return Task.FromResult(false); try { mission.Cancel(reason); return Task.FromResult(true); } catch { return Task.FromResult(false); } } #endregion }