Skip to content

Commit e86b949

Browse files
committed
notification changes and task queue feature
1 parent f50e586 commit e86b949

File tree

2 files changed

+237
-59
lines changed

2 files changed

+237
-59
lines changed

src/orders/orders.service.ts

Lines changed: 224 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
/* eslint-disable @typescript-eslint/ban-types */
12
/* eslint-disable @typescript-eslint/ban-ts-comment */
23
import {
34
BadRequestException,
45
ForbiddenException,
56
Inject,
67
Injectable,
8+
InternalServerErrorException,
79
forwardRef,
810
} from '@nestjs/common';
911
import { OrderEntity } from './entities/order.entity';
@@ -19,6 +21,8 @@ import { IOrdersByCartTimestamp } from 'src/static/interfaces/orders.interfaces'
1921
import { UsersService } from 'src/users/users.service';
2022
import { CloseOrdersDto } from './dto/close-order.dto';
2123
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';
2226

2327
@Injectable()
2428
export class OrdersService {
@@ -30,8 +34,11 @@ export class OrdersService {
3034
private readonly usersService: UsersService,
3135
@Inject(forwardRef(() => TelegramBotService))
3236
private readonly telegramBotService: TelegramBotService,
33-
) {}
37+
) {
38+
this.timestampsTasksQueue = new OrdersTasksQueue();
39+
}
3440

41+
readonly timestampsTasksQueue: OrdersTasksQueue;
3542
readonly cacheKeys: ICacheKeys = this.cacheService.cacheKeys();
3643

3744
async confirmCart(
@@ -74,6 +81,18 @@ export class OrdersService {
7481
return this.findOneById(result.id);
7582
}),
7683
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),
7796
]);
7897

7998
return Promise.all(
@@ -102,46 +121,49 @@ export class OrdersService {
102121
throw new BadRequestException(ExceptionMessages.OrderAlreadyTaken);
103122
}
104123

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,
122139
},
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)),
124155
);
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);
143164

144-
return true;
165+
return true;
166+
}, cartTimestamp);
145167
}
146168

147169
async closeOrders(
@@ -167,23 +189,24 @@ export class OrdersService {
167189
throw new ForbiddenException(ExceptionMessages.IncorrectCloseOrdersDto);
168190
}
169191

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+
// }
187210

188211
await Promise.all([
189212
...orders.map((order, index) => {
@@ -219,7 +242,7 @@ export class OrdersService {
219242
},
220243
);
221244
}),
222-
workerNotification,
245+
// workerNotification,
223246
]);
224247

225248
const timestamp = new Date(cartTimestamp);
@@ -454,3 +477,148 @@ export class OrdersService {
454477
return result;
455478
}
456479
}
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+
}

src/telegram-bot/telegram-bot.service.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,20 @@ export class TelegramBotService {
3838
// this.previousCheckDate = new Date().getTime();
3939
// }
4040

41+
async newOrderNotification(
42+
telegramUserId: number,
43+
date: Date,
44+
): Promise<void> {
45+
const message: string = `Появился новый заказ (${dateFormatToString(
46+
date,
47+
)})`;
48+
this.bot.sendMessage(telegramUserId, message);
49+
}
50+
4151
async sendOrderTakenByNotification(
4252
telegramUserId: number,
4353
cartTimestamp: TimestampType,
44-
) {
54+
): Promise<void> {
4555
const message: string = `Ваш заказ от даты "${dateFormatToString(
4656
cartTimestamp as Date,
4757
)}" взят в работу.`;
@@ -51,7 +61,7 @@ export class TelegramBotService {
5161
async sendOrderFinishedNotification(
5262
telegramUserId: number,
5363
cartTimestamp: TimestampType,
54-
) {
64+
): Promise<void> {
5565
const message: string = `Ваш заказ от даты "${dateFormatToString(
5666
cartTimestamp as Date,
5767
)}" завершен.`;
@@ -61,7 +71,7 @@ export class TelegramBotService {
6171
async sendOrderCanceledNotification(
6272
telegramUserId: number,
6373
cartTimestamp: TimestampType,
64-
) {
74+
): Promise<void> {
6575
const message: string = `Доставщик, что взял Ваш заказ от даты "${dateFormatToString(
6676
cartTimestamp as Date,
6777
)}", отказался от него.`;

0 commit comments

Comments
 (0)