@navaramap/worker 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/LICENSE +8 -0
  2. package/README.md +3 -0
  3. package/dist/helpers/transferConstructedPolygonGeometry.d.ts +6 -0
  4. package/dist/helpers/transferConstructedPolylineGeometry.d.ts +6 -0
  5. package/dist/helpers/transferReturnedConstructedTerrainMesh.d.ts +6 -0
  6. package/dist/index.d.ts +4 -0
  7. package/dist/index.js +3203 -0
  8. package/dist/index.umd.cjs +11 -0
  9. package/dist/manager.d.ts +19 -0
  10. package/dist/pool.d.ts +17 -0
  11. package/dist/recyclingPool.d.ts +86 -0
  12. package/dist/tasks/constructPolygonBatchedFeature.d.ts +2 -0
  13. package/dist/tasks/constructPolylineBatchedFeature.d.ts +2 -0
  14. package/dist/tasks/constructQuantizedMeshTerrainMesh.d.ts +4 -0
  15. package/dist/tasks/constructTerrainMesh.d.ts +4 -0
  16. package/dist/tasks/getImageDataFromBlob.d.ts +12 -0
  17. package/dist/tasks/getImageDataFromImageBitmap.d.ts +1 -0
  18. package/dist/tasks/index.d.ts +26 -0
  19. package/dist/tasks/parseMvtTile.d.ts +15 -0
  20. package/dist/tasks/upsampleQuantizedMeshTerrainMesh.d.ts +2 -0
  21. package/dist/tasks/upsampleTerrainMesh.d.ts +2 -0
  22. package/dist/tasks/waitWasm.d.ts +8 -0
  23. package/dist/utils/index.d.ts +5 -0
  24. package/dist/utils/toExtentRadianF32Like.d.ts +3 -0
  25. package/dist/utils/toPolygonMaterialLike.d.ts +3 -0
  26. package/dist/utils/toPolylineMaterialLike.d.ts +3 -0
  27. package/dist/utils/toTransferableMartiniLike.d.ts +3 -0
  28. package/dist/utils/toTransferablePolygonBatchedFeatureLike.d.ts +3 -0
  29. package/dist/utils/toTransferablePolylineBatchedFeatureLike.d.ts +3 -0
  30. package/dist/utils/toTransferableRasterDEMDataLike.d.ts +3 -0
  31. package/dist/utils/toTransferableTileLike.d.ts +5 -0
  32. package/dist/utils/toUpsamplableTerrainGeometryLike.d.ts +3 -0
  33. package/dist/utils/toVec3Like.d.ts +3 -0
  34. package/dist/worker/index.d.ts +4 -0
  35. package/dist/worker/transfer.d.ts +1 -0
  36. package/package.json +37 -0
  37. package/src/helpers/transferConstructedPolygonGeometry.ts +25 -0
  38. package/src/helpers/transferConstructedPolylineGeometry.ts +28 -0
  39. package/src/helpers/transferReturnedConstructedTerrainMesh.ts +21 -0
  40. package/src/index.ts +4 -0
  41. package/src/manager.test.ts +45 -0
  42. package/src/manager.ts +43 -0
  43. package/src/pool.test.ts +87 -0
  44. package/src/pool.ts +150 -0
  45. package/src/recyclingPool.test.ts +404 -0
  46. package/src/recyclingPool.ts +385 -0
  47. package/src/tasks/constructPolygonBatchedFeature.ts +40 -0
  48. package/src/tasks/constructPolylineBatchedFeature.ts +36 -0
  49. package/src/tasks/constructQuantizedMeshTerrainMesh.ts +36 -0
  50. package/src/tasks/constructTerrainMesh.ts +44 -0
  51. package/src/tasks/getImageDataFromBlob.ts +30 -0
  52. package/src/tasks/getImageDataFromImageBitmap.ts +19 -0
  53. package/src/tasks/index.ts +31 -0
  54. package/src/tasks/parseMvtTile.ts +67 -0
  55. package/src/tasks/upsampleQuantizedMeshTerrainMesh.ts +38 -0
  56. package/src/tasks/upsampleTerrainMesh.ts +40 -0
  57. package/src/tasks/waitWasm.ts +19 -0
  58. package/src/utils/index.ts +5 -0
  59. package/src/utils/toExtentRadianF32Like.ts +6 -0
  60. package/src/utils/toPolygonMaterialLike.ts +20 -0
  61. package/src/utils/toPolylineMaterialLike.ts +17 -0
  62. package/src/utils/toTransferableMartiniLike.ts +6 -0
  63. package/src/utils/toTransferablePolygonBatchedFeatureLike.ts +41 -0
  64. package/src/utils/toTransferablePolylineBatchedFeatureLike.ts +21 -0
  65. package/src/utils/toTransferableRasterDEMDataLike.ts +22 -0
  66. package/src/utils/toTransferableTileLike.ts +34 -0
  67. package/src/utils/toUpsamplableTerrainGeometryLike.ts +14 -0
  68. package/src/utils/toVec3Like.ts +6 -0
  69. package/src/vite-env.d.ts +1 -0
  70. package/src/worker/index.ts +44 -0
  71. package/src/worker/transfer.ts +6 -0
