Skip to content

Commit

Permalink
feat: broadcast changes to single clients
Browse files Browse the repository at this point in the history
  • Loading branch information
ju4n97 committed Nov 17, 2023
1 parent 6573d95 commit 5f64711
Show file tree
Hide file tree
Showing 29 changed files with 337 additions and 82 deletions.
4 changes: 2 additions & 2 deletions apps/server/envs/development.env
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ SECURITY_HELMET_ENABLED=true

SECURITY_CORS_ENABLED=true
SECURITY_CORS_ALLOWED_ORIGIN=*
# SECURITY_CORS_ALLOWED_METHODS=
# SECURITY_CORS_ALLOWED_HEADERS=
SECURITY_CORS_ALLOWED_METHODS=*
SECURITY_CORS_ALLOWED_HEADERS=*

SECURITY_THROTTLE_ENABLED=true
SECURITY_THROTTLE_TTL=1
Expand Down
4 changes: 2 additions & 2 deletions apps/server/envs/production.env
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ SECURITY_HELMET_ENABLED=true

SECURITY_CORS_ENABLED=true
SECURITY_CORS_ALLOWED_ORIGIN=*
# SECURITY_CORS_ALLOWED_METHODS=
# SECURITY_CORS_ALLOWED_HEADERS=
SECURITY_CORS_ALLOWED_METHODS=GET,HEAD,PUT,PATCH,POST,DELETE
SECURITY_CORS_ALLOWED_HEADERS="Origin, Content-Type, Accept, Authorization, X-Requested-With, x-correlation-id, x-xsighub-client-id"

SECURITY_THROTTLE_ENABLED=true
SECURITY_THROTTLE_TTL=1
Expand Down
Binary file modified apps/server/prisma/xsighub.db
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { ExecutionContext } from '@nestjs/common';
import { ROUTE_ARGS_METADATA } from '@nestjs/common/constants';
import { randomUUID } from 'crypto';
import { XsighubHttpHeaders } from '../../http-headers';
import { ClientId } from './client-id.decorator';

describe('ClientId', () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/ban-types, @typescript-eslint/explicit-function-return-type
function getParamDecoratorFactory(decorator: Function) {
class TestDecorator {
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
public test(@ClientId() clientId: string): void {}
}

const args = Reflect.getMetadata(ROUTE_ARGS_METADATA, TestDecorator, 'test');

return args[Object.keys(args)[0]].factory;
}

it('should return the client ID if it exists in the request', () => {
const uuid = randomUUID();

const mockRequest = {
headers: {
[XsighubHttpHeaders.HTTP_HEADER_CLIENT_ID]: uuid,
},
};

const mockContext = {
switchToHttp: jest.fn().mockReturnValue({
getRequest: jest.fn().mockReturnValue(mockRequest),
}),
} as unknown as ExecutionContext;

const factory = getParamDecoratorFactory(ClientId);

const result = factory(null, mockContext);

expect(result).toBe(uuid);
});

it('should return undefined if the client ID cannot be obtained from the request', () => {
const mockRequest = {
headers: {},
};

const mockContext = {
switchToHttp: jest.fn().mockReturnValue({
getRequest: jest.fn().mockReturnValue(mockRequest),
}),
} as unknown as ExecutionContext;

const factory = getParamDecoratorFactory(ClientId);

const result = factory(null, mockContext);

expect(result).toBeUndefined();
});
});
16 changes: 16 additions & 0 deletions apps/server/src/lib/decorators/client-id/client-id.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { Request } from 'express';
import { XsighubHttpHeaders } from '../../http-headers';

