feat(realtime): add disconnect reason

The frontend now doesn't try to reconnect, when the disconnection happened because of a lack of permissions

Signed-off-by: Philip Molares <philip.molares@udo.edu>
This commit is contained in:
Philip Molares 2023-10-22 21:33:34 +02:00
parent f6cfe74d8c
commit 723f3f611c
11 changed files with 111 additions and 46 deletions

View file

@ -3,9 +3,14 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { ConnectionState, Message, MessageType } from '@hedgedoc/commons';
import {
ConnectionState,
DisconnectReason,
Message,
MessageType,
} from '@hedgedoc/commons';
import { Mock } from 'ts-mockery';
import WebSocket, { MessageEvent } from 'ws';
import WebSocket, { CloseEvent, MessageEvent } from 'ws';
import { BackendWebsocketAdapter } from './backend-websocket-adapter';
@ -29,17 +34,26 @@ describe('backend websocket adapter', () => {
});
it('can bind and unbind the close event', () => {
const handler = jest.fn();
const handler = jest.fn((reason?: DisconnectReason) => console.log(reason));
let modifiedHandler: (event: CloseEvent) => void = jest.fn();
jest
.spyOn(mockedSocket, 'addEventListener')
.mockImplementation((event, handler_) => {
modifiedHandler = handler_;
});
const unbind = sut.bindOnCloseEvent(handler);
expect(mockedSocket.addEventListener).toHaveBeenCalledWith(
'close',
handler,
modifiedHandler(
Mock.of<CloseEvent>({ code: DisconnectReason.USER_NOT_PERMITTED }),
);
expect(handler).toHaveBeenCalledTimes(1);
expect(handler).toHaveBeenCalledWith(DisconnectReason.USER_NOT_PERMITTED);
unbind();
expect(mockedSocket.removeEventListener).toHaveBeenCalledWith(
'close',
handler,
);
expect(mockedSocket.removeEventListener).toHaveBeenCalled();
});
it('can bind and unbind the connect event', () => {

View file

@ -3,9 +3,14 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { ConnectionState, Message, MessageType } from '@hedgedoc/commons';
import {
ConnectionState,
DisconnectReason,
Message,
MessageType,
} from '@hedgedoc/commons';
import type { TransportAdapter } from '@hedgedoc/commons';
import WebSocket, { MessageEvent } from 'ws';
import WebSocket, { CloseEvent, MessageEvent } from 'ws';
/**
* Implements a transport adapter that communicates using a nodejs socket.
@ -13,10 +18,13 @@ import WebSocket, { MessageEvent } from 'ws';
export class BackendWebsocketAdapter implements TransportAdapter {
constructor(private socket: WebSocket) {}
bindOnCloseEvent(handler: () => void): () => void {
this.socket.addEventListener('close', handler);
bindOnCloseEvent(handler: (reason?: DisconnectReason) => void): () => void {
function callback(event: CloseEvent): void {
handler(event.code);
}
this.socket.addEventListener('close', callback);
return () => {
this.socket.removeEventListener('close', handler);
this.socket.removeEventListener('close', callback);
};
}

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import {
DisconnectReason,
MessageTransporter,
NotePermissions,
userCanEdit,
@ -66,13 +67,11 @@ export class WebsocketGateway implements OnGatewayConnection {
note,
);
if (notePermission < NotePermission.READ) {
//TODO: [mrdrogdrog] inform client about reason of disconnect.
// (https://github.com/hedgedoc/hedgedoc/issues/5034)
this.logger.log(
`Access denied to note '${note.id}' for user '${username}'`,
'handleConnection',
);
clientSocket.close();
clientSocket.close(DisconnectReason.USER_NOT_PERMITTED);
return;
}