maplibre-gl
Version:
BSD licensed community fork of mapbox-gl, a WebGL interactive maps library
111 lines (92 loc) • 3.81 kB
text/typescript
import {browser} from '../util/browser.ts';
import {Event, Evented} from '../util/evented.ts';
import {warnOnce} from '../util/util.ts';
import {type RTLPluginStatus, RTLPluginLoadedEventName, type PluginState} from './rtl_text_plugin_status.ts';
import {type GlobalDispatcher, getGlobalDispatcher} from '../util/global_dispatcher.ts';
import {MessageType} from '../util/actor_messages.ts';
class RTLMainThreadPlugin extends Evented {
status: RTLPluginStatus = 'unavailable';
url: string = null;
dispatcher: GlobalDispatcher = getGlobalDispatcher();
constructor() {
super();
this.dispatcher.on('workerscreate', () => this._resyncWorkers());
}
/**
* Re-syncs the plugin into freshly created workers. A `loading` plugin needs no re-sync: its
* in-flight request targets the newest workers, and re-requesting would double-load the
* script when the plugin's own broadcast is what created the workers.
*/
async _resyncWorkers(): Promise<void> {
try {
if (this.status === 'deferred') {
await this._syncState('deferred');
} else if (this.status === 'loaded') {
await this._requestImport();
}
} catch (error) {
warnOnce(`Failed to load the RTL text plugin into the new workers: ${error}`);
}
}
/** Sync RTL plugin state by broadcasting a message to the worker */
_syncState(statusToSend: RTLPluginStatus): Promise<PluginState[]> {
this.status = statusToSend;
return this.dispatcher.broadcast(MessageType.syncRTLPluginState, {pluginStatus: statusToSend, pluginURL: this.url})
.catch((e: any) => {
this.status = 'error';
throw e;
});
}
/** This one is exposed to outside */
getRTLTextPluginStatus(): RTLPluginStatus {
return this.status;
}
clearRTLTextPlugin(): void {
this.status = 'unavailable';
this.url = null;
}
async setRTLTextPlugin(url: string, deferred: boolean = false): Promise<void> {
if (this.url) {
// error
throw new Error('setRTLTextPlugin cannot be called multiple times.');
}
this.url = browser.resolveURL(url);
if (!this.url) {
throw new Error(`requested url ${url} is invalid`);
}
if (this.status === 'unavailable') {
// from initial state:
if (deferred) {
this.status = 'deferred';
// fire and forget: in this case it does not need wait for the broadcasting result
// it is important to sync the deferred status once because
// symbol_bucket will be checking it in worker
this._syncState(this.status);
} else {
return this._requestImport();
}
} else if (this.status === 'requested') {
return this._requestImport();
}
}
/** Send a message to worker which will import the RTL plugin script */
async _requestImport() : Promise<void> {
// all errors/exceptions will be handled by _syncState
await this._syncState('loading');
this.status = 'loaded';
this.fire(new Event(RTLPluginLoadedEventName));
}
/** Start a lazy loading process of RTL plugin */
lazyLoad(): void {
if (this.status === 'unavailable') {
this.status = 'requested';
} else if (this.status === 'deferred') {
this._requestImport();
}
}
}
let rtlMainThreadPlugin: RTLMainThreadPlugin = null;
export function rtlMainThreadPluginFactory(): RTLMainThreadPlugin {
rtlMainThreadPlugin ||= new RTLMainThreadPlugin();
return rtlMainThreadPlugin;
}