diff options
Diffstat (limited to 'remote/cdp/StreamRegistry.sys.mjs')
-rw-r--r-- | remote/cdp/StreamRegistry.sys.mjs | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/remote/cdp/StreamRegistry.sys.mjs b/remote/cdp/StreamRegistry.sys.mjs new file mode 100644 index 0000000000..9474f16a57 --- /dev/null +++ b/remote/cdp/StreamRegistry.sys.mjs @@ -0,0 +1,139 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + generateUUID: "chrome://remote/content/shared/UUID.sys.mjs", + UnsupportedError: "chrome://remote/content/cdp/Error.sys.mjs", +}); + +export class Stream { + #path; + #offset; + #length; + + constructor(path) { + this.#path = path; + this.#offset = 0; + this.#length = null; + } + + async destroy() { + await IOUtils.remove(this.#path); + } + + async seek(seekTo) { + // To keep compatibility with Chrome clip invalid offsets + this.#offset = Math.max(0, Math.min(seekTo, await this.length())); + } + + async readBytes(count) { + const bytes = await IOUtils.read(this.#path, { + offset: this.#offset, + maxBytes: count, + }); + this.#offset += bytes.length; + return bytes; + } + + async available() { + const length = await this.length(); + return length - this.#offset; + } + + async length() { + if (this.#length === null) { + const info = await IOUtils.stat(this.#path); + this.#length = info.size; + } + + return this.#length; + } + + get path() { + return this.#path; + } +} + +export class StreamRegistry { + constructor() { + // handle => stream + this.streams = new Map(); + + // Register an async shutdown blocker to ensure all open IO streams are + // closed, and remaining temporary files removed. Needs to happen before + // IOUtils has been shutdown. + IOUtils.profileBeforeChange.addBlocker( + "Remote Agent: Clean-up of open streams", + async () => { + await this.destructor(); + } + ); + } + + async destructor() { + for (const stream of this.streams.values()) { + await stream.destroy(); + } + + this.streams.clear(); + } + + /** + * Add a new stream to the registry. + * + * @param {Stream} stream + * The stream to use. + * + * @returns {string} + * Stream handle (uuid) + */ + add(stream) { + if (!(stream instanceof Stream)) { + // Bug 1602731 - Implement support for blob + throw new lazy.UnsupportedError(`Unknown stream type for ${stream}`); + } + + const handle = lazy.generateUUID(); + + this.streams.set(handle, stream); + return handle; + } + + /** + * Get a stream from the registry. + * + * @param {string} handle + * Handle of the stream to retrieve. + * + * @returns {Stream} + * The requested stream. + */ + get(handle) { + const stream = this.streams.get(handle); + + if (!stream) { + throw new TypeError(`Invalid stream handle`); + } + + return stream; + } + + /** + * Remove a stream from the registry. + * + * @param {string} handle + * Handle of the stream to remove. + * + * @returns {boolean} + * true if successfully removed + */ + async remove(handle) { + const stream = this.get(handle); + await stream.destroy(); + + return this.streams.delete(handle); + } +} |