@tangram.gl/tangram-renderer 0.0.0-stage → 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.
- package/README.md +59 -2
- package/dist/core.js +36923 -0
- package/dist/core.js.map +6 -0
- package/dist/index.js +32 -0
- package/dist/loaders-gl-worker.js +82 -0
- package/dist/loaders-gl-worker.js.map +6 -0
- package/dist/map-logic.js +2 -0
- package/dist/map-logic.js.map +6 -0
- package/dist/projected-basemaps-worker.js +3 -0
- package/dist/projected-basemaps-worker.js.map +6 -0
- package/dist/shader-modules.js +141 -0
- package/dist/shader-modules.js.map +6 -0
- package/dist/style-schema.js +126 -0
- package/dist/style-schema.js.map +6 -0
- package/dist/tangram-style.schema.json +882 -0
- package/dist/tangram.debug.mjs +37139 -0
- package/dist/tangram.debug.mjs.map +6 -0
- package/dist/tangram.min.mjs +4950 -0
- package/dist/types/builders/earcut.d.ts +15 -0
- package/dist/types/core.d.ts +29 -0
- package/dist/types/gl/constants.d.ts +2 -0
- package/dist/types/gl/globe_mesh.d.ts +48 -0
- package/dist/types/gl/glsl.d.ts +17 -0
- package/dist/types/gl/vertex-constants.d.ts +4 -0
- package/dist/types/gl/vertex-types.d.ts +34 -0
- package/dist/types/gl/vertex_data.d.ts +32 -0
- package/dist/types/gl/vertex_elements.d.ts +8 -0
- package/dist/types/gl/vertex_layout.d.ts +32 -0
- package/dist/types/glsl.d.ts +14 -0
- package/dist/types/gpu/luma_device_renderer.d.ts +66 -0
- package/dist/types/gpu/resource_lifecycle.d.ts +4 -0
- package/dist/types/gpu/tangram_gpu_backend.d.ts +151 -0
- package/dist/types/index.d.ts +155 -0
- package/dist/types/lights/light-definitions.d.ts +121 -0
- package/dist/types/map-logic/draped-terrain-bounds.d.ts +41 -0
- package/dist/types/map-logic/globe-terrain-preparation.d.ts +85 -0
- package/dist/types/map-logic/globe-terrain.d.ts +54 -0
- package/dist/types/map-logic/index.d.ts +33 -0
- package/dist/types/map-logic/label-identity.d.ts +22 -0
- package/dist/types/map-logic/label-placement.d.ts +32 -0
- package/dist/types/map-logic/screen-bounds.d.ts +15 -0
- package/dist/types/map-logic/terrain-data.d.ts +55 -0
- package/dist/types/map-logic/terrain-error.d.ts +51 -0
- package/dist/types/map-logic/terrain-ground-topology.d.ts +26 -0
- package/dist/types/map-logic/terrain-height-field.d.ts +59 -0
- package/dist/types/map-logic/terrain-navigation.d.ts +27 -0
- package/dist/types/map-logic/terrain-neighborhood.d.ts +5 -0
- package/dist/types/map-logic/terrain-query.d.ts +33 -0
- package/dist/types/map-logic/terrain-resource-budget.d.ts +51 -0
- package/dist/types/map-logic/terrain-transition-topology.d.ts +23 -0
- package/dist/types/map-logic/tile-build-queue.d.ts +51 -0
- package/dist/types/map-logic/tile-cache-policy.d.ts +46 -0
- package/dist/types/map-logic/tile-residency.d.ts +17 -0
- package/dist/types/map-logic/triangle-query-index.d.ts +87 -0
- package/dist/types/procedures/js-yaml.d.ts +15 -0
- package/dist/types/procedures/mesh-projector.d.ts +107 -0
- package/dist/types/procedures/mvt-dependencies.d.ts +20 -0
- package/dist/types/procedures/projected-coordinate-transform.d.ts +27 -0
- package/dist/types/procedures/projection-batch-executor.d.ts +53 -0
- package/dist/types/procedures/scene-yaml-legacy.d.ts +6 -0
- package/dist/types/procedures/terrain-draping.d.ts +165 -0
- package/dist/types/procedures/terrain-globe.d.ts +6 -0
- package/dist/types/procedures/terrain-styled-topology.d.ts +34 -0
- package/dist/types/procedures/web-mercator-legacy.d.ts +4 -0
- package/dist/types/procedures/web-mercator-math.d.ts +4 -0
- package/dist/types/scene/globals.d.ts +11 -0
- package/dist/types/scene/ground_footprint.d.ts +16 -0
- package/dist/types/scene/host_frame.d.ts +54 -0
- package/dist/types/scene/projection_math.d.ts +52 -0
- package/dist/types/scene/scene-resource-types.d.ts +177 -0
- package/dist/types/scene/scene_bundle.d.ts +69 -0
- package/dist/types/scene/visibility_adapter.d.ts +106 -0
- package/dist/types/selection/draped-terrain-surface.d.ts +78 -0
- package/dist/types/selection/terrain_surface.d.ts +149 -0
- package/dist/types/shader-modules/globe-horizon.d.ts +15 -0
- package/dist/types/shader-modules/height-decode.d.ts +13 -0
- package/dist/types/shader-modules/hillshade.d.ts +13 -0
- package/dist/types/shader-modules/index.d.ts +6 -0
- package/dist/types/shader-modules/planar.d.ts +12 -0
- package/dist/types/shader-modules/sphere-map.d.ts +13 -0
- package/dist/types/shader-modules/triplanar.d.ts +15 -0
- package/dist/types/sources/decoded_tile_store.d.ts +95 -0
- package/dist/types/sources/tile_source_metadata.d.ts +32 -0
- package/dist/types/styles/text/fontfaceobserver.d.ts +10 -0
- package/dist/types/tile/tile_id.d.ts +37 -0
- package/dist/types/tile/tile_traversal_adapter.d.ts +63 -0
- package/dist/types/types.d.ts +293 -0
- package/dist/types/utils/geo.d.ts +57 -0
- package/dist/types/utils/hash.d.ts +1 -0
- package/dist/types/utils/log.d.ts +27 -0
- package/dist/types/utils/props.d.ts +6 -0
- package/dist/types/utils/subscribe.d.ts +10 -0
- package/dist/types/utils/thread.d.ts +6 -0
- package/dist/types/utils/urls.d.ts +26 -0
- package/dist/types/utils/utils.d.ts +26 -0
- package/dist/types/utils/version.d.ts +2 -0
- package/dist/types/utils/worker-types.d.ts +68 -0
- package/dist/types/utils/worker_broker.d.ts +3 -0
- package/package.json +103 -3
- package/src/builders/common.ts +41 -0
- package/src/builders/earcut.d.ts +15 -0
- package/src/builders/geometry-types.ts +60 -0
- package/src/builders/points.ts +115 -0
- package/src/builders/polygons.ts +225 -0
- package/src/builders/polylines.ts +682 -0
- package/src/builders/wireframe.ts +31 -0
- package/src/core.d.ts +29 -0
- package/src/core.ts +33 -0
- package/src/experimental/loaders-gl-worker.ts +19 -0
- package/src/experimental/projected-basemaps-worker.ts +13 -0
- package/src/experimental/projected-mesh-cache.ts +137 -0
- package/src/experimental/projected-mesh-domain.ts +110 -0
- package/src/experimental/projected-mesh-refinement.ts +193 -0
- package/src/experimental/projected-mesh.ts +399 -0
- package/src/experimental/projected-normal.ts +26 -0
- package/src/experimental/projected-symbol-mesh.ts +74 -0
- package/src/gl/constants.ts +18 -0
- package/src/gl/context.ts +103 -0
- package/src/gl/extensions.ts +30 -0
- package/src/gl/globe_mesh.ts +285 -0
- package/src/gl/glsl.ts +257 -0
- package/src/gl/mesh-types.ts +56 -0
- package/src/gl/render_state.ts +111 -0
- package/src/gl/shader_program.ts +1310 -0
- package/src/gl/texture.ts +814 -0
- package/src/gl/uniform_buffer.ts +340 -0
- package/src/gl/vao.ts +154 -0
- package/src/gl/vbo_mesh.ts +349 -0
- package/src/gl/vertex-constants.ts +19 -0
- package/src/gl/vertex-types.ts +35 -0
- package/src/gl/vertex_data.ts +126 -0
- package/src/gl/vertex_elements.ts +54 -0
- package/src/gl/vertex_layout.ts +241 -0
- package/src/glsl.d.ts +14 -0
- package/src/gpu/luma_device_renderer.ts +579 -0
- package/src/gpu/pixel_readback.ts +51 -0
- package/src/gpu/resource_lifecycle.ts +32 -0
- package/src/gpu/tangram_gpu_backend.ts +195 -0
- package/src/index.d.ts +155 -0
- package/src/index.ts +105 -0
- package/src/labels/collision-types.ts +94 -0
- package/src/labels/collision.ts +273 -0
- package/src/labels/collision_grid.ts +61 -0
- package/src/labels/intersect.ts +30 -0
- package/src/labels/label-types.ts +91 -0
- package/src/labels/label.ts +207 -0
- package/src/labels/label_line.ts +801 -0
- package/src/labels/label_point.ts +131 -0
- package/src/labels/main-pass-types.ts +73 -0
- package/src/labels/main_pass.ts +221 -0
- package/src/labels/point_anchor.ts +100 -0
- package/src/labels/point_placement.ts +150 -0
- package/src/labels/projected-pass.ts +259 -0
- package/src/labels/repeat_group.ts +72 -0
- package/src/lights/ambient_light.glsl +18 -0
- package/src/lights/directional_light.glsl +39 -0
- package/src/lights/geographic-lights.ts +21 -0
- package/src/lights/light-definitions.ts +285 -0
- package/src/lights/light.ts +590 -0
- package/src/lights/lighting-uniforms.ts +80 -0
- package/src/lights/lighting-wgsl.ts +116 -0
- package/src/lights/material.glsl +237 -0
- package/src/lights/material.ts +145 -0
- package/src/lights/native-falloff.ts +37 -0
- package/src/lights/point_light.glsl +96 -0
- package/src/lights/spot_light.glsl +111 -0
- package/src/map-logic/draped-terrain-bounds.ts +71 -0
- package/src/map-logic/globe-terrain-preparation.ts +217 -0
- package/src/map-logic/globe-terrain.ts +296 -0
- package/src/map-logic/index.ts +37 -0
- package/src/map-logic/label-identity.ts +36 -0
- package/src/map-logic/label-placement.ts +117 -0
- package/src/map-logic/screen-bounds.ts +34 -0
- package/src/map-logic/terrain-data.ts +107 -0
- package/src/map-logic/terrain-error.ts +134 -0
- package/src/map-logic/terrain-ground-topology.ts +164 -0
- package/src/map-logic/terrain-height-field.ts +254 -0
- package/src/map-logic/terrain-navigation.ts +50 -0
- package/src/map-logic/terrain-neighborhood.ts +43 -0
- package/src/map-logic/terrain-query.ts +51 -0
- package/src/map-logic/terrain-resource-budget.ts +124 -0
- package/src/map-logic/terrain-transition-topology.ts +164 -0
- package/src/map-logic/tile-build-queue.ts +110 -0
- package/src/map-logic/tile-cache-policy.ts +89 -0
- package/src/map-logic/tile-residency.ts +50 -0
- package/src/map-logic/triangle-query-index.ts +265 -0
- package/src/procedures/js-yaml.d.ts +15 -0
- package/src/procedures/mesh-projector.ts +191 -0
- package/src/procedures/mlt-loaders.ts +55 -0
- package/src/procedures/mvt-dependencies.d.ts +20 -0
- package/src/procedures/mvt-legacy.ts +150 -0
- package/src/procedures/mvt-loaders.ts +53 -0
- package/src/procedures/mvt-parser.ts +48 -0
- package/src/procedures/mvt-properties.ts +36 -0
- package/src/procedures/mvt-tile-provider.ts +72 -0
- package/src/procedures/pmtiles-loader.ts +75 -0
- package/src/procedures/projected-coordinate-transform.ts +79 -0
- package/src/procedures/projection-batch-executor.ts +140 -0
- package/src/procedures/scene-yaml-legacy.ts +16 -0
- package/src/procedures/scene-yaml-loaders.ts +10 -0
- package/src/procedures/terrain-draping.ts +713 -0
- package/src/procedures/terrain-globe.ts +32 -0
- package/src/procedures/terrain-styled-topology.ts +184 -0
- package/src/procedures/web-mercator-legacy.ts +24 -0
- package/src/procedures/web-mercator-math.ts +50 -0
- package/src/scene/camera.ts +298 -0
- package/src/scene/camera_base.ts +116 -0
- package/src/scene/classic_scene.ts +20 -0
- package/src/scene/external_camera.ts +101 -0
- package/src/scene/globals.ts +120 -0
- package/src/scene/ground_footprint.ts +139 -0
- package/src/scene/host_frame.ts +326 -0
- package/src/scene/projected_tile_lod.ts +125 -0
- package/src/scene/projection_math.ts +142 -0
- package/src/scene/projection_shaders.ts +183 -0
- package/src/scene/renderer.ts +516 -0
- package/src/scene/scene-resource-types.ts +174 -0
- package/src/scene/scene.ts +2378 -0
- package/src/scene/scene_bundle.ts +304 -0
- package/src/scene/scene_debug.ts +129 -0
- package/src/scene/scene_loader.ts +402 -0
- package/src/scene/scene_worker.ts +528 -0
- package/src/scene/view.ts +683 -0
- package/src/scene/visibility_adapter.ts +319 -0
- package/src/scene/worker_url.ts +15 -0
- package/src/selection/draped-terrain-surface.ts +377 -0
- package/src/selection/selection-types.ts +79 -0
- package/src/selection/selection.ts +542 -0
- package/src/selection/selection_fragment.glsl +18 -0
- package/src/selection/selection_globals.glsl +9 -0
- package/src/selection/selection_pixels.ts +59 -0
- package/src/selection/selection_vertex.glsl +15 -0
- package/src/selection/terrain_surface.ts +298 -0
- package/src/shader-modules/globe-horizon.ts +52 -0
- package/src/shader-modules/height-decode.ts +41 -0
- package/src/shader-modules/hillshade.ts +70 -0
- package/src/shader-modules/index.ts +10 -0
- package/src/shader-modules/planar.ts +24 -0
- package/src/shader-modules/sphere-map.ts +38 -0
- package/src/shader-modules/triplanar.ts +45 -0
- package/src/sources/aligned_tile_source.ts +122 -0
- package/src/sources/data_source.ts +655 -0
- package/src/sources/decoded_tile_store.ts +245 -0
- package/src/sources/geojson.ts +300 -0
- package/src/sources/mvt.ts +247 -0
- package/src/sources/raster.ts +341 -0
- package/src/sources/shared_tile_source_adapter.ts +117 -0
- package/src/sources/sources.ts +10 -0
- package/src/sources/tile_source_adapter.ts +84 -0
- package/src/sources/tile_source_metadata.ts +65 -0
- package/src/sources/tile_source_state.ts +112 -0
- package/src/sources/topojson.ts +90 -0
- package/src/styles/feature_annotations.ts +16 -0
- package/src/styles/filter.ts +190 -0
- package/src/styles/geometry-style-types.ts +209 -0
- package/src/styles/globe_visibility_wgsl.ts +22 -0
- package/src/styles/layer-types.ts +45 -0
- package/src/styles/layer.ts +586 -0
- package/src/styles/lines/dasharray.ts +49 -0
- package/src/styles/lines/lines.ts +707 -0
- package/src/styles/lines/lines_wgsl.ts +224 -0
- package/src/styles/points/point-runtime-types.ts +125 -0
- package/src/styles/points/points.ts +1079 -0
- package/src/styles/points/points_fragment.glsl +126 -0
- package/src/styles/points/points_vertex.glsl +230 -0
- package/src/styles/points/points_wgsl.ts +189 -0
- package/src/styles/polygons/polygons.ts +268 -0
- package/src/styles/polygons/polygons_fragment.glsl +173 -0
- package/src/styles/polygons/polygons_vertex.glsl +213 -0
- package/src/styles/polygons/polygons_wgsl.ts +127 -0
- package/src/styles/property-types.ts +125 -0
- package/src/styles/raster/raster.ts +33 -0
- package/src/styles/raster/raster_globals.glsl +46 -0
- package/src/styles/style-mixing-types.ts +101 -0
- package/src/styles/style-runtime-types.ts +220 -0
- package/src/styles/style-schema.ts +133 -0
- package/src/styles/style.ts +1033 -0
- package/src/styles/style_globals.glsl +69 -0
- package/src/styles/style_manager.ts +464 -0
- package/src/styles/style_parser.ts +620 -0
- package/src/styles/text/font_manager.ts +180 -0
- package/src/styles/text/fontfaceobserver.d.ts +10 -0
- package/src/styles/text/text-types.ts +220 -0
- package/src/styles/text/text.ts +378 -0
- package/src/styles/text/text_canvas.ts +773 -0
- package/src/styles/text/text_labels.ts +436 -0
- package/src/styles/text/text_segments.ts +142 -0
- package/src/styles/text/text_settings.ts +228 -0
- package/src/styles/text/text_wgsl.ts +159 -0
- package/src/styles/text/text_wrap.ts +194 -0
- package/src/tile/globe_tile_preload.ts +40 -0
- package/src/tile/tangram_tileset_2d.ts +108 -0
- package/src/tile/tile-build-types.ts +155 -0
- package/src/tile/tile.ts +807 -0
- package/src/tile/tile_id.ts +172 -0
- package/src/tile/tile_manager.ts +889 -0
- package/src/tile/tile_pyramid.ts +119 -0
- package/src/tile/tile_resource_cache.ts +91 -0
- package/src/tile/tile_traversal_adapter.ts +132 -0
- package/src/types.ts +332 -0
- package/src/utils/debounce.ts +17 -0
- package/src/utils/debug_settings.ts +43 -0
- package/src/utils/errors.ts +12 -0
- package/src/utils/functions.ts +95 -0
- package/src/utils/geo.ts +364 -0
- package/src/utils/hash.ts +14 -0
- package/src/utils/log.ts +108 -0
- package/src/utils/media_capture.ts +193 -0
- package/src/utils/merge.ts +44 -0
- package/src/utils/obb.ts +134 -0
- package/src/utils/props.ts +43 -0
- package/src/utils/slice.ts +14 -0
- package/src/utils/subscribe.ts +58 -0
- package/src/utils/task.ts +154 -0
- package/src/utils/thread.ts +26 -0
- package/src/utils/urls.ts +223 -0
- package/src/utils/utils.ts +310 -0
- package/src/utils/vector.ts +197 -0
- package/src/utils/version.ts +8 -0
- package/src/utils/worker-types.ts +79 -0
- package/src/utils/worker_broker.ts +523 -0
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
// Tangram
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) 2013-2016 Brett Camper and Mapzen
|
|
4
|
+
// Copyright (c) 2026 vis.gl contributors
|
|
5
|
+
|
|
6
|
+
/*jshint worker: true*/
|
|
7
|
+
|
|
8
|
+
// WorkerBroker routes messages between web workers and the main thread, allowing for simpler
|
|
9
|
+
// async code via promises. Example usage:
|
|
10
|
+
//
|
|
11
|
+
// In web worker, register self as a callable "target", and define a method:
|
|
12
|
+
//
|
|
13
|
+
// WorkerBroker.addTarget('self', self);
|
|
14
|
+
//
|
|
15
|
+
// self.square = function (x) {
|
|
16
|
+
// return x * x;
|
|
17
|
+
// };
|
|
18
|
+
//
|
|
19
|
+
// In main thread, invoke that method and receive the result (if any) as a promise.
|
|
20
|
+
//
|
|
21
|
+
// worker = new Worker(...);
|
|
22
|
+
// WorkerBroker.addWorker(worker);
|
|
23
|
+
//
|
|
24
|
+
// WorkerBroker.postMessage(worker, 'self.square', 5).then(function(y) {
|
|
25
|
+
// console.log(y);
|
|
26
|
+
// });
|
|
27
|
+
//
|
|
28
|
+
// -> prints 25
|
|
29
|
+
//
|
|
30
|
+
// Async code:
|
|
31
|
+
//
|
|
32
|
+
// For synchronous code that must pass a return value to the main thread, the function can simply
|
|
33
|
+
// return an immediate value (see example above). For cases where the worker method needs to run
|
|
34
|
+
// asynchronous code, the function can return a promise, and the resolved or rejected value will
|
|
35
|
+
// be sent back to the main thread when the promise is fulfilled.
|
|
36
|
+
//
|
|
37
|
+
// Error handling:
|
|
38
|
+
//
|
|
39
|
+
// If the worker method either throws an error, or returns a promise that is rejected, it will be
|
|
40
|
+
// sent back to the main thread as a promise rejection. These two examples are equivalent:
|
|
41
|
+
//
|
|
42
|
+
// In worker, throwing an error:
|
|
43
|
+
//
|
|
44
|
+
// self.broken = function () {
|
|
45
|
+
// throw new Error('error in worker!');
|
|
46
|
+
// };
|
|
47
|
+
//
|
|
48
|
+
// In worker, returning a rejected promise:
|
|
49
|
+
//
|
|
50
|
+
// self.broken = function () {
|
|
51
|
+
// return Promise.reject(new Error('error in worker!'));
|
|
52
|
+
// };
|
|
53
|
+
//
|
|
54
|
+
// In main thread, both errors are received as a promise rejection:
|
|
55
|
+
//
|
|
56
|
+
// WorkerBroker.postMessage(worker, 'self.broken').then(
|
|
57
|
+
// // Promise resolved
|
|
58
|
+
// function() {
|
|
59
|
+
// console.log('success!');
|
|
60
|
+
// },
|
|
61
|
+
// // Promise rejected
|
|
62
|
+
// function(error) {
|
|
63
|
+
// console.log('error!', error);
|
|
64
|
+
// });
|
|
65
|
+
//
|
|
66
|
+
// -> prints 'error! error in worker'
|
|
67
|
+
//
|
|
68
|
+
// Calling from worker to main thread:
|
|
69
|
+
//
|
|
70
|
+
// The same style of calls can be made *from* a web worker, to the main thread. The API is the same
|
|
71
|
+
// with the exception that the first argument, 'worker', is not needed for WorkerBroker.postMessage(),
|
|
72
|
+
// since the main thread is the implicit target.
|
|
73
|
+
//
|
|
74
|
+
// In main thread, define a method and register it:
|
|
75
|
+
//
|
|
76
|
+
// var geometry = {
|
|
77
|
+
// length: function(x, y) {
|
|
78
|
+
// return Math.sqrt(x * x + y * y);
|
|
79
|
+
// }
|
|
80
|
+
// };
|
|
81
|
+
//
|
|
82
|
+
// WorkerBroker.addTarget('geometry', geometry);
|
|
83
|
+
//
|
|
84
|
+
// In worker thread):
|
|
85
|
+
//
|
|
86
|
+
// WorkerBroker.postMessage('geometry.length', 3, 4).then(function(d) {
|
|
87
|
+
// console.log(d);
|
|
88
|
+
// });
|
|
89
|
+
//
|
|
90
|
+
// -> prints 5
|
|
91
|
+
//
|
|
92
|
+
|
|
93
|
+
import Thread from './thread';
|
|
94
|
+
import log from './log';
|
|
95
|
+
import type {BrokerMethod, BrokerPacket, BrokerPostMessage, BrokerTransferable, BrokerWorker,
|
|
96
|
+
PendingBrokerMessage, TransferEnvelope, TransferEnvelopeFactory, WorkerBrokerApi} from './worker-types';
|
|
97
|
+
|
|
98
|
+
// The object is populated below; keeping staged construction preserves logger/broker initialization.
|
|
99
|
+
export const WorkerBroker = {} as WorkerBrokerApi;
|
|
100
|
+
export default WorkerBroker;
|
|
101
|
+
|
|
102
|
+
// Global list of all worker messages
|
|
103
|
+
// Uniquely tracks every call made between main thread and a worker
|
|
104
|
+
var message_id = 0;
|
|
105
|
+
var messages: Record<number, PendingBrokerMessage> = {};
|
|
106
|
+
|
|
107
|
+
// Register an object to receive calls from other thread
|
|
108
|
+
WorkerBroker.targets = {};
|
|
109
|
+
WorkerBroker.addTarget = function (name, target) {
|
|
110
|
+
WorkerBroker.targets[name] = target;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
WorkerBroker.removeTarget = function (name) {
|
|
114
|
+
if (name) {
|
|
115
|
+
delete WorkerBroker.targets[name];
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// Given a dot-notation-style method name, e.g. 'Object.object.method',
|
|
120
|
+
// find the object to call the method on from the list of registered targets
|
|
121
|
+
function findTarget (method: string | undefined): [] | [string | undefined, Record<string, unknown>] {
|
|
122
|
+
var chain: string[] = [];
|
|
123
|
+
if (typeof method === 'string') {
|
|
124
|
+
chain = method.split('.');
|
|
125
|
+
method = chain.pop();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
var target = WorkerBroker.targets;
|
|
129
|
+
|
|
130
|
+
for (let m=0; m < chain.length; m++) {
|
|
131
|
+
if (target[chain[m]]) {
|
|
132
|
+
target = target[chain[m]] as Record<string, unknown>;
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return [method, target];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Main thread:
|
|
143
|
+
// - Send messages to workers, and optionally receive an async response as a promise
|
|
144
|
+
// - Receive messages from workers, and optionally send an async response back as a promise
|
|
145
|
+
function setupMainThread (): void {
|
|
146
|
+
|
|
147
|
+
// Send a message to a worker, and optionally get an async response
|
|
148
|
+
// Arguments:
|
|
149
|
+
// - worker: one or more web worker instances to send the message to (single value or array)
|
|
150
|
+
// - method: the method with this name, specified with dot-notation, will be invoked in the worker
|
|
151
|
+
// - message: spread of arguments to call the method with
|
|
152
|
+
// Returns:
|
|
153
|
+
// - a promise that will be fulfilled if the worker method returns a value (could be immediately, or async)
|
|
154
|
+
//
|
|
155
|
+
WorkerBroker.postMessage = function (worker: BrokerWorker | BrokerWorker[], method: BrokerMethod, ...message: unknown[]) {
|
|
156
|
+
// If more than one worker specified, post to multiple
|
|
157
|
+
if (Array.isArray(worker)) {
|
|
158
|
+
return Promise.all(
|
|
159
|
+
worker.map(w => WorkerBroker.postMessage(w, method, ...message))
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Parse options
|
|
164
|
+
let options: {stringify?: boolean} = {};
|
|
165
|
+
if (typeof method === 'object') {
|
|
166
|
+
options = method;
|
|
167
|
+
method = method.method;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Track state of this message
|
|
171
|
+
var promise = new Promise<unknown>((resolve, reject) => {
|
|
172
|
+
messages[message_id] = { method, message, resolve, reject };
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
let payload: BrokerPacket | string, transferables: BrokerTransferable[] = [];
|
|
177
|
+
|
|
178
|
+
if (message && message.length === 1 && message[0] instanceof WorkerBroker.withTransferables) {
|
|
179
|
+
transferables = message[0].transferables;
|
|
180
|
+
message = message[0].value;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
payload = {
|
|
184
|
+
type: 'main_send', // mark message as method invocation from main thread
|
|
185
|
+
message_id, // unique id for this message, for life of program
|
|
186
|
+
method, // will dispatch to a function of this name within the worker
|
|
187
|
+
message // message payload
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
if (options.stringify) {
|
|
191
|
+
payload = JSON.stringify(payload);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
worker.postMessage(payload, transferables.map(t => t.object));
|
|
195
|
+
freeTransferables(transferables);
|
|
196
|
+
if (transferables.length > 0) {
|
|
197
|
+
log('trace', `'${method}' transferred ${transferables.length} objects to worker thread`);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
message_id++;
|
|
201
|
+
return promise;
|
|
202
|
+
} as BrokerPostMessage;
|
|
203
|
+
|
|
204
|
+
// Add a worker to communicate with - each worker must be registered from the main thread
|
|
205
|
+
WorkerBroker.addWorker = function (worker) {
|
|
206
|
+
if (!(worker instanceof Worker)) {
|
|
207
|
+
throw Error('Worker broker could not add non-Worker object', worker as unknown as ErrorOptions);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
worker.addEventListener('message', function WorkerBrokerMainThreadHandler(event) {
|
|
211
|
+
let data = ((typeof event.data === 'string') ? JSON.parse(event.data) : event.data) as BrokerPacket;
|
|
212
|
+
let id = data.message_id;
|
|
213
|
+
|
|
214
|
+
// Listen for messages coming back from the worker, and fulfill that message's promise
|
|
215
|
+
if (data.type === 'worker_reply') {
|
|
216
|
+
// Pass the result to the promise
|
|
217
|
+
if (messages[id]) {
|
|
218
|
+
if (data.error) {
|
|
219
|
+
messages[id].reject(data.error);
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
messages[id].resolve(data.message);
|
|
223
|
+
}
|
|
224
|
+
delete messages[id];
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// Listen for messages initiating a call from the worker, dispatch them,
|
|
228
|
+
// and send any return value back to the worker
|
|
229
|
+
// Unique id for this message & return call to main thread
|
|
230
|
+
else if (data.type === 'worker_send' && id != null) {
|
|
231
|
+
// Call the requested method and save the return value
|
|
232
|
+
let result: unknown, error: unknown, target: Record<string, unknown> | undefined, method_name: string | undefined, method;
|
|
233
|
+
try {
|
|
234
|
+
[method_name, target] = findTarget(data.method);
|
|
235
|
+
if (!target) {
|
|
236
|
+
throw Error(`Worker broker could not dispatch message type ${data.method} on target ${data.target} because no object with that name is registered on main thread`);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
method = (typeof target[method_name!] === 'function') && target[method_name!] as ((...arguments_: unknown[]) => unknown);
|
|
240
|
+
if (!method) {
|
|
241
|
+
throw Error(`Worker broker could not dispatch message type ${data.method} on target ${data.target} because object has no method with that name`);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
result = method.apply(target, data.message);
|
|
245
|
+
}
|
|
246
|
+
catch(e) {
|
|
247
|
+
// Thrown errors will be passed back (in string form) to worker
|
|
248
|
+
error = e;
|
|
249
|
+
|
|
250
|
+
}
|
|
251
|
+
// Send return value to worker
|
|
252
|
+
let payload: BrokerPacket | string, transferables: BrokerTransferable[] = [];
|
|
253
|
+
|
|
254
|
+
// Async result
|
|
255
|
+
if (result instanceof Promise) {
|
|
256
|
+
result.then((value) => {
|
|
257
|
+
if (value instanceof WorkerBroker.withTransferables) {
|
|
258
|
+
transferables = value.transferables;
|
|
259
|
+
value = value.value[0];
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
payload = {
|
|
263
|
+
type: 'main_reply',
|
|
264
|
+
message_id: id,
|
|
265
|
+
message: value
|
|
266
|
+
};
|
|
267
|
+
worker.postMessage(payload, transferables.map(t => t.object));
|
|
268
|
+
freeTransferables(transferables);
|
|
269
|
+
if (transferables.length > 0) {
|
|
270
|
+
log('trace', `'${method_name}' transferred ${transferables.length} objects to worker thread`);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
}, (error) => {
|
|
274
|
+
worker.postMessage({
|
|
275
|
+
type: 'main_reply',
|
|
276
|
+
message_id: id,
|
|
277
|
+
error: (error instanceof Error ? `${error.message}: ${error.stack}` : error)
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
// Immediate result
|
|
282
|
+
else {
|
|
283
|
+
if (result instanceof WorkerBroker.withTransferables) {
|
|
284
|
+
transferables = result.transferables;
|
|
285
|
+
result = result.value[0];
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
payload = {
|
|
289
|
+
type: 'main_reply',
|
|
290
|
+
message_id: id,
|
|
291
|
+
message: result,
|
|
292
|
+
error: (error instanceof Error ? `${error.message}: ${error.stack}` : error)
|
|
293
|
+
};
|
|
294
|
+
worker.postMessage(payload, transferables.map(t => t.object));
|
|
295
|
+
freeTransferables(transferables);
|
|
296
|
+
if (transferables.length > 0) {
|
|
297
|
+
log('trace', `'${method_name}' transferred ${transferables.length} objects to worker thread`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
// Expose for debugging
|
|
306
|
+
WorkerBroker.getMessages = function () {
|
|
307
|
+
return messages;
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
WorkerBroker.getMessageId = function () {
|
|
311
|
+
return message_id;
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Worker threads:
|
|
317
|
+
// - Receive messages from main thread, and optionally send an async response back as a promise
|
|
318
|
+
// - Send messages to main thread, and optionally receive an async response as a promise
|
|
319
|
+
function setupWorkerThread (): void {
|
|
320
|
+
|
|
321
|
+
// Send a message to the main thread, and optionally get an async response as a promise
|
|
322
|
+
// Arguments:
|
|
323
|
+
// - method: the method with this name, specified with dot-notation, will be invoked on the main thread
|
|
324
|
+
// - message: array of arguments to call the method with
|
|
325
|
+
// Returns:
|
|
326
|
+
// - a promise that will be fulfilled if the main thread method returns a value (could be immediately, or async)
|
|
327
|
+
//
|
|
328
|
+
WorkerBroker.postMessage = function (method: BrokerMethod, ...message: unknown[]) {
|
|
329
|
+
// Parse options
|
|
330
|
+
let options: {stringify?: boolean} = {};
|
|
331
|
+
if (typeof method === 'object') {
|
|
332
|
+
options = method;
|
|
333
|
+
method = method.method;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Track state of this message
|
|
337
|
+
var promise = new Promise<unknown>((resolve, reject) => {
|
|
338
|
+
messages[message_id] = { method, message, resolve, reject };
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
let payload: BrokerPacket | string, transferables: BrokerTransferable[] = [];
|
|
342
|
+
|
|
343
|
+
if (message && message.length === 1 && message[0] instanceof WorkerBroker.withTransferables) {
|
|
344
|
+
transferables = message[0].transferables;
|
|
345
|
+
message = message[0].value;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
payload = {
|
|
349
|
+
type: 'worker_send', // mark message as method invocation from worker
|
|
350
|
+
message_id, // unique id for this message, for life of program
|
|
351
|
+
method, // will dispatch to a method of this name on the main thread
|
|
352
|
+
message // message payload
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
if (options.stringify) {
|
|
356
|
+
payload = JSON.stringify(payload);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
(self as DedicatedWorkerGlobalScope).postMessage(payload, transferables.map(t => t.object));
|
|
360
|
+
freeTransferables(transferables);
|
|
361
|
+
if (transferables.length > 0) {
|
|
362
|
+
log('trace', `'${method}' transferred ${transferables.length} objects to main thread`);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
message_id++;
|
|
366
|
+
return promise;
|
|
367
|
+
} as BrokerPostMessage;
|
|
368
|
+
|
|
369
|
+
self.addEventListener('message', function WorkerBrokerWorkerThreadHandler(event: MessageEvent<unknown>) {
|
|
370
|
+
let data = ((typeof event.data === 'string') ? JSON.parse(event.data) : event.data) as BrokerPacket;
|
|
371
|
+
let id = data.message_id;
|
|
372
|
+
|
|
373
|
+
// Listen for messages coming back from the main thread, and fulfill that message's promise
|
|
374
|
+
if (data.type === 'main_reply') {
|
|
375
|
+
// Pass the result to the promise
|
|
376
|
+
if (messages[id]) {
|
|
377
|
+
if (data.error) {
|
|
378
|
+
messages[id].reject(data.error);
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
messages[id].resolve(data.message);
|
|
382
|
+
}
|
|
383
|
+
delete messages[id];
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
// Receive messages from main thread, dispatch them, and send back a reply
|
|
387
|
+
// Unique id for this message & return call to main thread
|
|
388
|
+
else if (data.type === 'main_send' && id != null) {
|
|
389
|
+
// Call the requested worker method and save the return value
|
|
390
|
+
let result: unknown, error: unknown, target: Record<string, unknown> | undefined, method_name: string | undefined, method;
|
|
391
|
+
try {
|
|
392
|
+
[method_name, target] = findTarget(data.method);
|
|
393
|
+
if (!target) {
|
|
394
|
+
throw Error(`Worker broker could not dispatch message type ${data.method} on target ${data.target} because no object with that name is registered on main thread`);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
method = (typeof target[method_name!] === 'function') && target[method_name!] as ((...arguments_: unknown[]) => unknown);
|
|
398
|
+
|
|
399
|
+
if (!method) {
|
|
400
|
+
throw Error(`Worker broker could not dispatch message type ${data.method} because worker has no method with that name`);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
result = method.apply(target, data.message);
|
|
404
|
+
}
|
|
405
|
+
catch(e) {
|
|
406
|
+
// Thrown errors will be passed back (in string form) to main thread
|
|
407
|
+
error = e;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Send return value to main thread
|
|
411
|
+
let payload: BrokerPacket | string, transferables: BrokerTransferable[] = [];
|
|
412
|
+
|
|
413
|
+
// Async result
|
|
414
|
+
if (result instanceof Promise) {
|
|
415
|
+
result.then((value) => {
|
|
416
|
+
if (value instanceof WorkerBroker.withTransferables) {
|
|
417
|
+
transferables = value.transferables;
|
|
418
|
+
value = value.value[0];
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
payload = {
|
|
422
|
+
type: 'worker_reply',
|
|
423
|
+
message_id: id,
|
|
424
|
+
message: value
|
|
425
|
+
};
|
|
426
|
+
(self as DedicatedWorkerGlobalScope).postMessage(payload, transferables.map(t => t.object));
|
|
427
|
+
freeTransferables(transferables);
|
|
428
|
+
if (transferables.length > 0) {
|
|
429
|
+
log('trace', `'${method_name}' transferred ${transferables.length} objects to main thread`);
|
|
430
|
+
}
|
|
431
|
+
}, (error) => {
|
|
432
|
+
(self as DedicatedWorkerGlobalScope).postMessage({
|
|
433
|
+
type: 'worker_reply',
|
|
434
|
+
message_id: id,
|
|
435
|
+
error: (error instanceof Error ? `${error.message}: ${error.stack}` : error)
|
|
436
|
+
});
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
// Immediate result
|
|
440
|
+
else {
|
|
441
|
+
if (result instanceof WorkerBroker.withTransferables) {
|
|
442
|
+
transferables = result.transferables;
|
|
443
|
+
result = result.value[0];
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
payload = {
|
|
447
|
+
type: 'worker_reply',
|
|
448
|
+
message_id: id,
|
|
449
|
+
message: result,
|
|
450
|
+
error: (error instanceof Error ? `${error.message}: ${error.stack}` : error)
|
|
451
|
+
};
|
|
452
|
+
(self as DedicatedWorkerGlobalScope).postMessage(payload, transferables.map(t => t.object));
|
|
453
|
+
freeTransferables(transferables);
|
|
454
|
+
if (transferables.length > 0) {
|
|
455
|
+
log('trace', `'${method_name}' transferred ${transferables.length} objects to main thread`);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// Special value wrapper, to indicate that we want to find and include transferable objects in the message
|
|
464
|
+
WorkerBroker.withTransferables = function (this: TransferEnvelope | undefined, ...value: unknown[]) {
|
|
465
|
+
if (!(this instanceof WorkerBroker.withTransferables)) {
|
|
466
|
+
return new WorkerBroker.withTransferables(...value);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
this.value = value;
|
|
470
|
+
this.transferables = findTransferables(this.value);
|
|
471
|
+
} as TransferEnvelopeFactory;
|
|
472
|
+
|
|
473
|
+
// Build a list of transferable objects from a source object
|
|
474
|
+
// Returns a list of info about each transferable:
|
|
475
|
+
// - object: the actual transferable object
|
|
476
|
+
// - parent: the parent object that the transferable is a property of (if any)
|
|
477
|
+
// - property: the property name of the transferable on the parent object (if any)
|
|
478
|
+
// TODO: add option in case you DON'T want to transfer objects
|
|
479
|
+
function findTransferables(source: unknown, parent: object | null = null, property: string | number | null = null,
|
|
480
|
+
list: BrokerTransferable[] = []): BrokerTransferable[] {
|
|
481
|
+
if (!source) {
|
|
482
|
+
return list;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (Array.isArray(source)) {
|
|
486
|
+
// Check each array element
|
|
487
|
+
source.forEach((x, i) => findTransferables(x, source, i, list));
|
|
488
|
+
}
|
|
489
|
+
else if (typeof source === 'object') {
|
|
490
|
+
// Is the object a transferable array buffer?
|
|
491
|
+
if (source instanceof ArrayBuffer) {
|
|
492
|
+
list.push({ object: source, parent, property });
|
|
493
|
+
}
|
|
494
|
+
// Or looks like a typed array (has an array buffer property)?
|
|
495
|
+
else if ((source as {buffer?: unknown}).buffer instanceof ArrayBuffer) {
|
|
496
|
+
list.push({ object: (source as {buffer: ArrayBuffer}).buffer, parent, property });
|
|
497
|
+
}
|
|
498
|
+
// Otherwise check each property
|
|
499
|
+
else {
|
|
500
|
+
for (let prop in source) {
|
|
501
|
+
findTransferables((source as Record<string, unknown>)[prop], source, prop, list);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return list;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Remove neutered transferables from parent objects, as they should no longer be accessed after transfer
|
|
509
|
+
function freeTransferables(transferables: BrokerTransferable[]): void {
|
|
510
|
+
if (!Array.isArray(transferables)) {
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
transferables.filter(t => t.parent && t.property).forEach(t => delete (t.parent as Record<string | number, unknown>)[t.property!]);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Setup this thread as appropriate
|
|
517
|
+
if (Thread.is_main) {
|
|
518
|
+
setupMainThread();
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (Thread.is_worker) {
|
|
522
|
+
setupWorkerThread();
|
|
523
|
+
}
|