/**
* Decorador que extrae el socket client ID del objeto de solicitud.
* @param ctx - El contexto de ejecución de la solicitud actual.
* @returns Correlation ID asociado a la petición HTTP.
*/
export const ClientId = createParamDecorator((_, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest<Request>();

const clientId = request.headers?.[XsighubHttpHeaders.HTTP_HEADER_CLIENT_ID];

return clientId;
});
1 change: 1 addition & 0 deletions apps/server/src/lib/decorators/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './client-id/client-id.decorator';
export * from './client-ip/client-ip.decorator';
export * from './correlation-id/correlation-id.decorator';
export * from './user-agent/user-agent.decorator';
3 changes: 2 additions & 1 deletion apps/server/src/lib/http-headers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const XsighubHttpHeaders = {
HTTP_HEADER_CORRELATION_ID: 'X-Correlation-ID',
HTTP_HEADER_CORRELATION_ID: 'x-correlation-id',
HTTP_HEADER_CLIENT_ID: 'x-xsighub-client-id',
};
2 changes: 1 addition & 1 deletion apps/server/src/lib/types/api-extras.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export type ApiExtras = { correlationId: string };
export type ApiExtras = { correlationId: string; clientId: string };
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CorrelationId } from '@lib/decorators';
import { ClientId, CorrelationId } from '@lib/decorators';
import { XsighubLoggerService } from '@lib/logger';
import { ApiVersion } from '@lib/types';
import { Body, Controller, Delete, Get, Param, Patch, Post, Put } from '@nestjs/common';
Expand Down Expand Up @@ -29,63 +29,75 @@ export class SessionDocumentController {
@Post()
create(
@CorrelationId() correlationId: string,
@ClientId() clientId: string,
@Body() data: SessionDocumentCreateDto,
): Promise<SessionDocumentDto> {
this._logger.info(`[${this.create.name}]`, { correlationId });

return this._sessionDocumentService.create(data, { correlationId });
return this._sessionDocumentService.create(data, { correlationId, clientId });
}

@Get(':documentId')
findById(
@CorrelationId() correlationId: string,
@ClientId() clientId: string,
@Param('documentId') documentId: number,
): Promise<SessionDocumentDto> {
this._logger.info(`[${this.findById.name}]`, { correlationId });

return this._sessionDocumentService.findById(documentId, { correlationId });
return this._sessionDocumentService.findById(documentId, { correlationId, clientId });
}

@Put(':signatureId')
update(
@CorrelationId() correlationId: string,
@ClientId() clientId: string,
@Param('signatureId') signatureId: number,
@Body() data: SessionDocumentUpdateDto,
): Promise<SessionDocumentDto> {
this._logger.info(`[${this.delete.name}]`, { correlationId });

return this._sessionDocumentService.update(signatureId, data, { correlationId });
return this._sessionDocumentService.update(signatureId, data, { correlationId, clientId });
}

@Patch(':documentId/signatures/attach')
attachSignature(
@CorrelationId() correlationId: string,
@ClientId() clientId: string,
@Param('documentId') documentId: number,
@Body() data: SessionDocumentSignatureCreateDto,
): Promise<SessionDocumentDto> {
this._logger.info(`[${this.delete.name}]`, { correlationId });

return this._sessionDocumentService.attachSignature(documentId, data, { correlationId });
return this._sessionDocumentService.attachSignature(documentId, data, {
correlationId,
clientId,
});
}

@Patch(':documentId/metadata/load')
loadMetadata(
@CorrelationId() correlationId: string,
@ClientId() clientId: string,
@Param('documentId') documentId: number,
@Body() data: SessionDocumentMetadataLoadDto,
): Promise<SessionDocumentDto> {
this._logger.info(`[${this.loadMetadata.name}]`, { correlationId });

return this._sessionDocumentService.loadMetadata(documentId, data, { correlationId });
return this._sessionDocumentService.loadMetadata(documentId, data, {
correlationId,
clientId,
});
}

@Delete(':signatureId')
delete(
@CorrelationId() correlationId: string,
@ClientId() clientId: string,
@Param('signatureId') signatureId: number,
): Promise<SessionDocumentDto> {
this._logger.info(`[${this.delete.name}]`, { correlationId });

return this._sessionDocumentService.delete(signatureId, { correlationId });
return this._sessionDocumentService.delete(signatureId, { correlationId, clientId });
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CorrelationId } from '@lib/decorators';
import { ClientId, CorrelationId } from '@lib/decorators';
import { XsighubLoggerService } from '@lib/logger';
import { ApiVersion } from '@lib/types';
import { Body, Controller, Delete, Param, Post, Put } from '@nestjs/common';
Expand Down Expand Up @@ -27,31 +27,34 @@ export class SessionReferenceController {
@Post()
create(
@CorrelationId() correlationId: string,
@ClientId() clientId: string,
@Body() data: SessionReferenceCreateDto,
): Promise<SessionReferenceDto> {
this._logger.info(`[${this.create.name}]`, { correlationId });

return this._sessionReferenceService.create(data, { correlationId });
return this._sessionReferenceService.create(data, { correlationId, clientId });
}

@Put(':referenceId')
update(
@CorrelationId() correlationId: string,
@ClientId() clientId: string,
@Param('referenceId') referenceId: number,
@Body() data: SessionReferenceUpdateDto,
): Promise<SessionReferenceDto> {
this._logger.info(`[${this.delete.name}]`, { correlationId });

return this._sessionReferenceService.update(referenceId, data, { correlationId });
return this._sessionReferenceService.update(referenceId, data, { correlationId, clientId });
}

@Delete(':referenceId')
delete(
@CorrelationId() correlationId: string,
@ClientId() clientId: string,
@Param('referenceId') referenceId: number,
): Promise<SessionReferenceDto> {
this._logger.info(`[${this.delete.name}]`, { correlationId });

return this._sessionReferenceService.delete(referenceId, { correlationId });
return this._sessionReferenceService.delete(referenceId, { correlationId, clientId });
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CorrelationId } from '@lib/decorators';
import { ClientId, CorrelationId } from '@lib/decorators';
import { XsighubLoggerService } from '@lib/logger';
import { ApiVersion } from '@lib/types';
import { Body, Controller, Delete, Get, Param, Patch, Post, Put } from '@nestjs/common';
Expand Down Expand Up @@ -29,52 +29,60 @@ export class SessionSignatureController {
@Post()
create(
@CorrelationId() correlationId: string,
@ClientId() clientId: string,
@Body() data: SessionSignatureCreateDto,
): Promise<SessionSignatureDto> {
this._logger.info(`[${this.create.name}]`, { correlationId });

return this._sessionSignatureService.create(data, { correlationId });
return this._sessionSignatureService.create(data, { correlationId, clientId });
}

@Get(':signatureId')
findById(
@CorrelationId() correlationId: string,
@ClientId() clientId: string,
@Param('signatureId') signatureId: number,
): Promise<SessionSignatureDto> {
this._logger.info(`[${this.findById.name}]`, { correlationId });

return this._sessionSignatureService.findById(signatureId, { correlationId });
return this._sessionSignatureService.findById(signatureId, { correlationId, clientId });
}

@Put(':signatureId')
update(
@CorrelationId() correlationId: string,
@ClientId() clientId: string,
@Param('signatureId') signatureId: number,
@Body() data: SessionSignatureUpdateDto,
): Promise<SessionSignatureDto> {
this._logger.info(`[${this.delete.name}]`, { correlationId });

return this._sessionSignatureService.update(signatureId, data, { correlationId });
return this._sessionSignatureService.update(signatureId, data, { correlationId, clientId });
}

@Patch(':documentId/metadata/load')
loadMetadata(
@CorrelationId() correlationId: string,
@ClientId() clientId: string,
@Param('documentId') documentId: number,
@Body() data: SessionSignatureMetadataLoadDto,
): Promise<SessionSignatureDto> {
this._logger.info(`[${this.loadMetadata.name}]`, { correlationId });

return this._sessionSignatureService.loadMetadata(documentId, data, { correlationId });
return this._sessionSignatureService.loadMetadata(documentId, data, {
correlationId,
clientId,
});
}

@Delete(':signatureId')
delete(
@CorrelationId() correlationId: string,
@ClientId() clientId: string,
@Param('signatureId') signatureId: number,
): Promise<SessionSignatureDto> {
this._logger.info(`[${this.delete.name}]`, { correlationId });

return this._sessionSignatureService.delete(signatureId, { correlationId });
return this._sessionSignatureService.delete(signatureId, { correlationId, clientId });
}
}
20 changes: 13 additions & 7 deletions apps/server/src/modules/session/controllers/session.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ClientIp, CorrelationId, UserAgent } from '@lib/decorators';
import { ClientId, ClientIp, CorrelationId, UserAgent } from '@lib/decorators';
import { XsighubLoggerService } from '@lib/logger';
import { ApiVersion } from '@lib/types';
import { Controller, Delete, Get, Param, Patch, Post } from '@nestjs/common';
Expand All @@ -24,60 +24,66 @@ export class SessionController {
create(
@CorrelationId() correlationId: string,
@ClientIp() clientIp: string,
@ClientId() clientId: string,
@UserAgent() userAgent: UAParser.IResult,
): Promise<SessionDto> {
this._logger.info(`[${this.create.name}]`, { correlationId });

return this._sessionsService.create(clientIp, userAgent.ua, { correlationId });
return this._sessionsService.create(clientIp, userAgent.ua, { correlationId, clientId });
}

@Get()
findByIpAddress(
@CorrelationId() correlationId: string,
@ClientIp() clientIp: string,
@ClientId() clientId: string,
): Promise<SessionDto> {
this._logger.info(`[${this.findByIpAddress.name}]`, { correlationId });

return this._sessionsService.findByIpAddress(clientIp, { correlationId });
return this._sessionsService.findByIpAddress(clientIp, { correlationId, clientId });
}

@Get(':pairingKey')
findByPairingKey(
@CorrelationId() correlationId: string,
@ClientId() clientId: string,
@Param('pairingKey') pairingKey: string,
): Promise<SessionDto> {
this._logger.info(`[${this.findByPairingKey.name}]`, { correlationId });

return this._sessionsService.findByPairingKey(pairingKey, { correlationId });
return this._sessionsService.findByPairingKey(pairingKey, { correlationId, clientId });
}

@Patch(':pairingKey/pair')
pair(
@CorrelationId() correlationId: string,
@ClientId() clientId: string,
@Param('pairingKey') pairingKey: string,
): Promise<SessionDto> {
this._logger.info(`[${this.pair.name}]`, { correlationId });

return this._sessionsService.pair(pairingKey, { correlationId });
return this._sessionsService.pair(pairingKey, { correlationId, clientId });
}

@Patch(':pairingKey/unpair')
unpair(
@CorrelationId() correlationId: string,
@ClientId() clientId: string,
@Param('pairingKey') pairingKey: string,
): Promise<SessionDto> {
this._logger.info(`[${this.unpair.name}]`, { correlationId });

return this._sessionsService.unpair(pairingKey, { correlationId });
return this._sessionsService.unpair(pairingKey, { correlationId, clientId });
}

@Delete(':pairingKey')
destroy(
@CorrelationId() correlationId: string,
@ClientId() clientId: string,
@Param('pairingKey') pairingKey: string,
): Promise<SessionDto> {
this._logger.info(`[${this.destroy.name}]`, { correlationId });

return this._sessionsService.destroy(pairingKey, { correlationId });
return this._sessionsService.destroy(pairingKey, { correlationId, clientId });
}
}
Loading

0 comments on commit 5f64711

Please sign in to comment.