UNPKG

recoder-code

Version:

Complete AI-powered development platform with ML model training, plugin registry, real-time collaboration, monitoring, infrastructure automation, and enterprise deployment capabilities

143 lines (121 loc) 5.15 kB
var LocalPresence = require('./local-presence'); var ShareDBError = require('../../error'); var util = require('../../util'); var ERROR_CODE = ShareDBError.CODES; module.exports = LocalDocPresence; function LocalDocPresence(presence, presenceId) { LocalPresence.call(this, presence, presenceId); this.collection = this.presence.collection; this.id = this.presence.id; this._doc = this.connection.get(this.collection, this.id); this._emitter = this.connection._docPresenceEmitter; this._isSending = false; this._docDataVersionByPresenceVersion = Object.create(null); this._opHandler = this._transformAgainstOp.bind(this); this._createOrDelHandler = this._handleCreateOrDel.bind(this); this._loadHandler = this._handleLoad.bind(this); this._destroyHandler = this.destroy.bind(this); this._registerWithDoc(); } LocalDocPresence.prototype = Object.create(LocalPresence.prototype); LocalDocPresence.prototype.submit = function(value, callback) { if (!this._doc.type) { // If the Doc hasn't been created, we already assume all presence to // be null. Let's early return, instead of error since this is a harmless // no-op if (value === null) return this._callbackOrEmit(null, callback); var error = { code: ERROR_CODE.ERR_DOC_DOES_NOT_EXIST, message: 'Cannot submit presence. Document has not been created' }; return this._callbackOrEmit(error, callback); }; // Record the current data state version to check if we need to transform // the presence later this._docDataVersionByPresenceVersion[this.presenceVersion] = this._doc._dataStateVersion; LocalPresence.prototype.submit.call(this, value, callback); }; LocalDocPresence.prototype.destroy = function(callback) { this._emitter.removeEventListener(this._doc, 'op', this._opHandler); this._emitter.removeEventListener(this._doc, 'create', this._createOrDelHandler); this._emitter.removeEventListener(this._doc, 'del', this._createOrDelHandler); this._emitter.removeEventListener(this._doc, 'load', this._loadHandler); this._emitter.removeEventListener(this._doc, 'destroy', this._destroyHandler); LocalPresence.prototype.destroy.call(this, callback); }; LocalDocPresence.prototype._sendPending = function() { if (this._isSending) return; this._isSending = true; var presence = this; this._doc.whenNothingPending(function() { presence._isSending = false; if (!presence.connection.canSend) return; presence._pendingMessages.forEach(function(message) { message.t = presence._doc.type.uri; message.v = presence._doc.version; presence.connection.send(message); }); presence._pendingMessages = []; presence._docDataVersionByPresenceVersion = Object.create(null); }); }; LocalDocPresence.prototype._registerWithDoc = function() { this._emitter.addEventListener(this._doc, 'op', this._opHandler); this._emitter.addEventListener(this._doc, 'create', this._createOrDelHandler); this._emitter.addEventListener(this._doc, 'del', this._createOrDelHandler); this._emitter.addEventListener(this._doc, 'load', this._loadHandler); this._emitter.addEventListener(this._doc, 'destroy', this._destroyHandler); }; LocalDocPresence.prototype._transformAgainstOp = function(op, source) { var presence = this; var docDataVersion = this._doc._dataStateVersion; this._pendingMessages.forEach(function(message) { // Check if the presence needs transforming against the op - this is to check against // edge cases where presence is submitted from an 'op' event var messageDocDataVersion = presence._docDataVersionByPresenceVersion[message.pv]; if (messageDocDataVersion >= docDataVersion) return; try { message.p = presence._transformPresence(message.p, op, source); // Ensure the presence's data version is kept consistent to deal with "deep" op // submissions presence._docDataVersionByPresenceVersion[message.pv] = docDataVersion; } catch (error) { var callback = presence._getCallback(message.pv); presence._callbackOrEmit(error, callback); } }); try { this.value = this._transformPresence(this.value, op, source); } catch (error) { this.emit('error', error); } }; LocalDocPresence.prototype._handleCreateOrDel = function() { this._pendingMessages.forEach(function(message) { message.p = null; }); this.value = null; }; LocalDocPresence.prototype._handleLoad = function() { this.value = null; this._pendingMessages = []; this._docDataVersionByPresenceVersion = Object.create(null); }; LocalDocPresence.prototype._message = function() { var message = LocalPresence.prototype._message.call(this); message.c = this.collection, message.d = this.id, message.v = null; message.t = null; return message; }; LocalDocPresence.prototype._transformPresence = function(value, op, source) { var type = this._doc.type; if (!util.supportsPresence(type)) { throw new ShareDBError( ERROR_CODE.ERR_TYPE_DOES_NOT_SUPPORT_PRESENCE, 'Type does not support presence: ' + type.name ); } return type.transformPresence(value, op, source); };