feat: move all signal handling to backend plugin

Signed-off-by: Heikki Hellgren <heikki.hellgren@op.fi>
This commit is contained in:
Heikki Hellgren
2024-01-12 13:38:34 +02:00
parent 67ddf8d6d7
commit 169e3ffc1f
22 changed files with 392 additions and 358 deletions
+1 -1
View File
@@ -24,7 +24,7 @@ export class SignalClient implements SignalApi {
static readonly DEFAULT_RECONNECT_TIMEOUT_MS: number;
// (undocumented)
subscribe(
topic: string,
channel: string,
onMessage: (message: JsonObject) => void,
): {
unsubscribe: () => void;
+16 -13
View File
@@ -19,7 +19,7 @@ import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api';
import { v4 as uuid } from 'uuid';
type Subscription = {
topic: string;
channel: string;
callback: (message: JsonObject) => void;
};
@@ -63,20 +63,23 @@ export class SignalClient implements SignalApi {
) {}
subscribe(
topic: string,
channel: string,
onMessage: (message: JsonObject) => void,
): { unsubscribe: () => void } {
const subscriptionId = uuid();
const exists = [...this.subscriptions.values()].find(
sub => sub.topic === topic,
sub => sub.channel === channel,
);
this.subscriptions.set(subscriptionId, { topic, callback: onMessage });
this.subscriptions.set(subscriptionId, {
channel: channel,
callback: onMessage,
});
this.connect()
.then(() => {
// Do not subscribe twice to same topic even there is multiple callbacks
// Do not subscribe twice to same channel even there is multiple callbacks
if (!exists) {
this.send({ action: 'subscribe', topic });
this.send({ action: 'subscribe', channel });
}
})
.catch(() => {
@@ -90,12 +93,12 @@ export class SignalClient implements SignalApi {
}
this.subscriptions.delete(subscriptionId);
const multipleExists = [...this.subscriptions.values()].find(
s => s.topic === topic,
s => s.channel === channel,
);
// If there are subscriptions still listening to this topic, do not
// If there are subscriptions still listening to this channel, do not
// unsubscribe from the server
if (!multipleExists) {
this.send({ action: 'unsubscribe', topic: sub.topic });
this.send({ action: 'unsubscribe', channel: sub.channel });
}
// If there are no subscriptions, close the connection
@@ -176,9 +179,9 @@ export class SignalClient implements SignalApi {
private handleMessage(data: MessageEvent) {
try {
const json = JSON.parse(data.data) as JsonObject;
if (json.topic) {
if (json.channel) {
for (const sub of this.subscriptions.values()) {
if (sub.topic === json.topic) {
if (sub.channel === json.channel) {
sub.callback(json.message as JsonObject);
}
}
@@ -201,9 +204,9 @@ export class SignalClient implements SignalApi {
this.ws = null;
this.connect()
.then(() => {
// Resubscribe to existing topics in case we lost connection
// Resubscribe to existing channels in case we lost connection
for (const sub of this.subscriptions.values()) {
this.send({ action: 'subscribe', topic: sub.topic });
this.send({ action: 'subscribe', channel: sub.channel });
}
})
.catch(() => {
+13 -13
View File
@@ -44,21 +44,21 @@ describe('SignalsClient', () => {
it('should handle single subscription correctly', async () => {
const messageMock = jest.fn();
const client = SignalClient.create({ discoveryApi, identity });
const { unsubscribe } = client.subscribe('topic', messageMock);
const { unsubscribe } = client.subscribe('channel', messageMock);
await server.connected;
await expect(server).toReceiveMessage({
action: 'subscribe',
topic: 'topic',
channel: 'channel',
});
server.send({ topic: 'topic', message: { hello: 'world' } });
server.send({ channel: 'channel', message: { hello: 'world' } });
expect(messageMock).toHaveBeenCalledWith({ hello: 'world' });
await unsubscribe();
await expect(server).toReceiveMessage({
action: 'unsubscribe',
topic: 'topic',
channel: 'channel',
});
});
@@ -68,11 +68,11 @@ describe('SignalsClient', () => {
const client1 = SignalClient.create({ discoveryApi, identity });
const client2 = SignalClient.create({ discoveryApi, identity });
const { unsubscribe: unsubscribe1 } = client1.subscribe(
'topic',
'channel',
messageMock1,
);
const { unsubscribe: unsubscribe2 } = client2.subscribe(
'topic',
'channel',
messageMock2,
);
@@ -80,22 +80,22 @@ describe('SignalsClient', () => {
await expect(server).toReceiveMessage({
action: 'subscribe',
topic: 'topic',
channel: 'channel',
});
server.send({ topic: 'topic', message: { hello: 'world' } });
server.send({ channel: 'channel', message: { hello: 'world' } });
expect(messageMock1).toHaveBeenCalledWith({ hello: 'world' });
expect(messageMock2).toHaveBeenCalledWith({ hello: 'world' });
await unsubscribe1();
await expect(server).not.toReceiveMessage({
action: 'unsubscribe',
topic: 'topic',
channel: 'channel',
});
await unsubscribe2();
await expect(server).toReceiveMessage({
action: 'unsubscribe',
topic: 'topic',
channel: 'channel',
});
});
@@ -108,11 +108,11 @@ describe('SignalsClient', () => {
connectTimeout: 100,
});
client.subscribe('topic', messageMock);
client.subscribe('channel', messageMock);
await server.connected;
await expect(server).toReceiveMessage({
action: 'subscribe',
topic: 'topic',
channel: 'channel',
});
await server.server.emit('error', null);
@@ -120,7 +120,7 @@ describe('SignalsClient', () => {
await new Promise(r => setTimeout(r, 50));
await expect(server).toReceiveMessage({
action: 'subscribe',
topic: 'topic',
channel: 'channel',
});
});
});