Skip to content

Commit 68cb126

Browse files
committed
make object directory a config settings
1 parent 52624bc commit 68cb126

File tree

7 files changed

+69
-49
lines changed

7 files changed

+69
-49
lines changed

AvaGui/Models/ObjectEditorModel.cs

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
using System;
1313
using System.Collections.Generic;
1414
using System.Collections.ObjectModel;
15-
using System.Diagnostics;
1615
using System.IO;
1716
using System.Linq;
1817
using System.Net.Http;
@@ -255,20 +254,6 @@ public bool TryLoadObject(FileSystemItem filesystemItem, out UiLocoFile? uiLocoF
255254
return true;
256255
}
257256

258-
async Task CreateIndex(string[] allFiles, IProgress<float> progress)
259-
{
260-
Logger.Info($"Creating index on {allFiles.Length} files");
261-
262-
var sw = new Stopwatch();
263-
sw.Start();
264-
265-
var fileCount = allFiles.Length;
266-
ObjectIndex = await ObjectIndex.CreateIndexAsync(allFiles, progress);
267-
268-
sw.Stop();
269-
Logger.Info($"Indexed {fileCount} in {sw.Elapsed}");
270-
}
271-
272257
public bool LoadDataDirectory(string directory)
273258
{
274259
if (!Directory.Exists(directory))
@@ -373,26 +358,26 @@ async Task LoadObjDirectoryAsyncCore(string directory, IProgress<float> progress
373358
if (exception || ObjectIndex?.Objects == null || ObjectIndex.Objects.Any(x => string.IsNullOrEmpty(x.Filename) || (x is ObjectIndexEntry xx && string.IsNullOrEmpty(xx.ObjectName))) != false)
374359
{
375360
Logger.Warning("Index file format has changed or otherwise appears to be malformed - recreating now.");
376-
await RecreateIndex(progress, allFiles);
361+
await RecreateIndex(directory, allFiles, progress);
377362
return;
378363
}
379364

380365
var objectIndexFilenames = ObjectIndex.Objects.Select(x => x.Filename).Concat(ObjectIndex.ObjectsFailed.Select(x => x.Filename));
381366
if (objectIndexFilenames.Except(allFiles).Any() || allFiles.Except(objectIndexFilenames).Any())
382367
{
383368
Logger.Warning("Index file appears to be outdated - recreating now.");
384-
await RecreateIndex(progress, allFiles);
369+
await RecreateIndex(directory, allFiles, progress);
385370
}
386371
}
387372
else
388373
{
389-
await RecreateIndex(progress, allFiles);
374+
await RecreateIndex(directory, allFiles, progress);
390375
}
391376

392-
async Task RecreateIndex(IProgress<float> progress, string[] allFiles)
377+
async Task RecreateIndex(string rootObjectDirectory, string[] allFiles, IProgress<float> progress)
393378
{
394379
Logger.Info("Recreating index file");
395-
await CreateIndex(allFiles, progress); // do we need the array?
380+
ObjectIndex = await ObjectIndex.CreateIndexAsync(rootObjectDirectory, allFiles, progress);
396381
ObjectIndex?.SaveIndex(IndexFilename);
397382
}
398383
}

Common/EditorSettings.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,10 @@ public HashSet<string> SCV5Directories
6060
HashSet<string> scv5Directories;
6161

6262
public bool UseHttps { get; set; }
63-
public string ServerAddressHttp { get; set; } = "http://www.leftofzen.dev/";
64-
public string ServerAddressHttps { get; set; } = "https://www.leftofzen.dev/";
63+
public string ServerAddressHttp { get; set; } = "http://openloco.leftofzen.dev/";
64+
public string ServerAddressHttps { get; set; } = "https://openloco.leftofzen.dev/";
6565

6666
public string PaletteFile { get; set; } = "palette.png";
67-
public string MetadataFileName { get; set; } = "objectMetadata.json";
6867
public string IndexFileName { get; set; } = "objectIndex.json";
6968
public string G1DatFileName { get; set; } = "g1.DAT";
7069
public string DownloadFolder { get; set; } = string.Empty;

Dat/FileParsing/SawyerStreamUtils.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ static uint32_t ComputeChecksum(ReadOnlySpan<byte> data, uint32_t seed)
2424
return checksum;
2525
}
2626

