This commit is contained in:
2026-05-13 11:21:48 +09:00
parent 960163dad8
commit 8b5c92194f
66 changed files with 12393 additions and 939 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
using System.Threading;
using System.Threading.Tasks;
using Tornado3_2026Election.Domain;
namespace Tornado3_2026Election.Services;
public sealed class KarismaThumbnailGeneratorService
{
public KarismaThumbnailGeneratorService(LogService logService)
{
}
public Task<ThumbnailGenerationResult> GenerateAsync(
TornadoManager manager,
IReadOnlyList<FormatTemplateDefinition> templates,
string t3CutPath,
VideoWallLayoutPreset videoWallLayoutPreset,
CancellationToken cancellationToken)
{
return Task.FromResult(new ThumbnailGenerationResult(0, 0));
}
}
public readonly record struct ThumbnailGenerationResult(int GeneratedCount, int FailedCount)
{
public int TotalCount => GeneratedCount + FailedCount;
}

View File

@@ -337,6 +337,12 @@ if (args.Length > 0 && string.Equals(args[0], "--report-cut-debug-coverage", Str
return;
}
if (args.Length > 0 && string.Equals(args[0], "--audit-cut-files", StringComparison.OrdinalIgnoreCase))
{
Environment.ExitCode = await CutFileAudit.RunAsync(args[1..]).ConfigureAwait(false);
return;
}
var options = ProbeOptions.Parse(args);
Console.WriteLine($"Karisma TCP probe starting. target={options.Host}:{options.Port} timeout={options.Timeout.TotalSeconds:0}s");
@@ -862,6 +868,25 @@ static Task<SaveSceneImageProbeResult> SaveSceneImageAsync(SaveSceneImageOptions
}
}
IReadOnlyList<SceneValidationOperation> operations = string.IsNullOrWhiteSpace(options.OperationsPath)
? Array.Empty<SceneValidationOperation>()
: LoadSceneOperations(options.ScenePath, options.OperationsPath);
foreach (var operation in operations)
{
var operationResult = ApplySceneOperation(handler, scene!, operation, options.Connection.Timeout);
if (!string.Equals(operationResult.Result, eKResult.RESULT_SUCCESS.ToString(), StringComparison.Ordinal))
{
completion.TrySetResult(
new SaveSceneImageProbeResult(
true,
"SUCCESS",
operationResult.Result,
options.OutputPath,
$"Operation {operationResult.Method} failed for '{operationResult.ObjectName}': {operationResult.Detail}"));
return;
}
}
if (options.MaterialOpacity is not null)
{
Console.WriteLine(
@@ -1283,7 +1308,16 @@ static Task<SceneCatalogProbeResult> CatalogScenesAsync(SceneCatalogOptions opti
.EnumerateFiles(options.RootPath, "*.tscn", SearchOption.AllDirectories)
.Where(path => string.IsNullOrWhiteSpace(options.SceneFilter) ||
path.Contains(options.SceneFilter, StringComparison.OrdinalIgnoreCase))
.OrderBy(path => path, StringComparer.OrdinalIgnoreCase)
.Select(path => new
{
Path = path,
RelativePath = Path.GetRelativePath(options.RootPath, path)
})
.OrderBy(item => item.RelativePath.Count(character =>
character == Path.DirectorySeparatorChar ||
character == Path.AltDirectorySeparatorChar))
.ThenBy(item => item.RelativePath, StringComparer.OrdinalIgnoreCase)
.Select(item => item.Path)
.Take(options.MaxScenes ?? int.MaxValue)
.ToArray();
@@ -2309,142 +2343,7 @@ static Task<SceneValidationProbeResult> ValidateSceneOperationsAsync(SceneValida
foreach (var operation in operations)
{
Console.WriteLine($"[VALIDATE] {operation.Method} object={operation.ObjectName}");
var sceneObject = scene.GetObject(operation.ObjectName);
if (sceneObject is null)
{
results.Add(new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
"OBJECT_NOT_FOUND",
"scene.GetObject returned null."));
continue;
}
if (string.Equals(operation.Method, "SetCounterNumberKey", StringComparison.OrdinalIgnoreCase))
{
if (sceneObject is not IKACounter counter)
{
results.Add(new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
"NOT_A_COUNTER",
"Object does not implement IKACounter."));
continue;
}
handler.ResetCounterNumberKeyTask();
counter.SetCounterNumberKey(operation.KeyIndex, operation.Number);
if (!WaitForTaskWithMessagePump(handler.CounterNumberKeyTask, options.Connection.Timeout))
{
results.Add(new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
"TIMEOUT",
"OnSetCounterNumberKey timed out."));
continue;
}
var callbackResult = handler.CounterNumberKeyTask.Result;
results.Add(new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
callbackResult.ToString(),
string.Empty));
continue;
}
if (string.Equals(operation.Method, "SetVisible", StringComparison.OrdinalIgnoreCase))
{
handler.ResetVisibleTask();
sceneObject.SetVisible(operation.Visible ? 1 : 0);
if (!WaitForTaskWithMessagePump(handler.VisibleTask, options.Connection.Timeout))
{
results.Add(new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
"TIMEOUT",
"OnSetVisible timed out."));
continue;
}
var callbackResult = handler.VisibleTask.Result;
results.Add(new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
callbackResult.ToString(),
string.Empty));
continue;
}
if (string.Equals(operation.Method, "SetStyleColor", StringComparison.OrdinalIgnoreCase))
{
if (sceneObject is not IKAStyle style)
{
results.Add(new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
"NOT_A_STYLE_OBJECT",
"Object does not implement IKAStyle."));
continue;
}
handler.ResetStyleColorTask();
style.SetStyleColor(
ParseStyleType(operation.StyleType),
operation.Order,
operation.R,
operation.G,
operation.B,
operation.A);
if (!WaitForTaskWithMessagePump(handler.StyleColorTask, options.Connection.Timeout))
{
results.Add(new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
"TIMEOUT",
"OnSetStyleColor timed out."));
continue;
}
var callbackResult = handler.StyleColorTask.Result;
results.Add(new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
callbackResult.ToString(),
string.Empty));
continue;
}
handler.ResetSetValueTask();
sceneObject.SetValue(operation.Value ?? string.Empty);
if (!WaitForTaskWithMessagePump(handler.SetValueTask, options.Connection.Timeout))
{
results.Add(new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
"TIMEOUT",
"OnSetValue timed out."));
continue;
}
var setValueResult = handler.SetValueTask.Result;
results.Add(new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
setValueResult.ToString(),
string.Empty));
results.Add(ApplySceneOperation(handler, scene, operation, options.Connection.Timeout));
}
WriteSceneValidationMarkdown(options, results);
@@ -2532,7 +2431,16 @@ static Task<FolderInspectionProbeResult> InspectTscnFolderAsync(FolderInspection
.EnumerateFiles(options.RootPath, "*.tscn", SearchOption.AllDirectories)
.Where(path => string.IsNullOrWhiteSpace(options.SceneFilter) ||
path.Contains(options.SceneFilter, StringComparison.OrdinalIgnoreCase))
.OrderBy(path => path, StringComparer.OrdinalIgnoreCase)
.Select(path => new
{
Path = path,
RelativePath = Path.GetRelativePath(options.RootPath, path)
})
.OrderBy(item => item.RelativePath.Count(character =>
character == Path.DirectorySeparatorChar ||
character == Path.AltDirectorySeparatorChar))
.ThenBy(item => item.RelativePath, StringComparer.OrdinalIgnoreCase)
.Select(item => item.Path)
.Take(options.MaxScenes ?? int.MaxValue)
.ToArray();
@@ -2865,7 +2773,12 @@ static void WriteFolderInspectionMarkdown(
static List<SceneValidationOperation> LoadValidationOperations(SceneValidationOptions options)
{
var json = File.ReadAllText(options.OperationsPath);
return LoadSceneOperations(options.ScenePath, options.OperationsPath);
}
static List<SceneValidationOperation> LoadSceneOperations(string scenePath, string operationsPath)
{
var json = File.ReadAllText(operationsPath);
var operations = JsonSerializer.Deserialize<List<SceneValidationOperation>>(json, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
@@ -2875,13 +2788,143 @@ static List<SceneValidationOperation> LoadValidationOperations(SceneValidationOp
{
if (!string.IsNullOrWhiteSpace(operation.Value))
{
operation.Value = operation.Value.Replace("${SCENE_DIR}", Path.GetDirectoryName(options.ScenePath) ?? string.Empty, StringComparison.Ordinal);
operation.Value = operation.Value.Replace("${SCENE_DIR}", Path.GetDirectoryName(scenePath) ?? string.Empty, StringComparison.Ordinal);
}
}
return operations;
}
static SceneOperationValidationResult ApplySceneOperation(
ProbeEventHandler handler,
IKAScene scene,
SceneValidationOperation operation,
TimeSpan timeout)
{
Console.WriteLine($"[VALIDATE] {operation.Method} object={operation.ObjectName}");
var sceneObject = scene.GetObject(operation.ObjectName);
if (sceneObject is null)
{
return new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
"OBJECT_NOT_FOUND",
"scene.GetObject returned null.");
}
if (string.Equals(operation.Method, "SetCounterNumberKey", StringComparison.OrdinalIgnoreCase))
{
if (sceneObject is not IKACounter counter)
{
return new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
"NOT_A_COUNTER",
"Object does not implement IKACounter.");
}
handler.ResetCounterNumberKeyTask();
counter.SetCounterNumberKey(operation.KeyIndex, operation.Number);
if (!WaitForTaskWithMessagePump(handler.CounterNumberKeyTask, timeout))
{
return new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
"TIMEOUT",
"OnSetCounterNumberKey timed out.");
}
return new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
handler.CounterNumberKeyTask.Result.ToString(),
string.Empty);
}
if (string.Equals(operation.Method, "SetVisible", StringComparison.OrdinalIgnoreCase))
{
handler.ResetVisibleTask();
sceneObject.SetVisible(operation.Visible ? 1 : 0);
if (!WaitForTaskWithMessagePump(handler.VisibleTask, timeout))
{
return new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
"TIMEOUT",
"OnSetVisible timed out.");
}
return new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
handler.VisibleTask.Result.ToString(),
string.Empty);
}
if (string.Equals(operation.Method, "SetStyleColor", StringComparison.OrdinalIgnoreCase))
{
if (sceneObject is not IKAStyle style)
{
return new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
"NOT_A_STYLE_OBJECT",
"Object does not implement IKAStyle.");
}
handler.ResetStyleColorTask();
style.SetStyleColor(
ParseStyleType(operation.StyleType),
operation.Order,
operation.R,
operation.G,
operation.B,
operation.A);
if (!WaitForTaskWithMessagePump(handler.StyleColorTask, timeout))
{
return new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
"TIMEOUT",
"OnSetStyleColor timed out.");
}
return new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
handler.StyleColorTask.Result.ToString(),
string.Empty);
}
handler.ResetSetValueTask();
sceneObject.SetValue(operation.Value ?? string.Empty);
if (!WaitForTaskWithMessagePump(handler.SetValueTask, timeout))
{
return new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
"TIMEOUT",
"OnSetValue timed out.");
}
return new SceneOperationValidationResult(
operation.ObjectName,
operation.Method,
DescribeOperationPayload(operation),
handler.SetValueTask.Result.ToString(),
string.Empty);
}
static string DescribeOperationPayload(SceneValidationOperation operation)
{
if (string.Equals(operation.Method, "SetVisible", StringComparison.OrdinalIgnoreCase))
@@ -3393,6 +3436,7 @@ internal sealed record SaveSceneImageOptions(
bool? VisibleObjectValue,
VariableNameUpdate? VariableName,
CloneObjectUpdate? CloneObject,
string? OperationsPath,
MaterialOpacityUpdate? MaterialOpacity,
SizeUpdate? Size,
PositionUpdate? Position,
@@ -3419,6 +3463,7 @@ internal sealed record SaveSceneImageOptions(
string? variableNameValue = null;
string? cloneSourceObjectName = null;
string? cloneVariableName = null;
string? operationsPath = null;
string? materialOpacityObjectName = null;
float? materialOpacityValue = null;
string? sizeObjectName = null;
@@ -3481,6 +3526,9 @@ internal sealed record SaveSceneImageOptions(
case "--clone-name" when index + 1 < args.Length:
cloneVariableName = args[++index];
break;
case "--operations" when index + 1 < args.Length:
operationsPath = args[++index];
break;
case "--material-opacity-object" when index + 1 < args.Length:
materialOpacityObjectName = args[++index];
break;
@@ -3558,6 +3606,9 @@ internal sealed record SaveSceneImageOptions(
scenePath = Path.GetFullPath(scenePath);
outputPath = Path.GetFullPath(outputPath);
operationsPath = string.IsNullOrWhiteSpace(operationsPath)
? null
: Path.GetFullPath(operationsPath);
sceneAlias ??= Path.GetFileNameWithoutExtension(scenePath);
return new SaveSceneImageOptions(
connection,
@@ -3573,6 +3624,7 @@ internal sealed record SaveSceneImageOptions(
visibleObjectValue,
ParseVariableName(variableNameObjectName, variableNameValue),
ParseCloneObject(cloneSourceObjectName, cloneVariableName),
operationsPath,
ParseMaterialOpacity(materialOpacityObjectName, materialOpacityValue),
ParseSize(sizeObjectName, sizeRaw),
ParsePosition(positionObjectName, positionRaw),
@@ -3857,7 +3909,7 @@ internal sealed record SceneCatalogOptions(
switch (args[index])
{
case "--root" when index + 1 < args.Length:
index++;
rootPath = args[++index];
break;
case "--output" when index + 1 < args.Length:
outputPath = args[++index];
@@ -4195,7 +4247,7 @@ internal sealed record FolderInspectionOptions(ProbeOptions Connection, string R
switch (args[index])
{
case "--root" when index + 1 < args.Length:
index++;
rootPath = args[++index];
break;
case "--output" when index + 1 < args.Length:
outputPath = args[++index];