2023-03-22 15:21:40 -04:00
|
|
|
/*
|
|
|
|
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
*/
|
2023-06-28 13:25:16 -04:00
|
|
|
import { MessageTransporter } from '../message-transporters/index.js'
|
2023-03-22 15:21:40 -04:00
|
|
|
import { Message, MessageType } from '../message-transporters/message.js'
|
2023-06-28 13:25:16 -04:00
|
|
|
import { InMemoryConnectionTransportAdapter } from './in-memory-connection-transport-adapter.js'
|
2023-03-22 15:21:40 -04:00
|
|
|
import { RealtimeDoc } from './realtime-doc.js'
|
|
|
|
import { YDocSyncClientAdapter } from './y-doc-sync-client-adapter.js'
|
|
|
|
import { YDocSyncServerAdapter } from './y-doc-sync-server-adapter.js'
|
2023-06-28 13:25:16 -04:00
|
|
|
import { describe, expect, it, beforeAll, jest, afterAll } from '@jest/globals'
|
|
|
|
|
|
|
|
describe('y-doc-sync-adapter', () => {
|
|
|
|
beforeAll(() => {
|
|
|
|
jest.useFakeTimers()
|
|
|
|
})
|
|
|
|
afterAll(() => {
|
|
|
|
jest.useRealTimers()
|
|
|
|
})
|
2023-03-22 15:21:40 -04:00
|
|
|
|
|
|
|
it('server client communication', async () => {
|
|
|
|
const docServer: RealtimeDoc = new RealtimeDoc('This is a test note')
|
|
|
|
const docClient1: RealtimeDoc = new RealtimeDoc()
|
|
|
|
const docClient2: RealtimeDoc = new RealtimeDoc()
|
|
|
|
|
|
|
|
const textServer = docServer.getMarkdownContentChannel()
|
|
|
|
const textClient1 = docClient1.getMarkdownContentChannel()
|
|
|
|
const textClient2 = docClient2.getMarkdownContentChannel()
|
|
|
|
|
|
|
|
textServer.observe(() =>
|
2023-07-19 06:24:51 -04:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
2023-06-28 13:25:16 -04:00
|
|
|
console.log('textServer', new Date(), textServer.toString())
|
2023-03-22 15:21:40 -04:00
|
|
|
)
|
|
|
|
textClient1.observe(() =>
|
2023-07-19 06:24:51 -04:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
2023-06-28 13:25:16 -04:00
|
|
|
console.log('textClient1', new Date(), textClient1.toString())
|
2023-03-22 15:21:40 -04:00
|
|
|
)
|
|
|
|
textClient2.observe(() =>
|
2023-07-19 06:24:51 -04:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
2023-06-28 13:25:16 -04:00
|
|
|
console.log('textClient2', new Date(), textClient2.toString())
|
|
|
|
)
|
|
|
|
|
|
|
|
const transporterAdapterServerTo1 = new InMemoryConnectionTransportAdapter(
|
|
|
|
's>1'
|
|
|
|
)
|
|
|
|
const transporterAdapterServerTo2 = new InMemoryConnectionTransportAdapter(
|
|
|
|
's>2'
|
|
|
|
)
|
|
|
|
const transporterAdapterClient1 = new InMemoryConnectionTransportAdapter(
|
|
|
|
'1>s'
|
|
|
|
)
|
|
|
|
const transporterAdapterClient2 = new InMemoryConnectionTransportAdapter(
|
|
|
|
'2>s'
|
2023-03-22 15:21:40 -04:00
|
|
|
)
|
|
|
|
|
2023-06-28 13:25:16 -04:00
|
|
|
const messageTransporterServerTo1 = new MessageTransporter()
|
|
|
|
const messageTransporterServerTo2 = new MessageTransporter()
|
|
|
|
const messageTransporterClient1 = new MessageTransporter()
|
|
|
|
const messageTransporterClient2 = new MessageTransporter()
|
2023-03-22 15:21:40 -04:00
|
|
|
|
2023-06-28 13:25:16 -04:00
|
|
|
messageTransporterServerTo1.on(MessageType.NOTE_CONTENT_UPDATE, () =>
|
|
|
|
console.log('Received NOTE_CONTENT_UPDATE from client 1 to server')
|
2023-03-22 15:21:40 -04:00
|
|
|
)
|
2023-06-28 13:25:16 -04:00
|
|
|
messageTransporterServerTo2.on(MessageType.NOTE_CONTENT_UPDATE, () =>
|
|
|
|
console.log('Received NOTE_CONTENT_UPDATE from client 2 to server')
|
2023-03-22 15:21:40 -04:00
|
|
|
)
|
2023-06-28 13:25:16 -04:00
|
|
|
messageTransporterClient1.on(MessageType.NOTE_CONTENT_UPDATE, () =>
|
|
|
|
console.log('Received NOTE_CONTENT_UPDATE from server to client 1')
|
2023-03-22 15:21:40 -04:00
|
|
|
)
|
2023-06-28 13:25:16 -04:00
|
|
|
messageTransporterClient2.on(MessageType.NOTE_CONTENT_UPDATE, () =>
|
|
|
|
console.log('Received NOTE_CONTENT_UPDATE from server to client 2')
|
2023-03-22 15:21:40 -04:00
|
|
|
)
|
2023-06-28 13:25:16 -04:00
|
|
|
messageTransporterServerTo1.on(MessageType.NOTE_CONTENT_STATE_REQUEST, () =>
|
|
|
|
console.log('Received NOTE_CONTENT_REQUEST from client 1 to server')
|
2023-03-22 15:21:40 -04:00
|
|
|
)
|
2023-06-28 13:25:16 -04:00
|
|
|
messageTransporterServerTo2.on(MessageType.NOTE_CONTENT_STATE_REQUEST, () =>
|
|
|
|
console.log('Received NOTE_CONTENT_REQUEST from client 2 to server')
|
2023-03-22 15:21:40 -04:00
|
|
|
)
|
2023-06-28 13:25:16 -04:00
|
|
|
messageTransporterClient1.on(MessageType.NOTE_CONTENT_STATE_REQUEST, () =>
|
|
|
|
console.log('Received NOTE_CONTENT_REQUEST from server to client 1')
|
2023-03-22 15:21:40 -04:00
|
|
|
)
|
2023-06-28 13:25:16 -04:00
|
|
|
messageTransporterClient2.on(MessageType.NOTE_CONTENT_STATE_REQUEST, () =>
|
|
|
|
console.log('Received NOTE_CONTENT_REQUEST from server to client 2')
|
2023-03-22 15:21:40 -04:00
|
|
|
)
|
2023-06-28 13:25:16 -04:00
|
|
|
messageTransporterClient1.doAsSoonAsConnected(() =>
|
|
|
|
console.log('1>s is connected')
|
2023-03-22 15:21:40 -04:00
|
|
|
)
|
2023-06-28 13:25:16 -04:00
|
|
|
messageTransporterClient2.doAsSoonAsConnected(() =>
|
|
|
|
console.log('2>s is connected')
|
|
|
|
)
|
|
|
|
messageTransporterServerTo1.doAsSoonAsConnected(() =>
|
|
|
|
console.log('s>1 is connected')
|
|
|
|
)
|
|
|
|
messageTransporterServerTo2.doAsSoonAsConnected(() =>
|
|
|
|
console.log('s>2 is connected')
|
|
|
|
)
|
|
|
|
messageTransporterClient1.doAsSoonAsReady(() => console.log('1>s is ready'))
|
|
|
|
messageTransporterClient2.doAsSoonAsReady(() => console.log('2>s is ready'))
|
|
|
|
messageTransporterServerTo1.doAsSoonAsReady(() =>
|
|
|
|
console.log('s>1 is connected')
|
|
|
|
)
|
|
|
|
messageTransporterServerTo2.doAsSoonAsReady(() =>
|
|
|
|
console.log('s>2 is connected')
|
2023-03-22 15:21:40 -04:00
|
|
|
)
|
|
|
|
|
2023-03-24 05:26:49 -04:00
|
|
|
docServer.on('update', (update: number[], origin: unknown) => {
|
2023-03-22 15:21:40 -04:00
|
|
|
const message: Message<MessageType.NOTE_CONTENT_UPDATE> = {
|
|
|
|
type: MessageType.NOTE_CONTENT_UPDATE,
|
2023-03-24 05:26:49 -04:00
|
|
|
payload: update
|
2023-03-22 15:21:40 -04:00
|
|
|
}
|
2023-06-28 13:25:16 -04:00
|
|
|
if (origin !== messageTransporterServerTo1) {
|
|
|
|
console.log('YDoc on Server updated. Sending to Client 1')
|
|
|
|
messageTransporterServerTo1.sendMessage(message)
|
2023-03-22 15:21:40 -04:00
|
|
|
}
|
2023-06-28 13:25:16 -04:00
|
|
|
if (origin !== messageTransporterServerTo2) {
|
|
|
|
console.log('YDoc on Server updated. Sending to Client 2')
|
|
|
|
messageTransporterServerTo2.sendMessage(message)
|
2023-03-22 15:21:40 -04:00
|
|
|
}
|
|
|
|
})
|
2023-03-24 05:26:49 -04:00
|
|
|
docClient1.on('update', (update: number[], origin: unknown) => {
|
2023-06-28 13:25:16 -04:00
|
|
|
if (origin !== messageTransporterClient1) {
|
|
|
|
console.log('YDoc on client 1 updated. Sending to Server')
|
2023-03-22 15:21:40 -04:00
|
|
|
}
|
|
|
|
})
|
2023-03-24 05:26:49 -04:00
|
|
|
docClient2.on('update', (update: number[], origin: unknown) => {
|
2023-06-28 13:25:16 -04:00
|
|
|
if (origin !== messageTransporterClient2) {
|
|
|
|
console.log('YDoc on client 2 updated. Sending to Server')
|
2023-03-22 15:21:40 -04:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2023-03-24 05:26:49 -04:00
|
|
|
const yDocSyncAdapter1 = new YDocSyncClientAdapter(
|
2023-06-28 13:25:16 -04:00
|
|
|
messageTransporterClient1,
|
2023-03-24 05:26:49 -04:00
|
|
|
docClient1
|
|
|
|
)
|
|
|
|
const yDocSyncAdapter2 = new YDocSyncClientAdapter(
|
2023-06-28 13:25:16 -04:00
|
|
|
messageTransporterClient2,
|
2023-03-24 05:26:49 -04:00
|
|
|
docClient2
|
|
|
|
)
|
2023-03-22 15:21:40 -04:00
|
|
|
|
|
|
|
const yDocSyncAdapterServerTo1 = new YDocSyncServerAdapter(
|
2023-06-28 13:25:16 -04:00
|
|
|
messageTransporterServerTo1,
|
2023-03-26 08:51:18 -04:00
|
|
|
docServer,
|
2023-05-08 12:06:54 -04:00
|
|
|
() => true
|
2023-03-22 15:21:40 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
const yDocSyncAdapterServerTo2 = new YDocSyncServerAdapter(
|
2023-06-28 13:25:16 -04:00
|
|
|
messageTransporterServerTo2,
|
2023-03-26 08:51:18 -04:00
|
|
|
docServer,
|
2023-05-08 12:06:54 -04:00
|
|
|
() => true
|
2023-03-22 15:21:40 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
const waitForClient1Sync = new Promise<void>((resolve) => {
|
|
|
|
yDocSyncAdapter1.doAsSoonAsSynced(() => {
|
2023-06-28 13:25:16 -04:00
|
|
|
console.log('client 1 received the first sync')
|
2023-03-22 15:21:40 -04:00
|
|
|
resolve()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
const waitForClient2Sync = new Promise<void>((resolve) => {
|
|
|
|
yDocSyncAdapter2.doAsSoonAsSynced(() => {
|
2023-06-28 13:25:16 -04:00
|
|
|
console.log('client 2 received the first sync')
|
2023-03-22 15:21:40 -04:00
|
|
|
resolve()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
const waitForServerTo11Sync = new Promise<void>((resolve) => {
|
|
|
|
yDocSyncAdapterServerTo1.doAsSoonAsSynced(() => {
|
2023-06-28 13:25:16 -04:00
|
|
|
console.log('server 1 received the first sync')
|
2023-03-22 15:21:40 -04:00
|
|
|
resolve()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
const waitForServerTo21Sync = new Promise<void>((resolve) => {
|
|
|
|
yDocSyncAdapterServerTo2.doAsSoonAsSynced(() => {
|
2023-06-28 13:25:16 -04:00
|
|
|
console.log('server 2 received the first sync')
|
2023-03-22 15:21:40 -04:00
|
|
|
resolve()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2023-06-28 13:25:16 -04:00
|
|
|
transporterAdapterClient1.connect(transporterAdapterServerTo1)
|
|
|
|
transporterAdapterClient2.connect(transporterAdapterServerTo2)
|
|
|
|
|
|
|
|
messageTransporterClient1.setAdapter(transporterAdapterClient1)
|
|
|
|
messageTransporterClient2.setAdapter(transporterAdapterClient2)
|
|
|
|
messageTransporterServerTo1.setAdapter(transporterAdapterServerTo1)
|
|
|
|
messageTransporterServerTo2.setAdapter(transporterAdapterServerTo2)
|
|
|
|
|
2023-07-05 15:04:24 -04:00
|
|
|
messageTransporterClient1.markAsReady()
|
|
|
|
messageTransporterClient2.markAsReady()
|
|
|
|
messageTransporterServerTo1.markAsReady()
|
|
|
|
messageTransporterServerTo2.markAsReady()
|
2023-06-28 13:25:16 -04:00
|
|
|
|
|
|
|
jest.advanceTimersByTime(1000)
|
|
|
|
|
|
|
|
expect(messageTransporterClient1.isReady()).toBeTruthy()
|
|
|
|
expect(messageTransporterClient2.isReady()).toBeTruthy()
|
|
|
|
expect(messageTransporterServerTo1.isReady()).toBeTruthy()
|
|
|
|
expect(messageTransporterServerTo2.isReady()).toBeTruthy()
|
2023-03-22 15:21:40 -04:00
|
|
|
|
|
|
|
yDocSyncAdapter1.requestDocumentState()
|
|
|
|
yDocSyncAdapter2.requestDocumentState()
|
|
|
|
|
|
|
|
await Promise.all([
|
|
|
|
waitForClient1Sync,
|
|
|
|
waitForClient2Sync,
|
|
|
|
waitForServerTo11Sync,
|
|
|
|
waitForServerTo21Sync
|
|
|
|
])
|
|
|
|
|
|
|
|
textClient1.insert(0, 'test2')
|
|
|
|
textClient1.insert(0, 'test3')
|
|
|
|
textClient2.insert(0, 'test4')
|
|
|
|
|
2023-07-19 06:24:51 -04:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
2023-03-22 15:21:40 -04:00
|
|
|
expect(textServer.toString()).toBe('test4test3test2This is a test note')
|
2023-07-19 06:24:51 -04:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
2023-03-22 15:21:40 -04:00
|
|
|
expect(textClient1.toString()).toBe('test4test3test2This is a test note')
|
2023-07-19 06:24:51 -04:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
2023-03-22 15:21:40 -04:00
|
|
|
expect(textClient2.toString()).toBe('test4test3test2This is a test note')
|
|
|
|
|
|
|
|
docServer.destroy()
|
|
|
|
docClient1.destroy()
|
|
|
|
docClient2.destroy()
|
|
|
|
})
|
|
|
|
})
|