UNPKG

scratch-storage

Version:

Load and store project and asset files for Scratch 3.0

168 lines (151 loc) 6.09 kB
const md5 = require('js-md5'); const log = require('./log'); const Asset = require('./Asset'); const AssetType = require('./AssetType'); const DataFormat = require('./DataFormat'); const Helper = require('./Helper'); /** * @typedef {object} BuiltinAssetRecord * @property {AssetType} type - The type of the asset. * @property {DataFormat} format - The format of the asset's data. * @property {?string} id - The asset's unique ID. * @property {Buffer} data - The asset's data. */ /** * @type {BuiltinAssetRecord[]} */ const DefaultAssets = [ { type: AssetType.ImageBitmap, format: DataFormat.PNG, id: null, data: Buffer.from( require('./builtins/defaultBitmap.png') // eslint-disable-line global-require ) }, { type: AssetType.Sound, format: DataFormat.WAV, id: null, data: Buffer.from( require('./builtins/defaultSound.wav') // eslint-disable-line global-require ) }, { type: AssetType.ImageVector, format: DataFormat.SVG, id: null, data: Buffer.from( require('./builtins/defaultVector.svg') // eslint-disable-line global-require ) } ]; /** * @type {BuiltinAssetRecord[]} */ const BuiltinAssets = DefaultAssets.concat([ ]); class BuiltinHelper extends Helper { constructor (parent) { super(parent); /** * In-memory storage for all built-in assets. * @type {Object.<AssetType, AssetIdMap>} Maps asset type to a map of asset ID to actual assets. * @typedef {Object.<string, BuiltinAssetRecord>} AssetIdMap - Maps asset ID to asset. */ this.assets = {}; BuiltinAssets.forEach(assetRecord => { assetRecord.id = this._store(assetRecord.type, assetRecord.format, assetRecord.data, assetRecord.id); }); } /** * Call `setDefaultAssetId` on the parent `ScratchStorage` instance to register all built-in default assets. */ registerDefaultAssets () { const numAssets = DefaultAssets.length; for (let assetIndex = 0; assetIndex < numAssets; ++assetIndex) { const assetRecord = DefaultAssets[assetIndex]; this.parent.setDefaultAssetId(assetRecord.type, assetRecord.id); } } /** * Synchronously fetch a cached asset for a given asset id. Returns null if not found. * @param {string} assetId - The id for the asset to fetch. * @returns {?Asset} The asset for assetId, if it exists. */ get (assetId) { let asset = null; if (Object.prototype.hasOwnProperty.call(this.assets, assetId)) { /** @type{BuiltinAssetRecord} */ const assetRecord = this.assets[assetId]; asset = new Asset(assetRecord.type, assetRecord.id, assetRecord.format, assetRecord.data); } return asset; } /** * Alias for store (old name of store) * @deprecated Use BuiltinHelper.store * @param {AssetType} assetType - The type of the asset to cache. * @param {DataFormat} dataFormat - The dataFormat of the data for the cached asset. * @param {Buffer} data - The data for the cached asset. * @param {string} id - The id for the cached asset. * @returns {string} The calculated id of the cached asset, or the supplied id if the asset is mutable. */ cache (assetType, dataFormat, data, id) { log.warn('Deprecation: BuiltinHelper.cache has been replaced with BuiltinHelper.store.'); return this.store(assetType, dataFormat, data, id); } /** * Deprecated external API for _store * @deprecated Not for external use. Create assets and keep track of them outside of the storage instance. * @param {AssetType} assetType - The type of the asset to cache. * @param {DataFormat} dataFormat - The dataFormat of the data for the cached asset. * @param {Buffer} data - The data for the cached asset. * @param {(string|number)} id - The id for the cached asset. * @returns {string} The calculated id of the cached asset, or the supplied id if the asset is mutable. */ store (assetType, dataFormat, data, id) { log.warn('Deprecation: use Storage.createAsset. BuiltinHelper is for internal use only.'); return this._store(assetType, dataFormat, data, id); } /** * Cache an asset for future lookups by ID. * @param {AssetType} assetType - The type of the asset to cache. * @param {DataFormat} dataFormat - The dataFormat of the data for the cached asset. * @param {Buffer} data - The data for the cached asset. * @param {(string|number)} id - The id for the cached asset. * @returns {string} The calculated id of the cached asset, or the supplied id if the asset is mutable. */ _store (assetType, dataFormat, data, id) { if (!dataFormat) throw new Error('Data cached without specifying its format'); if (id !== '' && id !== null && typeof id !== 'undefined') { if (Object.prototype.hasOwnProperty.call(this.assets, id) && assetType.immutable) return id; } else if (assetType.immutable) { id = md5(data); } else { throw new Error('Tried to cache data without an id'); } this.assets[id] = { type: assetType, format: dataFormat, id: id, data: data }; return id; } /** * Fetch an asset but don't process dependencies. * @param {AssetType} assetType - The type of asset to fetch. * @param {string} assetId - The ID of the asset to fetch: a project ID, MD5, etc. * @return {?Promise.<Asset>} A promise for the contents of the asset. */ load (assetType, assetId) { if (!this.get(assetId)) { // Return null immediately so Storage can quickly move to trying the // next helper. return null; } return Promise.resolve(this.get(assetId)); } } module.exports = BuiltinHelper;