27+
// returns paths relative to the input directory
2728
public static IEnumerable<string> GetDatFilesInDirectory(string directory)
2829
=> Directory
2930
.GetFiles(directory, "*", SearchOption.AllDirectories)
30-
.Where(x => Path.GetExtension(x).Equals(".dat", StringComparison.OrdinalIgnoreCase));
31+
.Where(x => Path.GetExtension(x).Equals(".dat", StringComparison.OrdinalIgnoreCase))
32+
.Select(x => Path.GetRelativePath(directory, x));
3133
}
3234
}

Dat/ObjectIndex.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@ public void AddObject(ObjectIndexEntryBase entryBase)
2727
}
2828
}
2929

30-
public static Task<ObjectIndex> CreateIndexAsync(string[] files, IProgress<float>? progress)
30+
public static Task<ObjectIndex> CreateIndexAsync(string rootObjectDirectory, string[] files, IProgress<float>? progress)
3131
{
3232
ConcurrentQueue<(string Filename, byte[] Data)> pendingFiles = [];
3333
ConcurrentQueue<ObjectIndexEntryBase> pendingIndices = [];
3434

3535
var producerTask = Task.Run(async () =>
3636
{
3737
var options = new ParallelOptions() { MaxDegreeOfParallelism = 32 };
38-
await Parallel.ForEachAsync(files, options, async (f, ct) => pendingFiles.Enqueue((f, await File.ReadAllBytesAsync(f, ct))));
38+
await Parallel.ForEachAsync(files, options, async (f, ct) => pendingFiles.Enqueue((f, await File.ReadAllBytesAsync(Path.Combine(rootObjectDirectory, f), ct))));
3939
});
4040

4141
var consumerTask = Task.Run(async () =>
@@ -80,7 +80,7 @@ public static ObjectIndex LoadOrCreateIndex(string directory)
8080
else
8181
{
8282
var fileArr = SawyerStreamUtils.GetDatFilesInDirectory(directory).ToArray();
83-
index = CreateIndexAsync(fileArr, null).Result;
83+
index = CreateIndexAsync(directory, fileArr, null).Result;
8484
index.SaveIndex(indexPath);
8585
}
8686

ObjectService/Program.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
};
4949
}));
5050

51+
builder.Services.AddSingleton<Server>();
52+
var serviceSettings = builder.Services.Configure<ObjectServiceSettings>(builder.Configuration.GetSection("ObjectService"));
53+
5154
builder.Logging.ClearProviders();
5255
builder.Logging.AddConsole();
5356

@@ -61,20 +64,23 @@
6164
_ = app.UseSwaggerUI();
6265
}
6366

67+
var objRoot = builder.Configuration["ObjectService:ObjectRootFolder"];
68+
var server = new Server(new ObjectServiceSettings() { ObjectRootFolder = objRoot! });
69+
6470
// GET
6571
_ = app.MapGet(Routes.ListObjects, Server.ListObjects)
6672
.RequireRateLimiting(tokenPolicy);
6773

68-
_ = app.MapGet(Routes.GetDat, Server.GetDat)
74+
_ = app.MapGet(Routes.GetDat, server.GetDat)
6975
.RequireRateLimiting(tokenPolicy);
7076

71-
_ = app.MapGet(Routes.GetObject, Server.GetObject)
77+
_ = app.MapGet(Routes.GetObject, server.GetObject)
7278
.RequireRateLimiting(tokenPolicy);
7379

74-
_ = app.MapGet(Routes.GetDatFile, Server.GetDatFile)
80+
_ = app.MapGet(Routes.GetDatFile, server.GetDatFile)
7581
.RequireRateLimiting(tokenPolicy);
7682

77-
_ = app.MapGet(Routes.GetObjectFile, Server.GetObjectFile)
83+
_ = app.MapGet(Routes.GetObjectFile, server.GetObjectFile)
7884
.RequireRateLimiting(tokenPolicy);
7985

8086
// PATCH
@@ -85,7 +91,7 @@
8591
.RequireRateLimiting(tokenPolicy);
8692

8793
// POST
88-
_ = app.MapPost(Routes.UploadDat, Server.UploadDat)
94+
_ = app.MapPost(Routes.UploadDat, server.UploadDat)
8995
.RequireRateLimiting(tokenPolicy);
9096

9197
_ = app.MapPost(Routes.UploadObject, /*Server.UploadDat*/ () => Results.Problem(statusCode: StatusCodes.Status501NotImplemented))

