mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
fix(director): reject cancellation during the final asset stream read
This commit is contained in:
1 parent
0265ad4c19
commit
cd7c23b36f
4 files changed
+49
No files matched your search
@@ -32,6 +32,7 @@
|
||||
- Tool string length validation counts Unicode characters correctly, including characters outside the basic multilingual plane.
|
||||
|
||||
- Director timeline seeks cross the dateline along the short longitude arc.
|
||||
- Director assets cancelled during the final stream read are discarded with reader cleanup.
|
||||
|
||||
- Treat explicitly current, complete empty vessel coverage as a successful update,
|
||||
clearing obsolete contacts while retaining stale or incomplete snapshots.
|
||||
|
||||
@@ -5326,3 +5326,8 @@ datacenters, dams and the Nepal locator retain that shared credit while displaye
|
||||
|
||||
Military fragments stitch by source identity. Different mapped parcels merge only
|
||||
when their footprints touch or contain one another, never across a seam tolerance gap.
|
||||
|
||||
|
||||
### fix(director): reject cancellation during the final asset stream read
|
||||
|
||||
Re-check caller cancellation immediately after every awaited read, including done reads, while retaining reader cancellation and lock cleanup.
|
||||
@@ -0,0 +1,42 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { createAssetDirectorySource } from './source.js';
|
||||
test('cancellation during the terminating read cannot return a scene asset', async () => {
|
||||
for (const cancel of [true, false]) {
|
||||
const controller = new AbortController();
|
||||
let reads = 0,
|
||||
cancelled = 0,
|
||||
released = 0;
|
||||
const source = createAssetDirectorySource({
|
||||
baseUrl: 'https://fixture.example/assets/',
|
||||
fetchImpl: async () => ({
|
||||
ok: true,
|
||||
headers: new Headers({ 'content-type': 'application/octet-stream' }),
|
||||
body: {
|
||||
getReader() {
|
||||
return {
|
||||
async read() {
|
||||
reads++;
|
||||
if (reads === 1)
|
||||
return { done: false, value: new Uint8Array([1, 2]) };
|
||||
if (cancel) controller.abort();
|
||||
return { done: true };
|
||||
},
|
||||
async cancel() {
|
||||
cancelled++;
|
||||
},
|
||||
releaseLock() {
|
||||
released++;
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
const pending = source({ path: 'scene.bin', signal: controller.signal });
|
||||
if (cancel) await assert.rejects(pending, { name: 'AbortError' });
|
||||
else assert.deepEqual([...(await pending).bytes], [1, 2]);
|
||||
assert.equal(cancelled, 1);
|
||||
assert.equal(released, 1);
|
||||
}
|
||||
});
|
||||
@@ -41,6 +41,7 @@ export function createAssetDirectorySource({
|
||||
for (;;) {
|
||||
signal?.throwIfAborted();
|
||||
const { done, value } = await reader.read();
|
||||
signal?.throwIfAborted();
|
||||
if (done) break;
|
||||
length += value.byteLength;
|
||||
if (length > maxBytes) throw new Error('Asset exceeds byte limit');
|
||||
|
||||
Reference in new issue
Block a user