Skip to content

Commit 88942d2

Browse files
committed
Type CLI import destinations
1 parent 653035c commit 88942d2

7 files changed

Lines changed: 90 additions & 29 deletions

File tree

src/PlateauResoniteLink.Cli/CliApplication.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,19 +68,19 @@ public async Task<int> RunAsync(string[] args, CancellationToken cancellationTok
6868
options.WorkRoot,
6969
cancellationToken);
7070

71-
if (options.CanonicalSceneDumpPath is null)
71+
if (options.Destination is ImportDestination.CanonicalSceneDump canonicalSceneDump)
7272
{
73-
await standardOutput.WriteLineAsync("Resonite import completed.");
73+
await standardOutput.WriteLineAsync("Canonical scene dump completed.");
74+
await standardOutput.WriteLineAsync($"Dump: {Path.GetFullPath(canonicalSceneDump.Path)}");
7475
}
7576
else
7677
{
77-
await standardOutput.WriteLineAsync("Canonical scene dump completed.");
78-
await standardOutput.WriteLineAsync($"Dump: {Path.GetFullPath(options.CanonicalSceneDumpPath)}");
78+
await standardOutput.WriteLineAsync("Resonite import completed.");
7979
}
8080

8181
await standardOutput.WriteLineAsync($"World: {result.Metadata.SceneName}");
8282

83-
if (options.CanonicalSceneDumpPath is null)
83+
if (options.Destination is ImportDestination.Live)
8484
{
8585
foreach (string destination in result.Destinations)
8686
{

src/PlateauResoniteLink.Cli/CliArgumentsParser.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -400,17 +400,19 @@ private static CliParseResult ParseImport(string[] args)
400400
"Specify either --resonitelink-port or --resonitelink-url.");
401401
}
402402

403+
ImportDestination destination = canonicalSceneDumpPath is null
404+
? new ImportDestination.Live(resoniteLinkUri!, resoniteLinkConnectionCount)
405+
: new ImportDestination.CanonicalSceneDump(canonicalSceneDumpPath);
406+
403407
return CliParseResult.Success(
404408
new ImportCommandOptions(
405409
request,
406410
workRoot,
407-
resoniteLinkUri,
408-
resoniteLinkConnectionCount,
411+
destination,
409412
memoryProfile,
410413
enableMeshBake,
411414
terrainTileCacheRoot,
412415
disableTerrainTileCache,
413-
canonicalSceneDumpPath,
414416
enableSendMetrics,
415417
verboseLogging));
416418
}

src/PlateauResoniteLink.Cli/CliHostFactory.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,20 +131,25 @@ public ISceneSink Create(ImportCommandOptions options, Action<string>? progressR
131131
AsyncServiceScope scope = serviceScopeFactory.CreateAsyncScope();
132132
try
133133
{
134-
if (!string.IsNullOrWhiteSpace(options.CanonicalSceneDumpPath))
134+
if (options.Destination is ImportDestination.CanonicalSceneDump canonicalSceneDump)
135135
{
136136
IResoniteCanonicalSceneDumpSinkFactory dumpSinkFactory =
137137
scope.ServiceProvider.GetRequiredService<IResoniteCanonicalSceneDumpSinkFactory>();
138138
return new ScopedSceneSink(
139139
scope,
140140
dumpSinkFactory.Create(
141141
CreateCanonicalDumpTargetOptions(options, progressReporter),
142-
options.CanonicalSceneDumpPath));
142+
canonicalSceneDump.Path));
143143
}
144144

