mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-26 13:48:33 +02:00
feat: Spike frontend applications registration (#9846)
This commit is contained in:
parent
3ac087e0f6
commit
1ccc6cae19
@ -35,6 +35,7 @@ const mapToDb = (client) => ({
|
||||
app_name: client.appName,
|
||||
instance_id: client.instanceId,
|
||||
sdk_version: client.sdkVersion || '',
|
||||
sdk_type: client.sdkType,
|
||||
client_ip: client.clientIp,
|
||||
last_seen: client.lastSeen || 'now()',
|
||||
environment: client.environment || 'default',
|
||||
|
@ -1,17 +1,23 @@
|
||||
import type { Request, Response } from 'express';
|
||||
import Controller from '../../routes/controller';
|
||||
import { type IUnleashConfig, type IUnleashServices, NONE } from '../../types';
|
||||
import {
|
||||
type IFlagResolver,
|
||||
type IUnleashConfig,
|
||||
type IUnleashServices,
|
||||
type IUser,
|
||||
NONE,
|
||||
} from '../../types';
|
||||
import type { Logger } from '../../logger';
|
||||
import type { IApiUser } from '../../types/api-user';
|
||||
import ApiUser, { type IApiUser } from '../../types/api-user';
|
||||
import {
|
||||
type ClientMetricsSchema,
|
||||
createRequestSchema,
|
||||
createResponseSchema,
|
||||
emptyResponse,
|
||||
getStandardResponses,
|
||||
type FrontendApiClientSchema,
|
||||
frontendApiFeaturesSchema,
|
||||
type FrontendApiFeaturesSchema,
|
||||
getStandardResponses,
|
||||
} from '../../openapi';
|
||||
import type { Context } from 'unleash-client';
|
||||
import { enrichContextWithIp } from './index';
|
||||
@ -34,7 +40,10 @@ interface ApiUserRequest<
|
||||
|
||||
type Services = Pick<
|
||||
IUnleashServices,
|
||||
'settingService' | 'frontendApiService' | 'openApiService'
|
||||
| 'settingService'
|
||||
| 'frontendApiService'
|
||||
| 'openApiService'
|
||||
| 'clientInstanceService'
|
||||
>;
|
||||
|
||||
export default class FrontendAPIController extends Controller {
|
||||
@ -44,10 +53,13 @@ export default class FrontendAPIController extends Controller {
|
||||
|
||||
private timer: Function;
|
||||
|
||||
private flagResolver: IFlagResolver;
|
||||
|
||||
constructor(config: IUnleashConfig, services: Services) {
|
||||
super(config);
|
||||
this.logger = config.getLogger('frontend-api-controller.ts');
|
||||
this.services = services;
|
||||
this.flagResolver = config.flagResolver;
|
||||
|
||||
this.timer = (functionName: string) =>
|
||||
metricsHelper.wrapTimer(config.eventBus, FUNCTION_TIME, {
|
||||
@ -216,6 +228,13 @@ export default class FrontendAPIController extends Controller {
|
||||
);
|
||||
}
|
||||
|
||||
private resolveProject(user: IUser | IApiUser) {
|
||||
if (user instanceof ApiUser) {
|
||||
return user.projects;
|
||||
}
|
||||
return ['default'];
|
||||
}
|
||||
|
||||
private async registerFrontendApiMetrics(
|
||||
req: ApiUserRequest<unknown, unknown, ClientMetricsSchema>,
|
||||
res: Response,
|
||||
@ -229,11 +248,29 @@ export default class FrontendAPIController extends Controller {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.services.frontendApiService.registerFrontendApiMetrics(
|
||||
req.user,
|
||||
req.body,
|
||||
req.ip,
|
||||
);
|
||||
const environment =
|
||||
await this.services.frontendApiService.registerFrontendApiMetrics(
|
||||
req.user,
|
||||
req.body,
|
||||
req.ip,
|
||||
);
|
||||
|
||||
if (
|
||||
req.body.instanceId &&
|
||||
req.headers['unleash-sdk'] &&
|
||||
this.flagResolver.isEnabled('registerFrontendClient')
|
||||
) {
|
||||
const client = {
|
||||
appName: req.body.appName,
|
||||
instanceId: req.body.instanceId,
|
||||
sdkVersion: req.headers['unleash-sdk'] as string,
|
||||
sdkType: 'frontend' as const,
|
||||
environment: environment,
|
||||
projects: this.resolveProject(req.user),
|
||||
};
|
||||
this.services.clientInstanceService.registerFrontendClient(client);
|
||||
}
|
||||
|
||||
res.sendStatus(200);
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,7 @@ export class FrontendApiService {
|
||||
token: IApiUser,
|
||||
metrics: ClientMetricsSchema,
|
||||
ip: string,
|
||||
): Promise<void> {
|
||||
): Promise<string> {
|
||||
FrontendApiService.assertExpectedTokenType(token);
|
||||
|
||||
const environment =
|
||||
@ -127,6 +127,8 @@ export class FrontendApiService {
|
||||
},
|
||||
ip,
|
||||
);
|
||||
|
||||
return environment;
|
||||
}
|
||||
|
||||
private async clientForFrontendApiToken(token: IApiUser): Promise<Unleash> {
|
||||
|
@ -13,7 +13,11 @@ import type {
|
||||
import type { IFeatureToggleStore } from '../../feature-toggle/types/feature-toggle-store-type';
|
||||
import type { IStrategyStore } from '../../../types/stores/strategy-store';
|
||||
import type { IClientInstanceStore } from '../../../types/stores/client-instance-store';
|
||||
import type { IClientApp, ISdkHeartbeat } from '../../../types/model';
|
||||
import type {
|
||||
IClientApp,
|
||||
IFrontendClientApp,
|
||||
ISdkHeartbeat,
|
||||
} from '../../../types/model';
|
||||
import { clientRegisterSchema } from '../shared/schema';
|
||||
|
||||
import type { IClientMetricsStoreV2 } from '../client-metrics/client-metrics-store-v2-type';
|
||||
@ -104,6 +108,12 @@ export default class ClientInstanceService {
|
||||
});
|
||||
}
|
||||
|
||||
public registerFrontendClient(data: IFrontendClientApp): void {
|
||||
data.createdBy = SYSTEM_USER.username!;
|
||||
|
||||
this.seenClients[this.clientKey(data)] = data;
|
||||
}
|
||||
|
||||
public async registerClient(
|
||||
data: PartialSome<IClientApp, 'instanceId'>,
|
||||
clientIp: string,
|
||||
@ -111,6 +121,7 @@ export default class ClientInstanceService {
|
||||
const value = await clientRegisterSchema.validateAsync(data);
|
||||
value.clientIp = clientIp;
|
||||
value.createdBy = SYSTEM_USER.username!;
|
||||
value.sdkType = 'backend';
|
||||
this.seenClients[this.clientKey(value)] = value;
|
||||
this.eventBus.emit(CLIENT_REGISTERED, value);
|
||||
|
||||
|
@ -69,7 +69,8 @@ export type IFlagKey =
|
||||
| 'flagsOverviewSearch'
|
||||
| 'flagsReleaseManagementUI'
|
||||
| 'cleanupReminder'
|
||||
| 'removeInactiveApplications';
|
||||
| 'removeInactiveApplications'
|
||||
| 'registerFrontendClient';
|
||||
|
||||
export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>;
|
||||
|
||||
@ -330,6 +331,10 @@ const flags: IFlags = {
|
||||
process.env.UNLEASH_EXPERIMENTAL_REMOVE_INACTIVE_APPLICATIONS,
|
||||
false,
|
||||
),
|
||||
registerFrontendClient: parseEnvVarBoolean(
|
||||
process.env.UNLEASH_EXPERIMENTAL_REGISTER_FRONTEND_CLIENT,
|
||||
false,
|
||||
),
|
||||
};
|
||||
|
||||
export const defaultExperimentalOptions: IExperimentalOptions = {
|
||||
|
@ -460,6 +460,16 @@ export interface IRoleIdentifier {
|
||||
roleName?: RoleName;
|
||||
}
|
||||
|
||||
export interface IFrontendClientApp {
|
||||
appName: string;
|
||||
instanceId: string;
|
||||
sdkVersion: string;
|
||||
sdkType: 'frontend';
|
||||
environment: string;
|
||||
projects: string[];
|
||||
createdBy?: string;
|
||||
}
|
||||
|
||||
export interface IClientApp {
|
||||
appName: string;
|
||||
instanceId: string;
|
||||
@ -478,6 +488,7 @@ export interface IClientApp {
|
||||
platformVersion?: string;
|
||||
yggdrasilVersion?: string;
|
||||
specVersion?: string;
|
||||
sdkType?: 'frontend' | 'backend';
|
||||
}
|
||||
|
||||
export interface IAppFeature {
|
||||
|
@ -63,6 +63,7 @@ process.nextTick(async () => {
|
||||
flagsOverviewSearch: true,
|
||||
cleanupReminder: true,
|
||||
strictSchemaValidation: true,
|
||||
registerFrontendClient: true,
|
||||
},
|
||||
},
|
||||
authentication: {
|
||||
|
Loading…
Reference in New Issue
Block a user