Add persistence-synced Y.Doc accessor functions

This commit is contained in:
Duane Johnson 2020-10-08 15:00:26 -06:00
parent 1a1b833b01
commit 576db4267e

View File

@ -33,18 +33,33 @@ if (typeof persistenceDir === 'string') {
const LeveldbPersistence = require('y-leveldb').LeveldbPersistence const LeveldbPersistence = require('y-leveldb').LeveldbPersistence
const ldb = new LeveldbPersistence(persistenceDir) const ldb = new LeveldbPersistence(persistenceDir)
persistence = { persistence = {
bindState: async (docName, ydoc) => { // Sync in-memory and ldb state
mutualSync: async (docName, ydoc) => {
const persistedYdoc = await ldb.getYDoc(docName) const persistedYdoc = await ldb.getYDoc(docName)
const newUpdates = Y.encodeStateAsUpdate(ydoc) const newUpdates = Y.encodeStateAsUpdate(ydoc)
ldb.storeUpdate(docName, newUpdates) ldb.storeUpdate(docName, newUpdates)
Y.applyUpdate(ydoc, Y.encodeStateAsUpdate(persistedYdoc)) Y.applyUpdate(ydoc, Y.encodeStateAsUpdate(persistedYdoc))
ydoc.on('update', update => { },
bindState: async (docName, ydoc) => {
await persistence.mutualSync(docName, ydoc)
ydoc.on('update', (update) => {
ldb.storeUpdate(docName, update) ldb.storeUpdate(docName, update)
}) })
}, },
writeState: async (docName, ydoc) => {}
writeState: async (docName, ydoc) => {},
// Gets a Y.Doc by name, whether in memory or on disk
getYDoc: async (docName) => {
const ydoc = findOrCreateDoc(docName)
await persistence.mutualSync(docName, ydoc)
return ydoc
},
} }
} }
// If enabled, provide access to persistence functions
exports.persistence = persistence
/** /**
* @param {{bindState: function(string,WSSharedDoc):void, * @param {{bindState: function(string,WSSharedDoc):void,
@ -130,6 +145,24 @@ class WSSharedDoc extends Y.Doc {
} }
} }
/**
* @param {string} docName - the name of the Y.Doc to find or create
* @param {boolean} gc - whether to allow gc on the doc (applies only when created)
*/
function findOrCreateDoc(docName, gc = true) {
// get doc, create if it does not exist yet
return map.setIfUndefined(docs, docName, () => {
const doc = new WSSharedDoc(docName)
doc.gc = gc
if (persistence !== null) {
persistence.bindState(docName, doc)
}
docs.set(docName, doc)
return doc
})
}
exports.findOrCreateDoc = findOrCreateDoc
/** /**
* @param {any} conn * @param {any} conn
* @param {WSSharedDoc} doc * @param {WSSharedDoc} doc
@ -196,6 +229,7 @@ const send = (doc, conn, m) => {
const pingTimeout = 30000 const pingTimeout = 30000
/** /**
* @param {any} conn * @param {any} conn
* @param {any} req * @param {any} req
@ -204,15 +238,7 @@ const pingTimeout = 30000
exports.setupWSConnection = (conn, req, { docName = req.url.slice(1).split('?')[0], gc = true } = {}) => { exports.setupWSConnection = (conn, req, { docName = req.url.slice(1).split('?')[0], gc = true } = {}) => {
conn.binaryType = 'arraybuffer' conn.binaryType = 'arraybuffer'
// get doc, create if it does not exist yet // get doc, create if it does not exist yet
const doc = map.setIfUndefined(docs, docName, () => { const doc = findOrCreateDoc(docName, gc)
const doc = new WSSharedDoc(docName)
doc.gc = gc
if (persistence !== null) {
persistence.bindState(docName, doc)
}
docs.set(docName, doc)
return doc
})
doc.conns.set(conn, new Set()) doc.conns.set(conn, new Set())
// listen and reply to events // listen and reply to events
conn.on('message', /** @param {ArrayBuffer} message */ message => messageListener(conn, doc, new Uint8Array(message))) conn.on('message', /** @param {ArrayBuffer} message */ message => messageListener(conn, doc, new Uint8Array(message)))