145+
ImportDestination.Live liveDestination = options.Destination switch
146+
{
147+
ImportDestination.Live live => live,
148+
_ => throw new InvalidOperationException($"Unsupported import destination '{options.Destination.GetType().Name}'."),
149+
};
145150
ResoniteLiveSceneImportTargetOptions targetOptions = new(
146-
options.ResoniteLinkUri!,
147-
options.ResoniteLinkConnectionCount,
151+
liveDestination.ResoniteLinkUri,
152+
liveDestination.ConnectionCount,
148153
options.EnableSendMetrics,
149154
options.MemoryProfile switch
150155
{

src/PlateauResoniteLink.Cli/ImportCommandOptions.cs

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,19 @@ namespace PlateauResoniteLink.Cli;
77
public sealed class ImportCommandOptions(
88
PlateauImportRequest Request,
99
string WorkRoot,
10-
Uri? ResoniteLinkUri,
11-
int ResoniteLinkConnectionCount,
10+
ImportDestination Destination,
1211
PlateauImportMemoryProfile MemoryProfile,
1312
bool EnableMeshBake,
1413
string? TerrainTileCacheRoot,
1514
bool DisableTerrainTileCache,
16-
string? CanonicalSceneDumpPath,
1715
bool EnableSendMetrics,
1816
bool VerboseLogging) : CliCommandOptions
1917
{
2018
public PlateauImportRequest Request { get; } = Request ?? throw new ArgumentNullException(nameof(Request));
2119

2220
public string WorkRoot { get; } = WorkRoot ?? throw new ArgumentNullException(nameof(WorkRoot));
2321

24-
public Uri? ResoniteLinkUri { get; } = ResoniteLinkUri;
25-
26-
public int ResoniteLinkConnectionCount { get; } = ResoniteLinkConnectionCount;
22+
public ImportDestination Destination { get; } = Destination ?? throw new ArgumentNullException(nameof(Destination));
2723

2824
public PlateauImportMemoryProfile MemoryProfile { get; } = MemoryProfile;
2925

@@ -33,9 +29,50 @@ public sealed class ImportCommandOptions(
3329

3430
public bool DisableTerrainTileCache { get; } = DisableTerrainTileCache;
3531

36-
public string? CanonicalSceneDumpPath { get; } = CanonicalSceneDumpPath;
37-
3832
public bool EnableSendMetrics { get; } = EnableSendMetrics;
3933

4034
public bool VerboseLogging { get; } = VerboseLogging;
4135
}
36+
37+
public abstract record ImportDestination
38+
{
39+
private ImportDestination()
40+
{
41+
}
42+
43+
public sealed record Live : ImportDestination
44+
{
45+
public Live(Uri resoniteLinkUri, int connectionCount)
46+
{
47+
ArgumentNullException.ThrowIfNull(resoniteLinkUri);
48+
if (!resoniteLinkUri.IsAbsoluteUri)
49+
{
50+
throw new ArgumentException("The ResoniteLink URI must be absolute.", nameof(resoniteLinkUri));
51+
}
52+
53+
if (connectionCount < 1)
54+
{
55+
throw new ArgumentOutOfRangeException(nameof(connectionCount), connectionCount, "Connection count must be positive.");
56+
}
57+
58+
ResoniteLinkUri = resoniteLinkUri;
59+
ConnectionCount = connectionCount;
60+
}
61+
62+
public Uri ResoniteLinkUri { get; }
63+
64+
public int ConnectionCount { get; }
65+
}
66+
67+
public sealed record CanonicalSceneDump : ImportDestination
68+
{
69+
public CanonicalSceneDump(string path)
70+
{
71+
ArgumentException.ThrowIfNullOrWhiteSpace(path);
72+
73+
Path = path;
74+
}
75+
76+
public string Path { get; }
77+
}
78+
}

tests/PlateauResoniteLink.Tests/Cli/CliArgumentsParserTests.cs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ public void ParseParsesLocalImportCommand()
2626
Assert.Equal("/data/plateau", options.Request.CityGmlLocalSourcePath);
2727
Assert.Null(options.Request.DemTextureSource);
2828
Assert.Equal(CliTestData.DocumentedDefaultPackageNames, options.Request.PackageNames);
29-
Assert.Equal(new Uri("ws://localhost:12345/"), options.ResoniteLinkUri);
29+
ImportDestination.Live destination = Assert.IsType<ImportDestination.Live>(options.Destination);
30+
Assert.Equal(new Uri("ws://localhost:12345/"), destination.ResoniteLinkUri);
31+
Assert.Equal(CliDefaultOptions.ResoniteLinkConnectionCount, destination.ConnectionCount);
3032
}
3133

3234
[Fact]
@@ -64,6 +66,25 @@ public void ParseParsesRemoteImportCommandAndOptionalGeoTiffSource()
6466
Assert.Equal(new Uri("https://example.invalid/53394525.tif"), options.Request.DemTextureServerUri);
6567
}
6668

69+
[Fact]
70+
public void ParseParsesLiveImportDestinationConnectionCount()
71+
{
72+
CliParseResult result = CliArgumentsParser.Parse(
73+
[
74+
"import",
75+
"--dataset", "tokyo23ku",
76+
"--mesh-code", "53394525",
77+
"--citygml-source", "/data/plateau",
78+
"--resonitelink-url", "wss://example.invalid/link",
79+
"--resonitelink-connections", "3",
80+
]);
81+
82+
ImportCommandOptions options = AssertImportSuccess(result);
83+
ImportDestination.Live destination = Assert.IsType<ImportDestination.Live>(options.Destination);
84+
Assert.Equal(new Uri("wss://example.invalid/link"), destination.ResoniteLinkUri);
85+
Assert.Equal(3, destination.ConnectionCount);
86+
}
87+
6788
[Fact]
6889
public void ParseRequiresCityGmlSource()
6990
{
@@ -91,8 +112,8 @@ public void ParseParsesCanonicalSceneDumpImportWithoutResoniteLinkEndpoint()
91112
]);
92113

