feat: update devtools almost real time using signals
Signed-off-by: Heikki Hellgren <heikki.hellgren@op.fi>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-devtools-backend': patch
|
||||
'@backstage/plugin-devtools': patch
|
||||
---
|
||||
|
||||
Update devtools information almost real time using signals plugin
|
||||
@@ -73,6 +73,7 @@ import { DefaultEventBroker } from '@backstage/plugin-events-backend';
|
||||
import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';
|
||||
import { MeterProvider } from '@opentelemetry/sdk-metrics';
|
||||
import { metrics } from '@opentelemetry/api';
|
||||
import { SignalService } from '@backstage/plugin-signals-node';
|
||||
|
||||
// Expose opentelemetry metrics using a Prometheus exporter on
|
||||
// http://localhost:9464/metrics . See prometheus.yml in packages/backend for
|
||||
@@ -99,6 +100,11 @@ function makeCreateEnv(config: Config) {
|
||||
});
|
||||
|
||||
const eventBroker = new DefaultEventBroker(root.child({ type: 'plugin' }));
|
||||
const signalService = SignalService.create({
|
||||
logger: root,
|
||||
eventBroker,
|
||||
identity,
|
||||
});
|
||||
|
||||
root.info(`Created UrlReader ${reader}`);
|
||||
|
||||
@@ -120,6 +126,7 @@ function makeCreateEnv(config: Config) {
|
||||
permissions,
|
||||
scheduler,
|
||||
identity,
|
||||
signalService,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -25,5 +25,6 @@ export default async function createPlugin(
|
||||
logger: env.logger,
|
||||
config: env.config,
|
||||
permissions: env.permissions,
|
||||
signalService: env.signalService,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,25 +15,13 @@
|
||||
*/
|
||||
import { Router } from 'express';
|
||||
import { createRouter } from '@backstage/plugin-signals-backend';
|
||||
import { SignalsService } from '@backstage/plugin-signals-node';
|
||||
import { PluginEnvironment } from '../types';
|
||||
|
||||
export default async function createPlugin(
|
||||
env: PluginEnvironment,
|
||||
): Promise<Router> {
|
||||
const service = SignalsService.create({
|
||||
logger: env.logger,
|
||||
identity: env.identity,
|
||||
eventBroker: env.eventBroker,
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
console.log('publishing');
|
||||
service.publish('*', 'devtools:info', { now: new Date().toISOString() });
|
||||
}, 5000);
|
||||
|
||||
return await createRouter({
|
||||
logger: env.logger,
|
||||
service,
|
||||
service: env.signalService,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import { PluginTaskScheduler } from '@backstage/backend-tasks';
|
||||
import { IdentityApi } from '@backstage/plugin-auth-node';
|
||||
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
|
||||
import { EventBroker } from '@backstage/plugin-events-node';
|
||||
import { SignalService } from '@backstage/plugin-signals-node';
|
||||
|
||||
export type PluginEnvironment = {
|
||||
logger: Logger;
|
||||
@@ -40,4 +41,5 @@ export type PluginEnvironment = {
|
||||
scheduler: PluginTaskScheduler;
|
||||
identity: IdentityApi;
|
||||
eventBroker: EventBroker;
|
||||
signalService: SignalService;
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@ import express from 'express';
|
||||
import { ExternalDependency } from '@backstage/plugin-devtools-common';
|
||||
import { Logger } from 'winston';
|
||||
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
|
||||
import { SignalService } from '@backstage/plugin-signals-node';
|
||||
|
||||
// @public (undocumented)
|
||||
export function createRouter(options: RouterOptions): Promise<express.Router>;
|
||||
@@ -40,5 +41,7 @@ export interface RouterOptions {
|
||||
logger: Logger;
|
||||
// (undocumented)
|
||||
permissions: PermissionEvaluator;
|
||||
// (undocumented)
|
||||
signalService?: SignalService;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"@backstage/plugin-devtools-common": "workspace:^",
|
||||
"@backstage/plugin-permission-common": "workspace:^",
|
||||
"@backstage/plugin-permission-node": "workspace:^",
|
||||
"@backstage/plugin-signals-node": "workspace:^",
|
||||
"@backstage/types": "workspace:^",
|
||||
"@manypkg/get-packages": "^1.1.3",
|
||||
"@types/express": "*",
|
||||
|
||||
@@ -33,6 +33,7 @@ import { errorHandler } from '@backstage/backend-common';
|
||||
import express from 'express';
|
||||
import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node';
|
||||
import { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node';
|
||||
import { SignalService } from '@backstage/plugin-signals-node';
|
||||
|
||||
/** @public */
|
||||
export interface RouterOptions {
|
||||
@@ -40,17 +41,28 @@ export interface RouterOptions {
|
||||
logger: Logger;
|
||||
config: Config;
|
||||
permissions: PermissionEvaluator;
|
||||
signalService?: SignalService;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export async function createRouter(
|
||||
options: RouterOptions,
|
||||
): Promise<express.Router> {
|
||||
const { logger, config, permissions } = options;
|
||||
const { logger, config, permissions, signalService } = options;
|
||||
|
||||
const devToolsBackendApi =
|
||||
options.devToolsBackendApi || new DevToolsBackendApi(logger, config);
|
||||
|
||||
if (signalService) {
|
||||
// Publish info periodically using the signal service
|
||||
setInterval(async () => {
|
||||
if (signalService.hasSubscribers('devtools:info')) {
|
||||
const info = await devToolsBackendApi.listInfo();
|
||||
await signalService.publish('*', 'devtools:info', info);
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
const router = Router();
|
||||
router.use(express.json());
|
||||
router.use(
|
||||
|
||||
@@ -27,10 +27,9 @@ import {
|
||||
makeStyles,
|
||||
Paper,
|
||||
Theme,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import { Alert } from '@material-ui/lab';
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useInfo } from '../../../hooks';
|
||||
import { InfoDependenciesTable } from './InfoDependenciesTable';
|
||||
import DescriptionIcon from '@material-ui/icons/Description';
|
||||
@@ -39,7 +38,7 @@ import DeveloperBoardIcon from '@material-ui/icons/DeveloperBoard';
|
||||
import { BackstageLogoIcon } from './BackstageLogoIcon';
|
||||
import FileCopyIcon from '@material-ui/icons/FileCopy';
|
||||
import { DevToolsInfo } from '@backstage/plugin-devtools-common';
|
||||
import { useSignalsApi } from '@backstage/plugin-signals-react';
|
||||
import { useSignalApi } from '@backstage/plugin-signals-react';
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -74,14 +73,18 @@ const copyToClipboard = ({ about }: { about: DevToolsInfo | undefined }) => {
|
||||
/** @public */
|
||||
export const InfoContent = () => {
|
||||
const classes = useStyles();
|
||||
const [info, setInfo] = useState<DevToolsInfo | undefined>(undefined);
|
||||
const { about, loading, error } = useInfo();
|
||||
// Just testing for signals
|
||||
const [messages, setMessages] = React.useState<string[]>([]);
|
||||
useSignalsApi('devtools:info', message => {
|
||||
messages.push(JSON.stringify(message));
|
||||
setMessages([...messages]);
|
||||
useSignalApi('devtools:info', message => {
|
||||
setInfo(message as DevToolsInfo);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading && !error && about) {
|
||||
setInfo(about);
|
||||
}
|
||||
}, [about, loading, error]);
|
||||
|
||||
if (loading) {
|
||||
return <Progress />;
|
||||
} else if (error) {
|
||||
@@ -89,11 +92,6 @@ export const InfoContent = () => {
|
||||
}
|
||||
return (
|
||||
<Box>
|
||||
<Paper>
|
||||
{messages.map((msg, i) => {
|
||||
return <Typography key={i}>{msg}</Typography>;
|
||||
})}
|
||||
</Paper>
|
||||
<Paper className={classes.paperStyle}>
|
||||
<List className={classes.flexContainer}>
|
||||
<ListItem>
|
||||
@@ -104,7 +102,7 @@ export const InfoContent = () => {
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary="Operating System"
|
||||
secondary={about?.operatingSystem}
|
||||
secondary={info?.operatingSystem}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
@@ -115,7 +113,7 @@ export const InfoContent = () => {
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary="Resource utilization"
|
||||
secondary={about?.resourceUtilization}
|
||||
secondary={info?.resourceUtilization}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
@@ -126,7 +124,7 @@ export const InfoContent = () => {
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary="NodeJS Version"
|
||||
secondary={about?.nodeJsVersion}
|
||||
secondary={info?.nodeJsVersion}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
@@ -137,14 +135,14 @@ export const InfoContent = () => {
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary="Backstage Version"
|
||||
secondary={about?.backstageVersion}
|
||||
secondary={info?.backstageVersion}
|
||||
/>
|
||||
</ListItem>
|
||||
<Divider orientation="vertical" variant="middle" flexItem />
|
||||
<ListItem
|
||||
button
|
||||
onClick={() => {
|
||||
copyToClipboard({ about });
|
||||
copyToClipboard({ about: info });
|
||||
}}
|
||||
className={classes.copyButton}
|
||||
>
|
||||
@@ -157,7 +155,7 @@ export const InfoContent = () => {
|
||||
</ListItem>
|
||||
</List>
|
||||
</Paper>
|
||||
<InfoDependenciesTable infoDependencies={about?.dependencies} />
|
||||
<InfoDependenciesTable infoDependencies={info?.dependencies} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
```ts
|
||||
import express from 'express';
|
||||
import { Logger } from 'winston';
|
||||
import { SignalsService } from '@backstage/plugin-signals-node';
|
||||
import { SignalService } from '@backstage/plugin-signals-node';
|
||||
|
||||
// @public (undocumented)
|
||||
export function createRouter(options: RouterOptions): Promise<express.Router>;
|
||||
@@ -15,7 +15,7 @@ export interface RouterOptions {
|
||||
// (undocumented)
|
||||
logger: Logger;
|
||||
// (undocumented)
|
||||
service: SignalsService;
|
||||
service: SignalService;
|
||||
}
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
|
||||
@@ -18,9 +18,9 @@ import express from 'express';
|
||||
import request from 'supertest';
|
||||
|
||||
import { createRouter } from './router';
|
||||
import { SignalsService } from '@backstage/plugin-signals-node';
|
||||
import { SignalService } from '@backstage/plugin-signals-node';
|
||||
|
||||
const signalsServiceMock: jest.Mocked<SignalsService> = {} as any;
|
||||
const signalsServiceMock: jest.Mocked<SignalService> = {} as any;
|
||||
|
||||
describe('createRouter', () => {
|
||||
let app: express.Express;
|
||||
|
||||
@@ -17,12 +17,12 @@ import { errorHandler } from '@backstage/backend-common';
|
||||
import express from 'express';
|
||||
import Router from 'express-promise-router';
|
||||
import { Logger } from 'winston';
|
||||
import { SignalsService } from '@backstage/plugin-signals-node';
|
||||
import { SignalService } from '@backstage/plugin-signals-node';
|
||||
|
||||
/** @public */
|
||||
export interface RouterOptions {
|
||||
logger: Logger;
|
||||
service: SignalsService;
|
||||
service: SignalService;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
import { Server } from 'http';
|
||||
import { Logger } from 'winston';
|
||||
import { createRouter } from './router';
|
||||
import { SignalsService } from '@backstage/plugin-signals-node';
|
||||
import { SignalService } from '@backstage/plugin-signals-node';
|
||||
import { DefaultIdentityClient } from '@backstage/plugin-auth-node';
|
||||
|
||||
export interface ServerOptions {
|
||||
@@ -43,7 +43,7 @@ export async function startStandaloneServer(
|
||||
issuer: await discovery.getExternalBaseUrl('auth'),
|
||||
});
|
||||
|
||||
const signals = SignalsService.create({
|
||||
const signals = SignalService.create({
|
||||
logger: logger,
|
||||
identity,
|
||||
});
|
||||
|
||||
@@ -19,19 +19,20 @@ export type ServiceOptions = {
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type SignalsEventBrokerPayload = {
|
||||
export type SignalEventBrokerPayload = {
|
||||
recipients?: string[];
|
||||
topic?: string;
|
||||
message?: JsonObject;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export class SignalsService implements EventSubscriber {
|
||||
export class SignalService implements EventSubscriber {
|
||||
// (undocumented)
|
||||
static create(options: ServiceOptions): SignalsService;
|
||||
static create(options: ServiceOptions): SignalService;
|
||||
handleUpgrade: (req: Request_2) => Promise<void>;
|
||||
hasSubscribers(topic: string): boolean;
|
||||
// (undocumented)
|
||||
onEvent(params: EventParams<SignalsEventBrokerPayload>): Promise<void>;
|
||||
onEvent(params: EventParams<SignalEventBrokerPayload>): Promise<void>;
|
||||
publish(
|
||||
to: string | string[],
|
||||
topic: string,
|
||||
|
||||
+18
-5
@@ -22,7 +22,7 @@ import { Logger } from 'winston';
|
||||
import {
|
||||
ServiceOptions,
|
||||
SignalConnection,
|
||||
SignalsEventBrokerPayload,
|
||||
SignalEventBrokerPayload,
|
||||
} from './types';
|
||||
import { RawData, WebSocket, WebSocketServer } from 'ws';
|
||||
import { IncomingMessage } from 'http';
|
||||
@@ -36,7 +36,7 @@ import {
|
||||
} from '@backstage/plugin-auth-node';
|
||||
|
||||
/** @public */
|
||||
export class SignalsService implements EventSubscriber {
|
||||
export class SignalService implements EventSubscriber {
|
||||
private readonly serverId: string;
|
||||
private connections: Map<string, SignalConnection> = new Map<
|
||||
string,
|
||||
@@ -48,7 +48,7 @@ export class SignalsService implements EventSubscriber {
|
||||
private server: WebSocketServer;
|
||||
|
||||
static create(options: ServiceOptions) {
|
||||
return new SignalsService(options);
|
||||
return new SignalService(options);
|
||||
}
|
||||
|
||||
private constructor(options: ServiceOptions) {
|
||||
@@ -75,7 +75,7 @@ export class SignalsService implements EventSubscriber {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles request upgradce to websocket and adds the connection to internal
|
||||
* Handles request upgrade to websocket and adds the connection to internal
|
||||
* list for publish/subscribe functionality
|
||||
* @param req - Request
|
||||
*/
|
||||
@@ -184,6 +184,19 @@ export class SignalsService implements EventSubscriber {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there is active subscriptions to specific topic.
|
||||
* This can be useful to skip heavy processing before publishing messages if there are no subscriptions.
|
||||
* @param topic - topic to check for subscriptions
|
||||
*/
|
||||
hasSubscribers(topic: string): boolean {
|
||||
return (
|
||||
[...this.connections.values()].find(conn =>
|
||||
conn.subscriptions.has(topic),
|
||||
) !== undefined
|
||||
);
|
||||
}
|
||||
|
||||
private async publishInternal(
|
||||
recipients: string[],
|
||||
topic: string,
|
||||
@@ -229,7 +242,7 @@ export class SignalsService implements EventSubscriber {
|
||||
}
|
||||
}
|
||||
|
||||
async onEvent(params: EventParams<SignalsEventBrokerPayload>): Promise<void> {
|
||||
async onEvent(params: EventParams<SignalEventBrokerPayload>): Promise<void> {
|
||||
const { eventPayload, metadata } = params;
|
||||
// Discard message from same server to prevent duplicate messages
|
||||
if (!metadata?.server || metadata.server === this.serverId) {
|
||||
@@ -14,5 +14,5 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './SignalsService';
|
||||
export * from './SignalService';
|
||||
export * from './types';
|
||||
|
||||
@@ -29,7 +29,7 @@ export type ServiceOptions = {
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export type SignalsEventBrokerPayload = {
|
||||
export type SignalEventBrokerPayload = {
|
||||
recipients?: string[];
|
||||
topic?: string;
|
||||
message?: JsonObject;
|
||||
|
||||
@@ -7,16 +7,16 @@ import { ApiRef } from '@backstage/core-plugin-api';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
|
||||
// @public (undocumented)
|
||||
export type SignalsApi = {
|
||||
export type SignalApi = {
|
||||
subscribe(topic: string, onMessage: (message: JsonObject) => void): string;
|
||||
unsubscribe(subscription: string): void;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export const signalsApiRef: ApiRef<SignalsApi>;
|
||||
export const signalApiRef: ApiRef<SignalApi>;
|
||||
|
||||
// @public (undocumented)
|
||||
export const useSignalsApi: (
|
||||
export const useSignalApi: (
|
||||
topic: string,
|
||||
onMessage: (message: JsonObject) => void,
|
||||
) => void;
|
||||
|
||||
+3
-3
@@ -17,12 +17,12 @@ import { createApiRef } from '@backstage/core-plugin-api';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
|
||||
/** @public */
|
||||
export const signalsApiRef = createApiRef<SignalsApi>({
|
||||
id: 'plugin.signals.service',
|
||||
export const signalApiRef = createApiRef<SignalApi>({
|
||||
id: 'plugin.signal.service',
|
||||
});
|
||||
|
||||
/** @public */
|
||||
export type SignalsApi = {
|
||||
export type SignalApi = {
|
||||
subscribe(topic: string, onMessage: (message: JsonObject) => void): string;
|
||||
|
||||
unsubscribe(subscription: string): void;
|
||||
@@ -13,4 +13,4 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export * from './SignalsApi';
|
||||
export * from './SignalApi';
|
||||
|
||||
@@ -13,4 +13,4 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export * from './useSignalsApi';
|
||||
export * from './useSignalApi';
|
||||
|
||||
+3
-3
@@ -13,17 +13,17 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { signalsApiRef } from '../api';
|
||||
import { signalApiRef } from '../api';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
/** @public */
|
||||
export const useSignalsApi = (
|
||||
export const useSignalApi = (
|
||||
topic: string,
|
||||
onMessage: (message: JsonObject) => void,
|
||||
) => {
|
||||
const signals = useApi(signalsApiRef);
|
||||
const signals = useApi(signalApiRef);
|
||||
const [subscription, setSubscription] = useState<null | string>(null);
|
||||
useEffect(() => {
|
||||
if (!subscription) {
|
||||
@@ -7,17 +7,17 @@ import { BackstagePlugin } from '@backstage/core-plugin-api';
|
||||
import { DiscoveryApi } from '@backstage/core-plugin-api';
|
||||
import { IdentityApi } from '@backstage/core-plugin-api';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { SignalsApi } from '@backstage/plugin-signals-react';
|
||||
import { SignalApi } from '@backstage/plugin-signals-react';
|
||||
|
||||
// @public (undocumented)
|
||||
export class SignalsClient implements SignalsApi {
|
||||
export class SignalClient implements SignalApi {
|
||||
// (undocumented)
|
||||
static create(options: {
|
||||
identity: IdentityApi;
|
||||
discoveryApi: DiscoveryApi;
|
||||
connectTimeout?: number;
|
||||
reconnectTimeout?: number;
|
||||
}): SignalsClient;
|
||||
}): SignalClient;
|
||||
// (undocumented)
|
||||
static readonly DEFAULT_CONNECT_TIMEOUT_MS: number;
|
||||
// (undocumented)
|
||||
|
||||
@@ -13,24 +13,21 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { SignalsApi } from '@backstage/plugin-signals-react';
|
||||
import { SignalApi } from '@backstage/plugin-signals-react';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
/** @internal */
|
||||
type Subscription = {
|
||||
topic: string;
|
||||
callback: (message: JsonObject) => void;
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
const WS_CLOSE_NORMAL = 1000;
|
||||
/** @internal */
|
||||
const WS_CLOSE_GOING_AWAY = 1001;
|
||||
|
||||
/** @public */
|
||||
export class SignalsClient implements SignalsApi {
|
||||
export class SignalClient implements SignalApi {
|
||||
static readonly DEFAULT_CONNECT_TIMEOUT_MS: number = 1000;
|
||||
static readonly DEFAULT_RECONNECT_TIMEOUT_MS: number = 5000;
|
||||
private ws: WebSocket | null = null;
|
||||
@@ -47,10 +44,10 @@ export class SignalsClient implements SignalsApi {
|
||||
const {
|
||||
identity,
|
||||
discoveryApi,
|
||||
connectTimeout = SignalsClient.DEFAULT_CONNECT_TIMEOUT_MS,
|
||||
reconnectTimeout = SignalsClient.DEFAULT_RECONNECT_TIMEOUT_MS,
|
||||
connectTimeout = SignalClient.DEFAULT_CONNECT_TIMEOUT_MS,
|
||||
reconnectTimeout = SignalClient.DEFAULT_RECONNECT_TIMEOUT_MS,
|
||||
} = options;
|
||||
return new SignalsClient(
|
||||
return new SignalClient(
|
||||
identity,
|
||||
discoveryApi,
|
||||
connectTimeout,
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api';
|
||||
import WS from 'jest-websocket-mock';
|
||||
import { SignalsClient } from './SignalsClient';
|
||||
import { SignalClient } from './SignalClient';
|
||||
|
||||
describe('SignalsClient', () => {
|
||||
const tokenFunction = jest.fn();
|
||||
@@ -43,7 +43,7 @@ describe('SignalsClient', () => {
|
||||
|
||||
it('should handle single subscription correctly', async () => {
|
||||
const messageMock = jest.fn();
|
||||
const client = SignalsClient.create({ discoveryApi, identity });
|
||||
const client = SignalClient.create({ discoveryApi, identity });
|
||||
const sub = client.subscribe('topic', messageMock);
|
||||
await server.connected;
|
||||
|
||||
@@ -64,8 +64,8 @@ describe('SignalsClient', () => {
|
||||
it('should handle multiple subscription correctly', async () => {
|
||||
const messageMock1 = jest.fn();
|
||||
const messageMock2 = jest.fn();
|
||||
const client1 = SignalsClient.create({ discoveryApi, identity });
|
||||
const client2 = SignalsClient.create({ discoveryApi, identity });
|
||||
const client1 = SignalClient.create({ discoveryApi, identity });
|
||||
const client2 = SignalClient.create({ discoveryApi, identity });
|
||||
const sub1 = client1.subscribe('topic', messageMock1);
|
||||
const sub2 = client2.subscribe('topic', messageMock2);
|
||||
|
||||
@@ -94,7 +94,7 @@ describe('SignalsClient', () => {
|
||||
|
||||
it('should reconnect on error', async () => {
|
||||
const messageMock = jest.fn();
|
||||
const client = SignalsClient.create({
|
||||
const client = SignalClient.create({
|
||||
discoveryApi,
|
||||
identity,
|
||||
reconnectTimeout: 10,
|
||||
|
||||
@@ -13,4 +13,4 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export * from './SignalsClient';
|
||||
export * from './SignalClient';
|
||||
|
||||
@@ -19,21 +19,21 @@ import {
|
||||
discoveryApiRef,
|
||||
identityApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { signalsApiRef } from '@backstage/plugin-signals-react';
|
||||
import { SignalsClient } from './api/SignalsClient';
|
||||
import { signalApiRef } from '@backstage/plugin-signals-react';
|
||||
import { SignalClient } from './api/SignalClient';
|
||||
|
||||
/** @public */
|
||||
export const signalsPlugin = createPlugin({
|
||||
id: 'signals',
|
||||
apis: [
|
||||
createApiFactory({
|
||||
api: signalsApiRef,
|
||||
api: signalApiRef,
|
||||
deps: {
|
||||
identity: identityApiRef,
|
||||
discoveryApi: discoveryApiRef,
|
||||
},
|
||||
factory: ({ identity, discoveryApi }) =>
|
||||
SignalsClient.create({
|
||||
SignalClient.create({
|
||||
identity,
|
||||
discoveryApi,
|
||||
}),
|
||||
|
||||
@@ -6203,6 +6203,7 @@ __metadata:
|
||||
"@backstage/plugin-devtools-common": "workspace:^"
|
||||
"@backstage/plugin-permission-common": "workspace:^"
|
||||
"@backstage/plugin-permission-node": "workspace:^"
|
||||
"@backstage/plugin-signals-node": "workspace:^"
|
||||
"@backstage/types": "workspace:^"
|
||||
"@manypkg/get-packages": ^1.1.3
|
||||
"@types/express": "*"
|
||||
|
||||
Reference in New Issue
Block a user