UNPKG

@fontoxml/fontoxml-development-tools

Version:

Development tools for Fonto.

243 lines (211 loc) 6.21 kB
import FileSystemStore from './FileSystemStore.js'; import HistoryStore from './HistoryStore.js'; import MemoryStore from './MemoryStore.js'; import mergeItems from './mergeItems.js'; /** @typedef {import('../../../src/getAppConfig.js').DevCmsConfig} DevCmsConfig */ export default class DevelopmentCms { /** * @param {DevCmsConfig} config */ constructor(config) { this._memoryStoreById = Object.create(null); this._memoryStoreCleanupById = Object.create(null); this._fileSystem = new FileSystemStore(config); this._history = new HistoryStore(this); /** @type {DevCmsConfig['memoryStoreTtl']} */ this._memoryStoreTtl = config.memoryStoreTtl; /** @type {DevCmsConfig['saveMode']} */ this._saveMode = config.saveMode; } _getOrCreateMemoryStore(editSessionToken) { const memoryStoreId = this._saveMode === 'shared-memory' ? 'shared-memory-store-id' : editSessionToken; let memoryStore = this._memoryStoreById[memoryStoreId]; if (!memoryStore) { memoryStore = this._memoryStoreById[memoryStoreId] = new MemoryStore(); } if (this._memoryStoreTtl < 0) { return memoryStore; } if (this._memoryStoreCleanupById[memoryStoreId]) { clearTimeout(this._memoryStoreCleanupById[memoryStoreId]); } this._memoryStoreCleanupById[memoryStoreId] = setTimeout(() => { delete this._memoryStoreCleanupById[memoryStoreId]; delete this._memoryStoreById[memoryStoreId]; }, this._memoryStoreTtl); return memoryStore; } /** * @param {string} documentId path of document relative to dev-cms/files * @param {string} editSessionToken * @param {function(Error, string)} callback called with content of document */ load(documentId, editSessionToken, callback) { // Load from memory or the file system this._getOrCreateMemoryStore(editSessionToken).load( documentId, (error, content) => { if (error) { this._fileSystem.load(documentId, callback); return; } callback(null, content); } ); } /** * @param {string} documentId path of document relative to dev-cms/files * @param {string} editSessionToken * @param {function(Error, string)} callback called with the revisionId */ getLatestRevisionId(documentId, editSessionToken, callback) { this._history.getLatestRevisionId( documentId, editSessionToken, callback ); } /** * @param {string} documentId * @param {string} editSessionToken * * @return {string} absolute path */ getPath(documentId, _editSessionToken) { return this._fileSystem.getPath(documentId); } /** * @param {string} documentId * @param {string} editSessionToken * * @return {boolean} */ existsSync(documentId, editSessionToken) { return ( this._getOrCreateMemoryStore(editSessionToken).existsSync( documentId ) || this._fileSystem.existsSync(documentId) ); } saveToStore(documentId, content, editSessionToken, callback) { function handleSaveToStore(error) { callback(error, documentId); } switch (this._saveMode) { case 'session-memory': case 'shared-memory': this._getOrCreateMemoryStore(editSessionToken).save( documentId, content, handleSaveToStore ); return; default: this._fileSystem.save(documentId, content, handleSaveToStore); } } /** * @param {string} documentId * @param {string} content * @param {FontoSession} currentSession * @param {function(Error)} callback */ save(documentId, content, currentSession, callback) { // If saveMode is off, saving to non-existing documents should not error. Is might be that this document is newly created. if (!this.existsSync(documentId, currentSession.editSessionToken)) { const error = new Error('File does not exist.'); error.status = 404; callback(error); return; } // First save history, then the actual document this._history.save(documentId, content, currentSession, (error) => { if (error) { callback(error); return; } this.saveToStore( documentId, content, currentSession.editSessionToken, callback ); }); } /** * @param {string} documentId * @param {string} content * @param {FontoSession} currentSession * @param {function(Error)} callback */ createNew(documentId, content, currentSession, callback) { if (this.existsSync(documentId, currentSession.editSessionToken)) { const error = new Error('File already exists.'); error.status = 409; callback(error); return; } // First create new history, then the actual document this._history.createNew( documentId, content, currentSession, (error, _revisions) => { if (error) { callback(error); return; } this.saveToStore( documentId, content, currentSession.editSessionToken, callback ); } ); } removeSync(documentId, editSessionToken) { this._getOrCreateMemoryStore(editSessionToken).removeSync(documentId); this._fileSystem.removeSync(documentId); } /** * @param {string} folderId * @param {string} editSessionToken * * @return {Object[]|null} items in folder, combined from all stores, or null if the folder does not exist. */ listSync(folderId, editSessionToken) { folderId = folderId || ''; const fileSystemItems = this._fileSystem.listSync(folderId); const memoryItems = this._getOrCreateMemoryStore(editSessionToken).listSync(folderId); if (!fileSystemItems && !memoryItems) { return null; } return mergeItems(fileSystemItems, memoryItems); } /** * @param {string} documentId * @param {function(Error, Object[])} callback */ loadHistory(documentId, editSessionToken, callback) { this._history.loadHistory(documentId, editSessionToken, callback); } /** * @param {string} documentId * @param {string} revisionId * @param {function(Error, string)} callback */ loadRevision(documentId, revisionId, editSessionToken, callback) { this._history.loadRevision( documentId, revisionId, editSessionToken, callback ); } }