93114
ImportCommandOptions options = AssertImportSuccess(result);
94-
Assert.Null(options.ResoniteLinkUri);
95-
Assert.Equal("out/scene.json", options.CanonicalSceneDumpPath);
115+
ImportDestination.CanonicalSceneDump destination = Assert.IsType<ImportDestination.CanonicalSceneDump>(options.Destination);
116+
Assert.Equal("out/scene.json", destination.Path);
96117
}
97118

98119
[Fact]

tests/PlateauResoniteLink.Tests/Cli/CliHostFactoryTests.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,11 @@ public async Task CreateSceneSinkFactoryBuildsCanonicalDumpSinkThroughRegistered
5858
MeshCode: "53394525",
5959
CityGmlSource: DatasetLocation.Local(Path.GetTempPath())),
6060
WorkRoot: Path.GetTempPath(),
61-
ResoniteLinkUri: null,
62-
ResoniteLinkConnectionCount: 4,
61+
Destination: new ImportDestination.CanonicalSceneDump(Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid():N}.json")),
6362
MemoryProfile: PlateauImportMemoryProfile.Large,
6463
EnableMeshBake: true,
6564
TerrainTileCacheRoot: null,
6665
DisableTerrainTileCache: false,
67-
CanonicalSceneDumpPath: Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid():N}.json"),
6866
EnableSendMetrics: true,
6967
VerboseLogging: false),
7068
progressReporter: null);

tests/PlateauResoniteLink.Tests/Cli/ImportServiceFactoryTests.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,11 @@ private static ImportCommandOptions CreateOptions(string meshCode, bool enableMe
5656
return new ImportCommandOptions(
5757
request,
5858
"local",
59-
new Uri("ws://localhost:12345/"),
60-
4,
59+
new ImportDestination.Live(new Uri("ws://localhost:12345/"), 4),
6160
PlateauImportMemoryProfile.Large,
6261
enableMeshBake,
6362
TerrainTileCacheRoot: null,
6463
DisableTerrainTileCache: false,
65-
CanonicalSceneDumpPath: null,
6664
EnableSendMetrics: false,
6765
VerboseLogging: false);
6866
}

0 commit comments

Comments
 (0)