Run JSON schema validation in separate thread
This commit is contained in:
parent
aa73231f38
commit
6f2ebe5a5a
@ -7,15 +7,14 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Json.Schema;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Questionable.Data;
|
using Questionable.Data;
|
||||||
using Questionable.Model;
|
using Questionable.Model;
|
||||||
using Questionable.Model.V1;
|
using Questionable.Model.V1;
|
||||||
using Questionable.QuestPaths;
|
using Questionable.QuestPaths;
|
||||||
using Questionable.Validation;
|
using Questionable.Validation;
|
||||||
|
using Questionable.Validation.Validators;
|
||||||
|
|
||||||
namespace Questionable.Controller;
|
namespace Questionable.Controller;
|
||||||
|
|
||||||
@ -25,18 +24,19 @@ internal sealed class QuestRegistry
|
|||||||
private readonly QuestData _questData;
|
private readonly QuestData _questData;
|
||||||
private readonly QuestValidator _questValidator;
|
private readonly QuestValidator _questValidator;
|
||||||
private readonly ILogger<QuestRegistry> _logger;
|
private readonly ILogger<QuestRegistry> _logger;
|
||||||
private readonly JsonSchema _questSchema;
|
private readonly JsonSchemaValidator _jsonSchemaValidator;
|
||||||
|
|
||||||
private readonly Dictionary<ushort, Quest> _quests = new();
|
private readonly Dictionary<ushort, Quest> _quests = new();
|
||||||
|
|
||||||
public QuestRegistry(IDalamudPluginInterface pluginInterface, QuestData questData,
|
public QuestRegistry(IDalamudPluginInterface pluginInterface, QuestData questData,
|
||||||
QuestValidator questValidator, ILogger<QuestRegistry> logger)
|
QuestValidator questValidator, JsonSchemaValidator jsonSchemaValidator,
|
||||||
|
ILogger<QuestRegistry> logger)
|
||||||
{
|
{
|
||||||
_pluginInterface = pluginInterface;
|
_pluginInterface = pluginInterface;
|
||||||
_questData = questData;
|
_questData = questData;
|
||||||
_questValidator = questValidator;
|
_questValidator = questValidator;
|
||||||
|
_jsonSchemaValidator = jsonSchemaValidator;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_questSchema = JsonSchema.FromStream(AssemblyQuestLoader.QuestSchema).AsTask().Result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Quest> AllQuests => _quests.Values;
|
public IEnumerable<Quest> AllQuests => _quests.Values;
|
||||||
@ -46,7 +46,7 @@ internal sealed class QuestRegistry
|
|||||||
|
|
||||||
public void Reload()
|
public void Reload()
|
||||||
{
|
{
|
||||||
_questValidator.ClearIssues();
|
_questValidator.Reset();
|
||||||
_quests.Clear();
|
_quests.Clear();
|
||||||
|
|
||||||
LoadQuestsFromAssembly();
|
LoadQuestsFromAssembly();
|
||||||
@ -130,26 +130,8 @@ internal sealed class QuestRegistry
|
|||||||
if (questId == null)
|
if (questId == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var questNode = JsonNode.Parse(stream);
|
var questNode = JsonNode.Parse(stream)!;
|
||||||
Task.Run(() =>
|
_jsonSchemaValidator.Enqueue(questId.Value, questNode);
|
||||||
{
|
|
||||||
var evaluationResult = _questSchema.Evaluate(questNode, new EvaluationOptions
|
|
||||||
{
|
|
||||||
Culture = CultureInfo.InvariantCulture,
|
|
||||||
OutputFormat = OutputFormat.List
|
|
||||||
});
|
|
||||||
if (!evaluationResult.IsValid)
|
|
||||||
{
|
|
||||||
_questValidator.AddIssue(new ValidationIssue
|
|
||||||
{
|
|
||||||
QuestId = questId.Value,
|
|
||||||
Sequence = null,
|
|
||||||
Step = null,
|
|
||||||
Severity = EIssueSeverity.Error,
|
|
||||||
Description = "JSON Validation failed"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Quest quest = new Quest
|
Quest quest = new Quest
|
||||||
{
|
{
|
||||||
|
@ -67,6 +67,23 @@ public sealed class QuestionablePlugin : IDalamudPlugin
|
|||||||
serviceCollection.AddSingleton(new WindowSystem(nameof(Questionable)));
|
serviceCollection.AddSingleton(new WindowSystem(nameof(Questionable)));
|
||||||
serviceCollection.AddSingleton((Configuration?)pluginInterface.GetPluginConfig() ?? new Configuration());
|
serviceCollection.AddSingleton((Configuration?)pluginInterface.GetPluginConfig() ?? new Configuration());
|
||||||
|
|
||||||
|
AddBasicFunctionsAndData(serviceCollection);
|
||||||
|
AddTaskFactories(serviceCollection);
|
||||||
|
AddControllers(serviceCollection);
|
||||||
|
AddWindows(serviceCollection);
|
||||||
|
AddQuestValidators(serviceCollection);
|
||||||
|
|
||||||
|
serviceCollection.AddSingleton<CommandHandler>();
|
||||||
|
serviceCollection.AddSingleton<DalamudInitializer>();
|
||||||
|
|
||||||
|
_serviceProvider = serviceCollection.BuildServiceProvider();
|
||||||
|
_serviceProvider.GetRequiredService<QuestRegistry>().Reload();
|
||||||
|
_serviceProvider.GetRequiredService<CommandHandler>();
|
||||||
|
_serviceProvider.GetRequiredService<DalamudInitializer>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddBasicFunctionsAndData(ServiceCollection serviceCollection)
|
||||||
|
{
|
||||||
serviceCollection.AddSingleton<GameFunctions>();
|
serviceCollection.AddSingleton<GameFunctions>();
|
||||||
serviceCollection.AddSingleton<ChatFunctions>();
|
serviceCollection.AddSingleton<ChatFunctions>();
|
||||||
serviceCollection.AddSingleton<AetherCurrentData>();
|
serviceCollection.AddSingleton<AetherCurrentData>();
|
||||||
@ -76,12 +93,15 @@ public sealed class QuestionablePlugin : IDalamudPlugin
|
|||||||
serviceCollection.AddSingleton<NavmeshIpc>();
|
serviceCollection.AddSingleton<NavmeshIpc>();
|
||||||
serviceCollection.AddSingleton<LifestreamIpc>();
|
serviceCollection.AddSingleton<LifestreamIpc>();
|
||||||
serviceCollection.AddSingleton<YesAlreadyIpc>();
|
serviceCollection.AddSingleton<YesAlreadyIpc>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddTaskFactories(ServiceCollection serviceCollection)
|
||||||
|
{
|
||||||
// individual tasks
|
// individual tasks
|
||||||
serviceCollection.AddTransient<MountTask>();
|
serviceCollection.AddTransient<MountTask>();
|
||||||
serviceCollection.AddTransient<UnmountTask>();
|
serviceCollection.AddTransient<UnmountTask>();
|
||||||
|
|
||||||
// tasks with factories
|
// task factories
|
||||||
serviceCollection.AddTaskWithFactory<StepDisabled.Factory, StepDisabled.Task>();
|
serviceCollection.AddTaskWithFactory<StepDisabled.Factory, StepDisabled.Task>();
|
||||||
serviceCollection.AddTaskWithFactory<AetheryteShortcut.Factory, AetheryteShortcut.UseAetheryteShortcut>();
|
serviceCollection.AddTaskWithFactory<AetheryteShortcut.Factory, AetheryteShortcut.UseAetheryteShortcut>();
|
||||||
serviceCollection.AddTaskWithFactory<SkipCondition.Factory, SkipCondition.CheckTask>();
|
serviceCollection.AddTaskWithFactory<SkipCondition.Factory, SkipCondition.CheckTask>();
|
||||||
@ -115,7 +135,10 @@ public sealed class QuestionablePlugin : IDalamudPlugin
|
|||||||
WaitAtEnd.WaitObjectAtPosition>();
|
WaitAtEnd.WaitObjectAtPosition>();
|
||||||
serviceCollection.AddTransient<WaitAtEnd.WaitQuestAccepted>();
|
serviceCollection.AddTransient<WaitAtEnd.WaitQuestAccepted>();
|
||||||
serviceCollection.AddTransient<WaitAtEnd.WaitQuestCompleted>();
|
serviceCollection.AddTransient<WaitAtEnd.WaitQuestCompleted>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddControllers(ServiceCollection serviceCollection)
|
||||||
|
{
|
||||||
serviceCollection.AddSingleton<MovementController>();
|
serviceCollection.AddSingleton<MovementController>();
|
||||||
serviceCollection.AddSingleton<MovementOverrideController>();
|
serviceCollection.AddSingleton<MovementOverrideController>();
|
||||||
serviceCollection.AddSingleton<QuestRegistry>();
|
serviceCollection.AddSingleton<QuestRegistry>();
|
||||||
@ -125,27 +148,27 @@ public sealed class QuestionablePlugin : IDalamudPlugin
|
|||||||
serviceCollection.AddSingleton<CombatController>();
|
serviceCollection.AddSingleton<CombatController>();
|
||||||
|
|
||||||
serviceCollection.AddSingleton<ICombatModule, RotationSolverRebornModule>();
|
serviceCollection.AddSingleton<ICombatModule, RotationSolverRebornModule>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddWindows(ServiceCollection serviceCollection)
|
||||||
|
{
|
||||||
serviceCollection.AddSingleton<QuestWindow>();
|
serviceCollection.AddSingleton<QuestWindow>();
|
||||||
serviceCollection.AddSingleton<ConfigWindow>();
|
serviceCollection.AddSingleton<ConfigWindow>();
|
||||||
serviceCollection.AddSingleton<DebugOverlay>();
|
serviceCollection.AddSingleton<DebugOverlay>();
|
||||||
serviceCollection.AddSingleton<QuestSelectionWindow>();
|
serviceCollection.AddSingleton<QuestSelectionWindow>();
|
||||||
serviceCollection.AddSingleton<QuestValidationWindow>();
|
serviceCollection.AddSingleton<QuestValidationWindow>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddQuestValidators(ServiceCollection serviceCollection)
|
||||||
|
{
|
||||||
serviceCollection.AddSingleton<QuestValidator>();
|
serviceCollection.AddSingleton<QuestValidator>();
|
||||||
serviceCollection.AddSingleton<IQuestValidator, QuestDisabledValidator>();
|
serviceCollection.AddSingleton<IQuestValidator, QuestDisabledValidator>();
|
||||||
serviceCollection.AddSingleton<IQuestValidator, BasicSequenceValidator>();
|
serviceCollection.AddSingleton<IQuestValidator, BasicSequenceValidator>();
|
||||||
serviceCollection.AddSingleton<IQuestValidator, UniqueStartStopValidator>();
|
serviceCollection.AddSingleton<IQuestValidator, UniqueStartStopValidator>();
|
||||||
serviceCollection.AddSingleton<IQuestValidator, NextQuestValidator>();
|
serviceCollection.AddSingleton<IQuestValidator, NextQuestValidator>();
|
||||||
serviceCollection.AddSingleton<IQuestValidator, CompletionFlagsValidator>();
|
serviceCollection.AddSingleton<IQuestValidator, CompletionFlagsValidator>();
|
||||||
|
serviceCollection.AddSingleton<JsonSchemaValidator>();
|
||||||
serviceCollection.AddSingleton<CommandHandler>();
|
serviceCollection.AddSingleton<IQuestValidator>(sp => sp.GetRequiredService<JsonSchemaValidator>());
|
||||||
serviceCollection.AddSingleton<DalamudInitializer>();
|
|
||||||
|
|
||||||
_serviceProvider = serviceCollection.BuildServiceProvider();
|
|
||||||
_serviceProvider.GetRequiredService<QuestRegistry>().Reload();
|
|
||||||
_serviceProvider.GetRequiredService<CommandHandler>();
|
|
||||||
_serviceProvider.GetRequiredService<DalamudInitializer>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -6,4 +6,8 @@ namespace Questionable.Validation;
|
|||||||
internal interface IQuestValidator
|
internal interface IQuestValidator
|
||||||
{
|
{
|
||||||
IEnumerable<ValidationIssue> Validate(Quest quest);
|
IEnumerable<ValidationIssue> Validate(Quest quest);
|
||||||
|
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Questionable.Model;
|
using Questionable.Model;
|
||||||
@ -26,11 +27,16 @@ internal sealed class QuestValidator
|
|||||||
public int IssueCount => _validationIssues.Count;
|
public int IssueCount => _validationIssues.Count;
|
||||||
public int ErrorCount => _validationIssues.Count(x => x.Severity == EIssueSeverity.Error);
|
public int ErrorCount => _validationIssues.Count(x => x.Severity == EIssueSeverity.Error);
|
||||||
|
|
||||||
public void ClearIssues() => _validationIssues.Clear();
|
public void Reset()
|
||||||
|
{
|
||||||
|
foreach (var validator in _validators)
|
||||||
|
validator.Reset();
|
||||||
|
_validationIssues.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
public void Validate(IEnumerable<Quest> quests)
|
public void Validate(IEnumerable<Quest> quests)
|
||||||
{
|
{
|
||||||
Task.Run(() =>
|
Task.Factory.StartNew(() =>
|
||||||
{
|
{
|
||||||
foreach (var quest in quests)
|
foreach (var quest in quests)
|
||||||
{
|
{
|
||||||
@ -52,8 +58,6 @@ internal sealed class QuestValidator
|
|||||||
.ThenBy(x => x.Step)
|
.ThenBy(x => x.Step)
|
||||||
.ThenBy(x => x.Description)
|
.ThenBy(x => x.Description)
|
||||||
.ToList();
|
.ToList();
|
||||||
});
|
}, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddIssue(ValidationIssue issue) => _validationIssues.Add(issue);
|
|
||||||
}
|
}
|
||||||
|
44
Questionable/Validation/Validators/JsonSchemaValidator.cs
Normal file
44
Questionable/Validation/Validators/JsonSchemaValidator.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using Json.Schema;
|
||||||
|
using Questionable.Model;
|
||||||
|
using Questionable.QuestPaths;
|
||||||
|
|
||||||
|
namespace Questionable.Validation.Validators;
|
||||||
|
|
||||||
|
internal sealed class JsonSchemaValidator : IQuestValidator
|
||||||
|
{
|
||||||
|
private readonly Dictionary<ushort, JsonNode> _questNodes = new();
|
||||||
|
private JsonSchema? _questSchema;
|
||||||
|
|
||||||
|
public IEnumerable<ValidationIssue> Validate(Quest quest)
|
||||||
|
{
|
||||||
|
_questSchema ??= JsonSchema.FromStream(AssemblyQuestLoader.QuestSchema).AsTask().Result;
|
||||||
|
|
||||||
|
if (_questNodes.TryGetValue(quest.QuestId, out JsonNode? questNode))
|
||||||
|
{
|
||||||
|
var evaluationResult = _questSchema.Evaluate(questNode, new EvaluationOptions
|
||||||
|
{
|
||||||
|
Culture = CultureInfo.InvariantCulture,
|
||||||
|
OutputFormat = OutputFormat.List
|
||||||
|
});
|
||||||
|
if (!evaluationResult.IsValid)
|
||||||
|
{
|
||||||
|
yield return new ValidationIssue
|
||||||
|
{
|
||||||
|
QuestId = quest.QuestId,
|
||||||
|
Sequence = null,
|
||||||
|
Step = null,
|
||||||
|
Severity = EIssueSeverity.Error,
|
||||||
|
Description = "JSON Validation failed"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Enqueue(ushort questId, JsonNode questNode) => _questNodes[questId] = questNode;
|
||||||
|
|
||||||
|
public void Reset() => _questNodes.Clear();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user