Definitions/Web/Server.cs renamed to ObjectService/Server.cs

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,28 @@
1-
using Microsoft.AspNetCore.Http;
21
using Microsoft.EntityFrameworkCore;
2+
using Microsoft.Extensions.Options;
33
using OpenLoco.Dat.Data;
44
using OpenLoco.Dat.FileParsing;
55
using OpenLoco.Dat.Objects;
6+
using OpenLoco.Definitions;
67
using OpenLoco.Definitions.Database;
78
using OpenLoco.Definitions.DTO;
9+
using OpenLoco.Definitions.Web;
810

9-
namespace OpenLoco.Definitions.Web
11+
namespace OpenLoco.ObjectService
1012
{
1113
// this must be done because eager-loading related many-to-many data in entity framework is recursive and cannot be turned off...
1214
internal record ExpandedTblLocoObject(TblLocoObject Object, ICollection<TblAuthor> Authors, ICollection<TblTag> Tags, ICollection<TblModpack> Modpacks);
1315

14-
public static class Server
16+
public class ObjectServiceSettings
1517
{
18+
public required string ObjectRootFolder { get; set; }
19+
}
20+
21+
public class Server(ObjectServiceSettings settings)
22+
{
23+
public Server(IOptions<ObjectServiceSettings> options) : this(options.Value)
24+
{ }
25+
1626
// eg: https://localhost:7230/objects/list
1727
public static async Task<IResult> ListObjects(LocoDb db)
1828
=> Results.Ok(
@@ -27,7 +37,7 @@ await db.Objects
2737
x.VehicleType)).ToListAsync());
2838

