UNPKG

@dodona/papyros

Version:

Scratchpad for multiple programming languages in the browser.

100 lines 4.07 kB
import { ProgrammingLanguage } from "../ProgrammingLanguage"; import { BackendEventType } from "./BackendEvent"; import { LogType, papyrosLog } from "../util/Logging"; import { makeChannel } from "sync-message"; import { SyncClient } from "comsync"; import { PyodideClient } from "pyodide-worker-runner"; /** * Abstract class to implement the singleton pattern * Static methods group functionality */ export class BackendManager { /** * @param {ProgrammingLanguage} language The language to support * @param {Function} backendCreator The constructor for a SyncClient */ static registerBackend(language, backendCreator) { BackendManager.removeBackend(language); BackendManager.createBackendMap.set(language, backendCreator); } /** * Start a backend for the given language and cache for reuse * @param {ProgrammingLanguage} language The programming language supported by the backend * @return {SyncClient<Backend>} A SyncClient for the Backend */ static getBackend(language) { if (this.backendMap.has(language)) { // Cached return this.backendMap.get(language); } else if (this.createBackendMap.has(language)) { // Create and then cache const syncClient = this.createBackendMap.get(language)(); this.backendMap.set(language, syncClient); return syncClient; } else { throw new Error(`${language} is not yet supported.`); } } /** * Remove a backend for the given language * @param {ProgrammingLanguage} language The programming language supported by the backend * @return {boolean} Whether the remove operation had any effect */ static removeBackend(language) { this.backendMap.delete(language); return this.createBackendMap.delete(language); } /** * Register a callback for when an event of a certain type is published * @param {BackendEventType} type The type of event to subscribe to * @param {BackendEventListener} subscriber Callback for when an event * of the given type is published */ static subscribe(type, subscriber) { if (!this.subscriberMap.has(type)) { this.subscriberMap.set(type, []); } const subscribers = this.subscriberMap.get(type); if (!subscribers.includes(subscriber)) { subscribers.push(subscriber); } } /** * Publish an event, notifying all listeners for its type * @param {BackendEventType} e The event to publish */ static publish(e) { papyrosLog(LogType.Debug, "Publishing event: ", e); if (e.type === BackendEventType.Start) { BackendManager.halted = false; } if ((!BackendManager.halted || e.type === BackendEventType.FrameChange || e.type === BackendEventType.Files) && this.subscriberMap.has(e.type)) { this.subscriberMap.get(e.type).forEach((cb) => cb(e)); } } static halt() { BackendManager.halted = true; } } /** * Initialise the fields and setup the maps */ (() => { BackendManager.channel = makeChannel(); BackendManager.createBackendMap = new Map(); BackendManager.backendMap = new Map(); BackendManager.subscriberMap = new Map(); BackendManager.registerBackend(ProgrammingLanguage.Python, () => new PyodideClient(() => new Worker(new URL("../backend/workers/python/worker", import.meta.url), { type: "module", }), BackendManager.channel)); BackendManager.registerBackend(ProgrammingLanguage.JavaScript, () => new SyncClient(() => new Worker(new URL("../backend/workers/javascript/worker", import.meta.url), { type: "module", }), BackendManager.channel)); BackendManager.halted = false; BackendManager.subscribe(BackendEventType.End, () => BackendManager.halt()); BackendManager.subscribe(BackendEventType.Interrupt, () => BackendManager.halt()); })(); //# sourceMappingURL=BackendManager.js.map