Skip to content

Commit

Permalink
Remove callbacks, cancelable, simplify addProtocol, add global dispat…
Browse files Browse the repository at this point in the history
…cher (#3433)

* Remove callbacks, cancelable and simplify add protocol

* Update changelog with PR id.

* Correct example

* Update CHANGELOG.md

* Fix issue with RTL dispatcher related to worker code.

* Fixes the problem with the dispatcher

---------

Co-authored-by: neodescis <nsteinbaugh@gmail.com>
  • Loading branch information
HarelM and neodescis authored Dec 3, 2023
1 parent 47d7403 commit 3abe643
Show file tree
Hide file tree
Showing 19 changed files with 173 additions and 143 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

### ✨ Features and improvements

- ⚠️ Changes `addProtocol` to be promise-based without the usage of callbacks and cancelable ([#3433](https://github.com/maplibre/maplibre-gl-js/pull/3433))
- ⚠️ Moved the `addSrouceType` to be a part of the global maplibregl object instead of being per map object ([#3420](https://github.com/maplibre/maplibre-gl-js/pull/3420))
- ⚠️ Removed callback usage from `map.loadImage` in continue to below change ([#3422](https://github.com/maplibre/maplibre-gl-js/pull/3422))
- ⚠️ Changed the `GeoJSONSource`'s `getClusterExpansionZoom`, `getClusterChildren`, `getClusterLeaves` methods to return a `Promise` instead of a callback usage ([#3421](https://github.com/maplibre/maplibre-gl-js/pull/3421))
Expand Down
36 changes: 15 additions & 21 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ describe('maplibre', () => {
const protocolName = 'custom';
expect(Object.keys(config.REGISTERED_PROTOCOLS)).toHaveLength(0);

maplibre.addProtocol(protocolName, () => { return {cancel: () => { }}; });
maplibre.addProtocol(protocolName, async () => Promise.resolve({} as any));
expect(Object.keys(config.REGISTERED_PROTOCOLS)[0]).toBe(protocolName);
});

test('removeProtocol', () => {
const protocolName = 'custom';
expect(Object.keys(config.REGISTERED_PROTOCOLS)).toHaveLength(0);

maplibre.addProtocol(protocolName, () => { return {cancel: () => { }}; });
maplibre.addProtocol(protocolName, () => Promise.resolve({} as any));
expect(Object.keys(config.REGISTERED_PROTOCOLS)[0]).toBe(protocolName);

maplibre.removeProtocol(protocolName);
Expand All @@ -37,10 +37,9 @@ describe('maplibre', () => {

test('#addProtocol - getJSON', async () => {
let protocolCallbackCalled = false;
maplibre.addProtocol('custom', (reqParam, callback) => {
maplibre.addProtocol('custom', () => {
protocolCallbackCalled = true;
callback(null, {'foo': 'bar'});
return {cancel: () => {}};
return Promise.resolve({data: {'foo': 'bar'}});
});
const response = await getJSON({url: 'custom://test/url/json'}, new AbortController());
expect(response.data).toEqual({foo: 'bar'});
Expand All @@ -49,10 +48,9 @@ describe('maplibre', () => {

test('#addProtocol - getArrayBuffer', async () => {
let protocolCallbackCalled = false;
maplibre.addProtocol('custom', (_reqParam, callback) => {
maplibre.addProtocol('custom', () => {
protocolCallbackCalled = true;
callback(null, new ArrayBuffer(1), 'cache-control', 'expires');
return {cancel: () => {}};
return Promise.resolve({data: new ArrayBuffer(1), cacheControl: 'cache-control', expires: 'expires'});
});
const response = await getArrayBuffer({url: 'custom://test/url/getArrayBuffer'}, new AbortController());
expect(response.data).toBeInstanceOf(ArrayBuffer);
Expand All @@ -63,10 +61,9 @@ describe('maplibre', () => {

test('#addProtocol - returning ImageBitmap for getImage', async () => {
let protocolCallbackCalled = false;
maplibre.addProtocol('custom', (_reqParam, callback) => {
maplibre.addProtocol('custom', () => {
protocolCallbackCalled = true;
callback(null, new ImageBitmap());
return {cancel: () => {}};
return Promise.resolve({data: new ImageBitmap()});
});

const img = await ImageRequest.getImage({url: 'custom://test/url/getImage'}, new AbortController());
Expand All @@ -76,21 +73,17 @@ describe('maplibre', () => {

test('#addProtocol - returning HTMLImageElement for getImage', async () => {
let protocolCallbackCalled = false;
maplibre.addProtocol('custom', (reqParam, callback) => {
maplibre.addProtocol('custom', () => {
protocolCallbackCalled = true;
callback(null, new Image());
return {cancel: () => {}};
return Promise.resolve({data: new Image()});
});
const img = await ImageRequest.getImage({url: 'custom://test/url/getImage'}, new AbortController());
expect(img.data).toBeInstanceOf(HTMLImageElement);
expect(protocolCallbackCalled).toBeTruthy();
});

test('#addProtocol - error', () => {
maplibre.addProtocol('custom', (reqParam, callback) => {
callback(new Error('error'));
return {cancel: () => { }};
});
maplibre.addProtocol('custom', () => Promise.reject(new Error('test error')));

getJSON({url: 'custom://test/url/json'}, new AbortController()).catch((error) => {
expect(error).toBeTruthy();
Expand All @@ -99,10 +92,11 @@ describe('maplibre', () => {

test('#addProtocol - Cancel request', async () => {
let cancelCalled = false;
maplibre.addProtocol('custom', () => {
return {cancel: () => {
maplibre.addProtocol('custom', (_req, abortController) => {
abortController.signal.addEventListener('abort', () => {
cancelCalled = true;
}};
});
return Promise.resolve({} as any);
});
const abortController = new AbortController();
const promise = getJSON({url: 'custom://test/url/json'}, abortController);
Expand Down
34 changes: 12 additions & 22 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,14 @@ import {LngLatBounds} from './geo/lng_lat_bounds';
import Point from '@mapbox/point-geometry';
import {MercatorCoordinate} from './geo/mercator_coordinate';
import {Evented} from './util/evented';
import {config} from './util/config';
import {AddProtocolAction, config} from './util/config';
import {Debug} from './util/debug';
import {isSafari} from './util/util';
import {rtlMainThreadPluginFactory} from './source/rtl_text_plugin_main_thread';
import {WorkerPool} from './util/worker_pool';
import {prewarm, clearPrewarmedResources} from './util/global_worker_pool';
import {PerformanceUtils} from './util/performance';
import {AJAXError} from './util/ajax';
import type {RequestParameters, ResponseCallback} from './util/ajax';
import type {Cancelable} from './types/cancelable';
import {GeoJSONSource} from './source/geojson_source';
import {CanvasSource} from './source/canvas_source';
import {ImageSource} from './source/image_source';
Expand Down Expand Up @@ -191,30 +189,22 @@ class MapLibreGL {
* @example
* This will fetch a file using the fetch API (this is obviously a non interesting example...)
* ```ts
* maplibregl.addProtocol('custom', (params, callback) => {
fetch(`https://${params.url.split("://")[1]}`)
.then(t => {
if (t.status == 200) {
t.arrayBuffer().then(arr => {
callback(null, arr, null, null);
});
} else {
callback(new Error(`Tile fetch error: ${t.statusText}`));
}
})
.catch(e => {
callback(new Error(e));
});
return { cancel: () => { } };
* maplibregl.addProtocol('custom', async (params, abortController) => {
const t = await fetch(`https://${params.url.split("://")[1]}`);
if (t.status == 200) {
const buffer = await t.arrayBuffer();
return {data: buffer}
} else {
throw new Error(`Tile fetch error: ${t.statusText}`));
}
});
* // the following is an example of a way to return an error when trying to load a tile
* maplibregl.addProtocol('custom2', (params, callback) => {
* callback(new Error('someErrorMessage'));
* return { cancel: () => { } };
* maplibregl.addProtocol('custom2', async (params, abortController) => {
* throw new Error('someErrorMessage'));
* });
* ```
*/
static addProtocol(customProtocol: string, loadFn: (requestParameters: RequestParameters, callback: ResponseCallback<any>) => Cancelable) {
static addProtocol(customProtocol: string, loadFn: AddProtocolAction) {
config.REGISTERED_PROTOCOLS[customProtocol] = loadFn;
}

Expand Down
6 changes: 1 addition & 5 deletions src/source/image_source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import type {CanvasSourceSpecification} from './canvas_source';
import type {Map} from '../ui/map';
import type {Dispatcher} from '../util/dispatcher';
import type {Tile} from './tile';
import type {Callback} from '../types/callback';
import type {VertexBuffer} from '../gl/vertex_buffer';
import type {
ImageSourceSpecification,
Expand Down Expand Up @@ -280,7 +279,7 @@ export class ImageSource extends Evented implements Source {
}
}

async loadTile(tile: Tile, callback?: Callback<void>): Promise<void> {
async loadTile(tile: Tile): Promise<void> {
// We have a single tile -- whose coordinates are this.tileID -- that
// covers the image we want to render. If that's the one being
// requested, set it up with the image; otherwise, mark the tile as
Expand All @@ -293,9 +292,6 @@ export class ImageSource extends Evented implements Source {
} else {
tile.state = 'errored';
}
if (callback) {
callback();
}
}

serialize(): ImageSourceSpecification | VideoSourceSpecification | CanvasSourceSpecification {
Expand Down
3 changes: 2 additions & 1 deletion src/source/rtl_text_plugin_main_thread.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {FakeServer, fakeServer} from 'nise';
import {rtlMainThreadPluginFactory} from './rtl_text_plugin_main_thread';
import {sleep} from '../util/test/util';
import {browser} from '../util/browser';
import {Dispatcher} from '../util/dispatcher';

const rtlMainThreadPlugin = rtlMainThreadPluginFactory();

Expand All @@ -13,7 +14,7 @@ describe('RTLMainThreadPlugin', () => {
global.fetch = null;
// Reset the singleton instance before each test
rtlMainThreadPlugin.clearRTLTextPlugin();
broadcastSpy = jest.spyOn(rtlMainThreadPlugin.dispatcher, 'broadcast').mockImplementation(() => { return Promise.resolve({} as any); });
broadcastSpy = jest.spyOn(Dispatcher.prototype, 'broadcast').mockImplementation(() => { return Promise.resolve({} as any); });
});

afterEach(() => {
Expand Down
5 changes: 2 additions & 3 deletions src/source/rtl_text_plugin_main_thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ import {getArrayBuffer} from '../util/ajax';
import {browser} from '../util/browser';
import {Event, Evented} from '../util/evented';
import {RTLPluginStatus, PluginState} from './rtl_text_plugin_status';
import {Dispatcher} from '../util/dispatcher';
import {getGlobalWorkerPool} from '../util/global_worker_pool';
import {Dispatcher, getGlobalDispatcher} from '../util/dispatcher';

class RTLMainThreadPlugin extends Evented {
pluginStatus: RTLPluginStatus = 'unavailable';
pluginURL: string = null;
dispatcher: Dispatcher = new Dispatcher(getGlobalWorkerPool(), 'rtl-text-plugin-dispacher');
dispatcher: Dispatcher = getGlobalDispatcher();
queue: PluginState[] = [];

async _sendPluginStateToWorker() {
Expand Down
6 changes: 2 additions & 4 deletions src/source/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import {GeoJSONSource} from '../source/geojson_source';
import {VideoSource} from '../source/video_source';
import {ImageSource} from '../source/image_source';
import {CanvasSource} from '../source/canvas_source';
import {Dispatcher} from '../util/dispatcher';
import {getGlobalWorkerPool} from '../util/global_worker_pool';
import {Dispatcher, getGlobalDispatcher} from '../util/dispatcher';

import type {SourceSpecification} from '@maplibre/maplibre-gl-style-spec';
import type {Event, Evented} from '../util/evented';
Expand Down Expand Up @@ -194,7 +193,6 @@ export const addSourceType = async (name: string, SourceType: SourceClass): Prom
if (!SourceType.workerSourceURL) {
return;
}
const dispatcher = new Dispatcher(getGlobalWorkerPool(), 'add-custom-source-dispatcher');
const dispatcher = getGlobalDispatcher();
await dispatcher.broadcast('loadWorkerSource', SourceType.workerSourceURL.toString());
dispatcher.remove();
};
12 changes: 3 additions & 9 deletions src/source/source_cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {Event, ErrorEvent, Evented} from '../util/evented';
import {extend} from '../util/util';
import {browser} from '../util/browser';
import {Dispatcher} from '../util/dispatcher';
import {Callback} from '../types/callback';
import {TileBounds} from './tile_bounds';
import {sleep} from '../util/test/util';

Expand All @@ -22,7 +21,7 @@ class SourceMock extends Evented implements Source {
type: string;
tileSize: number;

constructor(id: string, sourceOptions: any, _dispatcher, eventedParent: Evented) {
constructor(id: string, sourceOptions: any, _dispatcher: Dispatcher, eventedParent: Evented) {
super();
this.id = id;
this.minzoom = 0;
Expand All @@ -34,18 +33,13 @@ class SourceMock extends Evented implements Source {
this.hasTile = sourceOptions.hasTile;
}
}
loadTile(tile: Tile, callback?: Callback<void>): Promise<void> {
loadTile(tile: Tile): Promise<void> {
if (this.sourceOptions.expires) {
tile.setExpiryData({
expires: this.sourceOptions.expires
});
}
if (callback) {
setTimeout(callback, 0);
} else {
return new Promise(resolve => setTimeout(resolve, 0));
}

return new Promise(resolve => setTimeout(resolve, 0));
}
loaded() {
return true;
Expand Down
4 changes: 2 additions & 2 deletions src/source/worker.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Actor, ActorTarget} from '../util/actor';
import {Actor, ActorTarget, IActor} from '../util/actor';
import {StyleLayerIndex} from '../style/style_layer_index';
import {VectorTileWorkerSource} from './vector_tile_worker_source';
import {RasterDEMTileWorkerSource} from './raster_dem_tile_worker_source';
Expand Down Expand Up @@ -218,7 +218,7 @@ export default class Worker {
if (!this.workerSources[mapId][sourceType][sourceName]) {
// use a wrapped actor so that we can attach a target mapId param
// to any messages invoked by the WorkerSource, this is very important when there are multiple maps
const actor = {
const actor: IActor = {
sendAsync: (message, abortController) => {
message.targetMapId = mapId;
return this.actor.sendAsync(message, abortController);
Expand Down
10 changes: 1 addition & 9 deletions src/style/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {Light} from './light';
import {LineAtlas} from '../render/line_atlas';
import {pick, clone, extend, deepEqual, filterObject, mapObject} from '../util/util';
import {coerceSpriteToArray} from '../util/style';
import {getJSON, getReferrer, makeRequest} from '../util/ajax';
import {getJSON, getReferrer} from '../util/ajax';
import {ResourceType} from '../util/request_manager';
import {browser} from '../util/browser';
import {Dispatcher} from '../util/dispatcher';
Expand Down Expand Up @@ -40,7 +40,6 @@ import type {Transform} from '../geo/transform';
import type {StyleImage} from './style_image';
import type {EvaluationParameters} from './evaluation_parameters';
import type {Placement} from '../symbol/placement';
import type {GetResourceResponse, RequestParameters} from '../util/ajax';
import type {
LayerSpecification,
FilterSpecification,
Expand Down Expand Up @@ -239,9 +238,6 @@ export class Style extends Evented {
this.dispatcher.registerMessageHandler('getImages', (mapId, params) => {
return this.getImages(mapId, params);
});
this.dispatcher.registerMessageHandler('getResource', (mapId, params, abortController) => {
return this.getResource(mapId, params, abortController);
});
this.imageManager = new ImageManager();
this.imageManager.setEventedParent(this);
this.glyphManager = new GlyphManager(map._requestManager, options.localIdeographFontFamily);
Expand Down Expand Up @@ -1594,10 +1590,6 @@ export class Style extends Evented {
return glypgs;
}

getResource(mapId: string | number, params: RequestParameters, abortController: AbortController): Promise<GetResourceResponse<any>> {
return makeRequest(params, abortController);
}

getGlyphsUrl() {
return this.stylesheet.glyphs || null;
}
Expand Down
15 changes: 0 additions & 15 deletions src/types/callback.ts

This file was deleted.

6 changes: 0 additions & 6 deletions src/types/cancelable.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/util/actor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export class Actor implements IActor {
mapId: string | number | null;
resolveRejects: { [x: string]: ResolveReject};
name: string;
tasks: { [x: number]: MessageData };
tasks: { [x: string]: MessageData };
taskQueue: Array<string>;
abortControllers: { [x: number | string]: AbortController };
invoker: ThrottledInvoker;
Expand Down Expand Up @@ -205,7 +205,7 @@ export class Actor implements IActor {
return;
}
if (!this.messageHandlers[task.type]) {
this.completeTask(id, new Error(`Could not find a registered handler for ${task.type}`));
this.completeTask(id, new Error(`Could not find a registered handler for ${task.type}, map ID: ${this.mapId}, available handlers: ${Object.keys(this.messageHandlers).join(', ')}`));
return;
}
const params = deserialize(task.data) as RequestResponseMessageMap[MessageType][0];
Expand Down
Loading

0 comments on commit 3abe643

Please sign in to comment.