UNPKG

webgme-engine

Version:

WebGME server and Client API without a GUI

303 lines (244 loc) 9.8 kB
/*globals define*/ /*eslint-env node, browser*/ /** * @author pmeijer / https://github.com/pmeijer */ define(['common/storage/constants'], function (CONSTANTS) { 'use strict'; function Branch(name, mainLogger) { var self = this, logger = mainLogger.fork('Branch:' + name), originHash = '', localHash = '', commitQueue = [], updateQueue = [], branchStatus = CONSTANTS.BRANCH_STATUS.SYNC; logger.debug('ctor'); this.name = name; this.isOpen = true; this.inSync = true; this.branchStatusHandlers = []; this.hashUpdateHandlers = []; this.callbackQueue = []; this.pendingWorkerRequests = {}; /** * @type {Error[]} */ this.errorList = []; this._remoteUpdateHandler = null; this.cleanUp = function () { var commitHash, i, commitResult; self.isOpen = false; self.branchStatusHandlers = []; self.hashUpdateHandlers = []; self._remoteUpdateHandler = null; for (i = 0; i < self.callbackQueue.length; i += 1) { // Make sure there are no pending callbacks, invoke with status CANCELED. commitResult = { status: CONSTANTS.CANCELED, hash: commitQueue[i].commitObject[CONSTANTS.MONGO_ID] }; self.callbackQueue[i](null, commitResult); } self.callbackQueue = []; for (commitHash in self.pendingWorkerRequests) { (this.pendingWorkerRequests[commitHash] || []) .forEach(function (action) { action.abort(); }); } self.pendingWorkerRequests = {}; commitQueue = []; updateQueue = []; }; // Hash related functions this.getLocalHash = function () { return localHash; }; this.getOriginHash = function () { return originHash; }; this.getQueuedHashes = function () { return commitQueue .map(function (commitData) { return commitData.commitObject[CONSTANTS.MONGO_ID]; }); }; this.updateHashes = function (newLocal, newOrigin) { logger.debug('updatingHashes'); if (newLocal !== null) { logger.debug('localHash: old, new', localHash, newLocal); localHash = newLocal; } if (newOrigin !== null) { logger.debug('originHash: old, new', originHash, newOrigin); originHash = newOrigin; } }; // Queue related functions this.queueCommit = function (commitData, commitCallback) { commitQueue.push(commitData); self.callbackQueue.push(commitCallback); logger.debug('Adding new commit to queue', commitQueue.length); }; this.getFirstCommit = function (shift) { var commitData; if (shift) { commitData = commitQueue.shift(); self.callbackQueue.shift(); logger.debug('Removed commit from queue', commitQueue.length); } else { commitData = commitQueue[0]; } return commitData; }; this.getMergedCommit = function (mergeHash) { var mergeCommit, i = updateQueue.length; while (i) { i -= 1; if (updateQueue[i].commitObject[CONSTANTS.MONGO_ID] === mergeHash) { mergeCommit = updateQueue[i]; break; } } if (!mergeCommit) { logger.error('mergeCommit not available in updateQueue', mergeHash, JSON.stringify(updateQueue, null, 2)); } updateQueue = []; return mergeCommit; }; this.getCommitQueue = function () { return commitQueue; }; this.getCommitsForNewFork = function (upTillCommitHash) { var i, commitData, commitHash, commitHashExisted = false, subQueue = []; logger.debug('getCommitsForNewFork', upTillCommitHash); if (commitQueue.length === 0) { commitHash = localHash; logger.debug('No commits queued will fork from', commitHash); upTillCommitHash = upTillCommitHash || commitHash; commitHashExisted = upTillCommitHash === commitHash; } else { upTillCommitHash = upTillCommitHash || commitQueue[commitQueue.length - 1].commitObject[CONSTANTS.MONGO_ID]; } logger.debug('Will fork up to commitHash', upTillCommitHash); // Move over all commit-data up till the chosen commitHash to the fork's queue, // except the commit that caused the fork (all its objects are already in the database). for (i = 0; i < commitQueue.length; i += 1) { commitData = commitQueue[i]; commitHash = commitData.commitObject[CONSTANTS.MONGO_ID]; if (i !== 0) { subQueue.push(commitData); } if (commitData.commitObject[CONSTANTS.MONGO_ID] === upTillCommitHash) { // The commitHash from where to fork has been reached. // If any, the rest of the 'pending' commits will not be used. commitHashExisted = true; break; } } if (commitHashExisted === false) { logger.error('Could not find the specified commitHash', upTillCommitHash); return false; } return {commitHash: commitHash, queue: subQueue}; }; this.queueUpdate = function (updateData) { updateQueue.push(updateData); logger.debug('Adding new update to queue', updateQueue.length); }; this.getUpdateQueue = function () { return updateQueue; }; this.getFirstUpdate = function (shift) { var updateData; if (shift) { updateData = updateQueue.shift(); logger.debug('Removed update from queue', updateQueue.length); } else { updateData = updateQueue[0]; } return updateData; }; // Event related functions this.addBranchStatusHandler = function (fn) { self.branchStatusHandlers.push(fn); }; this.removeBranchStatusHandler = function (fn) { var i; for (i = 0; i < self.branchStatusHandlers.length; i += 1) { if (self.branchStatusHandlers[i] === fn) { self.branchStatusHandlers.splice(i, 1); return true; } } return false; }; this.dispatchBranchStatus = function (newStatus, err) { var i; logger.debug('dispatchBranchStatus old, new', branchStatus, newStatus); if (branchStatus === CONSTANTS.BRANCH_STATUS.ERROR) { logger.error('In error state, action from user required!'); newStatus = branchStatus; } else { branchStatus = newStatus; } if (err) { this.errorList.push(err instanceof Error ? err : new Error(err)); } for (i = 0; i < self.branchStatusHandlers.length; i += 1) { self.branchStatusHandlers[i](newStatus, commitQueue, updateQueue); } }; this.addHashUpdateHandler = function (fn) { self.hashUpdateHandlers.push(fn); }; this.removeHashUpdateHandler = function (fn) { var i; for (i = 0; i < self.hashUpdateHandlers.length; i += 1) { if (self.hashUpdateHandlers[i] === fn) { self.hashUpdateHandlers.splice(i, 1); return true; } } return false; }; this.dispatchHashUpdate = function (data, callback) { var i, error = null, counter = self.hashUpdateHandlers.length, allProceed = true, counterCallback = function (err, proceed) { error = error || err; // Use the latest error allProceed = allProceed && proceed === true; counter -= 1; if (counter === 0) { callback(error, allProceed); } }; for (i = 0; i < self.hashUpdateHandlers.length; i += 1) { self.hashUpdateHandlers[i](data, commitQueue, updateQueue, counterCallback); } }; this.queueWorkerRequest = function (commitHash, action) { this.pendingWorkerRequests[commitHash] = this.pendingWorkerRequests[commitHash] || []; this.pendingWorkerRequests[commitHash].push(action); }; this.commitInserted = function (commitHash) { (this.pendingWorkerRequests[commitHash] || []).forEach(function (action) { action.release(); }); delete this.pendingWorkerRequests[commitHash]; }; } return Branch; });