From a293cdc04c1141bddb813ed8750c331e9ffca06a Mon Sep 17 00:00:00 2001 From: harshithnrao Date: Tue, 25 Mar 2025 17:10:22 +0530 Subject: [PATCH] redis with ttl socketio for bookticket --- package-lock.json | 270 ++++++++++++++++++ package.json | 2 + src/app.module.ts | 4 +- src/booking-gateway/booking-gateway.module.ts | 11 + src/booking-gateway/booking.gateway.ts | 45 +++ src/booking-gateway/booking.service.ts | 31 ++ src/redis/redis.controller.ts | 23 +- src/redis/redis.service.ts | 15 + src/seat/seat.entity.ts | 4 + src/seat/seat.service.ts | 12 +- src/ticket/ticket.service.ts | 4 + 11 files changed, 411 insertions(+), 10 deletions(-) create mode 100644 src/booking-gateway/booking-gateway.module.ts create mode 100644 src/booking-gateway/booking.gateway.ts create mode 100644 src/booking-gateway/booking.service.ts diff --git a/package-lock.json b/package-lock.json index e4b67e3..ac9238a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "@nestjs/platform-express": "^10.0.0", "@nestjs/swagger": "^8.1.1", "@nestjs/typeorm": "^10.0.1", + "@nestjs/websockets": "^10.4.15", "dotenv": "^16.3.1", "handlebars": "^4.7.8", "ioredis": "^5.6.0", @@ -30,6 +31,7 @@ "rxjs": "^7.8.1", "sequelize": "^6.35.2", "sequelize-typescript": "^2.1.6", + "socket.io": "^4.8.1", "typeorm": "^0.3.17", "web-push": "^3.6.7" }, @@ -2022,6 +2024,35 @@ "typeorm": "^0.3.0" } }, + "node_modules/@nestjs/websockets": { + "version": "10.4.15", + "resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-10.4.15.tgz", + "integrity": "sha512-OmCUJwvtagzXfMVko595O98UI3M9zg+URL+/HV7vd3QPMCZ3uGCKSq15YYJ99LHJn9NyK4e4Szm2KnHtUg2QzA==", + "license": "MIT", + "dependencies": { + "iterare": "1.2.1", + "object-hash": "3.0.0", + "tslib": "2.8.1" + }, + "peerDependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/core": "^10.0.0", + "@nestjs/platform-socket.io": "^10.0.0", + "reflect-metadata": "^0.1.12 || ^0.2.0", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "@nestjs/platform-socket.io": { + "optional": true + } + } + }, + "node_modules/@nestjs/websockets/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2127,6 +2158,12 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, "node_modules/@sqltools/formatter": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", @@ -2222,6 +2259,15 @@ "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", "dev": true }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -3326,6 +3372,15 @@ } ] }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "license": "MIT", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -4411,6 +4466,44 @@ "node": ">= 0.8" } }, + "node_modules/engine.io": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", + "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", + "license": "MIT", + "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/enhanced-resolve": { "version": "5.18.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", @@ -7494,6 +7587,15 @@ "node": ">=0.10.0" } }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -8970,6 +9072,47 @@ "node": ">=8" } }, + "node_modules/socket.io": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", + "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "license": "MIT", + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.17.1" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/source-map": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", @@ -10451,6 +10594,27 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -11901,6 +12065,23 @@ "uuid": "9.0.1" } }, + "@nestjs/websockets": { + "version": "10.4.15", + "resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-10.4.15.tgz", + "integrity": "sha512-OmCUJwvtagzXfMVko595O98UI3M9zg+URL+/HV7vd3QPMCZ3uGCKSq15YYJ99LHJn9NyK4e4Szm2KnHtUg2QzA==", + "requires": { + "iterare": "1.2.1", + "object-hash": "3.0.0", + "tslib": "2.8.1" + }, + "dependencies": { + "tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + } + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -11979,6 +12160,11 @@ "@sinonjs/commons": "^3.0.0" } }, + "@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" + }, "@sqltools/formatter": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", @@ -12074,6 +12260,14 @@ "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", "dev": true }, + "@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "requires": { + "@types/node": "*" + } + }, "@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -12930,6 +13124,11 @@ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -13676,6 +13875,34 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" }, + "engine.io": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", + "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", + "requires": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, + "dependencies": { + "cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==" + } + } + }, + "engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==" + }, "enhanced-resolve": { "version": "5.18.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", @@ -15947,6 +16174,11 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, + "object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==" + }, "object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -16973,6 +17205,38 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, + "socket.io": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", + "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", + "requires": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + } + }, + "socket.io-adapter": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "requires": { + "debug": "~4.3.4", + "ws": "~8.17.1" + } + }, + "socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + } + }, "source-map": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", @@ -17946,6 +18210,12 @@ } } }, + "ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "requires": {} + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index 395f130..abb3aeb 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "@nestjs/platform-express": "^10.0.0", "@nestjs/swagger": "^8.1.1", "@nestjs/typeorm": "^10.0.1", + "@nestjs/websockets": "^10.4.15", "dotenv": "^16.3.1", "handlebars": "^4.7.8", "ioredis": "^5.6.0", @@ -44,6 +45,7 @@ "rxjs": "^7.8.1", "sequelize": "^6.35.2", "sequelize-typescript": "^2.1.6", + "socket.io": "^4.8.1", "typeorm": "^0.3.17", "web-push": "^3.6.7" }, diff --git a/src/app.module.ts b/src/app.module.ts index 9d14597..1ae74aa 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -22,6 +22,7 @@ import { TicketPricingModule } from './ticketPricing/ticketPricing.module'; import { TimeSlotModule } from './timeSlot/timeSlot.module'; import { PushSubscriptionModule } from './push-subscription/push-subscription.module'; import { RedisModule } from './redis/redis.module'; +import { BookingGatewayModule } from './booking-gateway/booking-gateway.module'; @Module({ imports: [ @@ -42,7 +43,8 @@ import { RedisModule } from './redis/redis.module'; TimeSlotModule, UserModule, PushSubscriptionModule, - RedisModule + RedisModule, + BookingGatewayModule ], controllers: [AppController, AppConfigController], diff --git a/src/booking-gateway/booking-gateway.module.ts b/src/booking-gateway/booking-gateway.module.ts new file mode 100644 index 0000000..5e3105f --- /dev/null +++ b/src/booking-gateway/booking-gateway.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { BookingGateway } from './booking.gateway'; +import { BookingService } from './booking.service'; +import { SeatService } from 'src/seat/seat.service'; + +@Module({ + providers: [BookingGateway, BookingService], + exports: [BookingService], + imports: [SeatService] +}) +export class BookingGatewayModule { } diff --git a/src/booking-gateway/booking.gateway.ts b/src/booking-gateway/booking.gateway.ts new file mode 100644 index 0000000..0d5b538 --- /dev/null +++ b/src/booking-gateway/booking.gateway.ts @@ -0,0 +1,45 @@ +import { WebSocketServer, OnGatewayConnection, OnGatewayDisconnect, SubscribeMessage, MessageBody, WebSocketGateway } from '@nestjs/websockets'; +import { Server, Socket } from 'socket.io'; +import { BookingService } from './booking.service'; +import Ticket from 'src/ticket/ticket.entity'; + +@WebSocketGateway() +export class BookingGateway implements OnGatewayConnection, OnGatewayDisconnect { + + constructor(private readonly bookingService: BookingService) { } + + @WebSocketServer() + server: Server; + + private connectedClients = 0; + + handleConnection(client: Socket) { + this.connectedClients++; + console.log(`Client connected: ${client.id}`); + this.server.emit('clientsUpdated', this.connectedClients); + } + + handleDisconnect(client: Socket) { + this.connectedClients--; + console.log(`Client disconnected: ${client.id}`); + this.server.emit('clientsUpdated', this.connectedClients); + } + + @SubscribeMessage('bookTciket') + async handleBookTicket(@MessageBody() ticket: Ticket) { + const response = await this.bookingService.bookTicket(ticket); + this.server.emit('ticketBooked', response); + } + @SubscribeMessage('checkSeatAvailability') + async handleCheckSeatAvailability(@MessageBody() data: { event_id: number, seatNumber: string }) { + const { event_id: eventId, seatNumber } = data; + const isAvailable = await this.bookingService.isSeatAvailable(eventId, seatNumber); + this.server.emit('seatAvailability', { isAvailable }); + } + + @SubscribeMessage('getBookedSeats') + async handleGetBookedSeats(@MessageBody() movieId: string) { + const bookedSeats = await this.bookingService.getBookedSeats(movieId); + this.server.emit('bookedSeatsList', bookedSeats); + } +} diff --git a/src/booking-gateway/booking.service.ts b/src/booking-gateway/booking.service.ts new file mode 100644 index 0000000..dbd0cc6 --- /dev/null +++ b/src/booking-gateway/booking.service.ts @@ -0,0 +1,31 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { BookingGateway } from './booking.gateway'; +import { SeatService } from 'src/seat/seat.service'; +import { TicketService } from 'src/ticket/ticket.service'; +import Ticket from 'src/ticket/ticket.entity'; +import Seat from 'src/seat/seat.entity'; + +@Injectable() +export class BookingService { + constructor( + @Inject('BookingGateway') private readonly bookingGateway: BookingGateway, + private readonly seatService: SeatService, + private readonly ticketService: TicketService + ) { } + + async bookTicket(ticket: Ticket) { + this.ticketService.upsert(ticket, true); + this.seatService.bookSeat(ticket.eventId, ticket.seatNumber); + } + async getBookedSeats(event_id) { + const bookedSeats = await this.seatService.filter(new Seat({ eventId: event_id, available: 'booked' })); + return bookedSeats; + } + async isSeatAvailable(event_id: number, seatNumber: string) { + const seat = await this.seatService.findOne(new Seat({ eventId: event_id, seatNumber: seatNumber })); + if (seat.available === 'booked') { + return false; + } + return true; + } +} diff --git a/src/redis/redis.controller.ts b/src/redis/redis.controller.ts index d40308d..fa6a91f 100644 --- a/src/redis/redis.controller.ts +++ b/src/redis/redis.controller.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Param, Post, Body } from '@nestjs/common'; +import { Controller, Get, Param, Post, Body, Delete } from '@nestjs/common'; import { RedisService } from './redis.service'; @Controller('redis') @@ -6,8 +6,13 @@ export class RedisController { constructor(private readonly redisService: RedisService) { } @Post('set') - async setValue(@Body() body: { key: string; value: string }) { - await this.redisService.set(body.key, body.value); + async setValue(@Body() body: { key: string, value: string, ttl?: number }) { + if (body.ttl) { + await this.redisService.setTimed(body.key, body.value, body.ttl); + } + else { + await this.redisService.set(body.key, body.value); + } return { message: 'Value set in Redis' }; } @@ -16,4 +21,16 @@ export class RedisController { const value = await this.redisService.get(key); return { value }; } + + @Delete('del/:key') + async deleteValue(@Param('key') key: string) { + await this.redisService.del(key); + return { message: 'Value deleted from Redis' }; + } + + @Delete('flushall') + async flushall() { + await this.redisService.flushall(); + return { message: 'Redis flushed' }; + } } diff --git a/src/redis/redis.service.ts b/src/redis/redis.service.ts index cd60b3a..19ec639 100644 --- a/src/redis/redis.service.ts +++ b/src/redis/redis.service.ts @@ -10,6 +10,21 @@ export class RedisService { await client.set(key, value, ); } + async del(key: string): Promise { + const client = this.redisProvider.client; + await client.del(key); + } + + async flushall(): Promise { + const client = this.redisProvider.client; + await client.flushall(); + } + + async setTimed(key: string, value: string, ttl: number): Promise { + const client = this.redisProvider.client; + await client.set(key, value, 'EX', ttl); + } + async get(key: string): Promise { const client = this.redisProvider.client; return client.get(key); diff --git a/src/seat/seat.entity.ts b/src/seat/seat.entity.ts index 4950825..f13cb24 100644 --- a/src/seat/seat.entity.ts +++ b/src/seat/seat.entity.ts @@ -20,6 +20,10 @@ export default class Seat extends Model { @Column({ type: DataType.TEXT, field: 'column' }) column: string; + @ApiProperty({ type: String }) + @Column({ type: DataType.TEXT, field: 'available' }) + available: string; + @ApiProperty({ type: String }) @Column({ type: DataType.TEXT, field: 'status' }) status: string; diff --git a/src/seat/seat.service.ts b/src/seat/seat.service.ts index 27d59d0..125bcb7 100644 --- a/src/seat/seat.service.ts +++ b/src/seat/seat.service.ts @@ -14,9 +14,7 @@ export class SeatService { async findByPk(id: number): Promise { - const seat = Seat.findByPk(id,) - // //const textbookExists = await this.checkTextbookExists((await seat).textbookId); - + const seat = Seat.findByPk(id,) return seat } @@ -32,6 +30,10 @@ export class SeatService { return Seat.destroy({ where: { id: id } }); } + async bookSeat(eventId: number, seatNumber: string) { + return Seat.update({ awailable: 'booked' }, { where: { eventId: eventId, seatNumber: seatNumber } }); + } + async upsert(seat: Seat, insertIfNotFound: boolean): Promise { if (seat.id) { const existingSeat = await this.findByPk(seat.id); @@ -39,9 +41,7 @@ export class SeatService { return Seat.update(seat, { where: { id: seat.id } }); } } - if (insertIfNotFound) { - //const textbookExists = await this.checkTextbookExists(seat.textbookId); - + if (insertIfNotFound) { return Seat.create(seat as any) } } diff --git a/src/ticket/ticket.service.ts b/src/ticket/ticket.service.ts index 01cbfd8..e14405a 100644 --- a/src/ticket/ticket.service.ts +++ b/src/ticket/ticket.service.ts @@ -46,4 +46,8 @@ export class TicketService { } } + // async assignTicketToUser(ticketId: number, userId: number): Promise { + // return Ticket.update({ userId: userId }, { where: { id: ticketId } }); + // } + }