2939
// eg: https://localhost:7230/objects/getdat?objectName=114&checksum=123$returnObjBytes=false
30-
public static async Task<IResult> GetDat(string objectName, uint checksum, bool? returnObjBytes, LocoDb db)
40+
public async Task<IResult> GetDat(string objectName, uint checksum, bool? returnObjBytes, LocoDb db)
3141
{
3242
var eObj = await db.Objects
3343
.Where(x => x.OriginalName == objectName && x.OriginalChecksum == checksum)
@@ -37,11 +47,11 @@ public static async Task<IResult> GetDat(string objectName, uint checksum, bool?
3747

3848
return eObj == null || eObj.Object == null
3949
? Results.NotFound()
40-
: Results.Ok(await PrepareLocoObject(eObj, returnObjBytes ?? false));
50+
: Results.Ok(await PrepareLocoObject(eObj, settings.ObjectRootFolder, returnObjBytes ?? false));
4151
}
4252

4353
// eg: https://localhost:7230/objects/getobject?uniqueObjectId=246263256&returnObjBytes=false
44-
public static async Task<IResult> GetObject(int uniqueObjectId, bool? returnObjBytes, LocoDb db)
54+
public async Task<IResult> GetObject(int uniqueObjectId, bool? returnObjBytes, LocoDb db)
4555
{
4656
Console.WriteLine($"Object [{uniqueObjectId}] requested");
4757
var eObj = await db.Objects
@@ -52,11 +62,11 @@ public static async Task<IResult> GetObject(int uniqueObjectId, bool? returnObjB
5262

5363
return eObj == null || eObj.Object == null
5464
? Results.NotFound()
55-
: Results.Ok(await PrepareLocoObject(eObj, returnObjBytes ?? false));
65+
: Results.Ok(await PrepareLocoObject(eObj, settings.ObjectRootFolder, returnObjBytes ?? false));
5666
}
5767

5868
// eg: https://localhost:7230/objects/originaldatfile?objectName=114&checksum=123
59-
public static async Task<IResult> GetDatFile(string objectName, uint checksum, LocoDb db)
69+
public async Task<IResult> GetDatFile(string objectName, uint checksum, LocoDb db)
6070
{
6171
var obj = await db.Objects
6272
.Where(x => x.OriginalName == objectName && x.OriginalChecksum == checksum)
@@ -70,23 +80,36 @@ public static async Task<IResult> GetDatFile(string objectName, uint checksum, L
7080
}
7181

7282
// eg: https://localhost:7230/objects/getobjectfile?objectName=114&checksum=123
73-
public static async Task<IResult> GetObjectFile(int uniqueObjectId, LocoDb db)
83+
public async Task<IResult> GetObjectFile(int uniqueObjectId, LocoDb db)
7484
{
7585
var obj = await db.Objects
7686
.Where(x => x.Id == uniqueObjectId)
7787
.SingleOrDefaultAsync();
7888

7989
const string contentType = "application/octet-stream";
8090

81-
return obj?.IsVanilla == false && File.Exists(obj.PathOnDisk)
82-
? Results.File(obj.PathOnDisk, contentType, Path.GetFileName(obj.PathOnDisk))
91+
if (obj == null)
92+
{
93+
return Results.NotFound();
94+
}
95+
96+
if (obj.IsVanilla)
97+
{
98+
return Results.BadRequest("Nice try genius. Downloading vanilla objects is not allowed.");
99+
}
100+
101+
var pathOnDisk = Path.Combine(settings.ObjectRootFolder, obj.PathOnDisk);
102+
return File.Exists(pathOnDisk)
103+
? Results.File(pathOnDisk, contentType, Path.GetFileName(pathOnDisk))
83104
: Results.NotFound();
84105
}
85106

86-
internal static async Task<DtoLocoObject> PrepareLocoObject(ExpandedTblLocoObject eObj, bool returnObjBytes)
107+
internal static async Task<DtoLocoObject> PrepareLocoObject(ExpandedTblLocoObject eObj, string objectRootFolder, bool returnObjBytes)
87108
{
88109
var obj = eObj!.Object;
89-
var bytes = returnObjBytes && !obj.IsVanilla && File.Exists(obj.PathOnDisk) ? Convert.ToBase64String(await File.ReadAllBytesAsync(obj.PathOnDisk)) : null;
110+
111+
var pathOnDisk = Path.Combine(objectRootFolder, obj.PathOnDisk);
112+
var bytes = returnObjBytes && !obj.IsVanilla && File.Exists(pathOnDisk) ? Convert.ToBase64String(await File.ReadAllBytesAsync(pathOnDisk)) : null;
90113

91114
return new DtoLocoObject(
92115
obj.Id,
@@ -109,7 +132,7 @@ internal static async Task<DtoLocoObject> PrepareLocoObject(ExpandedTblLocoObjec
109132
}
110133

111134
// eg: <todo>
112-
public static async Task<IResult> UploadDat(DtoUploadDat request, LocoDb db)
135+
public async Task<IResult> UploadDat(DtoUploadDat request, LocoDb db)
113136
{
114137
if (string.IsNullOrEmpty(request.DatBytesAsBase64))
115138
{
@@ -158,15 +181,17 @@ public static async Task<IResult> UploadDat(DtoUploadDat request, LocoDb db)
158181
return Results.Accepted($"Object already exists in the database. OriginalName={s5Header.Name} OriginalChecksum={s5Header.Checksum} UploadDate={existingObject!.UploadDate}");
159182
}
160183

161-
const string UploadFolder = "Q:\\Games\\Locomotion\\Server\\CustomObjects\\Uploaded";
184+
const string SettingsPath = "Q:\\Games\\Locomotion\\Server\\CustomObjects";
185+
const string UploadFolder = "UploadedObjects";
162186
var uuid = Guid.NewGuid();
163-
var saveFileName = Path.Combine(UploadFolder, $"{uuid}.dat");
187+
var saveFileName = Path.Combine(SettingsPath, UploadFolder, $"{uuid}.dat");
188+
File.WriteAllBytes(saveFileName, datFileBytes);
189+
164190
Console.WriteLine($"File accepted OriginalName={s5Header.Name} OriginalChecksum={s5Header.Checksum} PathOnDisk={saveFileName}");
165191

166192
var locoTbl = new TblLocoObject()
167193
{
168194
Name = $"{s5Header.Name}_{s5Header.Checksum}", // same as DB seeder name
169-
PathOnDisk = saveFileName,
170195
OriginalName = s5Header.Name,
171196
OriginalChecksum = s5Header.Checksum,
172197
IsVanilla = false, // not possible to upload vanilla objects

ObjectService/appsettings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,8 @@
2020
"ConnectionStrings": {
2121
"SQLiteConnection": "Data Source=Q:\\Games\\Locomotion\\Server\\loco-dev.db"
2222

23+
},
24+
"ObjectService": {
25+
"ObjectRootFolder": "Q:\\Games\\Locomotion\\Server\\Objects"
2326
}
2427
}

0 commit comments

Comments
 (0)