mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-09 13:51:57 -04:00
refactor: remove isomorphic-ws
The package caused some issues while working on other features. Mostly because bundlers have been unable to determine the correct websocket constructor. So I replaced it with a more object-oriented approach. Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
14ba7ea9ce
commit
753c6e593f
23 changed files with 724 additions and 283 deletions
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
import {
|
||||
MessageTransporter,
|
||||
MockedBackendMessageTransporter,
|
||||
MockedBackendTransportAdapter,
|
||||
YDocSyncServerAdapter,
|
||||
} from '@hedgedoc/commons';
|
||||
import * as HedgeDocCommonsModule from '@hedgedoc/commons';
|
||||
|
@ -49,7 +49,8 @@ describe('websocket connection', () => {
|
|||
displayName: mockedDisplayName,
|
||||
});
|
||||
|
||||
mockedMessageTransporter = new MockedBackendMessageTransporter('');
|
||||
mockedMessageTransporter = new MessageTransporter();
|
||||
mockedMessageTransporter.setAdapter(new MockedBackendTransportAdapter(''));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
|
|
@ -5,16 +5,15 @@
|
|||
*/
|
||||
import {
|
||||
Message,
|
||||
MessageTransporter,
|
||||
MessageType,
|
||||
MockedBackendMessageTransporter,
|
||||
MockedBackendTransportAdapter,
|
||||
waitForOtherPromisesToFinish,
|
||||
} from '@hedgedoc/commons';
|
||||
|
||||
import { RealtimeUserStatusAdapter } from './realtime-user-status-adapter';
|
||||
|
||||
type SendMessageSpy = jest.SpyInstance<
|
||||
void,
|
||||
[Required<MockedBackendMessageTransporter['sendMessage']>]
|
||||
>;
|
||||
type SendMessageSpy = jest.SpyInstance<void, [content: Message<MessageType>]>;
|
||||
|
||||
describe('realtime user status adapter', () => {
|
||||
let clientLoggedIn1: RealtimeUserStatusAdapter | undefined;
|
||||
|
@ -36,24 +35,42 @@ describe('realtime user status adapter', () => {
|
|||
|
||||
const guestDisplayName = 'Virtuous Mockingbird';
|
||||
|
||||
let messageTransporterLoggedIn1: MockedBackendMessageTransporter;
|
||||
let messageTransporterLoggedIn2: MockedBackendMessageTransporter;
|
||||
let messageTransporterGuest: MockedBackendMessageTransporter;
|
||||
let messageTransporterNotReady: MockedBackendMessageTransporter;
|
||||
let messageTransporterDecline: MockedBackendMessageTransporter;
|
||||
let messageTransporterLoggedIn1: MessageTransporter;
|
||||
let messageTransporterLoggedIn2: MessageTransporter;
|
||||
let messageTransporterGuest: MessageTransporter;
|
||||
let messageTransporterNotReady: MessageTransporter;
|
||||
let messageTransporterDecline: MessageTransporter;
|
||||
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
clientLoggedIn1 = undefined;
|
||||
clientLoggedIn2 = undefined;
|
||||
clientGuest = undefined;
|
||||
clientNotReady = undefined;
|
||||
clientDecline = undefined;
|
||||
|
||||
messageTransporterLoggedIn1 = new MockedBackendMessageTransporter('');
|
||||
messageTransporterLoggedIn2 = new MockedBackendMessageTransporter('');
|
||||
messageTransporterGuest = new MockedBackendMessageTransporter('');
|
||||
messageTransporterNotReady = new MockedBackendMessageTransporter('');
|
||||
messageTransporterDecline = new MockedBackendMessageTransporter('');
|
||||
messageTransporterLoggedIn1 = new MessageTransporter();
|
||||
messageTransporterLoggedIn2 = new MessageTransporter();
|
||||
messageTransporterGuest = new MessageTransporter();
|
||||
messageTransporterNotReady = new MessageTransporter();
|
||||
messageTransporterDecline = new MessageTransporter();
|
||||
|
||||
const mockedTransportAdapterLoggedIn1 = new MockedBackendTransportAdapter(
|
||||
'',
|
||||
);
|
||||
const mockedTransportAdapterLoggedIn2 = new MockedBackendTransportAdapter(
|
||||
'',
|
||||
);
|
||||
const mockedTransportAdapterGuest = new MockedBackendTransportAdapter('');
|
||||
const mockedTransportAdapterNotReady = new MockedBackendTransportAdapter(
|
||||
'',
|
||||
);
|
||||
const mockedTransportAdapterDecline = new MockedBackendTransportAdapter('');
|
||||
|
||||
messageTransporterLoggedIn1.setAdapter(mockedTransportAdapterLoggedIn1);
|
||||
messageTransporterLoggedIn2.setAdapter(mockedTransportAdapterLoggedIn2);
|
||||
messageTransporterGuest.setAdapter(mockedTransportAdapterGuest);
|
||||
messageTransporterNotReady.setAdapter(mockedTransportAdapterNotReady);
|
||||
messageTransporterDecline.setAdapter(mockedTransportAdapterDecline);
|
||||
|
||||
function otherAdapterCollector(): RealtimeUserStatusAdapter[] {
|
||||
return [
|
||||
|
@ -126,14 +143,15 @@ describe('realtime user status adapter', () => {
|
|||
messageTransporterLoggedIn2.sendReady();
|
||||
messageTransporterGuest.sendReady();
|
||||
messageTransporterDecline.sendReady();
|
||||
await waitForOtherPromisesToFinish();
|
||||
});
|
||||
|
||||
it('can answer a state request', () => {
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientLoggedIn2SendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientGuestSendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientLoggedIn2SendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientGuestSendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientNotReadySendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
|
||||
messageTransporterLoggedIn1.emit(MessageType.REALTIME_USER_STATE_REQUEST);
|
||||
|
||||
|
@ -176,21 +194,21 @@ describe('realtime user status adapter', () => {
|
|||
},
|
||||
};
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
2,
|
||||
expectedMessage1,
|
||||
);
|
||||
expect(clientLoggedIn2SendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientGuestSendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientLoggedIn2SendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientGuestSendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientNotReadySendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('can save an cursor update', () => {
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientLoggedIn2SendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientGuestSendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientLoggedIn2SendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientGuestSendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientNotReadySendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
|
||||
const newFrom = Math.floor(Math.random() * 100);
|
||||
const newTo = Math.floor(Math.random() * 100);
|
||||
|
@ -323,28 +341,28 @@ describe('realtime user status adapter', () => {
|
|||
},
|
||||
};
|
||||
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientLoggedIn2SendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
2,
|
||||
expectedMessage2,
|
||||
);
|
||||
expect(clientGuestSendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
2,
|
||||
expectedMessage3,
|
||||
);
|
||||
expect(clientNotReadySendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
2,
|
||||
expectedMessage5,
|
||||
);
|
||||
});
|
||||
|
||||
it('will inform other clients about removed client', () => {
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientLoggedIn2SendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientGuestSendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientLoggedIn2SendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientGuestSendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientNotReadySendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
|
||||
messageTransporterLoggedIn2.disconnect();
|
||||
|
||||
|
@ -439,27 +457,27 @@ describe('realtime user status adapter', () => {
|
|||
};
|
||||
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
2,
|
||||
expectedMessage1,
|
||||
);
|
||||
expect(clientLoggedIn2SendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientLoggedIn2SendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientGuestSendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
2,
|
||||
expectedMessage3,
|
||||
);
|
||||
expect(clientNotReadySendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
2,
|
||||
expectedMessage5,
|
||||
);
|
||||
});
|
||||
|
||||
it('will inform other clients about inactivity and reactivity', () => {
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientLoggedIn2SendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientGuestSendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientLoggedIn2SendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientGuestSendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientNotReadySendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
|
||||
messageTransporterLoggedIn1.emit(MessageType.REALTIME_USER_SET_ACTIVITY, {
|
||||
type: MessageType.REALTIME_USER_SET_ACTIVITY,
|
||||
|
@ -591,18 +609,18 @@ describe('realtime user status adapter', () => {
|
|||
},
|
||||
};
|
||||
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientLoggedIn2SendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
2,
|
||||
expectedInactivityMessage2,
|
||||
);
|
||||
expect(clientGuestSendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
2,
|
||||
expectedInactivityMessage3,
|
||||
);
|
||||
expect(clientNotReadySendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
2,
|
||||
expectedInactivityMessage5,
|
||||
);
|
||||
|
||||
|
@ -613,18 +631,18 @@ describe('realtime user status adapter', () => {
|
|||
},
|
||||
});
|
||||
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientLoggedIn2SendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
2,
|
||||
expectedInactivityMessage2,
|
||||
);
|
||||
expect(clientGuestSendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
2,
|
||||
expectedInactivityMessage3,
|
||||
);
|
||||
expect(clientNotReadySendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
2,
|
||||
expectedInactivityMessage5,
|
||||
);
|
||||
|
||||
|
@ -765,18 +783,18 @@ describe('realtime user status adapter', () => {
|
|||
},
|
||||
};
|
||||
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientLoggedIn2SendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
2,
|
||||
expectedReactivityMessage2,
|
||||
);
|
||||
expect(clientGuestSendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
2,
|
||||
expectedReactivityMessage3,
|
||||
);
|
||||
expect(clientNotReadySendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
2,
|
||||
expectedReactivityMessage5,
|
||||
);
|
||||
|
||||
|
@ -787,18 +805,18 @@ describe('realtime user status adapter', () => {
|
|||
},
|
||||
});
|
||||
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientLoggedIn2SendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
2,
|
||||
expectedReactivityMessage2,
|
||||
);
|
||||
expect(clientGuestSendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
2,
|
||||
expectedReactivityMessage3,
|
||||
);
|
||||
expect(clientNotReadySendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
2,
|
||||
expectedReactivityMessage5,
|
||||
);
|
||||
});
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import {
|
||||
MockedBackendMessageTransporter,
|
||||
MessageTransporter,
|
||||
MockedBackendTransportAdapter,
|
||||
YDocSyncServerAdapter,
|
||||
} from '@hedgedoc/commons';
|
||||
import { Mock } from 'ts-mockery';
|
||||
|
@ -81,7 +82,8 @@ export class MockConnectionBuilder {
|
|||
public build(): RealtimeConnection {
|
||||
const displayName = this.deriveDisplayName();
|
||||
|
||||
const transporter = new MockedBackendMessageTransporter('');
|
||||
const transporter = new MessageTransporter();
|
||||
transporter.setAdapter(new MockedBackendTransportAdapter(''));
|
||||
const realtimeUserStateAdapter: RealtimeUserStatusAdapter =
|
||||
this.includeRealtimeUserStatus === RealtimeUserState.WITHOUT
|
||||
? Mock.of<RealtimeUserStatusAdapter>({})
|
||||
|
|
129
backend/src/realtime/websocket/backend-websocket-adapter.spec.ts
Normal file
129
backend/src/realtime/websocket/backend-websocket-adapter.spec.ts
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { ConnectionState, Message, MessageType } from '@hedgedoc/commons';
|
||||
import { Mock } from 'ts-mockery';
|
||||
import WebSocket, { MessageEvent } from 'ws';
|
||||
|
||||
import { BackendWebsocketAdapter } from './backend-websocket-adapter';
|
||||
|
||||
describe('backend websocket adapter', () => {
|
||||
let sut: BackendWebsocketAdapter;
|
||||
let mockedSocket: WebSocket;
|
||||
|
||||
function mockSocket(readyState: 0 | 1 | 2 | 3 = 0) {
|
||||
mockedSocket = Mock.of<WebSocket>({
|
||||
addEventListener: jest.fn(),
|
||||
removeEventListener: jest.fn(),
|
||||
close: jest.fn(),
|
||||
send: jest.fn(),
|
||||
readyState: readyState,
|
||||
});
|
||||
sut = new BackendWebsocketAdapter(mockedSocket);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
mockSocket(0);
|
||||
});
|
||||
|
||||
it('can bind and unbind the close event', () => {
|
||||
const handler = jest.fn();
|
||||
const unbind = sut.bindOnCloseEvent(handler);
|
||||
expect(mockedSocket.addEventListener).toHaveBeenCalledWith(
|
||||
'close',
|
||||
handler,
|
||||
);
|
||||
unbind();
|
||||
expect(mockedSocket.removeEventListener).toHaveBeenCalledWith(
|
||||
'close',
|
||||
handler,
|
||||
);
|
||||
});
|
||||
|
||||
it('can bind and unbind the connect event', () => {
|
||||
const handler = jest.fn();
|
||||
const unbind = sut.bindOnConnectedEvent(handler);
|
||||
expect(mockedSocket.addEventListener).toHaveBeenCalledWith('open', handler);
|
||||
unbind();
|
||||
expect(mockedSocket.removeEventListener).toHaveBeenCalledWith(
|
||||
'open',
|
||||
handler,
|
||||
);
|
||||
});
|
||||
|
||||
it('can bind and unbind the error event', () => {
|
||||
const handler = jest.fn();
|
||||
const unbind = sut.bindOnErrorEvent(handler);
|
||||
expect(mockedSocket.addEventListener).toHaveBeenCalledWith(
|
||||
'error',
|
||||
handler,
|
||||
);
|
||||
unbind();
|
||||
expect(mockedSocket.removeEventListener).toHaveBeenCalledWith(
|
||||
'error',
|
||||
handler,
|
||||
);
|
||||
});
|
||||
|
||||
it('can bind, unbind and translate the message event', () => {
|
||||
const handler = jest.fn();
|
||||
|
||||
let modifiedHandler: (event: MessageEvent) => void = jest.fn();
|
||||
jest
|
||||
.spyOn(mockedSocket, 'addEventListener')
|
||||
.mockImplementation((event, handler_) => {
|
||||
modifiedHandler = handler_;
|
||||
});
|
||||
|
||||
const unbind = sut.bindOnMessageEvent(handler);
|
||||
|
||||
modifiedHandler(Mock.of<MessageEvent>({ data: new ArrayBuffer(0) }));
|
||||
expect(handler).toHaveBeenCalledTimes(0);
|
||||
|
||||
modifiedHandler(Mock.of<MessageEvent>({ data: '{ "type": "READY" }' }));
|
||||
expect(handler).toHaveBeenCalledWith({ type: 'READY' });
|
||||
|
||||
expect(mockedSocket.addEventListener).toHaveBeenCalledWith(
|
||||
'message',
|
||||
modifiedHandler,
|
||||
);
|
||||
unbind();
|
||||
expect(mockedSocket.removeEventListener).toHaveBeenCalledWith(
|
||||
'message',
|
||||
modifiedHandler,
|
||||
);
|
||||
});
|
||||
|
||||
it('can disconnect the socket', () => {
|
||||
sut.disconnect();
|
||||
expect(mockedSocket.close).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('can send messages', () => {
|
||||
const value: Message<MessageType> = { type: MessageType.READY };
|
||||
sut.send(value);
|
||||
expect(mockedSocket.send).toHaveBeenCalledWith('{"type":"READY"}');
|
||||
});
|
||||
|
||||
it('can read the connection state when open', () => {
|
||||
mockSocket(WebSocket.OPEN);
|
||||
expect(sut.getConnectionState()).toBe(ConnectionState.CONNECTED);
|
||||
});
|
||||
|
||||
it('can read the connection state when connecting', () => {
|
||||
mockSocket(WebSocket.CONNECTING);
|
||||
expect(sut.getConnectionState()).toBe(ConnectionState.CONNECTING);
|
||||
});
|
||||
|
||||
it('can read the connection state when closing', () => {
|
||||
mockSocket(WebSocket.CLOSING);
|
||||
expect(sut.getConnectionState()).toBe(ConnectionState.DISCONNECTED);
|
||||
});
|
||||
|
||||
it('can read the connection state when closed', () => {
|
||||
mockSocket(WebSocket.CLOSED);
|
||||
expect(sut.getConnectionState()).toBe(ConnectionState.DISCONNECTED);
|
||||
});
|
||||
});
|
71
backend/src/realtime/websocket/backend-websocket-adapter.ts
Normal file
71
backend/src/realtime/websocket/backend-websocket-adapter.ts
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { ConnectionState, Message, MessageType } from '@hedgedoc/commons';
|
||||
import type { TransportAdapter } from '@hedgedoc/commons';
|
||||
import WebSocket, { MessageEvent } from 'ws';
|
||||
|
||||
/**
|
||||
* Implements a transport adapter that communicates using a nodejs socket.
|
||||
*/
|
||||
export class BackendWebsocketAdapter implements TransportAdapter {
|
||||
constructor(private socket: WebSocket) {}
|
||||
|
||||
bindOnCloseEvent(handler: () => void): () => void {
|
||||
this.socket.addEventListener('close', handler);
|
||||
return () => {
|
||||
this.socket.removeEventListener('close', handler);
|
||||
};
|
||||
}
|
||||
|
||||
bindOnConnectedEvent(handler: () => void): () => void {
|
||||
this.socket.addEventListener('open', handler);
|
||||
return () => {
|
||||
this.socket.removeEventListener('open', handler);
|
||||
};
|
||||
}
|
||||
|
||||
bindOnErrorEvent(handler: () => void): () => void {
|
||||
this.socket.addEventListener('error', handler);
|
||||
return () => {
|
||||
this.socket.removeEventListener('error', handler);
|
||||
};
|
||||
}
|
||||
|
||||
bindOnMessageEvent(
|
||||
handler: (value: Message<MessageType>) => void,
|
||||
): () => void {
|
||||
function adjustedHandler(message: MessageEvent): void {
|
||||
if (typeof message.data !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
handler(JSON.parse(message.data) as Message<MessageType>);
|
||||
}
|
||||
|
||||
this.socket.addEventListener('message', adjustedHandler);
|
||||
return () => {
|
||||
this.socket.removeEventListener('message', adjustedHandler);
|
||||
};
|
||||
}
|
||||
|
||||
disconnect(): void {
|
||||
this.socket.close();
|
||||
}
|
||||
|
||||
getConnectionState(): ConnectionState {
|
||||
if (this.socket.readyState === WebSocket.OPEN) {
|
||||
return ConnectionState.CONNECTED;
|
||||
} else if (this.socket.readyState === WebSocket.CONNECTING) {
|
||||
return ConnectionState.CONNECTING;
|
||||
} else {
|
||||
return ConnectionState.DISCONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
send(value: Message<MessageType>): void {
|
||||
this.socket.send(JSON.stringify(value));
|
||||
}
|
||||
}
|
|
@ -4,9 +4,9 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import {
|
||||
MessageTransporter,
|
||||
NotePermissions,
|
||||
userCanEdit,
|
||||
WebsocketTransporter,
|
||||
} from '@hedgedoc/commons';
|
||||
import { OnGatewayConnection, WebSocketGateway } from '@nestjs/websockets';
|
||||
import { IncomingMessage } from 'http';
|
||||
|
@ -21,6 +21,7 @@ import { User } from '../../users/user.entity';
|
|||
import { UsersService } from '../../users/users.service';
|
||||
import { RealtimeConnection } from '../realtime-note/realtime-connection';
|
||||
import { RealtimeNoteService } from '../realtime-note/realtime-note.service';
|
||||
import { BackendWebsocketAdapter } from './backend-websocket-adapter';
|
||||
import { extractNoteIdFromRequestUrl } from './utils/extract-note-id-from-request-url';
|
||||
|
||||
/**
|
||||
|
@ -85,7 +86,7 @@ export class WebsocketGateway implements OnGatewayConnection {
|
|||
const realtimeNote =
|
||||
await this.realtimeNoteService.getOrCreateRealtimeNote(note);
|
||||
|
||||
const websocketTransporter = new WebsocketTransporter();
|
||||
const websocketTransporter = new MessageTransporter();
|
||||
const permissions = await this.noteService.toNotePermissionsDto(note);
|
||||
const acceptEdits: boolean = userCanEdit(
|
||||
permissions as NotePermissions,
|
||||
|
@ -97,7 +98,9 @@ export class WebsocketGateway implements OnGatewayConnection {
|
|||
realtimeNote,
|
||||
acceptEdits,
|
||||
);
|
||||
websocketTransporter.setWebsocket(clientSocket);
|
||||
websocketTransporter.setAdapter(
|
||||
new BackendWebsocketAdapter(clientSocket),
|
||||
);
|
||||
|
||||
realtimeNote.addClient(connection);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue