mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 02:44:02 +00:00
Embed the files Cesium's workers load in the panel's workers script
The ground-polyline worker loads approximateTerrainHeights.json itself, and a worker's requests go to the panel page's own site, where they failed with 404 and stopped rendering once ground-clamped lines such as military installations appeared. The panel build now embeds that file in the workers script, which answers the worker's request from memory.
This commit is contained in:
1 parent
d4311a9d54
commit
9e5ef78f91
3 files changed
+118
-1
No files matched your search
@@ -101,3 +101,66 @@ export function panelBuildPlugin({ outDir = PANEL_OUT_DIR } = {}) {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Cesium files its workers load themselves, as paths under Cesium's base.
|
||||
* Workers request them from the panel page's own site, which has none of
|
||||
* the app's files, so the panel build embeds them in the workers script.
|
||||
*/
|
||||
export const PANEL_WORKER_FILES = Object.freeze([
|
||||
'Assets/approximateTerrainHeights.json',
|
||||
]);
|
||||
|
||||
/**
|
||||
* A script, run in each worker before Cesium's, that answers the worker's
|
||||
* requests for `files` (Cesium-relative path → text) from memory and lets
|
||||
* every other request through.
|
||||
*/
|
||||
export function workerFilesPrelude(files) {
|
||||
const answer = (FILES) => {
|
||||
const find = (url) => {
|
||||
const path = String(url).split(/[?#]/)[0];
|
||||
for (const name of Object.keys(FILES))
|
||||
if (path.endsWith(`/${name}`)) return FILES[name];
|
||||
return null;
|
||||
};
|
||||
const xhr = XMLHttpRequest.prototype;
|
||||
const { open, send, setRequestHeader } = xhr;
|
||||
xhr.open = function (method, url, ...rest) {
|
||||
this.__gevFile = find(url);
|
||||
if (this.__gevFile === null) return open.call(this, method, url, ...rest);
|
||||
};
|
||||
xhr.setRequestHeader = function (...args) {
|
||||
if (this.__gevFile === null) return setRequestHeader.apply(this, args);
|
||||
};
|
||||
xhr.send = function (body) {
|
||||
const text = this.__gevFile;
|
||||
if (text === null || text === undefined) return send.call(this, body);
|
||||
const type = this.responseType;
|
||||
const response =
|
||||
type === 'json'
|
||||
? JSON.parse(text)
|
||||
: type === 'arraybuffer'
|
||||
? new TextEncoder().encode(text).buffer
|
||||
: text;
|
||||
const state = {
|
||||
readyState: 4,
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
response,
|
||||
responseText: typeof response === 'string' ? response : '',
|
||||
getAllResponseHeaders: () => 'content-type: application/json\r\n',
|
||||
getResponseHeader: (name) =>
|
||||
name.toLowerCase() === 'content-type' ? 'application/json' : null,
|
||||
};
|
||||
for (const [name, value] of Object.entries(state))
|
||||
Object.defineProperty(this, name, { configurable: true, value });
|
||||
setTimeout(() => {
|
||||
this.dispatchEvent(new Event('readystatechange'));
|
||||
this.dispatchEvent(new ProgressEvent('load'));
|
||||
this.dispatchEvent(new ProgressEvent('loadend'));
|
||||
});
|
||||
};
|
||||
};
|
||||
return `(${answer})(${JSON.stringify(files)});\n`;
|
||||
}
|
||||
+11
-1
@@ -4,7 +4,7 @@
|
||||
* See build/panel.js.
|
||||
*/
|
||||
|
||||
import { readdir, rename, rm, writeFile } from 'node:fs/promises';
|
||||
import { readFile, readdir, rename, rm, writeFile } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { build as esbuild } from 'esbuild';
|
||||
@@ -13,8 +13,10 @@ import standaloneConfig from '../server/standalone/vite.config.js';
|
||||
import {
|
||||
PANEL_BASE,
|
||||
PANEL_OUT_DIR,
|
||||
PANEL_WORKER_FILES,
|
||||
PANEL_WORKERS_PATH,
|
||||
panelBuildConfig,
|
||||
workerFilesPrelude,
|
||||
workersEntrySource,
|
||||
} from '../build/panel.js';
|
||||
|
||||
@@ -49,4 +51,12 @@ await esbuild({
|
||||
logLevel: 'warning',
|
||||
});
|
||||
await rm(entry);
|
||||
const files = {};
|
||||
for (const name of PANEL_WORKER_FILES)
|
||||
files[name] = await readFile(join(outDir, 'cesium', name), 'utf8');
|
||||
const workers = join(outDir, PANEL_WORKERS_PATH);
|
||||
await writeFile(
|
||||
workers,
|
||||
workerFilesPrelude(files) + (await readFile(workers, 'utf8')),
|
||||
);
|
||||
console.log(`Panel build written to ${PANEL_OUT_DIR}`);
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
PANEL_WORKERS_PATH,
|
||||
panelBuildConfig,
|
||||
panelBuildPlugin,
|
||||
workerFilesPrelude,
|
||||
workersEntrySource,
|
||||
} from '../../build/panel.js';
|
||||
|
||||
@@ -81,3 +82,46 @@ test('the dev server serves the panel build and nothing outside it', async () =>
|
||||
await rm(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("Cesium's workers get embedded files from memory and other requests from the network", async () => {
|
||||
const sent = [];
|
||||
class FakeRequest extends EventTarget {
|
||||
open(method, url) {
|
||||
this.url = url;
|
||||
}
|
||||
setRequestHeader() {}
|
||||
send() {
|
||||
sent.push(this.url);
|
||||
}
|
||||
}
|
||||
const saved = {
|
||||
XMLHttpRequest: globalThis.XMLHttpRequest,
|
||||
ProgressEvent: globalThis.ProgressEvent,
|
||||
};
|
||||
globalThis.XMLHttpRequest = FakeRequest;
|
||||
globalThis.ProgressEvent ??= class extends Event {};
|
||||
try {
|
||||
new Function(workerFilesPrelude({ 'Assets/heights.json': '{"a":1}' }))();
|
||||
const embedded = new XMLHttpRequest();
|
||||
embedded.open(
|
||||
'GET',
|
||||
'https://panel.example/panel/cesium/Assets/heights.json?v=1',
|
||||
);
|
||||
embedded.setRequestHeader('Accept', 'application/json');
|
||||
embedded.responseType = 'text';
|
||||
const loaded = new Promise((resolve) =>
|
||||
embedded.addEventListener('load', resolve),
|
||||
);
|
||||
embedded.send();
|
||||
await loaded;
|
||||
assert.equal(embedded.status, 200);
|
||||
assert.equal(embedded.response, '{"a":1}');
|
||||
const other = new XMLHttpRequest();
|
||||
other.open('GET', 'https://tiles.example/1.png');
|
||||
other.send();
|
||||
assert.deepEqual(sent, ['https://tiles.example/1.png']);
|
||||
} finally {
|
||||
globalThis.XMLHttpRequest = saved.XMLHttpRequest;
|
||||
globalThis.ProgressEvent = saved.ProgressEvent;
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user