refactor: reimplement realtime-communication

This commit refactors a lot of things that are not easy to separate.
It replaces the binary protocol of y-protocols with json.
It introduces event based message processing.
It implements our own code mirror plugins for synchronisation of content and remote cursors

Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
Tilman Vatteroth 2023-03-22 20:21:40 +01:00
parent 67cf1432b2
commit 3a06f84af1
110 changed files with 3920 additions and 2201 deletions

View file

@ -3,21 +3,61 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import {
MockedBackendMessageTransporter,
YDocSyncServerAdapter,
} from '@hedgedoc/commons';
import { Mock } from 'ts-mockery';
import { User } from '../../../users/user.entity';
import { WebsocketConnection } from '../websocket-connection';
import { RealtimeConnection } from '../realtime-connection';
import { RealtimeNote } from '../realtime-note';
import { RealtimeUserStatusAdapter } from '../realtime-user-status-adapter';
/**
* Provides a partial mock for {@link WebsocketConnection}.
*
* @param synced Defines the return value for the `isSynced` function.
*/
export function mockConnection(synced: boolean): WebsocketConnection {
return Mock.of<WebsocketConnection>({
isSynced: jest.fn(() => synced),
send: jest.fn(),
getUser: jest.fn(() => Mock.of<User>({ username: 'mockedUser' })),
getUsername: jest.fn(() => 'mocked user'),
});
export class MockConnectionBuilder {
private username = 'mock';
private includeRealtimeUserState = false;
constructor(private readonly realtimeNote: RealtimeNote) {}
public withUsername(username: string): this {
this.username = username;
return this;
}
public withRealtimeUserState(): this {
this.includeRealtimeUserState = true;
return this;
}
public build(): RealtimeConnection {
const transporter = new MockedBackendMessageTransporter('');
let realtimeUserStateAdapter: RealtimeUserStatusAdapter =
Mock.of<RealtimeUserStatusAdapter>();
const connection = Mock.of<RealtimeConnection>({
getUser: jest.fn(() => Mock.of<User>({ username: this.username })),
getDisplayName: jest.fn(() => this.username),
getSyncAdapter: jest.fn(() => Mock.of<YDocSyncServerAdapter>({})),
getTransporter: jest.fn(() => transporter),
getRealtimeUserStateAdapter: () => realtimeUserStateAdapter,
getRealtimeNote: () => this.realtimeNote,
});
transporter.on('disconnected', () =>
this.realtimeNote.removeClient(connection),
);
if (this.includeRealtimeUserState) {
realtimeUserStateAdapter = new RealtimeUserStatusAdapter(
this.username,
this.username,
connection,
);
}
this.realtimeNote.addClient(connection);
return connection;
}
}