|
|
@ -1,4 +1,4 @@
|
|
|
|
import subprocess, json, psutil, time, os, win32security, sys, base64, logging #Get input argument
|
|
|
|
import subprocess, json, psutil, time, os, win32security, sys, base64, logging, ctypes #Get input argument
|
|
|
|
from . import Server
|
|
|
|
from . import Server
|
|
|
|
from . import Timer
|
|
|
|
from . import Timer
|
|
|
|
from . import Processor
|
|
|
|
from . import Processor
|
|
|
@ -807,175 +807,185 @@ from .. import __version__ # Get version from the package
|
|
|
|
# Main def for orchestrator
|
|
|
|
# Main def for orchestrator
|
|
|
|
def Orchestrator(inGSettings):
|
|
|
|
def Orchestrator(inGSettings):
|
|
|
|
lL = inGSettings["Logger"]
|
|
|
|
lL = inGSettings["Logger"]
|
|
|
|
|
|
|
|
# https://stackoverflow.com/questions/130763/request-uac-elevation-from-within-a-python-script
|
|
|
|
#mGlobalDict = Settings.Settings(sys.argv[1])
|
|
|
|
def is_admin():
|
|
|
|
gSettingsDict = inGSettings # Alias for old name in alg
|
|
|
|
|
|
|
|
inGSettings["VersionStr"] = __version__
|
|
|
|
|
|
|
|
#Logger alias
|
|
|
|
|
|
|
|
lL = gSettingsDict["Logger"]
|
|
|
|
|
|
|
|
if lL: lL.info("Link the gSettings in submodules") #Logging
|
|
|
|
|
|
|
|
Processor.gSettingsDict = gSettingsDict
|
|
|
|
|
|
|
|
Timer.gSettingsDict = gSettingsDict
|
|
|
|
|
|
|
|
Timer.Processor.gSettingsDict = gSettingsDict
|
|
|
|
|
|
|
|
Server.gSettingsDict = gSettingsDict
|
|
|
|
|
|
|
|
Server.ProcessorOld.gSettingsDict = gSettingsDict # Backward compatibility
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Check _SessionLast_RDPList.json in working directory. if exist - load into gsettings
|
|
|
|
|
|
|
|
# GSettings
|
|
|
|
|
|
|
|
#"RobotRDPActive": {
|
|
|
|
|
|
|
|
# "RDPList": {
|
|
|
|
|
|
|
|
if os.path.exists("_SessionLast_RDPList.json"):
|
|
|
|
|
|
|
|
lFile = open("_SessionLast_RDPList.json", "r", encoding="utf-8")
|
|
|
|
|
|
|
|
lSessionLastRDPList = json.loads(lFile.read())
|
|
|
|
|
|
|
|
lFile.close() # Close the file
|
|
|
|
|
|
|
|
os.remove("_SessionLast_RDPList.json") # remove the temp file
|
|
|
|
|
|
|
|
gSettingsDict["RobotRDPActive"]["RDPList"]=lSessionLastRDPList # Set the last session dict
|
|
|
|
|
|
|
|
if lL: lL.warning(f"RDP Session List was restored from previous Orchestrator session")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Init SettingsUpdate defs from file list (after RDP restore)
|
|
|
|
|
|
|
|
lSettingsUpdateFilePathList = gSettingsDict.get("OrchestratorStart", {}).get("DefSettingsUpdatePathList",[])
|
|
|
|
|
|
|
|
lSubmoduleFunctionName = "SettingsUpdate"
|
|
|
|
|
|
|
|
lSettingsPath = "\\".join(os.path.join(os.getcwd(), __file__).split("\\")[:-1])
|
|
|
|
|
|
|
|
for lModuleFilePathItem in lSettingsUpdateFilePathList: # Import defs with try catch
|
|
|
|
|
|
|
|
try: # Try to init - go next if error and log in logger
|
|
|
|
|
|
|
|
lModuleName = lModuleFilePathItem[0:-3]
|
|
|
|
|
|
|
|
lFileFullPath = os.path.join(lSettingsPath, lModuleFilePathItem)
|
|
|
|
|
|
|
|
lTechSpecification = importlib.util.spec_from_file_location(lModuleName, lFileFullPath)
|
|
|
|
|
|
|
|
lTechModuleFromSpec = importlib.util.module_from_spec(lTechSpecification)
|
|
|
|
|
|
|
|
lTechSpecificationModuleLoader = lTechSpecification.loader.exec_module(lTechModuleFromSpec)
|
|
|
|
|
|
|
|
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
|
|
|
|
|
|
|
|
# Run SettingUpdate function in submodule
|
|
|
|
|
|
|
|
getattr(lTechModuleFromSpec, lSubmoduleFunctionName)(gSettingsDict)
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
|
|
if lL: lL.exception(f"Error when init .py file in orchestrator '{lModuleFilePathItem}'. Exception is below:")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Turn on backward compatibility
|
|
|
|
|
|
|
|
BackwardCompatibility.Update(inGSettings= gSettingsDict)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Init the log dump to WEB
|
|
|
|
|
|
|
|
#import pdb; pdb.set_trace()
|
|
|
|
|
|
|
|
############################################
|
|
|
|
|
|
|
|
if len(lL.handlers)== 0:
|
|
|
|
|
|
|
|
mRobotLoggerFormatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
mRobotLoggerFormatter = lL.handlers[0].formatter
|
|
|
|
|
|
|
|
mHandlerDumpLogList = LoggerHandlerDumpLogList.LoggerHandlerDumpLogList(inDict=inGSettings["Client"],
|
|
|
|
|
|
|
|
inKeyStr="DumpLogList",
|
|
|
|
|
|
|
|
inHashKeyStr="DumpLogListHashStr",
|
|
|
|
|
|
|
|
inRowCountInt=inGSettings["Client"]["DumpLogListCountInt"])
|
|
|
|
|
|
|
|
mHandlerDumpLogList.setFormatter(mRobotLoggerFormatter)
|
|
|
|
|
|
|
|
lL.addHandler(mHandlerDumpLogList)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Append Orchestrator def to ProcessorDictAlias
|
|
|
|
|
|
|
|
lModule = sys.modules[__name__]
|
|
|
|
|
|
|
|
lModuleDefList = dir(lModule)
|
|
|
|
|
|
|
|
for lItemDefNameStr in lModuleDefList:
|
|
|
|
|
|
|
|
# Dont append alias for defs Orchestrator and ___deprecated_orchestrator_start__
|
|
|
|
|
|
|
|
if lItemDefNameStr not in ["Orchestrator", "___deprecated_orchestrator_start__"]:
|
|
|
|
|
|
|
|
lItemDef = getattr(lModule,lItemDefNameStr)
|
|
|
|
|
|
|
|
if callable(lItemDef): inGSettings["ProcessorDict"]["AliasDefDict"][lItemDefNameStr]=lItemDef
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#Инициализация настроечных параметров
|
|
|
|
|
|
|
|
lDaemonLoopSeconds=gSettingsDict["SchedulerDict"]["CheckIntervalSecFloat"]
|
|
|
|
|
|
|
|
lDaemonActivityLogDict={} #Словарь отработанных активностей, ключ - кортеж (<activityType>, <datetime>, <processPath || processName>, <processArgs>)
|
|
|
|
|
|
|
|
lDaemonLastDateTime=datetime.datetime.now()
|
|
|
|
|
|
|
|
gSettingsDict["ServerDict"]["WorkingDirectoryPathStr"] = os.getcwd() # Set working directory in g settings
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#Инициализация сервера
|
|
|
|
|
|
|
|
lThreadServer = Server.RobotDaemonServer("ServerThread", gSettingsDict)
|
|
|
|
|
|
|
|
lThreadServer.start()
|
|
|
|
|
|
|
|
if lL: lL.info("Web server has been started") #Logging
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Init the RobotScreenActive in another thread
|
|
|
|
|
|
|
|
lRobotScreenActiveThread = threading.Thread(target= Monitor.CheckScreen)
|
|
|
|
|
|
|
|
lRobotScreenActiveThread.daemon = True # Run the thread in daemon mode.
|
|
|
|
|
|
|
|
lRobotScreenActiveThread.start() # Start the thread execution.
|
|
|
|
|
|
|
|
if lL: lL.info("Robot Screen active has been started") #Logging
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Init the RobotRDPActive in another thread
|
|
|
|
|
|
|
|
lRobotRDPActiveThread = threading.Thread(target= RobotRDPActive.RobotRDPActive, kwargs={"inGSettings":gSettingsDict})
|
|
|
|
|
|
|
|
lRobotRDPActiveThread.daemon = True # Run the thread in daemon mode.
|
|
|
|
|
|
|
|
lRobotRDPActiveThread.start() # Start the thread execution.
|
|
|
|
|
|
|
|
if lL: lL.info("Robot RDP active has been started") #Logging
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Init autocleaner in another thread
|
|
|
|
|
|
|
|
lAutocleanerThread = threading.Thread(target= GSettingsAutocleaner, kwargs={"inGSettings":gSettingsDict})
|
|
|
|
|
|
|
|
lAutocleanerThread.daemon = True # Run the thread in daemon mode.
|
|
|
|
|
|
|
|
lAutocleanerThread.start() # Start the thread execution.
|
|
|
|
|
|
|
|
if lL: lL.info("Autocleaner thread has been started") #Logging
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Orchestrator start activity
|
|
|
|
|
|
|
|
if lL: lL.info("Orchestrator start activity run") #Logging
|
|
|
|
|
|
|
|
for lActivityItem in gSettingsDict["OrchestratorStart"]["ActivityList"]:
|
|
|
|
|
|
|
|
Processor.ActivityListOrDict(lActivityItem)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Processor thread
|
|
|
|
|
|
|
|
lProcessorThread = threading.Thread(target= Processor.ProcessorRunSync, kwargs={"inGSettings":gSettingsDict})
|
|
|
|
|
|
|
|
lProcessorThread.daemon = True # Run the thread in daemon mode.
|
|
|
|
|
|
|
|
lProcessorThread.start() # Start the thread execution.
|
|
|
|
|
|
|
|
if lL: lL.info("Processor has been started (ProcessorDict)") #Logging
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if lL: lL.info("Scheduler loop start") #Logging
|
|
|
|
|
|
|
|
gDaemonActivityLogDictRefreshSecInt = 10 # The second period for clear lDaemonActivityLogDict from old items
|
|
|
|
|
|
|
|
gDaemonActivityLogDictLastTime = time.time() # The second perioad for clean lDaemonActivityLogDict from old items
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
lCurrentDateTime = datetime.datetime.now()
|
|
|
|
return ctypes.windll.shell32.IsUserAnAdmin()
|
|
|
|
#Циклический обход правил
|
|
|
|
except:
|
|
|
|
lFlagSearchActivityType=True
|
|
|
|
return False
|
|
|
|
# Periodically clear the lDaemonActivityLogDict
|
|
|
|
if not is_admin():
|
|
|
|
if time.time()-gDaemonActivityLogDictLastTime>=gDaemonActivityLogDictRefreshSecInt:
|
|
|
|
# Re-run the program with admin rights
|
|
|
|
gDaemonActivityLogDictLastTime = time.time() # Update the time
|
|
|
|
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
|
|
|
|
for lIndex, lItem in enumerate(lDaemonActivityLogDict):
|
|
|
|
else:
|
|
|
|
if lItem["ActivityEndDateTime"] and lCurrentDateTime<=lItem["ActivityEndDateTime"]:
|
|
|
|
# Code of your program here
|
|
|
|
pass
|
|
|
|
#mGlobalDict = Settings.Settings(sys.argv[1])
|
|
|
|
# Activity is actual - do not delete now
|
|
|
|
gSettingsDict = inGSettings # Alias for old name in alg
|
|
|
|
else:
|
|
|
|
inGSettings["VersionStr"] = __version__
|
|
|
|
# remove the activity - not actual
|
|
|
|
#Logger alias
|
|
|
|
lDaemonActivityLogDict.pop(lIndex,None)
|
|
|
|
lL = gSettingsDict["Logger"]
|
|
|
|
lIterationLastDateTime = lDaemonLastDateTime # Get current datetime before iterator (need for iterate all activities in loop)
|
|
|
|
if lL: lL.info("Link the gSettings in submodules") #Logging
|
|
|
|
# Iterate throught the activity list
|
|
|
|
Processor.gSettingsDict = gSettingsDict
|
|
|
|
for lIndex, lItem in enumerate(gSettingsDict["SchedulerDict"]["ActivityTimeList"]):
|
|
|
|
Timer.gSettingsDict = gSettingsDict
|
|
|
|
try:
|
|
|
|
Timer.Processor.gSettingsDict = gSettingsDict
|
|
|
|
# Prepare GUID of the activity
|
|
|
|
Server.gSettingsDict = gSettingsDict
|
|
|
|
lGUID = None
|
|
|
|
Server.ProcessorOld.gSettingsDict = gSettingsDict # Backward compatibility
|
|
|
|
if "GUID" in lItem and lItem["GUID"]:
|
|
|
|
|
|
|
|
lGUID = lItem["GUID"]
|
|
|
|
# Check _SessionLast_RDPList.json in working directory. if exist - load into gsettings
|
|
|
|
else:
|
|
|
|
# GSettings
|
|
|
|
lGUID = str(uuid.uuid4())
|
|
|
|
#"RobotRDPActive": {
|
|
|
|
lItem["GUID"]=lGUID
|
|
|
|
# "RDPList": {
|
|
|
|
|
|
|
|
if os.path.exists("_SessionLast_RDPList.json"):
|
|
|
|
#Проверка дней недели, в рамках которых можно запускать активность
|
|
|
|
lFile = open("_SessionLast_RDPList.json", "r", encoding="utf-8")
|
|
|
|
lItemWeekdayList=lItem.get("WeekdayList", [0, 1, 2, 3, 4, 5, 6])
|
|
|
|
lSessionLastRDPList = json.loads(lFile.read())
|
|
|
|
if lCurrentDateTime.weekday() in lItemWeekdayList:
|
|
|
|
lFile.close() # Close the file
|
|
|
|
if lFlagSearchActivityType:
|
|
|
|
os.remove("_SessionLast_RDPList.json") # remove the temp file
|
|
|
|
#######################################################################
|
|
|
|
gSettingsDict["RobotRDPActive"]["RDPList"]=lSessionLastRDPList # Set the last session dict
|
|
|
|
#Branch 1 - if has TimeHH:MM
|
|
|
|
if lL: lL.warning(f"RDP Session List was restored from previous Orchestrator session")
|
|
|
|
#######################################################################
|
|
|
|
|
|
|
|
if "TimeHH:MM" in lItem:
|
|
|
|
# Init SettingsUpdate defs from file list (after RDP restore)
|
|
|
|
#Вид активности - запуск процесса
|
|
|
|
lSettingsUpdateFilePathList = gSettingsDict.get("OrchestratorStart", {}).get("DefSettingsUpdatePathList",[])
|
|
|
|
#Сформировать временной штамп, относительно которого надо будет проверять время
|
|
|
|
lSubmoduleFunctionName = "SettingsUpdate"
|
|
|
|
#часовой пояс пока не учитываем
|
|
|
|
lSettingsPath = "\\".join(os.path.join(os.getcwd(), __file__).split("\\")[:-1])
|
|
|
|
lActivityDateTime=datetime.datetime.strptime(lItem["TimeHH:MM"],"%H:%M")
|
|
|
|
for lModuleFilePathItem in lSettingsUpdateFilePathList: # Import defs with try catch
|
|
|
|
lActivityDateTime=lActivityDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day)
|
|
|
|
try: # Try to init - go next if error and log in logger
|
|
|
|
#Убедиться в том, что время наступило
|
|
|
|
lModuleName = lModuleFilePathItem[0:-3]
|
|
|
|
if (
|
|
|
|
lFileFullPath = os.path.join(lSettingsPath, lModuleFilePathItem)
|
|
|
|
lActivityDateTime>=lDaemonLastDateTime and
|
|
|
|
lTechSpecification = importlib.util.spec_from_file_location(lModuleName, lFileFullPath)
|
|
|
|
lCurrentDateTime>=lActivityDateTime):
|
|
|
|
lTechModuleFromSpec = importlib.util.module_from_spec(lTechSpecification)
|
|
|
|
# Log info about activity
|
|
|
|
lTechSpecificationModuleLoader = lTechSpecification.loader.exec_module(lTechModuleFromSpec)
|
|
|
|
if lL: lL.info(f"Scheduler:: Activity list is started in new thread. Scheduler item: {lItem}") #Logging
|
|
|
|
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
|
|
|
|
# Do the activity
|
|
|
|
# Run SettingUpdate function in submodule
|
|
|
|
lThread = threading.Thread(target=Processor.ActivityListExecute, kwargs={"inGSettings": inGSettings, "inActivityList":lItem["ActivityList"]})
|
|
|
|
getattr(lTechModuleFromSpec, lSubmoduleFunctionName)(gSettingsDict)
|
|
|
|
lThread.start()
|
|
|
|
except Exception as e:
|
|
|
|
lIterationLastDateTime = datetime.datetime.now() # Set the new datetime for the new processor activity
|
|
|
|
if lL: lL.exception(f"Error when init .py file in orchestrator '{lModuleFilePathItem}'. Exception is below:")
|
|
|
|
except Exception as e:
|
|
|
|
|
|
|
|
if lL: lL.exception(f"Scheduler: Exception has been catched in Scheduler module when activity time item was initialising. ActivityTimeItem is {lItem}")
|
|
|
|
# Turn on backward compatibility
|
|
|
|
lDaemonLastDateTime = lIterationLastDateTime # Set the new datetime for the new processor activity
|
|
|
|
BackwardCompatibility.Update(inGSettings= gSettingsDict)
|
|
|
|
#Уснуть до следующего прогона
|
|
|
|
|
|
|
|
time.sleep(lDaemonLoopSeconds)
|
|
|
|
# Init the log dump to WEB
|
|
|
|
except Exception as e:
|
|
|
|
#import pdb; pdb.set_trace()
|
|
|
|
if lL: lL.exception(f"Scheduler: Exception has been catched in Scheduler module. Global error")
|
|
|
|
############################################
|
|
|
|
|
|
|
|
if len(lL.handlers)== 0:
|
|
|
|
|
|
|
|
mRobotLoggerFormatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
mRobotLoggerFormatter = lL.handlers[0].formatter
|
|
|
|
|
|
|
|
mHandlerDumpLogList = LoggerHandlerDumpLogList.LoggerHandlerDumpLogList(inDict=inGSettings["Client"],
|
|
|
|
|
|
|
|
inKeyStr="DumpLogList",
|
|
|
|
|
|
|
|
inHashKeyStr="DumpLogListHashStr",
|
|
|
|
|
|
|
|
inRowCountInt=inGSettings["Client"]["DumpLogListCountInt"])
|
|
|
|
|
|
|
|
mHandlerDumpLogList.setFormatter(mRobotLoggerFormatter)
|
|
|
|
|
|
|
|
lL.addHandler(mHandlerDumpLogList)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Append Orchestrator def to ProcessorDictAlias
|
|
|
|
|
|
|
|
lModule = sys.modules[__name__]
|
|
|
|
|
|
|
|
lModuleDefList = dir(lModule)
|
|
|
|
|
|
|
|
for lItemDefNameStr in lModuleDefList:
|
|
|
|
|
|
|
|
# Dont append alias for defs Orchestrator and ___deprecated_orchestrator_start__
|
|
|
|
|
|
|
|
if lItemDefNameStr not in ["Orchestrator", "___deprecated_orchestrator_start__"]:
|
|
|
|
|
|
|
|
lItemDef = getattr(lModule,lItemDefNameStr)
|
|
|
|
|
|
|
|
if callable(lItemDef): inGSettings["ProcessorDict"]["AliasDefDict"][lItemDefNameStr]=lItemDef
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#Инициализация настроечных параметров
|
|
|
|
|
|
|
|
lDaemonLoopSeconds=gSettingsDict["SchedulerDict"]["CheckIntervalSecFloat"]
|
|
|
|
|
|
|
|
lDaemonActivityLogDict={} #Словарь отработанных активностей, ключ - кортеж (<activityType>, <datetime>, <processPath || processName>, <processArgs>)
|
|
|
|
|
|
|
|
lDaemonLastDateTime=datetime.datetime.now()
|
|
|
|
|
|
|
|
gSettingsDict["ServerDict"]["WorkingDirectoryPathStr"] = os.getcwd() # Set working directory in g settings
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#Инициализация сервера
|
|
|
|
|
|
|
|
lThreadServer = Server.RobotDaemonServer("ServerThread", gSettingsDict)
|
|
|
|
|
|
|
|
lThreadServer.start()
|
|
|
|
|
|
|
|
if lL: lL.info("Web server has been started") #Logging
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Init the RobotScreenActive in another thread
|
|
|
|
|
|
|
|
lRobotScreenActiveThread = threading.Thread(target= Monitor.CheckScreen)
|
|
|
|
|
|
|
|
lRobotScreenActiveThread.daemon = True # Run the thread in daemon mode.
|
|
|
|
|
|
|
|
lRobotScreenActiveThread.start() # Start the thread execution.
|
|
|
|
|
|
|
|
if lL: lL.info("Robot Screen active has been started") #Logging
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Init the RobotRDPActive in another thread
|
|
|
|
|
|
|
|
lRobotRDPActiveThread = threading.Thread(target= RobotRDPActive.RobotRDPActive, kwargs={"inGSettings":gSettingsDict})
|
|
|
|
|
|
|
|
lRobotRDPActiveThread.daemon = True # Run the thread in daemon mode.
|
|
|
|
|
|
|
|
lRobotRDPActiveThread.start() # Start the thread execution.
|
|
|
|
|
|
|
|
if lL: lL.info("Robot RDP active has been started") #Logging
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Init autocleaner in another thread
|
|
|
|
|
|
|
|
lAutocleanerThread = threading.Thread(target= GSettingsAutocleaner, kwargs={"inGSettings":gSettingsDict})
|
|
|
|
|
|
|
|
lAutocleanerThread.daemon = True # Run the thread in daemon mode.
|
|
|
|
|
|
|
|
lAutocleanerThread.start() # Start the thread execution.
|
|
|
|
|
|
|
|
if lL: lL.info("Autocleaner thread has been started") #Logging
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Orchestrator start activity
|
|
|
|
|
|
|
|
if lL: lL.info("Orchestrator start activity run") #Logging
|
|
|
|
|
|
|
|
for lActivityItem in gSettingsDict["OrchestratorStart"]["ActivityList"]:
|
|
|
|
|
|
|
|
Processor.ActivityListOrDict(lActivityItem)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Processor thread
|
|
|
|
|
|
|
|
lProcessorThread = threading.Thread(target= Processor.ProcessorRunSync, kwargs={"inGSettings":gSettingsDict})
|
|
|
|
|
|
|
|
lProcessorThread.daemon = True # Run the thread in daemon mode.
|
|
|
|
|
|
|
|
lProcessorThread.start() # Start the thread execution.
|
|
|
|
|
|
|
|
if lL: lL.info("Processor has been started (ProcessorDict)") #Logging
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if lL: lL.info("Scheduler loop start") #Logging
|
|
|
|
|
|
|
|
gDaemonActivityLogDictRefreshSecInt = 10 # The second period for clear lDaemonActivityLogDict from old items
|
|
|
|
|
|
|
|
gDaemonActivityLogDictLastTime = time.time() # The second perioad for clean lDaemonActivityLogDict from old items
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
lCurrentDateTime = datetime.datetime.now()
|
|
|
|
|
|
|
|
#Циклический обход правил
|
|
|
|
|
|
|
|
lFlagSearchActivityType=True
|
|
|
|
|
|
|
|
# Periodically clear the lDaemonActivityLogDict
|
|
|
|
|
|
|
|
if time.time()-gDaemonActivityLogDictLastTime>=gDaemonActivityLogDictRefreshSecInt:
|
|
|
|
|
|
|
|
gDaemonActivityLogDictLastTime = time.time() # Update the time
|
|
|
|
|
|
|
|
for lIndex, lItem in enumerate(lDaemonActivityLogDict):
|
|
|
|
|
|
|
|
if lItem["ActivityEndDateTime"] and lCurrentDateTime<=lItem["ActivityEndDateTime"]:
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
# Activity is actual - do not delete now
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
# remove the activity - not actual
|
|
|
|
|
|
|
|
lDaemonActivityLogDict.pop(lIndex,None)
|
|
|
|
|
|
|
|
lIterationLastDateTime = lDaemonLastDateTime # Get current datetime before iterator (need for iterate all activities in loop)
|
|
|
|
|
|
|
|
# Iterate throught the activity list
|
|
|
|
|
|
|
|
for lIndex, lItem in enumerate(gSettingsDict["SchedulerDict"]["ActivityTimeList"]):
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
# Prepare GUID of the activity
|
|
|
|
|
|
|
|
lGUID = None
|
|
|
|
|
|
|
|
if "GUID" in lItem and lItem["GUID"]:
|
|
|
|
|
|
|
|
lGUID = lItem["GUID"]
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
lGUID = str(uuid.uuid4())
|
|
|
|
|
|
|
|
lItem["GUID"]=lGUID
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#Проверка дней недели, в рамках которых можно запускать активность
|
|
|
|
|
|
|
|
lItemWeekdayList=lItem.get("WeekdayList", [0, 1, 2, 3, 4, 5, 6])
|
|
|
|
|
|
|
|
if lCurrentDateTime.weekday() in lItemWeekdayList:
|
|
|
|
|
|
|
|
if lFlagSearchActivityType:
|
|
|
|
|
|
|
|
#######################################################################
|
|
|
|
|
|
|
|
#Branch 1 - if has TimeHH:MM
|
|
|
|
|
|
|
|
#######################################################################
|
|
|
|
|
|
|
|
if "TimeHH:MM" in lItem:
|
|
|
|
|
|
|
|
#Вид активности - запуск процесса
|
|
|
|
|
|
|
|
#Сформировать временной штамп, относительно которого надо будет проверять время
|
|
|
|
|
|
|
|
#часовой пояс пока не учитываем
|
|
|
|
|
|
|
|
lActivityDateTime=datetime.datetime.strptime(lItem["TimeHH:MM"],"%H:%M")
|
|
|
|
|
|
|
|
lActivityDateTime=lActivityDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day)
|
|
|
|
|
|
|
|
#Убедиться в том, что время наступило
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
|
|
|
lActivityDateTime>=lDaemonLastDateTime and
|
|
|
|
|
|
|
|
lCurrentDateTime>=lActivityDateTime):
|
|
|
|
|
|
|
|
# Log info about activity
|
|
|
|
|
|
|
|
if lL: lL.info(f"Scheduler:: Activity list is started in new thread. Scheduler item: {lItem}") #Logging
|
|
|
|
|
|
|
|
# Do the activity
|
|
|
|
|
|
|
|
lThread = threading.Thread(target=Processor.ActivityListExecute, kwargs={"inGSettings": inGSettings, "inActivityList":lItem["ActivityList"]})
|
|
|
|
|
|
|
|
lThread.start()
|
|
|
|
|
|
|
|
lIterationLastDateTime = datetime.datetime.now() # Set the new datetime for the new processor activity
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
|
|
if lL: lL.exception(f"Scheduler: Exception has been catched in Scheduler module when activity time item was initialising. ActivityTimeItem is {lItem}")
|
|
|
|
|
|
|
|
lDaemonLastDateTime = lIterationLastDateTime # Set the new datetime for the new processor activity
|
|
|
|
|
|
|
|
#Уснуть до следующего прогона
|
|
|
|
|
|
|
|
time.sleep(lDaemonLoopSeconds)
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
|
|
if lL: lL.exception(f"Scheduler: Exception has been catched in Scheduler module. Global error")
|
|
|
|
|
|
|
|
|
|
|
|
# Backward compatibility below to 1.2.0
|
|
|
|
# Backward compatibility below to 1.2.0
|
|
|
|
def __deprecated_orchestrator_start__():
|
|
|
|
def __deprecated_orchestrator_start__():
|
|
|
|