@@ -0,0 +1,21 @@
1
+ import { ReturnedConstructedTerrainMeshLike } from "@navaramap/core";
2
+ import type { ReturnedConstructedTerrainMesh } from "@navaramap/engine-worker";
3
+
4
+ export function transferReturnedConstructedTerrainMesh(
5
+ r: ReturnedConstructedTerrainMesh,
6
+ ) {
7
+ const like = new ReturnedConstructedTerrainMeshLike(r);
8
+ const transfers: ArrayBufferLike[] = [
9
+ like.vertices.buffer,
10
+ like.uvs.buffer,
11
+ like.indices.buffer,
12
+ like.heights.buffer,
13
+ ];
14
+ if (like.normals) transfers.push(like.normals.buffer);
15
+ if (like.skirt_vertices) transfers.push(like.skirt_vertices.buffer);
16
+ if (like.skirt_uvs) transfers.push(like.skirt_uvs.buffer);
17
+ if (like.skirt_indices) transfers.push(like.skirt_indices.buffer);
18
+ if (like.skirt_normals) transfers.push(like.skirt_normals.buffer);
19
+ if (like.watermask) transfers.push(like.watermask.buffer);
20
+ return { result: like, transfers };
21
+ }
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from "./pool";
2
+ export * from "./worker";
3
+ export * from "./manager";
4
+ export type { ParsedMvtTileResultLike } from "./tasks/parseMvtTile";
@@ -0,0 +1,45 @@
1
+ import { expect, it } from "vitest";
2
+
3
+ import { createConcurrencyManager } from "./manager";
4
+
5
+ it("should get correct concurrency states", () => {
6
+ const manager = createConcurrencyManager(1);
7
+
8
+ // Initialize
9
+ expect(manager.actives()).toBe(0);
10
+ expect(manager.idles()).toBe(1);
11
+ expect(manager.total).toBe(1);
12
+
13
+ // Increment
14
+
15
+ expect(manager.canIncrement()).toBeTruthy();
16
+
17
+ manager.increment();
18
+ expect(manager.actives()).toBe(1);
19
+ expect(manager.idles()).toBe(0);
20
+
21
+ expect(manager.canIncrement()).toBeFalsy();
22
+ manager.increment();
23
+ expect(manager.actives()).toBe(1);
24
+ expect(manager.idles()).toBe(0);
25
+
26
+ // Decrement
27
+
28
+ expect(manager.canDecrement()).toBeTruthy();
29
+
30
+ manager.decrement();
31
+ expect(manager.actives()).toBe(0);
32
+ expect(manager.idles()).toBe(1);
33
+
34
+ expect(manager.canDecrement()).toBeFalsy();
35
+ manager.decrement();
36
+ expect(manager.actives()).toBe(0);
37
+ expect(manager.idles()).toBe(1);
38
+
39
+ // Reset
40
+
41
+ manager.increment();
42
+ manager.reset();
43
+ expect(manager.actives()).toBe(0);
44
+ expect(manager.idles()).toBe(1);
45
+ });
package/src/manager.ts ADDED
@@ -0,0 +1,43 @@
1
+ export type ConcurrencyManager = {
2
+ /** Total concurrency */
3
+ total: number;
4
+ /** Increment the count according to the activated process */
5
+ increment: () => void;
6
+ /** Decrement the count according to the deactivated process */
7
+ decrement: () => void;
8
+ /** Reset the count */
9
+ reset: () => void;
10
+ /** The number of activated processes */
11
+ actives: () => number;
12
+ /** The number of idle processes */
13
+ idles: () => number;
14
+ /** Whether it can activate the process */
15
+ canIncrement: () => boolean;
16
+ /** Whether there is an activated process */
17
+ canDecrement: () => boolean;
18
+ };
19
+ export const createConcurrencyManager = (total: number): ConcurrencyManager => {
20
+ let actives = 0;
21
+
22
+ const canIncrement = () => actives !== total;
23
+ const canDecrement = () => actives !== 0;
24
+
25
+ return {
26
+ total,
27
+ actives: () => actives,
28
+ idles: () => total - actives,
29
+ increment: () => {
30
+ if (!canIncrement()) return;
31
+ actives++;
32
+ },
33
+ decrement: () => {
34
+ if (!canDecrement()) return;
35
+ actives--;
36
+ },
37
+ canIncrement,
38
+ canDecrement,
39
+ reset: () => {
40
+ actives = 0;
41
+ },
42
+ };
43
+ };
@@ -0,0 +1,87 @@
1
+ import { beforeEach, expect, it, vi } from "vitest";
2
+ import workerpool from "workerpool";
3
+ import type Pool from "workerpool/types/Pool";
4
+
5
+ import { createConcurrencyManager } from "./manager";
6
+ import { initializeWorkerPool, queueTask } from "./pool";
7
+
8
+ const workPoolExecStates = (() => {
9
+ const states = {
10
+ resolve: false,
11
+ reject: false,
12
+ rejectBeforePromise: false,
13
+ };
14
+ const reset = () => {
15
+ states.rejectBeforePromise = false;
16
+ states.resolve = false;
17
+ states.reject = false;
18
+ };
19
+
20
+ return { states, reset };
21
+ })();
22
+
23
+ vi.spyOn(workerpool, "pool").mockImplementation(
24
+ () =>
25
+ ({
26
+ exec: (_method: string, _params?: unknown, _options?: unknown) => {
27
+ if (workPoolExecStates.states.rejectBeforePromise) {
28
+ throw new Error();
29
+ }
30
+ return new workerpool.Promise(
31
+ (resolve: () => void, reject: () => void) => {
32
+ if (workPoolExecStates.states.resolve) {
33
+ resolve();
34
+ }
35
+ if (workPoolExecStates.states.reject) {
36
+ reject();
37
+ }
38
+ },
39
+ );
40
+ },
41
+ terminate: () => undefined,
42
+ }) as unknown as Pool,
43
+ );
44
+
45
+ // Worker pool is initialized globally.
46
+ const manager = createConcurrencyManager(1);
47
+ const incrementFnMock = vi.spyOn(manager, "increment");
48
+ initializeWorkerPool("https://example.com", manager);
49
+
50
+ beforeEach(() => {
51
+ workPoolExecStates.reset();
52
+ incrementFnMock.mockClear();
53
+ });
54
+
55
+ it("should increment and decrement concurrency when the promise is resolved", async () => {
56
+ workPoolExecStates.states.resolve = true;
57
+
58
+ const promise = queueTask("test" as any);
59
+ await promise;
60
+ expect(incrementFnMock).toHaveBeenCalledOnce();
61
+ expect(manager.actives()).toBe(0);
62
+ });
63
+
64
+ it("should increment and decrement concurrency when the promise is rejected", async () => {
65
+ workPoolExecStates.states.reject = true;
66
+
67
+ const promise = queueTask("test" as any);
68
+ try {
69
+ await promise;
70
+ expect.fail("Expect that this case throws an error");
71
+ } catch {
72
+ expect(incrementFnMock).toHaveBeenCalledOnce();
73
+ expect(manager.actives()).toBe(0);
74
+ }
75
+ });
76
+
77
+ it("should increment and decrement concurrency when the function throws an error before returning the promise", async () => {
78
+ workPoolExecStates.states.rejectBeforePromise = true;
79
+
80
+ try {
81
+ queueTask("test" as any);
82
+ expect.fail("Expect that this case throws an error");
83
+ } catch {
84
+ expect(incrementFnMock).toHaveBeenCalledOnce();
85
+ expect(manager.actives()).toBe(0);
86
+ }
87
+ });
package/src/pool.ts ADDED
@@ -0,0 +1,150 @@
1
+ import invariant from "tiny-invariant";
2
+ import type { Promise } from "workerpool";
3
+ import type { ExecOptions } from "workerpool/types/types";
4
+
5
+ import type { ConcurrencyManager } from "./manager";
6
+ import {
7
+ RecyclingWorkerPool,
8
+ type RecyclingWorkerPoolOptions,
9
+ } from "./recyclingPool";
10
+ import { type CommonTasks } from "./worker";
11
+
12
+ export type { Promise } from "workerpool";
13
+ export type {
14
+ RecyclingWorkerPoolOptions,
15
+ WorkerPoolHeapStats,
16
+ WorkerPoolStats,
17
+ } from "./recyclingPool";
18
+
19
+ const {
20
+ initializeWorkerPool,
21
+ terminateWorkerPool,
22
+ warmUpWorkerPool,
23
+ worker,
24
+ workerPoolStats,
25
+ workerPoolHeapStats,
26
+ probeWorkerPoolHeap,
27
+ } = (() => {
28
+ // Restrict access to this object.
29
+ let worker:
30
+ | {
31
+ pool: RecyclingWorkerPool;
32
+ manager: ConcurrencyManager;
33
+ }
34
+ | undefined;
35
+
36
+ return {
37
+ initializeWorkerPool: (
38
+ url: string,
39
+ manager: ConcurrencyManager,
40
+ options?: RecyclingWorkerPoolOptions,
41
+ ) => {
42
+ if (worker) {
43
+ throw new Error("Worker pool has already been initialized.");
44
+ }
45
+
46
+ worker = {
47
+ // Recycles worker threads to bound WASM linear memory growth; see
48
+ // recyclingPool.ts for the policy.
49
+ pool: new RecyclingWorkerPool(url, manager.total, options),
50
+ manager,
51
+ };
52
+ },
53
+ terminateWorkerPool: () => {
54
+ if (worker) {
55
+ worker.pool.terminate();
56
+ worker = undefined;
57
+ }
58
+ },
59
+ /**
60
+ * Pre-initializes WASM on the workers so that upcoming tasks don't pay
61
+ * the initialization latency. Warms a single worker and resolves once
62
+ * it is ready; the rest warm in the background.
63
+ */
64
+ warmUpWorkerPool: () => {
65
+ invariant(worker, "initializeWorkerPool() must be invoked first.");
66
+ return worker.pool.warmUp();
67
+ },
68
+ worker: () => {
69
+ invariant(worker, "initializeWorkerPool() must be invoked first.");
70
+ return {
71
+ pool: worker.pool,
72
+ manager: worker.manager,
73
+ };
74
+ },
75
+ workerPoolStats: () => worker?.pool.stats(),
76
+ /** Last-probed WASM heap per worker; see RecyclingWorkerPool.heapStats. */
77
+ workerPoolHeapStats: () => worker?.pool.heapStats(),
78
+ /** Requests fresh heap probes (coalesced per worker; display-rate safe). */
79
+ probeWorkerPoolHeap: () => worker?.pool.probeHeap(),
80
+ };
81
+ })();
82
+
83
+ export {
84
+ initializeWorkerPool,
85
+ terminateWorkerPool,
86
+ warmUpWorkerPool,
87
+ workerPoolStats,
88
+ workerPoolHeapStats,
89
+ probeWorkerPoolHeap,
90
+ };
91
+
92
+ export const canWorkerProcessImmediately = () => {
93
+ const { pool, manager } = worker();
94
+ // Also pauses intake while every worker is over its WASM heap budget
95
+ // (draining); a recycled worker restores capacity moments later.
96
+ return manager.canIncrement() && pool.canAcceptTasks();
97
+ };
98
+
99
+ export type { ExecOptions } from "workerpool/types/types";
100
+
101
+ type GetTaskName<Task> =
102
+ Task extends Record<string, unknown> ? keyof Task : string;
103
+
104
+ type AnyFunction = (...args: any) => any;
105
+
106
+ export type WorkerTask<T extends Record<string, AnyFunction>> = T & CommonTasks;
107
+
108
+ export type TaskParams<
109
+ Task extends CommonTasks,
110
+ Name extends keyof Task,
111
+ > = Parameters<
112
+ Task[Name] extends AnyFunction ? Task[Name] : (...args: unknown[]) => unknown
113
+ >;
114
+ type MethodReturnType<
115
+ Task extends CommonTasks,
116
+ Name extends GetTaskName<Task>,
117
+ R = Awaited<ReturnType<Task[Name]>>,
118
+ > = R extends infer U ? U : R;
119
+
120
+ export function queueTask<
121
+ Task extends CommonTasks,
122
+ Name extends GetTaskName<Task>,
123
+ >(
124
+ method: Name,
125
+ params?: TaskParams<Task, Name>,
126
+ options?: ExecOptions,
127
+ ): Promise<MethodReturnType<Task, Name>> {
128
+ const { pool, manager } = worker();
129
+
130
+ manager.increment();
131
+
132
+ try {
133
+ return (
134
+ pool
135
+ .exec(method, params, options)
136
+ // `finally` doesn't work, so use `then()` and `catch()` to ensure that `manager.decrement()` is invoked.
137
+ .then((p) => {
138
+ manager.decrement();
139
+ return p;
140
+ })
141
+ .catch((e) => {
142
+ manager.decrement();
143
+ throw e;
144
+ })
145
+ );
146
+ } catch (e) {
147
+ manager.decrement();
148
+ throw e;
149
+ }
150
+ }