diff --git a/packages/backend/src/AutomergeCollaboration.ts b/packages/backend/src/AutomergeCollaboration.ts index 5452ab6..c529f6c 100644 --- a/packages/backend/src/AutomergeCollaboration.ts +++ b/packages/backend/src/AutomergeCollaboration.ts @@ -7,6 +7,7 @@ import flatten from 'lodash/flatten' import { SyncDoc, CollabAction, toJS } from '@hiveteams/collab-bridge' import { debugCollabBackend } from './utils/debug' import AutomergeBackend from './AutomergeBackend' +import getActiveConnections from './utils/getActiveConnections' export interface IAutomergeMetaData { docId: string @@ -253,6 +254,10 @@ export default class AutomergeCollaboration { opCount: collabActions.length } + if (collabActions.length > 10) { + console.log(JSON.stringify(data.payload.changes, null, 2)) + } + this.onTrace(metaData, () => { switch (data.type) { case 'operation': @@ -344,11 +349,7 @@ export default class AutomergeCollaboration { garbageNsp = (socket: SocketIO.Socket) => { const { name: docId } = socket.nsp - // This is the only way to synchronously check the number of active Automerge.Connections - // for this docId. - // @ts-ignore - const activeConnectionsCount = this.backend.documentSetMap[docId]?.handlers - .size + const activeConnectionsCount = getActiveConnections(this.backend, docId) debugCollabBackend( 'Garbage namespace activeConnections=%s', diff --git a/packages/backend/src/utils/getActiveConnections.ts b/packages/backend/src/utils/getActiveConnections.ts new file mode 100644 index 0000000..e6b5f42 --- /dev/null +++ b/packages/backend/src/utils/getActiveConnections.ts @@ -0,0 +1,12 @@ +import AutomergeBackend from '../AutomergeBackend' + +const getActiveConnections = (backend: AutomergeBackend, docId: string) => { + // This is the only way to synchronously check the number of active Automerge.Connections + // for this docId. + // @ts-ignore + const activeConnectionsCount = backend.documentSetMap[docId]?.handlers.size + + return activeConnectionsCount +} + +export default getActiveConnections diff --git a/packages/client/src/client.spec.ts b/packages/client/src/client.spec.ts index d09dce9..b0eb16b 100644 --- a/packages/client/src/client.spec.ts +++ b/packages/client/src/client.spec.ts @@ -8,6 +8,7 @@ import AutomergeCollaboration from '@hiveteams/collab-backend/lib/AutomergeColla import withIOCollaboration from './withIOCollaboration' import { AutomergeOptions, SocketIOPluginOptions } from './interfaces' import { getTarget } from '@hiveteams/collab-bridge/src/path' +import getActiveConnections from '@hiveteams/collab-backend/src/utils/getActiveConnections' const connectionSlug = 'test' const docId = `/${connectionSlug}` @@ -50,6 +51,12 @@ const collabBackend = new AutomergeCollaboration({ }, async onDocumentLoad(pathname) { return defaultSlateJson + }, + onTrace(metaData, computationFn) { + if (metaData.opCount && metaData.opCount > 100) { + } + console.log('metaData', metaData) + computationFn() } }) @@ -60,6 +67,10 @@ describe('automerge editor client tests', () => { server.listen(5000, () => done()) }) + afterEach(done => { + waitForCondition(() => !collabBackend.backend.getDocument(docId)).then(done) + }) + const createCollabEditor = async ( editorOptions?: Partial & Partial ) => { @@ -232,6 +243,8 @@ describe('automerge editor client tests', () => { expect(editor.children.length).toEqual(2) expect(Node.string(editor.children[0])).toEqual('new') expect(Node.string(editor.children[1])).toEqual('nodes') + + editor.destroy() }) it('set node for children with missing value should not throw error', () => { @@ -265,6 +278,37 @@ describe('automerge editor client tests', () => { expect(target).toEqual(null) }) + it('should work with concurrent insert text operations', async () => { + const editor1 = await createCollabEditor() + const editor2 = await createCollabEditor() + + editor1.disconnect() + + await waitForCondition(() => { + return getActiveConnections(collabBackend.backend, docId) === 1 + }) + + editor2.insertNode({ type: 'paragraph', children: [{ text: 'hi' }] }) + + await waitForCondition(() => { + return collabBackend.backend.getDocument(docId)?.children.length === 2 + }) + + editor1.connect() + + await waitForCondition(() => { + return editor1.children.length === 2 + }) + + editor2.destroy() + + await waitForCondition(() => { + return getActiveConnections(collabBackend.backend, docId) === 1 + }) + + editor1.destroy() + }) + afterAll(() => { collabBackend.destroy() server.close()