diff --git a/packages/hoppscotch-backend/src/pubsub/pubsub.service.ts b/packages/hoppscotch-backend/src/pubsub/pubsub.service.ts index 47576871..bec39602 100644 --- a/packages/hoppscotch-backend/src/pubsub/pubsub.service.ts +++ b/packages/hoppscotch-backend/src/pubsub/pubsub.service.ts @@ -4,6 +4,7 @@ import { default as Redis, RedisOptions } from 'ioredis'; import { RedisPubSub } from 'graphql-redis-subscriptions'; import { PubSub as LocalPubSub } from 'graphql-subscriptions'; +import { TopicDef } from './topicsDefs'; /** * RedisPubSub uses JSON parsing for back and forth conversion, which loses Date objects, hence this reviver brings them back @@ -70,7 +71,7 @@ export class PubSubService implements OnModuleInit { return this.pubsub.asyncIterator(topic, options); } - async publish(topic: string, payload: any) { + async publish(topic: T, payload: TopicDef[T]) { await this.pubsub.publish(topic, payload); } } diff --git a/packages/hoppscotch-backend/src/pubsub/topicsDefs.ts b/packages/hoppscotch-backend/src/pubsub/topicsDefs.ts new file mode 100644 index 00000000..4a1fbcb2 --- /dev/null +++ b/packages/hoppscotch-backend/src/pubsub/topicsDefs.ts @@ -0,0 +1,10 @@ +import { UserEnvironment } from '../user-environment/user-environments.model'; + +// A custom message type that defines the topic and the corresponding payload. +// For every module that publishes a subscription add its type def and the possible subscription type. +export type TopicDef = { + [ + topic: `user_environment/${string}/${'created' | 'updated' | 'deleted'}` + ]: UserEnvironment; + [topic: `user_environment/${string}/deleted_many`]: number; +}; diff --git a/packages/hoppscotch-backend/src/subscription-handler.ts b/packages/hoppscotch-backend/src/subscription-handler.ts deleted file mode 100644 index a47730c3..00000000 --- a/packages/hoppscotch-backend/src/subscription-handler.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { PubSubService } from './pubsub/pubsub.service'; -import { PrimitiveTypes } from './types/primitive-types'; -import { CustomModuleTypes } from './types/custom-module-types'; -import { SubscriptionType } from './types/subscription-types'; - -// Custom generic type to indicate the type of module -type ModuleType = PrimitiveTypes | CustomModuleTypes; - -@Injectable() -export class SubscriptionHandler { - constructor(private readonly pubsub: PubSubService) {} - - /** - * Publishes a subscription using the pubsub module - * @param topic a string containing the "module_name/identifier" - * @param subscriptionType type of subscription being published - * @param moduleType type of the module model being called - * @returns a promise of type void - */ - async publish( - topic: string, - subscriptionType: SubscriptionType, - moduleType: ModuleType, - ) { - switch (subscriptionType) { - case SubscriptionType.Created: - await this.pubsub.publish(`${topic}/created`, moduleType); - break; - case SubscriptionType.Updated: - await this.pubsub.publish(`${topic}/updated`, moduleType); - break; - case SubscriptionType.Deleted: - await this.pubsub.publish(`${topic}/deleted`, moduleType); - break; - case SubscriptionType.DeleteMany: - await this.pubsub.publish(`${topic}/delete_many`, moduleType); - break; - default: - break; - } - } -} diff --git a/packages/hoppscotch-backend/src/types/custom-module-types.ts b/packages/hoppscotch-backend/src/types/custom-module-types.ts deleted file mode 100644 index 5d669e07..00000000 --- a/packages/hoppscotch-backend/src/types/custom-module-types.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { UserEnvironment } from '../user-environment/user-environments.model'; -import { User } from '../user/user.model'; - -export type CustomModuleTypes = UserEnvironment | User; diff --git a/packages/hoppscotch-backend/src/types/primitive-types.ts b/packages/hoppscotch-backend/src/types/primitive-types.ts deleted file mode 100644 index 11918cf3..00000000 --- a/packages/hoppscotch-backend/src/types/primitive-types.ts +++ /dev/null @@ -1 +0,0 @@ -export type PrimitiveTypes = number | string | boolean; diff --git a/packages/hoppscotch-backend/src/types/subscription-types.ts b/packages/hoppscotch-backend/src/types/subscription-types.ts deleted file mode 100644 index ee7ab75f..00000000 --- a/packages/hoppscotch-backend/src/types/subscription-types.ts +++ /dev/null @@ -1,7 +0,0 @@ -// Contains constants for the subscription types we use in Subscription Handler -export enum SubscriptionType { - Created = 'created', - Updated = 'updated', - Deleted = 'deleted', - DeleteMany = 'delete_many', -} diff --git a/packages/hoppscotch-backend/src/user-environment/user-environments.module.ts b/packages/hoppscotch-backend/src/user-environment/user-environments.module.ts index d82a1e89..04f39168 100644 --- a/packages/hoppscotch-backend/src/user-environment/user-environments.module.ts +++ b/packages/hoppscotch-backend/src/user-environment/user-environments.module.ts @@ -5,7 +5,6 @@ import { UserModule } from '../user/user.module'; import { UserEnvsUserResolver } from './user.resolver'; import { UserEnvironmentsResolver } from './user-environments.resolver'; import { UserEnvironmentsService } from './user-environments.service'; -import { SubscriptionHandler } from '../subscription-handler'; @Module({ imports: [PrismaModule, PubSubModule, UserModule], @@ -13,7 +12,6 @@ import { SubscriptionHandler } from '../subscription-handler'; UserEnvironmentsResolver, UserEnvironmentsService, UserEnvsUserResolver, - SubscriptionHandler, ], exports: [UserEnvironmentsService], }) diff --git a/packages/hoppscotch-backend/src/user-environment/user-environments.resolver.ts b/packages/hoppscotch-backend/src/user-environment/user-environments.resolver.ts index f053905b..cccdf11c 100644 --- a/packages/hoppscotch-backend/src/user-environment/user-environments.resolver.ts +++ b/packages/hoppscotch-backend/src/user-environment/user-environments.resolver.ts @@ -201,7 +201,7 @@ export class UserEnvironmentsResolver { @UseGuards(GqlAuthGuard) userEnvironmentDeleteMany(@GqlUser() user: User) { return this.pubsub.asyncIterator( - `user_environment/${user.uid}/delete_many`, + `user_environment/${user.uid}/deleted_many`, ); } } diff --git a/packages/hoppscotch-backend/src/user-environment/user-environments.service.spec.ts b/packages/hoppscotch-backend/src/user-environment/user-environments.service.spec.ts index 894872cd..849b589e 100644 --- a/packages/hoppscotch-backend/src/user-environment/user-environments.service.spec.ts +++ b/packages/hoppscotch-backend/src/user-environment/user-environments.service.spec.ts @@ -9,19 +9,15 @@ import { USER_ENVIRONMENT_INVALID_ENVIRONMENT_NAME, } from '../errors'; import { PubSubService } from '../pubsub/pubsub.service'; -import { SubscriptionHandler } from '../subscription-handler'; -import { SubscriptionType } from '../types/subscription-types'; const mockPrisma = mockDeep(); const mockPubSub = mockDeep(); -const mockSubscriptionHandler = mockDeep(); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const userEnvironmentsService = new UserEnvironmentsService( mockPrisma, mockPubSub as any, - mockSubscriptionHandler, ); const userPersonalEnvironments = [ @@ -245,9 +241,8 @@ describe('UserEnvironmentsService', () => { false, ); - return expect(mockSubscriptionHandler.publish).toHaveBeenCalledWith( - `user_environment/${result.userUid}`, - SubscriptionType.Created, + return expect(mockPubSub.publish).toHaveBeenCalledWith( + `user_environment/${result.userUid}/created`, result, ); }); @@ -276,9 +271,8 @@ describe('UserEnvironmentsService', () => { true, ); - return expect(mockSubscriptionHandler.publish).toHaveBeenCalledWith( - `user_environment/${result.userUid}`, - SubscriptionType.Created, + return expect(mockPubSub.publish).toHaveBeenCalledWith( + `user_environment/${result.userUid}/created`, result, ); }); @@ -374,9 +368,8 @@ describe('UserEnvironmentsService', () => { '[{}]', ); - return expect(mockSubscriptionHandler.publish).toHaveBeenCalledWith( - `user_environment/${result.id}`, - SubscriptionType.Updated, + return expect(mockPubSub.publish).toHaveBeenCalledWith( + `user_environment/${result.id}/updated`, result, ); }); @@ -404,9 +397,8 @@ describe('UserEnvironmentsService', () => { '[{}]', ); - return expect(mockSubscriptionHandler.publish).toHaveBeenCalledWith( - `user_environment/${result.id}`, - SubscriptionType.Updated, + return expect(mockPubSub.publish).toHaveBeenCalledWith( + `user_environment/${result.id}/updated`, result, ); }); @@ -470,9 +462,8 @@ describe('UserEnvironmentsService', () => { await userEnvironmentsService.deleteUserEnvironment('abc123', 'env1'); - return expect(mockSubscriptionHandler.publish).toHaveBeenCalledWith( - `user_environment/${result.id}`, - SubscriptionType.Deleted, + return expect(mockPubSub.publish).toHaveBeenCalledWith( + `user_environment/${result.id}/deleted`, result, ); }); @@ -486,9 +477,8 @@ describe('UserEnvironmentsService', () => { await userEnvironmentsService.deleteUserEnvironments('abc123'); - return expect(mockSubscriptionHandler.publish).toHaveBeenCalledWith( - `user_environment/abc123`, - SubscriptionType.DeleteMany, + return expect(mockPubSub.publish).toHaveBeenCalledWith( + `user_environment/${'abc123'}/deleted_many`, 1, ); }); @@ -566,9 +556,8 @@ describe('UserEnvironmentsService', () => { await userEnvironmentsService.clearGlobalEnvironments('abc123', 'env1'); - return expect(mockSubscriptionHandler.publish).toHaveBeenCalledWith( - `user_environment/${result.id}`, - SubscriptionType.Updated, + return expect(mockPubSub.publish).toHaveBeenCalledWith( + `user_environment/${result.id}/updated`, result, ); }); diff --git a/packages/hoppscotch-backend/src/user-environment/user-environments.service.ts b/packages/hoppscotch-backend/src/user-environment/user-environments.service.ts index a08549e0..9daa9cb4 100644 --- a/packages/hoppscotch-backend/src/user-environment/user-environments.service.ts +++ b/packages/hoppscotch-backend/src/user-environment/user-environments.service.ts @@ -13,8 +13,6 @@ import { USER_ENVIRONMENT_UPDATE_FAILED, USER_ENVIRONMENT_INVALID_ENVIRONMENT_NAME, } from '../errors'; -import { SubscriptionHandler } from '../subscription-handler'; -import { SubscriptionType } from '../types/subscription-types'; import { stringToJson } from '../utils'; @Injectable() @@ -22,7 +20,6 @@ export class UserEnvironmentsService { constructor( private readonly prisma: PrismaService, private readonly pubsub: PubSubService, - private readonly subscriptionHandler: SubscriptionHandler, ) {} /** @@ -119,9 +116,8 @@ export class UserEnvironmentsService { isGlobal: createdEnvironment.isGlobal, }; // Publish subscription for environment creation - await this.subscriptionHandler.publish( - `user_environment/${userEnvironment.userUid}`, - SubscriptionType.Created, + await this.pubsub.publish( + `user_environment/${userEnvironment.userUid}/created`, userEnvironment, ); return E.right(userEnvironment); @@ -154,9 +150,8 @@ export class UserEnvironmentsService { isGlobal: updatedEnvironment.isGlobal, }; // Publish subscription for environment update - await this.subscriptionHandler.publish( - `user_environment/${updatedUserEnvironment.id}`, - SubscriptionType.Updated, + await this.pubsub.publish( + `user_environment/${updatedUserEnvironment.id}/updated`, updatedUserEnvironment, ); return E.right(updatedUserEnvironment); @@ -196,9 +191,8 @@ export class UserEnvironmentsService { }; // Publish subscription for environment deletion - await this.subscriptionHandler.publish( - `user_environment/${deletedUserEnvironment.id}`, - SubscriptionType.Deleted, + await this.pubsub.publish( + `user_environment/${deletedUserEnvironment.id}/deleted`, deletedUserEnvironment, ); return E.right(true); @@ -220,9 +214,9 @@ export class UserEnvironmentsService { }, }); - await this.subscriptionHandler.publish( - `user_environment/${uid}`, - SubscriptionType.DeleteMany, + // Publish subscription for multiple environment deletions + await this.pubsub.publish( + `user_environment/${uid}/deleted_many`, deletedEnvironments.count, ); @@ -258,9 +252,8 @@ export class UserEnvironmentsService { }; // Publish subscription for environment update - await this.subscriptionHandler.publish( - `user_environment/${updatedUserEnvironment.id}`, - SubscriptionType.Updated, + await this.pubsub.publish( + `user_environment/${updatedUserEnvironment.id}/updated`, updatedUserEnvironment, ); return E.right(updatedUserEnvironment);