Browse Source

work around sequential schedule validation limit

pull/2655/head
Jason Dove 8 months ago
parent
commit
3884254bc3
No known key found for this signature in database
  1. 3
      CHANGELOG.md
  2. 1
      ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj
  3. 56
      ErsatzTV.Infrastructure/Scheduling/SequentialScheduleValidator.cs

3
CHANGELOG.md

@ -84,6 +84,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -84,6 +84,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Add disabled text color and `(D)` and `(H)` labels for disabled and hidden channels in channel list
- Graphics engine: fix subtitle path escaping and font loading
- Fix corrupt output (green artifacts) when decoding certain 10-bit content using AMD Polaris GPUs
- Work around sequential schedule validation limit (1000/hr by Newtonsoft.Json.Schema library)
- Playout builds now use JsonSchema.Net library which has no validation limit
- Validation tool in the UI still uses Newtonsoft.Json.Schema (with 1000/hr limit) as the error output is easier to understand
### Changed
- Classic schedules: `Refresh` classic playouts from playout list; do not `Reset` them

1
ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj

@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
<PackageReference Include="EFCore.BulkExtensions" Version="9.0.2" />
<PackageReference Include="Elastic.Clients.Elasticsearch" Version="9.2.1" />
<PackageReference Include="Jint" Version="4.4.2" />
<PackageReference Include="JsonSchema.Net" Version="7.4.0" />
<PackageReference Include="Lucene.Net" Version="4.8.0-beta00017" />
<PackageReference Include="Lucene.Net.Analysis.Common" Version="4.8.0-beta00017" />
<PackageReference Include="Lucene.Net.QueryParser" Version="4.8.0-beta00017" />

56
ErsatzTV.Infrastructure/Scheduling/SequentialScheduleValidator.cs

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
using System.Globalization;
using System.IO.Abstractions;
using System.Text.Json;
using System.Text.Json.Nodes;
using ErsatzTV.Core;
using ErsatzTV.Core.Interfaces.Scheduling;
using Microsoft.Extensions.Logging;
@ -9,6 +10,7 @@ using Newtonsoft.Json.Linq; @@ -9,6 +10,7 @@ using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Schema;
using YamlDotNet.RepresentationModel;
using JsonSerializer = System.Text.Json.JsonSerializer;
using JsonSchemaNet = Json.Schema;
namespace ErsatzTV.Infrastructure.Scheduling;
@ -19,21 +21,19 @@ public class SequentialScheduleValidator(IFileSystem fileSystem, ILogger<Sequent @@ -19,21 +21,19 @@ public class SequentialScheduleValidator(IFileSystem fileSystem, ILogger<Sequent
{
try
{
string schemaFileName = Path.Combine(
FileSystemLayout.ResourcesCacheFolder,
isImport ? "sequential-schedule-import.schema.json" : "sequential-schedule.schema.json");
using StreamReader sr = fileSystem.File.OpenText(schemaFileName);
await using var reader = new JsonTextReader(sr);
var schema = JSchema.Load(reader);
string schemaFileName = GetSchemaPath(isImport);
string schemaText = await fileSystem.File.ReadAllTextAsync(schemaFileName);
JsonSchemaNet.JsonSchema schema = JsonSchemaNet.JsonSchema.FromText(schemaText);
string jsonString = ConvertYamlToJsonString(yaml);
JsonNode jsonNode = JsonNode.Parse(jsonString);
using var textReader = new StringReader(yaml);
var yamlStream = new YamlStream();
yamlStream.Load(textReader);
var schedule = JObject.Parse(Convert(yamlStream));
JsonSchemaNet.EvaluationResults result = schema.Evaluate(jsonNode);
if (!schedule.IsValid(schema, out IList<string> errorMessages))
if (!result.IsValid)
{
logger.LogWarning("Failed to validate sequential schedule definition: {ErrorMessages}", errorMessages);
logger.LogWarning("Sequential schedule definition failed validation");
return false;
}
@ -49,30 +49,27 @@ public class SequentialScheduleValidator(IFileSystem fileSystem, ILogger<Sequent @@ -49,30 +49,27 @@ public class SequentialScheduleValidator(IFileSystem fileSystem, ILogger<Sequent
public string ToJson(string yaml)
{
using var textReader = new StringReader(yaml);
var yamlStream = new YamlStream();
yamlStream.Load(textReader);
var schedule = JObject.Parse(Convert(yamlStream));
string jsonString = ConvertYamlToJsonString(yaml);
var schedule = JObject.Parse(jsonString);
string formatted = JsonConvert.SerializeObject(schedule, Formatting.Indented);
string[] lines = formatted.Split('\n');
return string.Join('\n', lines.Select((line, index) => $"{index + 1,4}: {line}"));
}
// limited to 1000/hr, but only called manually from UI
public async Task<IList<string>> GetValidationMessages(string yaml, bool isImport)
{
try
{
string schemaFileName = Path.Combine(
FileSystemLayout.ResourcesCacheFolder,
isImport ? "sequential-schedule-import.schema.json" : "sequential-schedule.schema.json");
string schemaFileName = GetSchemaPath(isImport);
using StreamReader sr = fileSystem.File.OpenText(schemaFileName);
await using var reader = new JsonTextReader(sr);
var schema = JSchema.Load(reader);
using var textReader = new StringReader(yaml);
var yamlStream = new YamlStream();
yamlStream.Load(textReader);
var schedule = JObject.Parse(Convert(yamlStream));
string jsonString = ConvertYamlToJsonString(yaml);
var schedule = JObject.Parse(jsonString);
return schedule.IsValid(schema, out IList<string> errorMessages) ? [] : errorMessages;
}
@ -82,13 +79,24 @@ public class SequentialScheduleValidator(IFileSystem fileSystem, ILogger<Sequent @@ -82,13 +79,24 @@ public class SequentialScheduleValidator(IFileSystem fileSystem, ILogger<Sequent
}
}
private static string Convert(YamlStream yamlStream)
private static string ConvertYamlToJsonString(string yaml)
{
using var textReader = new StringReader(yaml);
var yamlStream = new YamlStream();
yamlStream.Load(textReader);
var visitor = new YamlToJsonVisitor();
yamlStream.Accept(visitor);
return JsonConvert.SerializeObject(JsonConvert.DeserializeObject(visitor.JsonString), Formatting.Indented);
}
private static string GetSchemaPath(bool isImport)
{
return Path.Combine(
FileSystemLayout.ResourcesCacheFolder,
isImport ? "sequential-schedule-import.schema.json" : "sequential-schedule.schema.json");
}
private sealed class YamlToJsonVisitor : IYamlVisitor
{
private readonly JsonSerializerOptions _options = new() { WriteIndented = false };

Loading…
Cancel
Save