TG-PlatformPlus/taskModel/taskActuator.py

428 lines
24 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/opt/homebrew/bin/python3
# -*- coding:utf-8 -*-
import json
import tracemalloc
import gc
import time
import base64
from PyQt6 import *
from PyQt6.QtCore import *
from logs import log
from typing import Union
from inspect import isfunction
from common import common
from influxDB import influxdb
from logModel.logManager import logManager
from instructionModel.instructionModel import InstructionModel
from projectModel.projectManager import projectManager
from userModel.userManager import userManager
from taskModel.taskManager import taskManager
from taskInstructionModel.taskInstructionManager import taskInstructionManager
from taskModel.taskModel import TaskModel
from interfaceSession.interfaceManager import interfaceManager
class TaskActuator(QThread):
TASK = 0
VIRTUAL = 1
INSTRUCTION = 2
logMsg = pyqtSignal(dict)
updateProgress = pyqtSignal(str, int, int)
updateInstructProgress = pyqtSignal(str, int, int)
updateDetails = pyqtSignal(str, int, int)
executeFinished = pyqtSignal(str)
def __init__(self, id):
super().__init__()
self.currentIndex = 0
self.task_instruction_id = ""
self.instructionList = []
self.currentTask = None
self.parentId = ""
self.running_lock = QMutex() # 新增互斥锁
self.running = False
self.eventInfo = {}
self.subTaskActuator = None
self.taskScript = ""
self.type = TaskActuator.INSTRUCTION
self.id = str(id)
self.name = ""
self.taskInfo = {}
def onUpdateProgress(self, taskId, current, total):
self.updateProgress.emit(taskId, current, total)
def onUpdateDetails(self, taskId, current, total):
self.updateDetails.emit(taskId, current, total)
def run(self):
try:
tracemalloc.start()
loopStartTime = 0
currentInstruction = InstructionModel()
session = None
proId = projectManager.getCurrentProId()
proInfo = projectManager.getCurrentProInfo()
bucketName = "name" in proInfo and proInfo["name"] or "DEFAULT"
influxdb.create(bucketName)
operator = userManager.getCurrentUser()
if proId != None and proId != "":
projectManager.addHistory(proId, {
"event": "执行",
"type": self.type,
"name": self.name,
"operator": operator,
})
instructionListLength = len(self.instructionList)
if self.type == TaskActuator.TASK and instructionListLength > 0:
self.currentTask = TaskModel(self.taskInfo)
self.currentTask.setProInfo(proInfo)
self.currentTask.logMsg.connect(self.onLogMsg, type=Qt.ConnectionType.DirectConnection)
self.currentTask.updateProgress.connect(self.onUpdateProgress)
loop = int(self.taskInfo.get("loop", 1))
delay = float(int(self.taskInfo.get("delay",0))/1000)
taskIndex = 0
self.updateProgress.emit(self.id, 0, instructionListLength)
self.updateDetails.emit(self.id, 0, instructionListLength)
self.updateDetails.emit(self.parentId, 0, instructionListLength)
self.currentTask.setTargetList(self.instructionList)
self.currentTask.start()
while not self.currentTask.isFinished and self.running:
if self.running == False:
break
self.currentTask.callBack(0)
self.currentIndex = 0
total = instructionListLength * loop
self.updateProgress.emit(self.id, 0, total)
# 执行任务
while not self.currentTask.isFinished and self.currentIndex < instructionListLength and self.running:
taskInstructionInfo = self.instructionList[self.currentIndex]
self.currentTask.setTargetId(taskInstructionInfo["target_id"])
self.currentTask.callBack(1)
task_instruction_id = str(taskInstructionInfo["id"]) or ""
target_id = str(taskInstructionInfo["target_id"]) or ""
target_type = taskInstructionInfo["target_type"] or ""
level = str(taskInstructionInfo["level"]) or ""
target_loop = "loop" in taskInstructionInfo and int(taskInstructionInfo["loop"]) or 1
target_delay = "delay" in taskInstructionInfo and float(int(taskInstructionInfo["delay"])/1000) or 0
if self.parentId == "":
self.parentId = self.id
if target_type == "instruction":
self.updateDetails.emit(str(self.parentId) + task_instruction_id, 0, target_loop)
for j in range(target_loop):
loopStartTime = time.time()
self.currentTask.callBack(2)
if self.currentTask.isFinished:
self.updateDetails.emit(str(self.parentId) + task_instruction_id, -1, -1)
break
if self.running == False:
self.updateDetails.emit(str(self.parentId) + task_instruction_id, -1, -1)
break
# 执行指令
currentInstruction.setInfo(taskInstructionInfo["instructionInfo"], taskInstructionInfo["target_param"])
currentInstruction.setProInfo(proInfo)
currentInstruction.setUserInfo(userManager.getCurrentUser())
currentInstruction.setDevInfo(taskInstructionInfo["device"])
interfaceInfos = interfaceManager.getInfo(taskInstructionInfo["interface"])
interfaceInfo = {}
if len(interfaceInfos) <= 0:
continue
interfaceInfo = interfaceInfos[0] #interface接口返回个数为1
currentInstruction.setInterfaceInfo(interfaceInfo)
session = interfaceManager.getSession(taskInstructionInfo["interface"])
try:
currentInstruction.logMsg.disconnect(self.onLogMsg)
currentInstruction.ioCtrl.disconnect(session.ioctrl)
currentInstruction.sendData.disconnect(session.send)
session.newDataArrive.disconnect(currentInstruction.dataHandler)
except:
pass
currentInstruction.logMsg.connect(self.onLogMsg, type=Qt.ConnectionType.DirectConnection)
currentInstruction.ioCtrl.connect(session.ioctrl, type=Qt.ConnectionType.DirectConnection)
currentInstruction.sendData.connect(session.send, type=Qt.ConnectionType.DirectConnection)
while not self.currentTask.isFinished and not session.lock() and self.running:
self.updateProgress.emit(self.id, int( self.currentIndex + int(taskIndex*instructionListLength)), total)
QThread.usleep(1)
session.newDataArrive.connect(currentInstruction.dataHandler, type=Qt.ConnectionType.DirectConnection)
currentInstruction.start()
while not self.currentTask.isFinished and not currentInstruction.isFinished and self.running:
self.updateProgress.emit(self.id, int( self.currentIndex + int(taskIndex*instructionListLength)), total)
currentInstruction.loop()
QThread.usleep(1)
self.updateDetails.emit(str(self.parentId) + task_instruction_id, j+1, target_loop)
#解除信号绑定
try:
currentInstruction.logMsg.disconnect(self.onLogMsg)
currentInstruction.ioCtrl.disconnect(session.ioctrl)
currentInstruction.sendData.disconnect(session.send)
session.newDataArrive.disconnect(currentInstruction.dataHandler)
except:
pass
session.unlock()
tmpTime = time.time()
if tmpTime < loopStartTime + target_delay:
time.sleep(target_delay - (tmpTime - loopStartTime))
# time.sleep(target_delay) 指令延时在指令内部处理
elif target_type == "task":
# 执行子任务
for j in range(target_loop):
if not self.running:
break
self.currentTask.callBack(5)
self.subTaskActuator = TaskActuator(target_id)
self.subTaskActuator.parentId = str(self.parentId) + task_instruction_id
self.subTaskActuator.task_instruction_id = str(self.parentId) + task_instruction_id
taskInfo = taskManager.getInfo(target_id)
taskInfo["params"] = taskInstructionInfo["target_param"]
taskInstructions = taskInstructionManager.getInfo(target_id)
common.getTaskDetails(taskInstructions)
self.subTaskActuator.updateDetails.connect(self.onUpdateDetails, type=Qt.ConnectionType.DirectConnection)
self.subTaskActuator.execute(taskInstructions, taskInfo)
self.subTaskActuator.wait()
self.currentTask.callBack(6)
time.sleep(target_delay)
# 子任务执行完毕
self.currentIndex += 1
if loop > 0:
if self.currentTask.isFinished:
self.updateProgress.emit(self.id,1,-1)
self.updateDetails.emit(self.id,-1,-1)
elif self.running:
if self.task_instruction_id != "":
self.updateDetails.emit( self.task_instruction_id, int( self.currentIndex + int(taskIndex*instructionListLength)), total)
else:
self.updateDetails.emit(self.id, int( self.currentIndex + int(taskIndex*instructionListLength)), total)
self.updateProgress.emit(self.id, int( self.currentIndex + int(taskIndex*instructionListLength)), total)
taskIndex += 1
self.currentTask.next()
if loop > 1:
time.sleep(delay)
self.updateProgress.emit(str(self.taskInfo["id"]),1,-1)
currentInstruction.deleteLater()
elif self.type == TaskActuator.VIRTUAL and instructionListLength > 0:
session = None
currentInstruction = InstructionModel()
self.currentIndex = 0
total = instructionListLength
# 执行任务
while self.currentIndex < instructionListLength and self.running:
taskInstructionInfo = self.instructionList[self.currentIndex]
target_id = str(taskInstructionInfo["target_id"]) or ""
target_type = taskInstructionInfo["target_type"] or ""
target_loop = "loop" in taskInstructionInfo and int(taskInstructionInfo["loop"]) or 1
target_delay = "delay" in taskInstructionInfo and float(int(taskInstructionInfo["delay"])/1000) or 0
if target_type == "instruction":
for j in range(target_loop):
if self.running == False:
break
# 执行指令
currentInstruction.setInfo(taskInstructionInfo["instructionInfo"], taskInstructionInfo["target_param"])
currentInstruction.setProInfo(proInfo)
currentInstruction.setUserInfo(userManager.getCurrentUser())
currentInstruction.setDevInfo(taskInstructionInfo["device"])
interfaceInfos = interfaceManager.getInfo(taskInstructionInfo["interface"])
interfaceInfo = {}
if len(interfaceInfos) <= 0:
continue
interfaceInfo = interfaceInfos[0] #interface接口返回个数为1
currentInstruction.setInterfaceInfo(interfaceInfo)
session = interfaceManager.getSession(taskInstructionInfo["interface"])
try:
currentInstruction.logMsg.disconnect(self.onLogMsg)
currentInstruction.ioCtrl.disconnect(session.ioctrl)
currentInstruction.sendData.disconnect(session.send)
session.newDataArrive.disconnect(currentInstruction.dataHandler)
except:
pass
currentInstruction.logMsg.connect(self.onLogMsg, type=Qt.ConnectionType.UniqueConnection)
currentInstruction.ioCtrl.connect(session.ioctrl, type=Qt.ConnectionType.UniqueConnection)
currentInstruction.sendData.connect(session.send, type=Qt.ConnectionType.UniqueConnection)
while not session.lock() and self.running:
QThread.usleep(1)
session.newDataArrive.connect(currentInstruction.dataHandler, type=Qt.ConnectionType.DirectConnection)
currentInstruction.start()
while not currentInstruction.isFinished and self.running:
currentInstruction.loop()
QThread.usleep(1)
# 解除信号绑定
try:
currentInstruction.logMsg.disconnect(self.onLogMsg)
currentInstruction.ioCtrl.disconnect(session.ioctrl)
currentInstruction.sendData.disconnect(session.send)
session.newDataArrive.disconnect(currentInstruction.dataHandler)
except:
pass
session.unlock()
time.sleep(target_delay)
elif target_type == "task":
# 执行子任务
for j in range(target_loop):
self.subTaskActuator = TaskActuator(target_id)
taskInfo = taskManager.getInfo(target_id)
taskInstructions = taskInstructionManager.getInfo(target_id)
common.getTaskDetails(taskInstructions)
self.subTaskActuator.execute(taskInstructions, taskInfo)
self.subTaskActuator.wait()
time.sleep(target_delay)
# 子任务执行完毕
self.currentIndex += 1
currentInstruction.deleteLater()
elif self.type == TaskActuator.INSTRUCTION and instructionListLength == 1:
session = None
currentInstruction = InstructionModel()
taskInstructionInfo = self.instructionList[0]
target_id = str(taskInstructionInfo["target_id"]) or ""
target_type = taskInstructionInfo["target_type"] or ""
target_loop = "loop" in taskInstructionInfo and int(taskInstructionInfo["loop"]) or 1
target_delay = "delay" in taskInstructionInfo and float(int(taskInstructionInfo["delay"])/1000) or 0
if target_type == "instruction":
self.updateInstructProgress.emit(target_id, 0, target_loop)
for j in range(target_loop):
if self.running == False:
break
# 执行指令
currentInstruction.setInfo(taskInstructionInfo["instructionInfo"], taskInstructionInfo["target_param"])
currentInstruction.setProInfo(proInfo)
currentInstruction.setUserInfo(userManager.getCurrentUser())
currentInstruction.setDevInfo(taskInstructionInfo["device"])
interfaceInfos = interfaceManager.getInfo(taskInstructionInfo["interface"])
interfaceInfo = {}
if len(interfaceInfos) <= 0:
continue
interfaceInfo = interfaceInfos[0]
currentInstruction.setInterfaceInfo(interfaceInfo)
session = interfaceManager.getSession(taskInstructionInfo["interface"])
try:
currentInstruction.logMsg.disconnect(self.onLogMsg)
currentInstruction.ioCtrl.disconnect(session.ioctrl)
currentInstruction.sendData.disconnect(session.send)
session.newDataArrive.disconnect(currentInstruction.dataHandler)
except:
pass
currentInstruction.logMsg.connect(self.onLogMsg, type=Qt.ConnectionType.DirectConnection)
currentInstruction.ioCtrl.connect(session.ioctrl, type=Qt.ConnectionType.UniqueConnection)
currentInstruction.sendData.connect(session.send, type=Qt.ConnectionType.UniqueConnection)
while not session.lock() and self.running:
self.updateInstructProgress.emit(target_id, j, target_loop)
QThread.msleep(10)
session.newDataArrive.connect(currentInstruction.dataHandler, type=Qt.ConnectionType.DirectConnection)
currentInstruction.start()
while not currentInstruction.isFinished and self.running:
self.updateInstructProgress.emit(target_id, j, target_loop)
currentInstruction.loop()
QThread.msleep(10)
# 解除信号绑定
try:
currentInstruction.ioCtrl.disconnect(session.ioctrl)
currentInstruction.sendData.disconnect(session.send)
currentInstruction.logMsg.disconnect(self.onLogMsg)
session.newDataArrive.disconnect(currentInstruction.dataHandler)
except:
pass
session.unlock()
time.sleep(target_delay)
self.updateInstructProgress.emit(self.id,1,-1)
currentInstruction.deleteLater()
except Exception as e:
try:
common.showAlert.emit("EXEC错误", str(e), 0)
except Exception as e:
log.info(str(e))
finally:
try:
currentInstruction.ioCtrl.disconnect(session.ioctrl)
currentInstruction.sendData.disconnect(session.send)
currentInstruction.logMsg.disconnect(self.onLogMsg)
session.newDataArrive.disconnect(currentInstruction.dataHandler)
session.unlock()
except:
pass
if proId != None and proId != "":
projectManager.addHistory(proId, {
"event": "结束",
"type": self.type,
"name": self.name,
"operator": operator,
})
self.updateInstructProgress.emit(self.id,1,-1)
self.updateProgress.emit(self.id,1,-1)
self.updateDetails.emit(self.id,1,-1)
self.executeFinished.emit(self.id)
self.quit()
# currentInstruction.deleteLater()
# currentInstruction = None
# gc.collect() # 手动触发垃圾回收
# snapshot = tracemalloc.take_snapshot()
# # 打印内存分配的前10条统计信息
# top_stats = snapshot.statistics('lineno')
# print("内存分配的前10行")
# for stat in top_stats[:10]:
# print(stat)
def onLogMsg(self, data):
logManager.addLogMsg(data)
# 执行指令或者队列
def execute(self, target, taskInfo = {}):
if self.isRunning():
return False
self.running = True
if isinstance(target, list): #队列
self.instructionList = target
self.taskInfo = taskInfo
self.type = taskInfo.get("type", TaskActuator.TASK)
self.name = taskInfo.get("name", TaskActuator.TASK)
self.start()
return True
elif isinstance(target, dict): #指令
self.instructionList = []
self.name = target["instructionInfo"]["name"]
self.instructionList.append(target)
self.type = TaskActuator.INSTRUCTION
self.start()
return True
return False
def stopSub(self):
self.running_lock.lock()
self.running = False
self.running_lock.unlock()
# 停止子任务
if self.subTaskActuator and self.subTaskActuator.isRunning():
self.subTaskActuator.stopSub()
self.updateDetails.emit(str(self.parentId) , -1, -1)
self.quit()
def stop(self):
self.running_lock.lock()
self.running = False
self.running_lock.unlock()
# 停止子任务
if self.subTaskActuator and self.subTaskActuator.isRunning():
self.subTaskActuator.stopSub()
self.quit()
defaultTaskActuator = TaskActuator("defaultTaskActuator")