1
+ /* eslint-disable @typescript-eslint/ban-types */
1
2
/* eslint-disable @typescript-eslint/ban-ts-comment */
2
3
import {
3
4
BadRequestException ,
4
5
ForbiddenException ,
5
6
Inject ,
6
7
Injectable ,
8
+ InternalServerErrorException ,
7
9
forwardRef ,
8
10
} from '@nestjs/common' ;
9
11
import { OrderEntity } from './entities/order.entity' ;
@@ -19,6 +21,8 @@ import { IOrdersByCartTimestamp } from 'src/static/interfaces/orders.interfaces'
19
21
import { UsersService } from 'src/users/users.service' ;
20
22
import { CloseOrdersDto } from './dto/close-order.dto' ;
21
23
import { TelegramBotService } from 'src/telegram-bot/telegram-bot.service' ;
24
+ import { UserEntity } from 'src/users/entities/user.entity' ;
25
+ import { Role } from 'src/static/enums/users.enum' ;
22
26
23
27
@Injectable ( )
24
28
export class OrdersService {
@@ -30,8 +34,11 @@ export class OrdersService {
30
34
private readonly usersService : UsersService ,
31
35
@Inject ( forwardRef ( ( ) => TelegramBotService ) )
32
36
private readonly telegramBotService : TelegramBotService ,
33
- ) { }
37
+ ) {
38
+ this . timestampsTasksQueue = new OrdersTasksQueue ( ) ;
39
+ }
34
40
41
+ readonly timestampsTasksQueue : OrdersTasksQueue ;
35
42
readonly cacheKeys : ICacheKeys = this . cacheService . cacheKeys ( ) ;
36
43
37
44
async confirmCart (
@@ -74,6 +81,18 @@ export class OrdersService {
74
81
return this . findOneById ( result . id ) ;
75
82
} ) ,
76
83
this . usersService . clearCart ( userId ) ,
84
+ ...( await this . usersService . findAll ( ) )
85
+ . map ( ( user : UserEntity ) => {
86
+ if ( user . telegramUserId && user . role === Role . Deliver ) {
87
+ return this . telegramBotService . newOrderNotification (
88
+ user . telegramUserId ,
89
+ now ,
90
+ ) ;
91
+ } else {
92
+ return undefined ;
93
+ }
94
+ } )
95
+ . filter ( ( promise ) => promise !== undefined ) ,
77
96
] ) ;
78
97
79
98
return Promise . all (
@@ -102,46 +121,49 @@ export class OrdersService {
102
121
throw new BadRequestException ( ExceptionMessages . OrderAlreadyTaken ) ;
103
122
}
104
123
105
- const workerUser = await this . usersService . findById ( orders [ 0 ] . creator . id ) ;
106
- const workerNotification = workerUser . telegramUserId
107
- ? this . telegramBotService . sendOrderTakenByNotification (
108
- workerUser . telegramUserId ,
109
- orders [ 0 ] . cartTimestamp ,
110
- )
111
- : async ( ) => { } ;
112
-
113
- await Promise . all ( [
114
- ...orders . map ( ( order ) => {
115
- return this . repository . update (
116
- {
117
- id : order . id ,
118
- } ,
119
- {
120
- takenBy : {
121
- id : userId ,
124
+ return await this . timestampsTasksQueue . addToQueue < boolean > ( async ( ) => {
125
+ // пока не нужно
126
+ // const workerUser = await this.usersService.findById(orders[0].creator.id);
127
+ // const workerNotification = workerUser.telegramUserId
128
+ // ? this.telegramBotService.sendOrderTakenByNotification(
129
+ // workerUser.telegramUserId,
130
+ // orders[0].cartTimestamp,
131
+ // )
132
+ // : async () => {};
133
+
134
+ await Promise . all ( [
135
+ ...orders . map ( ( order ) => {
136
+ return this . repository . update (
137
+ {
138
+ id : order . id ,
122
139
} ,
123
- } ,
140
+ {
141
+ takenBy : {
142
+ id : userId ,
143
+ } ,
144
+ } ,
145
+ ) ;
146
+ } ) ,
147
+ // workerNotification,
148
+ ] ) ;
149
+
150
+ const timestamp = new Date ( cartTimestamp ) ;
151
+ const allPromises : Promise < void > [ ] = [ ] ;
152
+ orders . forEach ( ( order ) => {
153
+ allPromises . push (
154
+ this . cacheService . del ( this . cacheKeys . orderById ( order . id ) ) ,
124
155
) ;
125
- } ) ,
126
- workerNotification ,
127
- ] ) ;
128
-
129
- const timestamp = new Date ( cartTimestamp ) ;
130
- const allPromises : Promise < void > [ ] = [ ] ;
131
- orders . forEach ( ( order ) => {
132
- allPromises . push (
133
- this . cacheService . del ( this . cacheKeys . orderById ( order . id ) ) ,
134
- ) ;
135
- allPromises . push (
136
- this . cacheService . del (
137
- this . cacheKeys . ordersByCartTimestamp ( timestamp . getTime ( ) ) ,
138
- ) ,
139
- ) ;
140
- } ) ;
141
- allPromises . push ( this . cacheService . del ( this . cacheKeys . allOrders ( ) ) ) ;
142
- await Promise . all ( allPromises ) ;
156
+ allPromises . push (
157
+ this . cacheService . del (
158
+ this . cacheKeys . ordersByCartTimestamp ( timestamp . getTime ( ) ) ,
159
+ ) ,
160
+ ) ;
161
+ } ) ;
162
+ allPromises . push ( this . cacheService . del ( this . cacheKeys . allOrders ( ) ) ) ;
163
+ await Promise . all ( allPromises ) ;
143
164
144
- return true ;
165
+ return true ;
166
+ } , cartTimestamp ) ;
145
167
}
146
168
147
169
async closeOrders (
@@ -167,23 +189,24 @@ export class OrdersService {
167
189
throw new ForbiddenException ( ExceptionMessages . IncorrectCloseOrdersDto ) ;
168
190
}
169
191
170
- const workerUser = await this . usersService . findById ( orders [ 0 ] . creator . id ) ;
171
- let workerNotification ;
172
- if ( workerUser . telegramUserId ) {
173
- if ( isFinishedNotCancel ) {
174
- workerNotification =
175
- this . telegramBotService . sendOrderFinishedNotification (
176
- workerUser . telegramUserId ,
177
- orders [ 0 ] . cartTimestamp ,
178
- ) ;
179
- } else {
180
- workerNotification =
181
- this . telegramBotService . sendOrderCanceledNotification (
182
- workerUser . telegramUserId ,
183
- orders [ 0 ] . cartTimestamp ,
184
- ) ;
185
- }
186
- }
192
+ // пока не нужно
193
+ // const workerUser = await this.usersService.findById(orders[0].creator.id);
194
+ // let workerNotification;
195
+ // if (workerUser.telegramUserId) {
196
+ // if (isFinishedNotCancel) {
197
+ // workerNotification =
198
+ // this.telegramBotService.sendOrderFinishedNotification(
199
+ // workerUser.telegramUserId,
200
+ // orders[0].cartTimestamp,
201
+ // );
202
+ // } else {
203
+ // workerNotification =
204
+ // this.telegramBotService.sendOrderCanceledNotification(
205
+ // workerUser.telegramUserId,
206
+ // orders[0].cartTimestamp,
207
+ // );
208
+ // }
209
+ // }
187
210
188
211
await Promise . all ( [
189
212
...orders . map ( ( order , index ) => {
@@ -219,7 +242,7 @@ export class OrdersService {
219
242
} ,
220
243
) ;
221
244
} ) ,
222
- workerNotification ,
245
+ // workerNotification,
223
246
] ) ;
224
247
225
248
const timestamp = new Date ( cartTimestamp ) ;
@@ -454,3 +477,148 @@ export class OrdersService {
454
477
return result ;
455
478
}
456
479
}
480
+
481
+ class OrdersTasksQueue {
482
+ constructor ( ) {
483
+ this . queue = [ ] ;
484
+ }
485
+
486
+ private readonly queue : ITimestampScope [ ] ;
487
+
488
+ public async addToQueue < T > ( fnc : Function , timestamp : string ) : Promise < T > {
489
+ if ( ! timestamp ) {
490
+ throw new InternalServerErrorException ( ) ;
491
+ }
492
+
493
+ let exist : boolean = false ;
494
+ let nearestEmptyIndexInQueue : number = - 1 ;
495
+ let queueIndex : number = - 1 ;
496
+ let taskIndex : number = - 1 ;
497
+
498
+ const newScope : ITimestampScope = {
499
+ timestamp,
500
+ tasks : [
501
+ {
502
+ function : fnc ,
503
+ solved : false ,
504
+ } ,
505
+ ] ,
506
+ working : false ,
507
+ } ;
508
+
509
+ this . queue . every ( ( scope : ITimestampScope , index : number ) => {
510
+ if ( nearestEmptyIndexInQueue === - 1 && this . queue [ index ] === undefined ) {
511
+ nearestEmptyIndexInQueue = index ;
512
+ }
513
+ if ( scope . timestamp === timestamp ) {
514
+ queueIndex = index ;
515
+ taskIndex = this . queue [ index ] . tasks . push ( newScope . tasks [ 0 ] ) - 1 ;
516
+ exist = true ;
517
+ return false ;
518
+ }
519
+
520
+ return true ;
521
+ } ) ;
522
+
523
+ if ( ! exist ) {
524
+ if ( nearestEmptyIndexInQueue >= 0 ) {
525
+ queueIndex = nearestEmptyIndexInQueue ;
526
+ this . queue [ nearestEmptyIndexInQueue ] = newScope ;
527
+ } else {
528
+ queueIndex = this . queue . push ( newScope ) - 1 ;
529
+ taskIndex = 0 ;
530
+ }
531
+ }
532
+
533
+ return new Promise ( ( resolve , reject ) => {
534
+ this . findAndStartNotWorkingScope ( queueIndex ) ;
535
+ const interval = setInterval ( ( ) => {
536
+ if ( ! this . queue [ queueIndex ] ) {
537
+ clearInterval ( interval ) ;
538
+ return reject (
539
+ `Timestamp Scope from this index (${ queueIndex } ) was been deleted!` ,
540
+ ) ;
541
+ }
542
+
543
+ if ( this . queue [ queueIndex ] . tasks [ taskIndex ] . error ) {
544
+ clearInterval ( interval ) ;
545
+ return reject ( this . queue [ queueIndex ] . tasks [ taskIndex ] . error ) ;
546
+ }
547
+
548
+ if ( this . queue [ queueIndex ] . tasks [ taskIndex ] . solved ) {
549
+ clearInterval ( interval ) ;
550
+ return resolve ( this . queue [ queueIndex ] . tasks [ taskIndex ] . result ) ;
551
+ }
552
+ } , 25 ) ;
553
+ } ) ;
554
+ }
555
+
556
+ private findAndStartNotWorkingScope ( queueIndex : number ) : void {
557
+ if ( this . queue [ queueIndex ] . working ) {
558
+ return ;
559
+ }
560
+
561
+ this . queue [ queueIndex ] . working = true ;
562
+
563
+ this . queue [ queueIndex ] . tasks . every ( ( task : ITimestampFunction , index ) => {
564
+ if ( task . solved ) {
565
+ return true ;
566
+ }
567
+
568
+ task
569
+ . function ( )
570
+ . then ( ( result : any ) => {
571
+ this . queue [ queueIndex ] . tasks [ index ] . result = result ;
572
+ } )
573
+ . catch ( ( err : any ) => {
574
+ this . queue [ queueIndex ] . tasks [ index ] . error = err ;
575
+ } )
576
+ . finally ( ( ) => {
577
+ this . queue [ queueIndex ] . tasks [ index ] . solved = true ;
578
+ let allSolved : boolean = true ;
579
+ this . queue [ queueIndex ] . tasks . every ( ( task ) => {
580
+ if ( task . solved === false ) {
581
+ allSolved = false ;
582
+ return false ;
583
+ }
584
+
585
+ return true ;
586
+ } ) ;
587
+
588
+ this . queue [ queueIndex ] . working = false ;
589
+
590
+ if ( ! allSolved ) {
591
+ this . findAndStartNotWorkingScope ( queueIndex ) ;
592
+ }
593
+ } ) ;
594
+
595
+ return false ;
596
+ } ) ;
597
+ }
598
+
599
+ public removeFromQueue ( timestamp : string ) : void {
600
+ let index : number ;
601
+ this . queue . every ( ( scope , _index ) => {
602
+ if ( scope . timestamp === timestamp ) {
603
+ index = _index ;
604
+ }
605
+ } ) ;
606
+
607
+ if ( index ) {
608
+ delete this . queue [ index ] ;
609
+ }
610
+ }
611
+ }
612
+
613
+ interface ITimestampScope {
614
+ timestamp : string ;
615
+ tasks : ITimestampFunction [ ] ;
616
+ working : boolean ;
617
+ }
618
+
619
+ interface ITimestampFunction {
620
+ function : Function ;
621
+ solved : boolean ;
622
+ result ?: any ;
623
+ error ?: any ;
624
+ }
0 commit comments