|
@@ -1,3 +1,4 @@
|
|
|
|
|
+import { compare } from 'bcrypt'
|
|
|
import { forwardRef, Inject, Injectable, Logger, OnModuleInit } from '@nestjs/common'
|
|
import { forwardRef, Inject, Injectable, Logger, OnModuleInit } from '@nestjs/common'
|
|
|
import { PageRequest } from '../common/dto/page-request'
|
|
import { PageRequest } from '../common/dto/page-request'
|
|
|
import { Device } from './entities/device.entity'
|
|
import { Device } from './entities/device.entity'
|
|
@@ -9,6 +10,12 @@ import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity
|
|
|
import { TaskService } from '../task/task.service'
|
|
import { TaskService } from '../task/task.service'
|
|
|
import { OperatorConfigService } from '../operator_config/operator_config.service'
|
|
import { OperatorConfigService } from '../operator_config/operator_config.service'
|
|
|
import { Interval } from '@nestjs/schedule'
|
|
import { Interval } from '@nestjs/schedule'
|
|
|
|
|
+import { EventsGateway } from 'src/events/events.gateway'
|
|
|
|
|
+import { DeviceTask, DeviceTaskStatus } from './entities/device-task.entity'
|
|
|
|
|
+import { DeviceTaskItem, DeviceTaskItemStatus } from './entities/device-task-item.entity'
|
|
|
|
|
+import PQueue from 'p-queue'
|
|
|
|
|
+import { randomUUID } from 'crypto'
|
|
|
|
|
+import { setTimeout } from 'timers/promises'
|
|
|
|
|
|
|
|
@Injectable()
|
|
@Injectable()
|
|
|
export class DeviceService implements OnModuleInit {
|
|
export class DeviceService implements OnModuleInit {
|
|
@@ -18,7 +25,13 @@ export class DeviceService implements OnModuleInit {
|
|
|
private deviceRepository: Repository<Device>,
|
|
private deviceRepository: Repository<Device>,
|
|
|
@Inject(forwardRef(() => TaskService))
|
|
@Inject(forwardRef(() => TaskService))
|
|
|
private taskService: TaskService,
|
|
private taskService: TaskService,
|
|
|
- private operatorConfigService: OperatorConfigService
|
|
|
|
|
|
|
+ private operatorConfigService: OperatorConfigService,
|
|
|
|
|
+ @Inject(forwardRef(() => EventsGateway))
|
|
|
|
|
+ private eventsGateway: EventsGateway,
|
|
|
|
|
+ @InjectRepository(DeviceTask)
|
|
|
|
|
+ private deviceTaskRepository: Repository<DeviceTask>,
|
|
|
|
|
+ @InjectRepository(DeviceTaskItem)
|
|
|
|
|
+ private deviceTaskItemRepository: Repository<DeviceTaskItem>
|
|
|
) {}
|
|
) {}
|
|
|
|
|
|
|
|
async onModuleInit() {
|
|
async onModuleInit() {
|
|
@@ -214,4 +227,89 @@ export class DeviceService implements OnModuleInit {
|
|
|
Logger.error(e)
|
|
Logger.error(e)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ async createTask({ taskType, payload }: { taskType: string; payload: any; total: number }) {
|
|
|
|
|
+ const devices = await this.deviceRepository.findBy({
|
|
|
|
|
+ online: true
|
|
|
|
|
+ })
|
|
|
|
|
+ const task = await this.deviceTaskRepository.save({
|
|
|
|
|
+ taskType,
|
|
|
|
|
+ payload,
|
|
|
|
|
+ total: devices.length,
|
|
|
|
|
+ progress: 0
|
|
|
|
|
+ })
|
|
|
|
|
+ const taskItems = devices.map((device) => {
|
|
|
|
|
+ return new DeviceTaskItem({
|
|
|
|
|
+ taskId: task.id,
|
|
|
|
|
+ deviceId: device.id,
|
|
|
|
|
+ status: DeviceTaskItemStatus.IDLE
|
|
|
|
|
+ })
|
|
|
|
|
+ })
|
|
|
|
|
+ await this.deviceTaskItemRepository.save(taskItems)
|
|
|
|
|
+ this.runTask(task)
|
|
|
|
|
+ return task
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async runTask(task: DeviceTask) {
|
|
|
|
|
+ await this.deviceTaskRepository.update(task.id, {
|
|
|
|
|
+ status: DeviceTaskStatus.PENDING
|
|
|
|
|
+ })
|
|
|
|
|
+ const taskItems = await this.deviceTaskItemRepository.findBy({ taskId: task.id })
|
|
|
|
|
+ const queue = new PQueue({ concurrency: 5 })
|
|
|
|
|
+ queue.on('next', async () => {
|
|
|
|
|
+ const progress = await this.deviceTaskItemRepository.countBy({
|
|
|
|
|
+ taskId: task.id,
|
|
|
|
|
+ status: In([DeviceTaskItemStatus.FAILED, DeviceTaskItemStatus.SUCCESS])
|
|
|
|
|
+ })
|
|
|
|
|
+ this.deviceTaskRepository.update(task.id, {
|
|
|
|
|
+ progress
|
|
|
|
|
+ })
|
|
|
|
|
+ })
|
|
|
|
|
+ for (const taskItem of taskItems) {
|
|
|
|
|
+ queue.add(async () => {
|
|
|
|
|
+ await this.deviceTaskItemRepository.update(taskItem.id, {
|
|
|
|
|
+ status: DeviceTaskItemStatus.PENDING
|
|
|
|
|
+ })
|
|
|
|
|
+ let error = ''
|
|
|
|
|
+ try {
|
|
|
|
|
+ const device = await this.deviceRepository.findOneBy({
|
|
|
|
|
+ id: taskItem.deviceId
|
|
|
|
|
+ })
|
|
|
|
|
+ if (device) {
|
|
|
|
|
+ const res = await Promise.race([
|
|
|
|
|
+ this.eventsGateway.sendForResult(
|
|
|
|
|
+ {
|
|
|
|
|
+ id: randomUUID(),
|
|
|
|
|
+ action: task.taskType,
|
|
|
|
|
+ data: task.payload
|
|
|
|
|
+ },
|
|
|
|
|
+ device.socketId
|
|
|
|
|
+ ),
|
|
|
|
|
+ setTimeout(5 * 60 * 100, 'timeout')
|
|
|
|
|
+ ])
|
|
|
|
|
+ if (res === 'timeout') {
|
|
|
|
|
+ error = 'timeout'
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ error = e.message
|
|
|
|
|
+ Logger.error(e)
|
|
|
|
|
+ }
|
|
|
|
|
+ if (error) {
|
|
|
|
|
+ await this.deviceTaskItemRepository.update(taskItem.id, {
|
|
|
|
|
+ status: DeviceTaskItemStatus.FAILED,
|
|
|
|
|
+ error
|
|
|
|
|
+ })
|
|
|
|
|
+ } else {
|
|
|
|
|
+ await this.deviceTaskItemRepository.update(taskItem.id, {
|
|
|
|
|
+ status: DeviceTaskItemStatus.SUCCESS
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ await queue.onIdle()
|
|
|
|
|
+ await this.deviceTaskRepository.update(task.id, {
|
|
|
|
|
+ status: DeviceTaskStatus.COMPLETE
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|