1+ import { RedisService } from '@liaoliaots/nestjs-redis' ;
12import { BadRequestException , Injectable , InternalServerErrorException , Logger } from '@nestjs/common' ;
23import { OnEvent } from '@nestjs/event-emitter' ;
4+ import Redis from 'ioredis' ;
35
46import { AuthService } from '../../../auth/service/auth.service' ;
57import { EventService } from '../../event/service/event.service' ;
68import { UserService } from '../../user/service/user.service' ;
79import { BookingAdmissionStatusDto } from '../dto/bookingAdmissionStatus.dto' ;
810import { ServerTimeDto } from '../dto/serverTime.dto' ;
911
12+ import { BookingSeatsService } from './booking-seats.service' ;
13+ import { EnterBookingService } from './enter-booking.service' ;
1014import { InBookingService } from './in-booking.service' ;
1115import { OpenBookingService } from './open-booking.service' ;
1216import { WaitingQueueService } from './waiting-queue.service' ;
@@ -16,30 +20,84 @@ const OFFSET = 1000 * 60 * 60 * 9;
1620@Injectable ( )
1721export class BookingService {
1822 private logger = new Logger ( BookingService . name ) ;
23+ private readonly redis : Redis | null ;
1924 constructor (
25+ private readonly redisService : RedisService ,
2026 private readonly eventService : EventService ,
2127 private readonly authService : AuthService ,
28+ private readonly bookingSeatsService : BookingSeatsService ,
2229 private readonly inBookingService : InBookingService ,
2330 private readonly openBookingService : OpenBookingService ,
2431 private readonly waitingQueueService : WaitingQueueService ,
2532 private readonly userService : UserService ,
26- ) { }
33+ private readonly enterBookingService : EnterBookingService ,
34+ ) {
35+ this . redis = this . redisService . getOrThrow ( ) ;
36+ }
2737
2838 @OnEvent ( 'seats-sse-close' )
29- async letInNextWaiting ( event : { sid : string } ) {
30- const eventId = await this . userService . getUserEventTarget ( event . sid ) ;
31- if ( ( await this . waitingQueueService . getQueueSize ( eventId ) ) < 1 ) {
32- return ;
39+ async onSeatsSseDisconnected ( event : { sid : string } ) {
40+ const sid = event . sid ;
41+ const eventId = await this . userService . getUserEventTarget ( sid ) ;
42+ await this . collectSeatsIfNotSaved ( eventId , sid ) ;
43+ await this . inBookingService . emitSession ( sid ) ;
44+ await this . letInNextWaiting ( eventId ) ;
45+ }
46+
47+ private async collectSeatsIfNotSaved ( eventId : number , sid : string ) {
48+ const inBookingSession = await this . inBookingService . getSession ( eventId , sid ) ;
49+ if ( inBookingSession && ! inBookingSession . saved ) {
50+ const bookedSeats = inBookingSession . bookedSeats ;
51+ bookedSeats . forEach ( ( seat ) => {
52+ this . bookingSeatsService . updateSeatDeleted ( eventId , seat ) ;
53+ } ) ;
54+ inBookingSession . bookedSeats = [ ] ;
55+ await this . inBookingService . setSession ( eventId , inBookingSession ) ;
3356 }
34- if ( await this . inBookingService . isInsertable ( eventId ) ) {
57+ }
58+
59+ @OnEvent ( 'entering-sessions-gc' )
60+ async onEnteringSessionsGc ( event : { eventId : number } ) {
61+ await this . letInNextWaiting ( event . eventId ) ;
62+ }
63+
64+ @OnEvent ( 'in-booking-max-size-changed' )
65+ async onSpecificInBookingMaxSizeChanged ( event : { eventId : number } ) {
66+ await this . letInNextWaiting ( event . eventId ) ;
67+ }
68+
69+ @OnEvent ( 'all-in-booking-max-size-changed' )
70+ async onAllInBookingMaxSizeChanged ( ) {
71+ const eventIds = await this . openBookingService . getOpenedEventIds ( ) ;
72+ await Promise . all (
73+ eventIds . map ( async ( eventId ) => {
74+ await this . letInNextWaiting ( eventId ) ;
75+ } ) ,
76+ ) ;
77+ }
78+
79+ private async letInNextWaiting ( eventId : number ) {
80+ const isQueueEmpty = async ( eventId : number ) =>
81+ ( await this . waitingQueueService . getQueueSize ( eventId ) ) < 1 ;
82+ while ( ! ( await isQueueEmpty ( eventId ) ) && ( await this . isInsertableInBooking ( eventId ) ) ) {
3583 const item = await this . waitingQueueService . popQueue ( eventId ) ;
3684 if ( ! item ) {
37- return ;
85+ break ;
3886 }
39- await this . authService . setUserStatusSelectingSeat ( item . sid ) ;
87+ await this . enterBookingService . addEnteringSession ( item . sid ) ;
88+ await this . authService . setUserStatusEntering ( item . sid ) ;
4089 }
4190 }
4291
92+ async setInBookingFromEntering ( sid : string ) {
93+ const eventId = await this . userService . getUserEventTarget ( sid ) ;
94+ const bookingAmount = await this . enterBookingService . getBookingAmount ( sid ) ;
95+
96+ await this . enterBookingService . removeEnteringSession ( sid ) ;
97+ await this . inBookingService . insertInBooking ( eventId , sid , bookingAmount ) ;
98+ await this . authService . setUserStatusSelectingSeat ( sid ) ;
99+ }
100+
43101 // 함수 이름 생각하기
44102 async isAdmission ( eventId : number , sid : string ) : Promise < BookingAdmissionStatusDto > {
45103 // eventId를 받아서 해당 이벤트가 존재하는지 확인한다.
@@ -61,10 +119,12 @@ export class BookingService {
61119 }
62120
63121 private async getForwarded ( sid : string ) {
64- const isEntered = await this . inBookingService . insertIfPossible ( sid ) ;
122+ const eventId = await this . userService . getUserEventTarget ( sid ) ;
123+ const isInsertable = await this . isInsertableInBooking ( eventId ) ;
65124
66- if ( isEntered ) {
67- await this . authService . setUserStatusSelectingSeat ( sid ) ;
125+ if ( isInsertable ) {
126+ await this . enterBookingService . addEnteringSession ( sid ) ;
127+ await this . authService . setUserStatusEntering ( sid ) ;
68128 return {
69129 waitingStatus : false ,
70130 enteringStatus : true ,
@@ -80,6 +140,21 @@ export class BookingService {
80140 } ;
81141 }
82142
143+ private async isInsertableInBooking ( eventId : number ) : Promise < boolean > {
144+ const inBookingCount = await this . inBookingService . getInBookingSessionCount ( eventId ) ;
145+ const enteringCount = await this . enterBookingService . getEnteringSessionCount ( eventId ) ;
146+ const maxSize = await this . inBookingService . getInBookingSessionsMaxSize ( eventId ) ;
147+ return inBookingCount + enteringCount < maxSize ;
148+ }
149+
150+ async setBookingAmount ( sid : string , bookingAmount : number ) {
151+ const isInBooking = await this . inBookingService . isInBooking ( sid ) ;
152+ if ( isInBooking ) {
153+ return await this . inBookingService . setBookingAmount ( sid , bookingAmount ) ;
154+ }
155+ return await this . enterBookingService . setBookingAmount ( sid , bookingAmount ) ;
156+ }
157+
83158 async getTimeMs ( ) : Promise < ServerTimeDto > {
84159 try {
85160 return {
0 commit comments