UNPKG

php-wasm

Version:

Run PHP right in the browser or anywhere else JS can run

160 lines (133 loc) 4.07 kB
import { PhpBase } from './PhpBase.mjs'; import { commitTransaction, startTransaction } from './webTransactions.mjs'; const defaultVersion = '8.4'; const defaultVariant = ''; /** * Browser-hosted PHP wrapper. */ export class PhpWeb extends PhpBase { /** * Creates a browser-hosted PHP runtime. * @param {PhpRuntimeArgs} args Runtime configuration. */ constructor(args = {}) { const version = args.version ?? defaultVersion; const variant = args.variant ?? defaultVariant; const vvId = version + variant; const constructorArgs = {version, variant, ...args}; switch(vvId) { case '8.5': super(import(`./php8.5-web.mjs`), constructorArgs); break; case '8.5_sdl': super(import(`./php8.5_sdl-web.mjs`), constructorArgs); break; case '8.4': super(import(`./php8.4-web.mjs`), constructorArgs); break; case '8.4_sdl': super(import(`./php8.4_sdl-web.mjs`), constructorArgs); break; case '8.3': super(import(`./php8.3-web.mjs`), constructorArgs); break; case '8.3_sdl': super(import(`./php8.3_sdl-web.mjs`), constructorArgs); break; case '8.2': super(import(`./php8.2-web.mjs`), constructorArgs); break; case '8.2_sdl': super(import(`./php8.2_sdl-web.mjs`), constructorArgs); break; case '8.1': super(import(`./php8.1-web.mjs`), constructorArgs); break; case '8.1_sdl': super(import(`./php8.1_sdl-web.mjs`), constructorArgs); break; case '8.0': super(import(`./php8.0-web.mjs`), constructorArgs); break; case '8.0_sdl': super(import(`./php8.0_sdl-web.mjs`), constructorArgs); break; default: throw new Error(`Unsupported PHP runtime: ${vvId}`); } } /** * Starts a persisted browser transaction for the runtime. * @returns {Promise<void>} Resolves when the transaction lock has been acquired. */ startTransaction() { return startTransaction(this); } /** * Commits a persisted browser transaction for the runtime. * @param {boolean} readOnly Indicates whether the transaction only performed reads. * @returns {Promise<void>} Resolves when the transaction has been committed. */ commitTransaction(readOnly = false) { return commitTransaction(this, readOnly); } /** * Refreshes the browser-hosted runtime and syncs its filesystem. * @returns {Promise<void>} Resolves after the browser runtime has been refreshed. */ async refresh() { await super.refresh(); const php = await this.binary; await navigator.locks.request('php-wasm-fs-lock', () => { return new Promise((accept, reject) => { php.FS.syncfs(true, error => { if(error) reject(error); else accept(); }); }); }); } /** * Serializes async runtime operations behind the browser FS lock. * @param {PhpQueuedCallback} callback Async operation to queue. * @param {PhpQueueParams} params Arguments passed to the queued callback. * @param {boolean} readOnly Indicates whether the queued operation mutates state. * @returns {Promise<PhpRuntimeValue>} Resolves with the queued callback result. */ async _enqueue(callback, params = [], readOnly = false) { await this.binary; let accept, reject; const coordinator = new Promise((a,r) => [accept, reject] = [a, r]); const _accept = result => accept(result); const _reject = reason => reject(reason); this.queue.push([callback, params, _accept, _reject]); navigator.locks.request('php-wasm-fs-lock', async () => { if(!this.queue.length) { return; } await ((this.autoTransaction && !readOnly) ? this.startTransaction() : Promise.resolve()); do { const [callback, params, accept, reject] = this.queue.shift(); const run = callback(...params); run.then(accept).catch(reject); await run; let lockChecks = 25; while(!this.queue.length && lockChecks--) { await new Promise(a => setTimeout(a, 5)); } } while(this.queue.length); await (this.autoTransaction ? this.commitTransaction(readOnly) : Promise.resolve()); }); return coordinator; } }