mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-27 02:41:06 -04:00
feat(server): take nest record counts, material and thickness from the archive
The server stored whatever plate count, part count, material and thickness the client claimed, so a record could disagree with its own archive, and a bulk importer had to read each written .nest back in full just to describe it (about a quarter of the PEP archive import's time). Uploads (POST and PUT /file) now read only the archive's nest.json - never programs or geometry, and without referencing OpenNest.IO - and overwrite those fields, following NestReader's fallbacks for thickness, material, parts with a missing drawing and the trailing new-plate slot. A file without a readable nest.json is 400 and stores nothing, so the server can guarantee the record describes the bytes; nest.json decompression stops at 64 MB. A metadata-only PUT keeps the stored counts because the archive is unchanged; material and thickness stay editable there, since the desktop applies the record's values on open. Server tests that uploaded placeholder bytes now upload small deterministic archives, and the container smoke's near-limit probe is a padded real archive. New tests pin the server's values to a full NestReader read of the same archive. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0eb6d5886a
commit
64e24fc6c8
12 files changed
+446
-73
No files matched your search
@@ -191,14 +191,14 @@ internal static class Program
|
||||
var before = await Snapshot(repository, ct);
|
||||
Check(before.Count > 0, "Limit checks require seeded records on an owned server.");
|
||||
|
||||
// Opaque synthetic bytes (the server does not parse archives) above the 64 KiB form
|
||||
// memory threshold, so the non-root runtime must buffer the part to its temp directory.
|
||||
var accepted = new byte[29_000_000];
|
||||
RandomNumberGenerator.Fill(accepted);
|
||||
// A readable nest archive (the server parses its nest.json) padded with incompressible
|
||||
// bytes above the 64 KiB form memory threshold, so the non-root runtime must buffer the
|
||||
// part to its temp directory.
|
||||
var accepted = PaddedArchive(29_000_000);
|
||||
var created = await repository.UploadAsync(accepted, new NestRecord
|
||||
{
|
||||
Name = "Synthetic upload-limit probe",
|
||||
Comments = "Random bytes; deleted by the same smoke stage",
|
||||
Comments = "Random padding; deleted by the same smoke stage",
|
||||
}, ct);
|
||||
Check(created.Id != Guid.Empty && created.FileSize == accepted.LongLength,
|
||||
"A near-limit upload must be stored with its exact size.");
|
||||
@@ -363,6 +363,23 @@ internal static class Program
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>A minimal nest archive with a stored random entry, close to <paramref name="size"/> bytes.</summary>
|
||||
private static byte[] PaddedArchive(int size)
|
||||
{
|
||||
using var stream = new MemoryStream();
|
||||
using (var zip = new System.IO.Compression.ZipArchive(stream, System.IO.Compression.ZipArchiveMode.Create, leaveOpen: true))
|
||||
{
|
||||
using (var writer = new StreamWriter(zip.CreateEntry("nest.json").Open()))
|
||||
writer.Write("""{"version":2,"name":"Synthetic upload-limit probe","drawings":[],"plates":[]}""");
|
||||
var padding = new byte[size - 1024];
|
||||
RandomNumberGenerator.Fill(padding);
|
||||
using var entry = zip.CreateEntry("padding.bin", System.IO.Compression.CompressionLevel.NoCompression).Open();
|
||||
entry.Write(padding);
|
||||
}
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
private static GeometryState Geometry(Nest nest) => new()
|
||||
{
|
||||
PlateWidth = nest.Plates[0].Size.Width,
|
||||
|
||||
Reference in new issue
Block a user