chain-client/src/models/ChainTask.ts
2023-04-10 16:19:12 +08:00

150 lines
4.2 KiB
TypeScript

import { getModelForClass, index, modelOptions, mongoose, pre, prop, Ref, Severity } from '@typegoose/typegoose'
import { BlockChain } from 'chain/BlockChain'
import { MAX_BATCH_REQ_COUNT, ZERO_BYTES32 } from 'common/Constants'
import { dbconn } from 'decorators/dbconn'
import { generateRandomBytes32 } from 'utils/wallet.util'
import { BaseModule } from './Base'
import { ReqTaskStatus, RequestTask, RequestTaskClass } from './RequestTask'
export enum TaskStatus {
NOTSTART = 0,
PEDING = 1,
SUCCESS = 2,
TX_ALL_CONFIRM = 3,
TX_PART_ERROR = 8,
TX_ERROR = 9,
}
@dbconn()
@index({ taskId: 1 }, { unique: false })
@modelOptions({
schemaOptions: { collection: 'chain_task', timestamps: true },
options: { allowMixed: Severity.ALLOW },
})
export class ChainTaskClass extends BaseModule {
@prop({ required: true })
public taskId!: string
@prop()
public name: string
@prop()
public desc: string
@prop()
public starter: string
@prop({ type: mongoose.Schema.Types.Mixed })
public taskData: any
@prop({ enum: TaskStatus, default: TaskStatus.NOTSTART })
public status: TaskStatus
@prop()
public startTime: number
@prop()
public endTime: number
@prop({ required: true, default: true })
public newRecord: boolean
@prop({ required: true, default: false })
public allEnd: boolean
@prop({ required: true, default: 0 })
public successCount: number
@prop({ required: true, default: 0 })
public errorCount: number
@prop({ type: String, required: true, default: [] })
public tasks!: Array<string>
/**
* 检查是否所有的任务都已完成(成功或重试次数达到上限)
* 调用时机
* 1. 每个 request task 成功
* 2. 每个 request task 重试达到预设次数
* @param chainTaskId
*/
public static async checkStatus(chainTaskId: string) {
let record = await ChainTask.findById(chainTaskId)
let sCount = 0
let errCount = 0
for (let subId of record.tasks) {
let subData = await RequestTask.findById(subId)
if (subData.status === ReqTaskStatus.SUCCESS) {
sCount += 1
} else if (subData.status === ReqTaskStatus.ERROR) {
errCount += 1
}
}
record.successCount = sCount
record.errorCount = errCount
if (sCount === record.tasks.length) {
record.status = TaskStatus.TX_ALL_CONFIRM
record.allEnd = true
} else {
record.allEnd = false
if (record.status === TaskStatus.NOTSTART && sCount > 0) {
record.status = TaskStatus.PEDING
} else if (errCount === record.tasks.length) {
record.status = TaskStatus.TX_ERROR
record.allEnd = true
} else if (errCount + sCount === record.tasks.length) {
record.status = TaskStatus.TX_PART_ERROR
record.allEnd = true
}
}
await record.save()
if (record.allEnd) {
setImmediate(async function () {
// TODO:: 通知前端
})
}
}
public static async allUnFinishedTask() {
return ChainTask.find({ allEnd: false })
}
/**
* 解析企业微信审批信息
*/
public static async parseWxApprovalInfo({ taskId, name, desc, data, starter }) {
let maxTryCount = parseInt(process.env.CHAIN_MAX_TRY)
let chainTask = await ChainTask.insertOrUpdate({ taskId }, { name, desc, starter, data })
let subTasks: any = []
if (chainTask.newRecord) {
let subTask
let index = 0
for (let sub of data) {
if (!subTask || subTask.reqDatas.length >= MAX_BATCH_REQ_COUNT) {
index += 1
subTask = new RequestTask({
taskId,
index,
chainTaskId: chainTask.id,
reqDatas: [],
maxTryCount,
predecessor: ZERO_BYTES32,
salt: generateRandomBytes32(),
})
subTasks.push(subTask)
}
subTask.reqDatas.push(sub)
subTask.targets.push(sub.address)
let abi = await new BlockChain().generateFunAbi(sub)
subTask.datas.push(abi)
subTask.values.push('0')
await subTask.save()
chainTask.tasks.pushOnce(subTask.id)
}
}
chainTask.newRecord = false
await chainTask.save()
return subTasks
}
}
export const ChainTask = getModelForClass(ChainTaskClass, { existingConnection: ChainTaskClass['db'] })