create-mongodb-persistence.ts 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. import type { Persistence } from 'y-socket.io/dist/server';
  2. import * as Y from 'yjs';
  3. import loggerFactory from '~/utils/logger';
  4. import type { MongodbPersistence } from './extended/mongodb-persistence';
  5. const logger = loggerFactory('growi:service:yjs:create-mongodb-persistence');
  6. /**
  7. * Based on the example by https://github.com/MaxNoetzold/y-mongodb-provider?tab=readme-ov-file#an-other-example
  8. * @param mdb
  9. * @returns
  10. */
  11. export const createMongoDBPersistence = (
  12. mdb: MongodbPersistence,
  13. ): Persistence => {
  14. const persistece: Persistence = {
  15. provider: mdb,
  16. bindState: async (docName, ydoc) => {
  17. logger.debug('bindState', { docName });
  18. const persistedYdoc = await mdb.getYDoc(docName);
  19. // get the state vector so we can just store the diffs between client and server
  20. const persistedStateVector = Y.encodeStateVector(persistedYdoc);
  21. const diff = Y.encodeStateAsUpdate(ydoc, persistedStateVector);
  22. // store the new data in db (if there is any: empty update is an array of 0s)
  23. if (
  24. diff.reduce(
  25. (previousValue, currentValue) => previousValue + currentValue,
  26. 0,
  27. ) > 0
  28. ) {
  29. mdb.storeUpdate(docName, diff);
  30. mdb.setTypedMeta(docName, 'updatedAt', Date.now());
  31. }
  32. // send the persisted data to clients
  33. Y.applyUpdate(ydoc, Y.encodeStateAsUpdate(persistedYdoc));
  34. // store updates of the document in db
  35. ydoc.on('update', async (update) => {
  36. mdb.storeUpdate(docName, update);
  37. mdb.setTypedMeta(docName, 'updatedAt', Date.now());
  38. });
  39. // cleanup some memory
  40. persistedYdoc.destroy();
  41. },
  42. writeState: async (docName) => {
  43. logger.debug('writeState', { docName });
  44. // This is called when all connections to the document are closed.
  45. // flush document on close to have the smallest possible database
  46. await mdb.flushDocument(docName);
  47. },
  48. };
  49. return persistece;
  50. };