v1.1.0 After 2 month test prefinal with new improovements (+RobotRDPActive in Orchestrator + Easy ControlPanelTemplate)
parent
b8e4cd82b5
commit
18b98d89d3
@ -1,207 +0,0 @@
|
|||||||
import psutil, datetime, logging, os, json
|
|
||||||
# # # # # # # ORCHESTRATOR CONTROL PANEL <Robot name> # # # # # # #
|
|
||||||
# Init parameters
|
|
||||||
gProcessNameWOEXE = "OpenRPA_RobotRDPActive_<RobotKeyName>"
|
|
||||||
gRDPOrchestratorStorageKey = "<RobotKeyName>"
|
|
||||||
gRDPStartFilePath = os.path.abspath(os.path.join(os.getcwd(), gRDPOrchestratorStorageKey+r"\pyOpenRPA.Tools.RobotRDPActive_x64.cmd")) # cwd is orchestrator working directory
|
|
||||||
gOrchestratorToRobotKeyList = ["Storage",gRDPOrchestratorStorageKey,"OrchestratorToRobotStorage"]
|
|
||||||
gOrchestratorToRobotResetKeyList = ["Storage",gRDPOrchestratorStorageKey,"OrchestratorToRobotResetStorage"]
|
|
||||||
gRobotToOrchestratorKeyList = ["Storage",gRDPOrchestratorStorageKey,"RobotToOrchestratorStorage"]
|
|
||||||
gRobotRDPActiveDefsFolderPath = ""
|
|
||||||
gRobotProcessNameWOEXE = "<RobotProcessName>"
|
|
||||||
gRobotProcessFilePath = r"path\to\start\link"
|
|
||||||
# Function, which is generate Dict for front-endswith
|
|
||||||
def ControlPanelRenderDict(inGSettings):
|
|
||||||
"""result={
|
|
||||||
"HeaderLeftText":"<Robot name>",
|
|
||||||
"HeaderRightText":"<header>",
|
|
||||||
"DataStorageKey":"Robot_Name", #Use key for set current dict in mGlobal.DataStorage["DataStorageKey"] on client side
|
|
||||||
"SubheaderText": "State: <span style=\"color:green\">Turned on</span>",
|
|
||||||
"BodyKeyValueList":[
|
|
||||||
{"Key":"Session list","Value":""},
|
|
||||||
{"Key":"Session list","Value":""}
|
|
||||||
],
|
|
||||||
"FooterText":"Last update: 9:38:00 09.10.2019",
|
|
||||||
"FooterButtonX2List":[
|
|
||||||
{"Text":"Turn on", "Color":"green", "Link":"", "OnClick": lOnClickRunButton.replace("\\","\\\\")},
|
|
||||||
],
|
|
||||||
"FooterButtonX1List":[
|
|
||||||
{"Text":"Kill", "Color":"red", "Link":"", "OnClick": lOnClickForceCloseButton.replace("\\","\\\\")}
|
|
||||||
]
|
|
||||||
}"""
|
|
||||||
# START :: Create activities :: START #
|
|
||||||
## RDP Start
|
|
||||||
lActivityRDPStartEscaped = (f"mGlobal.Controller.CMDRunText('start cmd /K {gRDPStartFilePath}');").replace("\\","\\\\").replace("\"","\'") # Need escape because this is render on client side and after that it goes to server side :(
|
|
||||||
## RDP Safe turn off
|
|
||||||
lActivityRDPSafeOffEscaped = (f"mGlobal.Processor.ServerValueSet({json.dumps(gOrchestratorToRobotKeyList+['SafeTurnOff'])},true);").replace("\\","\\\\").replace("\"","\'")
|
|
||||||
## RDP Kill
|
|
||||||
lActivityRDPKillEscaped = (f"mGlobal.Controller.CMDRunText('taskkill /F /im {gProcessNameWOEXE}.exe');").replace("\\","\\\\").replace("\"","\'")
|
|
||||||
## Robot start
|
|
||||||
lActivityROBOTStartList = [
|
|
||||||
{
|
|
||||||
"ModulePath": f"{os.path.abspath(os.path.join(gRobotRDPActiveDefsFolderPath,'Defs_SessionIndex.py'))}", # "RobotRDPActive\\SessionDefs.py"
|
|
||||||
"DefName":"ProcessStartIfNotRunning", # Function name
|
|
||||||
"ArgList":[], # Args list
|
|
||||||
"ArgDict":{"inSessionIndex": 0, "inProcessName": f"{gRobotProcessNameWOEXE}.exe", "inFilePath": gRobotProcessFilePath} # Args dictionary
|
|
||||||
}
|
|
||||||
]
|
|
||||||
lActivityROBOTStartEscaped = f"mGlobal.Processor.ServerValueSet({json.dumps(gOrchestratorToRobotResetKeyList+['ActivityList'])},{json.dumps(lActivityROBOTStartList)});".replace("\"","\'")
|
|
||||||
## ROBOT r3 stop
|
|
||||||
lActivityROBOTStopList = [
|
|
||||||
{
|
|
||||||
"ModulePath": f"{os.path.abspath(os.path.join(gRobotRDPActiveDefsFolderPath,'Defs_SessionIndex.py'))}", # "Session\\SessionDefs.py"
|
|
||||||
"DefName":"ProcessStop", # Function name
|
|
||||||
"ArgList":[], # Args list
|
|
||||||
"ArgDict":{"inSessionIndex": 0, "inProcessName": f"{gRobotProcessNameWOEXE}.exe", "inFlagForceClose":True} # Args dictionary
|
|
||||||
}
|
|
||||||
]
|
|
||||||
lActivityROBOTStopEscaped = f"mGlobal.Processor.ServerValueSet({json.dumps(gOrchestratorToRobotResetKeyList+['ActivityList'])},{json.dumps(lActivityROBOTStopList)});".replace("\"","\'")
|
|
||||||
## ROBOT r3 restart
|
|
||||||
lActivityROBOTRestartList = lActivityROBOTStartList + lActivityROBOTStopList
|
|
||||||
lActivityROBOTRestartEscaped = f"mGlobal.Processor.ServerValueSet({json.dumps(gOrchestratorToRobotResetKeyList+['ActivityList'])},{json.dumps(lActivityROBOTRestartList)});".replace("\"","\'")
|
|
||||||
# END :: Create activities :: END #
|
|
||||||
# START :: Init result dict template :: START #
|
|
||||||
lBodyKeyValue_r3_start=f'<a onclick="{lActivityROBOTStartEscaped}" style=\"color:green\">Start</a>'
|
|
||||||
lBodyKeyValue_r3_stop=f'<a onclick="{lActivityROBOTStopEscaped}" style=\"color:red\">Stop</a>'
|
|
||||||
lBodyKeyValue_r3_restart=f'<a onclick="{lActivityROBOTRestartEscaped}" style=\"color:orange\">restart</a>'
|
|
||||||
lResultDict={
|
|
||||||
"HeaderLeftText":"ROBOT r4",
|
|
||||||
"HeaderRightText":"r4",
|
|
||||||
"DataStorageKey":gRDPOrchestratorStorageKey, #Use key for set current dict in mGlobal.DataStorage["DataStorageKey"] on client side
|
|
||||||
"SubheaderText":"<Subheader text>",
|
|
||||||
"BodyKeyValueList":[
|
|
||||||
{"Key":"ROBOT robots (r1-r5) list","Value":""},
|
|
||||||
{"Key":"r4","Value":f"{lBodyKeyValue_r3_start}, {lBodyKeyValue_r3_stop}, {lBodyKeyValue_r3_restart}"},
|
|
||||||
{"Key":"Session list","Value":""}
|
|
||||||
],
|
|
||||||
"FooterText":"Last update: 9:38:00 09.10.2019",
|
|
||||||
"FooterButtonX2List":[
|
|
||||||
{"Text":"Turn on", "Color":"green", "Link":"", "OnClick": lActivityRDPStartEscaped},
|
|
||||||
{"Text":"Safe turn off", "Color":"orange", "Link":"", "OnClick": lActivityRDPSafeOffEscaped}
|
|
||||||
],
|
|
||||||
"FooterButtonX1List":[
|
|
||||||
{"Text":"Kill", "Color":"red", "Link":"", "OnClick": lActivityRDPKillEscaped}
|
|
||||||
],
|
|
||||||
"GlobalStorage": inGSettings.get("Storage",{}) # UNCOMMENT FOR DEBUG PURPOSE TO WATCH inGSettings on client side
|
|
||||||
}
|
|
||||||
# END :: Init result dict template :: END #
|
|
||||||
# START :: Fill BodyKeyValueList :: START #
|
|
||||||
## Read RDPList
|
|
||||||
lRDPList = TechDictKeyList_ItemGet(inDict=inGSettings, inKeyList=gRobotToOrchestratorKeyList+["RDPList"], inDefault=[])
|
|
||||||
lFullScreenSessionIndex = TechDictKeyList_ItemGet(inDict=inGSettings, inKeyList=gRobotToOrchestratorKeyList+["FullScreenSessionIndex"], inDefault=None)
|
|
||||||
lRDPListIndex = 0
|
|
||||||
for lItem in lRDPList:
|
|
||||||
### Lable that session has fullscreen
|
|
||||||
lLabelSessionFullScreen = ""
|
|
||||||
lLabelIsIgnored = ""
|
|
||||||
### Link set full screen
|
|
||||||
lOnClickSetFullScreen = f"mGlobal.Processor.ServerValueSet(['Storage','{gRDPOrchestratorStorageKey}','OrchestratorToRobotStorage','FullScreenSessionIndex'],{lRDPListIndex});"
|
|
||||||
lSetFullScreenA = f'<a onclick="{lOnClickSetFullScreen}" style=\"color:blue\">Set fullscreen</a>'
|
|
||||||
if lRDPListIndex == lFullScreenSessionIndex:
|
|
||||||
lLabelSessionFullScreen = '<span style=\"color:blue\">[Fullscreen]</span>'
|
|
||||||
lOnClickSetFullScreen = f"mGlobal.Processor.ServerValueSet(['Storage','{gRDPOrchestratorStorageKey}','OrchestratorToRobotStorage','FullScreenSessionIndex'],null);"
|
|
||||||
lSetFullScreenA = f'<a onclick="{lOnClickSetFullScreen}" style=\"color:blue\">Set minimized</a>'
|
|
||||||
lIgnoreIndexListOnClick = "$.ajax({type: 'POST', url: '{gRDPOrchestratorStorageKey}/IgnoreIndexListAppend', data: '"+str(lRDPListIndex)+"', success: function(lData,l2,l3){}, dataType: 'text'});"
|
|
||||||
lIgnoreIndexListLink = f'<a onclick="{lIgnoreIndexListOnClick}" style=\"color:red\">Ignore</a>'
|
|
||||||
### Check if in ignore
|
|
||||||
if lRDPListIndex in inGSettings.get("Storage",{}).get(gRDPOrchestratorStorageKey,{}).get("OrchestratorToRobotStorage",{}).get("IgnoreIndexList",[]):
|
|
||||||
lLabelIsIgnored = '<span style=\"color:red\">[Ignored]</span>'
|
|
||||||
lIgnoreIndexListOnClick = "$.ajax({type: 'POST', url: '"+gRDPOrchestratorStorageKey+"/IgnoreIndexListRemove', data: '"+str(lRDPListIndex)+"', success: function(lData,l2,l3){}, dataType: 'text'});"
|
|
||||||
lIgnoreIndexListLink = f'<a onclick="{lIgnoreIndexListOnClick}" style=\"color:red\">Unignore</a>'
|
|
||||||
### Session state
|
|
||||||
lItemSessionState='<span style=\"color:red\">Disconnected</span>'
|
|
||||||
if lItem.get("SessionIsWindowResponsibleBool",False):
|
|
||||||
lItemSessionState='<span style=\"color:green\">Connected</span>'
|
|
||||||
lResultDict["BodyKeyValueList"].append({"Key":f"[{str(lRDPListIndex)}]{lLabelSessionFullScreen}{lLabelIsIgnored}{lItem.get('Host','localhost')}:{lItem.get('Port','--')}","Value":f"{lItem.get('Login','--')}, {lItem.get('SessionHex','--')}, State {lItemSessionState}, {lSetFullScreenA}, {lIgnoreIndexListLink}"})
|
|
||||||
lRDPListIndex = lRDPListIndex + 1
|
|
||||||
# END :: Fill BodyKeyValueList :: END #
|
|
||||||
# START :: Fill SubheaderText :: START #
|
|
||||||
## Variants
|
|
||||||
lSubheaderRunTrueText="State: <span style=\"color:green\">Turned on</span>"
|
|
||||||
lSubheaderRunFalseText="State: <span style=\"color:red\">Turned off</span>"
|
|
||||||
if CheckIfProcessRunning(gProcessNameWOEXE):
|
|
||||||
lResultDict["SubheaderText"]=lSubheaderRunTrueText
|
|
||||||
else:
|
|
||||||
lResultDict["SubheaderText"]=lSubheaderRunFalseText
|
|
||||||
# END :: Fill SubheaderText :: END #
|
|
||||||
# Fill FooterText
|
|
||||||
lResultDict["FooterText"]=f'Last update: {datetime.datetime.now().strftime("%H:%M:%S %d.%m.%Y")}'
|
|
||||||
return lResultDict
|
|
||||||
# Check in control panel, that process is runnning
|
|
||||||
def CheckIfProcessRunning(processName):
|
|
||||||
'''Check if there is any running process that contains the given name processName.'''
|
|
||||||
#Iterate over the all the running process
|
|
||||||
for proc in psutil.process_iter():
|
|
||||||
try:
|
|
||||||
# Check if process name contains the given name string.
|
|
||||||
if processName.lower() in proc.name().lower():
|
|
||||||
return True
|
|
||||||
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
|
|
||||||
pass
|
|
||||||
return False
|
|
||||||
#Add to ignore list - AJAX request from client side
|
|
||||||
def IgnoreIndexListAppend(inRequest,inConfiguration):
|
|
||||||
lIgnoreList = TechDictKeyList_ItemGet(inDict=inConfiguration, inKeyList=gOrchestratorToRobotKeyList+["IgnoreIndexList"], inDefault=[])
|
|
||||||
lIgnoreIndex={}
|
|
||||||
if inRequest.headers.get('Content-Length') is not None:
|
|
||||||
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
|
|
||||||
lInputByteArray=inRequest.rfile.read(lInputByteArrayLength)
|
|
||||||
#Превращение массива байт в объект
|
|
||||||
lIgnoreIndex=int(lInputByteArray.decode('utf8'))
|
|
||||||
#check if index not in list
|
|
||||||
if lIgnoreIndex not in lIgnoreList:
|
|
||||||
#append to list
|
|
||||||
lIgnoreList.append(lIgnoreIndex)
|
|
||||||
#remove from Ignore list - AJAX request from client side
|
|
||||||
def IgnoreIndexListRemove(inRequest,inConfiguration):
|
|
||||||
lIgnoreList = TechDictKeyList_ItemGet(inDict=inConfiguration, inKeyList=gOrchestratorToRobotKeyList+["IgnoreIndexList"], inDefault=[])
|
|
||||||
lIgnoreIndex={}
|
|
||||||
if inRequest.headers.get('Content-Length') is not None:
|
|
||||||
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
|
|
||||||
lInputByteArray=inRequest.rfile.read(lInputByteArrayLength)
|
|
||||||
#Превращение массива байт в объект
|
|
||||||
lIgnoreIndex=int(lInputByteArray.decode('utf8'))
|
|
||||||
#check if index not in list
|
|
||||||
if lIgnoreIndex in lIgnoreList:
|
|
||||||
#append to list
|
|
||||||
lIgnoreList.remove(lIgnoreIndex) #Remove delete the element lIgnoreIndex
|
|
||||||
# Technical def - Get item by the list of keys
|
|
||||||
def TechDictKeyList_ItemGet(inDict, inKeyList, inDefault={}):
|
|
||||||
lResult=inDict
|
|
||||||
for lItem in inKeyList:
|
|
||||||
if lResult:
|
|
||||||
lResult = lResult.get(lItem,None)
|
|
||||||
if lResult is None:
|
|
||||||
lResult=inDefault
|
|
||||||
return lResult
|
|
||||||
# # # # # # # # # # # # # # # # # # # # # # # #
|
|
||||||
#Orchestrator settings
|
|
||||||
def SettingsUpdate(inGSettings):
|
|
||||||
#Add RobotRDPActive in control panel
|
|
||||||
inGSettings["ControlPanelDict"]["RobotList"].append({"RenderFunction": ControlPanelRenderDict})
|
|
||||||
#Default structure
|
|
||||||
inGSettings["Storage"][gRDPOrchestratorStorageKey]={
|
|
||||||
"OrchestratorToRobotResetStorage":{"SafeTurnOff":False, "ActivityList":[]},
|
|
||||||
"OrchestratorToRobotStorage":{
|
|
||||||
"FullScreenSessionIndex":None,
|
|
||||||
"IgnoreIndexList": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#Add methods
|
|
||||||
inGSettings["Server"]["URLList"].append(
|
|
||||||
{
|
|
||||||
"Method":"POST",
|
|
||||||
"URL": f"/{gRDPOrchestratorStorageKey}/IgnoreIndexListAppend", #URL of the request
|
|
||||||
"MatchType": "Equal", #"BeginWith|Contains|Equal|EqualCase",
|
|
||||||
"ResponseDefRequestGlobal": IgnoreIndexListAppend #Function with str result
|
|
||||||
}
|
|
||||||
)
|
|
||||||
inGSettings["Server"]["URLList"].append(
|
|
||||||
{
|
|
||||||
"Method":"POST",
|
|
||||||
"URL": f"/{gRDPOrchestratorStorageKey}/IgnoreIndexListRemove", #URL of the request
|
|
||||||
"MatchType": "Equal", #"BeginWith|Contains|Equal|EqualCase",
|
|
||||||
"ResponseDefRequestGlobal": IgnoreIndexListRemove #Function with str result
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return inGSettings
|
|
@ -0,0 +1,124 @@
|
|||||||
|
import psutil, datetime, logging, os, json
|
||||||
|
# # # # # # # ORCHESTRATOR CONTROL PANEL <Robot name> # # # # # # #
|
||||||
|
# Init parameters
|
||||||
|
gRobotStartFilePathStr = r"path\to\start\file" # path\to\start\file
|
||||||
|
gRobotProcessNameWOEXEStr = "process name" # RobotProcessName
|
||||||
|
gRobotADLoginStr = "Login" # Login of the robot session
|
||||||
|
gRobotADPasswordStr = "Password" # Password for session
|
||||||
|
gRobotKeyStr = "Robot_Template"
|
||||||
|
gRDPSessionKeyStr = "RDP_Template"
|
||||||
|
gRDPSessionHostStr = "localhost" # Rdp session host
|
||||||
|
gRDPSessionPortStr = "3389" # Default 3389
|
||||||
|
gControlPanelKeyStr = "ControlPanel_Template"
|
||||||
|
gControlPanelCheckRobotProcessFromOrchestratorUserBool = True # Check process activity from orchestrator GUI session (with help of task manager, when users on the same machine)
|
||||||
|
# !! ATTENTION !! SCHEDULE TIME START STOP FILL BELOW IN ACTIVITY SECTION
|
||||||
|
gRobotToOrchestratorKeyList = ["Storage",gRobotKeyStr,"RobotToOrchestrator"]
|
||||||
|
gOrchestratorToRobotResetKeyList = ["Storage",gRobotKeyStr,"OrchestratorToRobotReset"]
|
||||||
|
gOrchestratorToRobotResetSafeStopKeyList = gOrchestratorToRobotResetKeyList+["SafeTurnOffBool"]
|
||||||
|
|
||||||
|
# Function, which is generate Dict for front-endswith
|
||||||
|
def ControlPanelRenderDict(inGSettings):
|
||||||
|
"""result={
|
||||||
|
"HeaderLeftText":"<Robot name>",
|
||||||
|
"HeaderRightText":"<header>",
|
||||||
|
"DataStorageKey":"Robot_Name", #Use key for set current dict in mGlobal.DataStorage["DataStorageKey"] on client side
|
||||||
|
"SubheaderText": "State: <span style=\"color:green\">Turned on</span>",
|
||||||
|
"BodyKeyValueList":[
|
||||||
|
{"Key":"Session list","Value":""},
|
||||||
|
{"Key":"Session list","Value":""}
|
||||||
|
],
|
||||||
|
"FooterText":"Last update: 9:38:00 09.10.2019",
|
||||||
|
"FooterButtonX2List":[
|
||||||
|
{"Text":"Turn on", "Color":"green", "Link":"", "OnClick": lOnClickRunButton.replace("\\","\\\\")},
|
||||||
|
],
|
||||||
|
"FooterButtonX1List":[
|
||||||
|
{"Text":"Kill", "Color":"red", "Link":"", "OnClick": lOnClickForceCloseButton.replace("\\","\\\\")}
|
||||||
|
]
|
||||||
|
}"""
|
||||||
|
# START :: Create activities :: START #
|
||||||
|
## Robot START (create RDP session, send CMD to start process)
|
||||||
|
lActivityROBOTStartList = [
|
||||||
|
{ # Start RDP Session
|
||||||
|
"DefNameStr":"RDPSessionConnect", # Function name in RobotRDPActive.Processor
|
||||||
|
"ArgList":[], # Args list
|
||||||
|
"ArgDict":{"inRDPSessionKeyStr": gRDPSessionKeyStr, "inHostStr": gRDPSessionHostStr, "inPortStr": gRDPSessionPortStr, "inLoginStr": gRobotADLoginStr, "inPasswordStr": gRobotADPasswordStr} # Args dictionary
|
||||||
|
},
|
||||||
|
{ # Run robot file in RDP session
|
||||||
|
"DefNameStr":"RDPSessionProcessStartIfNotRunning", # Function name in RobotRDPActive.Processor
|
||||||
|
"ArgList":[], # Args list
|
||||||
|
"ArgDict":{"inRDPSessionKeyStr": gRDPSessionKeyStr, "inProcessNameWEXEStr": f"{gRobotProcessNameWOEXEStr}.exe", "inFilePathStr": gRobotStartFilePathStr, "inFlagGetAbsPathBool": False} # Args dictionary
|
||||||
|
}
|
||||||
|
]
|
||||||
|
lActivityROBOTStartEscaped = f"mGlobal.Processor.ServerValueSet({json.dumps(['RobotRDPActive','ActivityList'])},{json.dumps(lActivityROBOTStartList)});".replace("\"","\'")
|
||||||
|
## Robot SAFE STOP (SAFE STOP COMMAND (FROM ROBOT RULES), Logoff must do robot when safe turn off)
|
||||||
|
lActivityROBOTSafeStopEscaped = f"mGlobal.Processor.ServerValueSet({json.dumps(gOrchestratorToRobotResetSafeStopKeyList)},true);".replace("\"","\'")
|
||||||
|
## Robot FORCE STOP (create RDP session, send CMD to start process)
|
||||||
|
lActivityROBOTStopList = [
|
||||||
|
{ # Kill process
|
||||||
|
"DefNameStr":"RDPSessionProcessStop", # Function name in RobotRDPActive.Processor
|
||||||
|
"ArgList":[], # Args list
|
||||||
|
"ArgDict":{"inRDPSessionKeyStr": gRDPSessionKeyStr, "inProcessNameWEXEStr":f"{gRobotProcessNameWOEXEStr}.exe","inFlagForceCloseBool": True} # Args dictionary
|
||||||
|
},
|
||||||
|
{ # Logoff RDP Session
|
||||||
|
"DefNameStr":"RDPSessionLogoff", # Function name in RobotRDPActive.Processor
|
||||||
|
"ArgList":[], # Args list
|
||||||
|
"ArgDict":{"inRDPSessionKeyStr": gRDPSessionKeyStr} # Args dictionary
|
||||||
|
}
|
||||||
|
]
|
||||||
|
lActivityROBOTStopEscaped = f"mGlobal.Processor.ServerValueSet({json.dumps(['RobotRDPActive','ActivityList'])},{json.dumps(lActivityROBOTStopList)});".replace("\"","\'")
|
||||||
|
# END :: Create activities :: END #
|
||||||
|
# START :: Init result dict template :: START #
|
||||||
|
# lBodyKeyValue_r3_start=f'<a onclick="{lActivityROBOTStartEscaped}" style=\"color:green\">Start</a>'
|
||||||
|
lResultDict={
|
||||||
|
"HeaderLeftText":"ROBOT KEYWORD",
|
||||||
|
"HeaderRightText":"ROBOT NAME",
|
||||||
|
"DataStorageKey":gControlPanelKeyStr, # CLIENT SIDE:: Use key for set current dict in mGlobal.DataStorage["DataStorageKey"] on client side
|
||||||
|
"SubheaderText":"<Subheader text, state filled below>",
|
||||||
|
"BodyKeyValueList":[
|
||||||
|
{"Key":"Info","Value":"1"},
|
||||||
|
{"Key":"Info","Value":"2"},
|
||||||
|
{"Key":"Info","Value":"3"},
|
||||||
|
{"Key":"Statistic","Value":""}
|
||||||
|
],
|
||||||
|
"FooterText":"Last update: 9:38:00 09.10.2019",
|
||||||
|
"FooterButtonX2List":[
|
||||||
|
{"Text":"Turn on", "Color":"green", "Link":"", "OnClick": lActivityROBOTStartEscaped},
|
||||||
|
{"Text":"Safe turn off", "Color":"orange", "Link":"", "OnClick": lActivityROBOTSafeStopEscaped}
|
||||||
|
],
|
||||||
|
"FooterButtonX1List":[
|
||||||
|
{"Text":"Kill", "Color":"red", "Link":"", "OnClick": lActivityROBOTStopEscaped}
|
||||||
|
],
|
||||||
|
# "GlobalStorage": inGSettings.get("Storage",{}) # UNCOMMENT FOR DEBUG PURPOSE TO WATCH inGSettings on client side
|
||||||
|
}
|
||||||
|
# END :: Init result dict template :: END #
|
||||||
|
# START :: Fill BodyKeyValueList :: START #
|
||||||
|
|
||||||
|
# END :: Fill BodyKeyValueList :: END #
|
||||||
|
# START :: Fill SubheaderText :: START #
|
||||||
|
## FILL Robot state by the check the RDP session state
|
||||||
|
lSubheaderRunTrueText="State: <span style=\"color:green\">Turned on</span>"
|
||||||
|
lSubheaderRunFalseText="State: <span style=\"color:red\">Turned off</span>"
|
||||||
|
if gControlPanelCheckRobotProcessFromOrchestratorUserBool and gRDPSessionKeyStr in inGSettings["RobotRDPActive"]["RDPList"]:
|
||||||
|
lResultDict["SubheaderText"]=lSubheaderRunTrueText
|
||||||
|
else:
|
||||||
|
lResultDict["SubheaderText"]=lSubheaderRunFalseText
|
||||||
|
# END :: Fill SubheaderText :: END #
|
||||||
|
# Fill FooterText
|
||||||
|
lResultDict["FooterText"]=f'Last update: {datetime.datetime.now().strftime("%H:%M:%S %d.%m.%Y")}'
|
||||||
|
return lResultDict
|
||||||
|
|
||||||
|
# Technical def - Get item by the list of keys
|
||||||
|
def TechDictKeyList_ItemGet(inDict, inKeyList, inDefault={}):
|
||||||
|
lResult=inDict
|
||||||
|
for lItem in inKeyList:
|
||||||
|
if lResult:
|
||||||
|
lResult = lResult.get(lItem,None)
|
||||||
|
if lResult is None:
|
||||||
|
lResult=inDefault
|
||||||
|
return lResult
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
#Orchestrator settings update
|
||||||
|
def SettingsUpdate(inGSettings):
|
||||||
|
#Add RobotRDPActive in control panel
|
||||||
|
inGSettings["ControlPanelDict"]["RobotList"].append({"RenderFunction": ControlPanelRenderDict, "KeyStr": gControlPanelKeyStr})
|
||||||
|
return inGSettings
|
@ -1,6 +1,6 @@
|
|||||||
Metadata-Version: 2.1
|
Metadata-Version: 2.1
|
||||||
Name: pyOpenRPA
|
Name: pyOpenRPA
|
||||||
Version: 1.0.42
|
Version: 1.1.0
|
||||||
Summary: First open source RPA platform for business
|
Summary: First open source RPA platform for business
|
||||||
Home-page: https://gitlab.com/UnicodeLabs/OpenRPA
|
Home-page: https://gitlab.com/UnicodeLabs/OpenRPA
|
||||||
Author: Ivan Maslov
|
Author: Ivan Maslov
|
@ -0,0 +1,26 @@
|
|||||||
|
import os # Get abs path of the file
|
||||||
|
# Create CMD str to run file if process.exe is not running
|
||||||
|
def ProcessStartIfNotRunning(inProcessName, inFilePath, inFlagGetAbsPath=True):
|
||||||
|
lFileAbsPath = inFilePath
|
||||||
|
if inFlagGetAbsPath:
|
||||||
|
lFileAbsPath = os.path.abspath(inFilePath)
|
||||||
|
lResult = f'tasklist /nh /fi "imagename eq {inProcessName}" | find /i "{inProcessName}" > nul || (start {lFileAbsPath})'
|
||||||
|
return lResult
|
||||||
|
# Create CMD str to stop process
|
||||||
|
def ProcessStop(inProcessName, inFlagForceClose):
|
||||||
|
lResult = f'taskkill /im "{inProcessName}" /fi "username eq %USERNAME%"'
|
||||||
|
if inFlagForceClose:
|
||||||
|
lResult+= " /F"
|
||||||
|
return lResult
|
||||||
|
# Send file from Host to Session RDP using shared drive in RDP (force copy)
|
||||||
|
def FileStoredSend(inHostFilePath, inRDPFilePath):
|
||||||
|
lHostFileAbsPath = os.path.join("\\\\tsclient", os.path.abspath(inHostFilePath).replace(":","")) # \\tsclient\C\path\to\file
|
||||||
|
lHostRDPFileAbsPath = os.path.abspath(inRDPFilePath) # File location in RDP
|
||||||
|
lResult = f'copy /Y "{lHostFileAbsPath}" "{lHostRDPFileAbsPath}"'
|
||||||
|
return lResult
|
||||||
|
# Send file from Session RDP to Host using shared drive in RDP (force copy)
|
||||||
|
def FileStoredRecieve(inRDPFilePath, inHostFilePath):
|
||||||
|
lHostFileAbsPath = os.path.join("\\\\tsclient", os.path.abspath(inHostFilePath).replace(":","")) # \\tsclient\C\path\to\file
|
||||||
|
lHostRDPFileAbsPath = os.path.abspath(inRDPFilePath) # File location in RDP
|
||||||
|
lResult = f'copy /Y "{lHostRDPFileAbsPath}" "{lHostFileAbsPath}"'
|
||||||
|
return lResult
|
@ -0,0 +1,40 @@
|
|||||||
|
import win32clipboard
|
||||||
|
import keyboard # keyboard functions
|
||||||
|
import time # Some operations need wait
|
||||||
|
import random # random number for test
|
||||||
|
gWaitTextInClipboardSec = 1 # Second for wait text will be set in clipboard (for get operations)
|
||||||
|
# set clipboard data
|
||||||
|
def TextSet(inTextStr):
|
||||||
|
win32clipboard.OpenClipboard()
|
||||||
|
win32clipboard.EmptyClipboard()
|
||||||
|
win32clipboard.SetClipboardText(inTextStr)
|
||||||
|
win32clipboard.CloseClipboard()
|
||||||
|
# get clipboard data
|
||||||
|
def TextGet(inWaitTextInClipboardSec = gWaitTextInClipboardSec):
|
||||||
|
time.sleep(inWaitTextInClipboardSec) # Wait for clipboard will save
|
||||||
|
win32clipboard.OpenClipboard()
|
||||||
|
data = win32clipboard.GetClipboardData()
|
||||||
|
win32clipboard.CloseClipboard()
|
||||||
|
return data
|
||||||
|
# Test in has text cursor and ready to apply
|
||||||
|
def InputIsFocused():
|
||||||
|
keyboard.press_and_release("ctrl+a")
|
||||||
|
keyboard.press_and_release("backspace") # remove old text
|
||||||
|
lTextForTest = str(random.randrange(100,99999))
|
||||||
|
keyboard.write(lTextForTest)
|
||||||
|
keyboard.press_and_release("ctrl+a")
|
||||||
|
keyboard.press_and_release("ctrl+c")
|
||||||
|
time.sleep(2)
|
||||||
|
keyboard.press_and_release("backspace") # remove old text
|
||||||
|
lClipboardText = TextGet()
|
||||||
|
lResult = lClipboardText == lTextForTest
|
||||||
|
return lResult
|
||||||
|
# Check if cmd is opened
|
||||||
|
def CMDIsOpen():
|
||||||
|
lTextForTest = str(random.randrange(100,99999))
|
||||||
|
keyboard.write(lTextForTest+" |clip")
|
||||||
|
keyboard.press_and_release("enter")
|
||||||
|
time.sleep(2)
|
||||||
|
lClipboardText = TextGet()
|
||||||
|
lResult = lClipboardText == lTextForTest
|
||||||
|
return lResult
|
@ -0,0 +1,10 @@
|
|||||||
|
#####################################
|
||||||
|
# RobotRDPActive Exceptions class
|
||||||
|
#####################################
|
||||||
|
class SessionWindowNotExistError(Exception): pass #Error when Window not exists
|
||||||
|
class SessionWindowNotResponsibleError(Exception): pass # Error when Window not responding
|
||||||
|
class HostNoGUIError(Exception): pass # Orchestrator session has no GUI
|
||||||
|
#try:
|
||||||
|
# raise SessionWindowNotResponsibleError("Test")
|
||||||
|
#except SessionWindowNotResponsibleError as e:
|
||||||
|
# print("Catched")
|
@ -0,0 +1,66 @@
|
|||||||
|
# ATTENTION! HERE IS NO Relative import because it will be imported dynamically
|
||||||
|
# All function check the flag SessionIsWindowResponsibleBool == True else no cammand is processed
|
||||||
|
# All functions can return None, Bool or Dict { "IsSuccessful": True }
|
||||||
|
from pyOpenRPA.Tools.RobotRDPActive import CMDStr # Create CMD Strings
|
||||||
|
from pyOpenRPA.Tools.RobotRDPActive import Connector # RDP API
|
||||||
|
def ProcessStartIfNotRunning(inGlobalDict, inSessionIndex, inProcessName, inFilePath, inFlagGetAbsPath=True):
|
||||||
|
lResult = True
|
||||||
|
lCMDStr = CMDStr.ProcessStartIfNotRunning(inProcessName,inFilePath, inFlagGetAbsPath= inFlagGetAbsPath)
|
||||||
|
# Calculate the session Hex
|
||||||
|
lSessionHex = inGlobalDict["RDPList"][inSessionIndex]["SessionHex"]
|
||||||
|
# Check is Session is responsible
|
||||||
|
if inGlobalDict["RDPList"][inSessionIndex]["SessionIsWindowResponsibleBool"]:
|
||||||
|
# Run CMD
|
||||||
|
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
|
||||||
|
else:
|
||||||
|
# Write in logger - warning
|
||||||
|
inGlobalDict["Logger"].warning(f"GlobalDictSessionIndex_Defs.ProcessStartIfNotRunning: SessionIndex: {str(inSessionIndex)}, ProcessName: {inProcessName}:: Session is not responsible!")
|
||||||
|
lResult = False # Set false result - function has not been done
|
||||||
|
return lResult
|
||||||
|
# Create CMD str to stop process
|
||||||
|
def ProcessStop(inGlobalDict, inSessionIndex, inProcessName, inFlagForceClose):
|
||||||
|
lResult = True
|
||||||
|
lCMDStr = f'taskkill /im "{inProcessName}" /fi "username eq %USERNAME%"'
|
||||||
|
if inFlagForceClose:
|
||||||
|
lCMDStr+= " /F"
|
||||||
|
# Calculate the session Hex
|
||||||
|
lSessionHex = inGlobalDict["RDPList"][inSessionIndex]["SessionHex"]
|
||||||
|
# Check is Session is responsible
|
||||||
|
if inGlobalDict["RDPList"][inSessionIndex]["SessionIsWindowResponsibleBool"]:
|
||||||
|
# Run CMD
|
||||||
|
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
|
||||||
|
else:
|
||||||
|
# TODO Write in logger - warning
|
||||||
|
inGlobalDict["Logger"].warning(f"GlobalDictSessionIndex_Defs.ProcessStop: SessionIndex: {str(inSessionIndex)}, ProcessName: {inProcessName}:: Session is not responsible!")
|
||||||
|
lResult = False # Set false result - function has not been done
|
||||||
|
return lResult
|
||||||
|
# Send file from Host to Session RDP using shared drive in RDP
|
||||||
|
def FileStoredSend(inGlobalDict, inSessionIndex, inHostFilePath, inRDPFilePath):
|
||||||
|
lResult = True
|
||||||
|
lCMDStr = CMDStr.FileStoredSend(inHostFilePath = inHostFilePath, inRDPFilePath = inRDPFilePath)
|
||||||
|
# Calculate the session Hex
|
||||||
|
lSessionHex = inGlobalDict["RDPList"][inSessionIndex]["SessionHex"]
|
||||||
|
# Check is Session is responsible
|
||||||
|
if inGlobalDict["RDPList"][inSessionIndex]["SessionIsWindowResponsibleBool"]:
|
||||||
|
# Run CMD
|
||||||
|
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120)
|
||||||
|
else:
|
||||||
|
# Write in logger - warning
|
||||||
|
inGlobalDict["Logger"].warning(f"GlobalDictSessionIndex_Defs.FileStoredSend: SessionIndex: {str(inSessionIndex)}, HostFilePath: {inHostFilePath}:: Session is not responsible!")
|
||||||
|
lResult = False # Set false result - function has not been done
|
||||||
|
return lResult
|
||||||
|
# Recieve file from Session RDP to Host using shared drive in RDP
|
||||||
|
def FileStoredRecieve(inGlobalDict, inSessionIndex, inRDPFilePath, inHostFilePath):
|
||||||
|
lResult = True
|
||||||
|
lCMDStr = CMDStr.FileStoredRecieve(inRDPFilePath = inRDPFilePath, inHostFilePath = inHostFilePath)
|
||||||
|
# Calculate the session Hex
|
||||||
|
lSessionHex = inGlobalDict["RDPList"][inSessionIndex]["SessionHex"]
|
||||||
|
# Check is Session is responsible
|
||||||
|
if inGlobalDict["RDPList"][inSessionIndex]["SessionIsWindowResponsibleBool"]:
|
||||||
|
# Run CMD
|
||||||
|
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120)
|
||||||
|
else:
|
||||||
|
# Write in logger - warning
|
||||||
|
inGlobalDict["Logger"].warning(f"GlobalDictSessionIndex_Defs.FileStoredRecieve: SessionIndex: {str(inSessionIndex)}, HostFilePath: {inHostFilePath}:: Session is not responsible!")
|
||||||
|
lResult = False # Set false result - function has not been done
|
||||||
|
return lResult
|
@ -0,0 +1,158 @@
|
|||||||
|
from pyOpenRPA.Robot import UIDesktop
|
||||||
|
from . import Connector
|
||||||
|
import os
|
||||||
|
import time # Time wait operations
|
||||||
|
import importlib # from dynamic import module
|
||||||
|
from . import ConnectorExceptions # Exceptions classes
|
||||||
|
|
||||||
|
|
||||||
|
#Check for session is closed. Reopen if detected. Always keep session is active
|
||||||
|
def Monitor(inGlobalDict, inListUpdateTimeout):
|
||||||
|
lFlagWhile = True
|
||||||
|
lResponsibilityCheckLastSec = time.time() # Get current time for check interval
|
||||||
|
while lFlagWhile:
|
||||||
|
try:
|
||||||
|
# UIOSelector list init
|
||||||
|
lUIOSelectorList = []
|
||||||
|
#Prepare selectors list for check
|
||||||
|
for lIndex, lItem in enumerate(inGlobalDict["RDPList"]):
|
||||||
|
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']}.*", "backend": "win32"}])
|
||||||
|
#Run wait command
|
||||||
|
#import pdb
|
||||||
|
#pdb.set_trace()
|
||||||
|
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
|
||||||
|
#print(lRDPDissappearList)
|
||||||
|
###########################################
|
||||||
|
#Analyze if flag safeturn off is activated
|
||||||
|
if inGlobalDict.get("OrchestratorToRobotResetStorage",{}).get("SafeTurnOff",False):
|
||||||
|
lFlagWhile=False
|
||||||
|
#Set status disconnected for all RDP List
|
||||||
|
for lItem in inGlobalDict["RDPList"]:
|
||||||
|
lItem["SessionIsWindowExistBool"]=False
|
||||||
|
lItem["SessionIsWindowResponsibleBool"]=False
|
||||||
|
#Kill all RDP sessions
|
||||||
|
os.system('taskkill /F /im mstsc.exe')
|
||||||
|
#Return from function
|
||||||
|
return
|
||||||
|
###########################################
|
||||||
|
###########################################
|
||||||
|
for lItem in lRDPDissappearList:
|
||||||
|
inGlobalDict["RDPList"][lItem]["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
|
||||||
|
inGlobalDict["RDPList"][lItem]["SessionIsWindowResponsibleBool"]=False
|
||||||
|
#pdb.set_trace()
|
||||||
|
#Session start if it is not in ignore list
|
||||||
|
#add check for selector if it is not in ignoreIndexList
|
||||||
|
if lItem not in inGlobalDict["OrchestratorToRobotStorage"]["IgnoreIndexList"]:
|
||||||
|
try:
|
||||||
|
Connector.Session(inGlobalDict["RDPList"][lItem])
|
||||||
|
inGlobalDict["RDPList"][lItem]["SessionIsWindowExistBool"] = True # Flag that session is started
|
||||||
|
inGlobalDict["RDPList"][lItem]["SessionIsWindowResponsibleBool"]= True
|
||||||
|
# Write in logger - info
|
||||||
|
inGlobalDict["Logger"].info(f"SessionHex: {str(inGlobalDict['RDPList'][lItem]['SessionHex'])}:: Session has been initialized!")
|
||||||
|
# catch ConnectorExceptions.SessionWindowNotExistError
|
||||||
|
except ConnectorExceptions.SessionWindowNotExistError as e:
|
||||||
|
inGlobalDict["RDPList"][lItem]["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
|
||||||
|
inGlobalDict["RDPList"][lItem]["SessionIsWindowResponsibleBool"]=False
|
||||||
|
# Write in logger - warning
|
||||||
|
inGlobalDict["Logger"].warning(f"SessionHex: {str(inGlobalDict['RDPList'][lItem]['SessionHex'])}:: Session is not exist!")
|
||||||
|
# catch ConnectorExceptions.SessionWindowNotResponsibleError
|
||||||
|
except ConnectorExceptions.SessionWindowNotResponsibleError as e:
|
||||||
|
inGlobalDict["RDPList"][lItem]["SessionIsWindowExistBool"] = True # Set flag that session is disconnected
|
||||||
|
inGlobalDict["RDPList"][lItem]["SessionIsWindowResponsibleBool"]=False
|
||||||
|
# Write in logger - warning
|
||||||
|
inGlobalDict["Logger"].warning(f"SessionHex: {str(inGlobalDict['RDPList'][lItem]['SessionHex'])}:: Session is not responsible!")
|
||||||
|
# general exceptions
|
||||||
|
except Exception as e:
|
||||||
|
# Write in logger - warning
|
||||||
|
inGlobalDict["Logger"].exception(f"!!! ATTENTION !!! Unrecognized error")
|
||||||
|
#######################
|
||||||
|
# Click all warning messages
|
||||||
|
Connector.SystemRDPWarningClickOk()
|
||||||
|
#######################
|
||||||
|
###########################################
|
||||||
|
#Check if from Orchestrator full screen session is set
|
||||||
|
if inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"] != inGlobalDict["FullScreenSessionIndex"]:
|
||||||
|
#Do some switches
|
||||||
|
#If full screen mode we have now
|
||||||
|
if inGlobalDict["FullScreenSessionIndex"] is not None:
|
||||||
|
if inGlobalDict["RDPList"][inGlobalDict["FullScreenSessionIndex"]]["SessionIsWindowExistBool"]:
|
||||||
|
Connector.SessionScreen100x550(inGlobalDict["RDPList"][inGlobalDict["FullScreenSessionIndex"]]["SessionHex"])
|
||||||
|
#If new session is setted
|
||||||
|
if inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"] is not None:
|
||||||
|
if inGlobalDict["RDPList"][inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]]["SessionIsWindowExistBool"]:
|
||||||
|
Connector.SessionScreenFull(inGlobalDict["RDPList"][inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]]["SessionHex"])
|
||||||
|
#Set one to other equal
|
||||||
|
inGlobalDict["FullScreenSessionIndex"] = inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]
|
||||||
|
###########################################
|
||||||
|
####################################
|
||||||
|
##### Block check responsibility interval [ResponsibilityCheckIntervalSec]
|
||||||
|
if inGlobalDict['ResponsibilityCheckIntervalSec']: # Do check if ResponsibilityCheckIntervalSec is not None
|
||||||
|
if (time.time - lResponsibilityCheckLastSec()) > inGlobalDict['ResponsibilityCheckIntervalSec']:
|
||||||
|
# Set new time
|
||||||
|
lResponsibilityCheckLastSec = time.time()
|
||||||
|
# Do responsibility check
|
||||||
|
for lIndex, lItem in enumerate(inGlobalDict["RDPList"]):
|
||||||
|
# Check RDP responsibility
|
||||||
|
lDoCheckResponsibilityBool = True
|
||||||
|
lDoCheckResponsibilityCountMax = 20
|
||||||
|
lDoCheckResponsibilityCountCurrent = 0
|
||||||
|
while lDoCheckResponsibilityBool:
|
||||||
|
# Enter full screen mode
|
||||||
|
Connector.SessionScreenFull(lItem['SessionHex'])
|
||||||
|
time.sleep(2)
|
||||||
|
# Check responding
|
||||||
|
lDoCheckResponsibilityBool = not Connector.SystemRDPIsResponsible()
|
||||||
|
# Check if counter is exceed - raise exception
|
||||||
|
if lDoCheckResponsibilityCountCurrent >= lDoCheckResponsibilityCountMax:
|
||||||
|
lItem["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
|
||||||
|
lItem["SessionIsWindowResponsibleBool"]=False
|
||||||
|
# Session window is not responsible - restart RDP (close window here - next loop will reconnect)
|
||||||
|
Connector.SessionClose(lItem['SessionHex'])
|
||||||
|
# Turn off the loop
|
||||||
|
lDoCheckResponsibilityBool = False
|
||||||
|
else:
|
||||||
|
# Exit fullscreen mode
|
||||||
|
Connector.SessionScreen100x550(lItem['SessionHex'])
|
||||||
|
# Wait if is not responding
|
||||||
|
if lDoCheckResponsibilityBool:
|
||||||
|
time.sleep(3)
|
||||||
|
# increase the couter
|
||||||
|
lDoCheckResponsibilityCountCurrent+=1
|
||||||
|
####################################
|
||||||
|
# Check ActivityList from orchestrator
|
||||||
|
lActivityListNew = []
|
||||||
|
lActivityListOld = inGlobalDict["OrchestratorToRobotResetStorage"]["ActivityList"]+inGlobalDict["ActivityListStart"]
|
||||||
|
inGlobalDict["ActivityListStart"] = []
|
||||||
|
for lActivityItem in lActivityListOld:
|
||||||
|
#################
|
||||||
|
#Call function from Activity structure
|
||||||
|
################################################
|
||||||
|
lSubmoduleFunctionName = lActivityItem["DefName"]
|
||||||
|
lFileFullPath = lActivityItem["ModulePath"] # "path\\to\\module.py"
|
||||||
|
lModuleName = (lFileFullPath.split("\\")[-1])[0:-3]
|
||||||
|
lTechSpecification = importlib.util.spec_from_file_location(lModuleName, lFileFullPath)
|
||||||
|
lTechModuleFromSpec = importlib.util.module_from_spec(lTechSpecification)
|
||||||
|
lTechSpecificationModuleLoader = lTechSpecification.loader.exec_module(lTechModuleFromSpec)
|
||||||
|
# Set gSettings in module
|
||||||
|
lTechModuleFromSpec.gSettings = inGlobalDict
|
||||||
|
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
|
||||||
|
# Run SettingUpdate function in submodule
|
||||||
|
#mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
|
||||||
|
lActivityItemResult=getattr(lTechModuleFromSpec, lSubmoduleFunctionName)(*lActivityItem["ArgList"],**lActivityItem["ArgDict"])
|
||||||
|
lActivityItemResultType = type(lActivityItemResult)
|
||||||
|
# Check if Result is bool
|
||||||
|
if lActivityItemResultType is bool:
|
||||||
|
if not lActivityItemResult:
|
||||||
|
# Activity is not done - add to list (retry in future)
|
||||||
|
lActivityListNew.append(lActivityItem)
|
||||||
|
#################################################
|
||||||
|
inGlobalDict["OrchestratorToRobotResetStorage"]["ActivityList"] = lActivityListNew # Override the value
|
||||||
|
except RuntimeError as e:
|
||||||
|
# case noGUI error passed - do nothing
|
||||||
|
# Write in logger - warning
|
||||||
|
inGlobalDict["Logger"].warning(f"Host session has lost the GUI")
|
||||||
|
finally:
|
||||||
|
# Wait for the next iteration
|
||||||
|
time.sleep(0.7)
|
||||||
|
return None
|
||||||
|
#TODO Def garbage window cleaner (if connection was lost)
|
@ -0,0 +1,147 @@
|
|||||||
|
# ATTENTION! HERE IS NO Relative import because it will be imported dynamically
|
||||||
|
# All function check the flag SessionIsWindowResponsibleBool == True else no cammand is processed
|
||||||
|
# All functions can return None, Bool or Dict { "IsSuccessful": True }
|
||||||
|
from . import CMDStr # Create CMD Strings
|
||||||
|
from . import Connector # RDP API
|
||||||
|
from . import ConnectorExceptions # Exceptions
|
||||||
|
import time # sleep function
|
||||||
|
# ATTENTION
|
||||||
|
gSettings = None # Gsettings will be initialized after the import module
|
||||||
|
|
||||||
|
# Create new RDPSession in RobotRDPActive
|
||||||
|
def RDPSessionConnect(inRDPSessionKeyStr, inHostStr, inPortStr, inLoginStr, inPasswordStr):
|
||||||
|
lRDPConfigurationItem = { # Init the configuration item
|
||||||
|
"Host": inHostStr, # Host address, example "77.77.22.22"
|
||||||
|
"Port": inPortStr, # RDP Port, example "3389"
|
||||||
|
"Login": inLoginStr, # Login, example "test"
|
||||||
|
"Password": inPasswordStr, # Password, example "test"
|
||||||
|
"Screen": {
|
||||||
|
"Width": 1680, # Width of the remote desktop in pixels, example 1680
|
||||||
|
"Height": 1050, # Height of the remote desktop in pixels, example 1050
|
||||||
|
# "640x480" or "1680x1050" or "FullScreen". If Resolution not exists set full screen, example
|
||||||
|
"FlagUseAllMonitors": False, # True or False, example False
|
||||||
|
"DepthBit": "32" # "32" or "24" or "16" or "15", example "32"
|
||||||
|
},
|
||||||
|
"SharedDriveList": ["c"], # List of the Root sesion hard drives, example ["c"]
|
||||||
|
###### Will updated in program ############
|
||||||
|
"SessionHex": "77777sdfsdf77777dsfdfsf77777777", # Hex is created when robot runs, example ""
|
||||||
|
"SessionIsWindowExistBool": False, # Flag if the RDP window is exist, old name "FlagSessionIsActive". Check every n seconds , example False
|
||||||
|
"SessionIsWindowResponsibleBool": False, # Flag if RDP window is responsible (recieve commands). Check every nn seconds. If window is Responsible - window is Exist too , example False
|
||||||
|
"SessionIsIgnoredBool": False # Flag to ignore RDP window False - dont ignore, True - ignore, example False
|
||||||
|
}
|
||||||
|
# Add item in RDPList
|
||||||
|
gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr] = lRDPConfigurationItem
|
||||||
|
# Create the RDP session
|
||||||
|
Connector.Session(lRDPConfigurationItem)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Disconnect the RDP session
|
||||||
|
def RDPSessionDisconnect(inRDPSessionKeyStr):
|
||||||
|
global gSettings
|
||||||
|
lSessionHex = gSettings["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
|
||||||
|
if lSessionHex:
|
||||||
|
gSettings["RobotRDPActive"]["RDPList"].pop(inRDPSessionKeyStr,None)
|
||||||
|
Connector.SessionClose(inSessionHexStr=lSessionHex)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# RDP Session reconnect
|
||||||
|
def RDPSessionReconnect(inRDPSessionKeyStr):
|
||||||
|
global gSettings
|
||||||
|
lRDPConfigurationItem = gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr]
|
||||||
|
RDPSessionDisconnect(inRDPSessionKeyStr=inRDPSessionKeyStr) # Disconnect the RDP
|
||||||
|
# Add item in RDPList
|
||||||
|
gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr] = lRDPConfigurationItem
|
||||||
|
# Create the RDP session
|
||||||
|
Connector.Session(lRDPConfigurationItem)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Logoff the RDP session
|
||||||
|
def RDPSessionLogoff(inRDPSessionKeyStr):
|
||||||
|
global gSettings
|
||||||
|
lResult = True
|
||||||
|
lCMDStr = "shutdown -L" # CMD logoff command
|
||||||
|
# Calculate the session Hex
|
||||||
|
lSessionHex = gSettings["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
|
||||||
|
if lSessionHex:
|
||||||
|
gSettings["RobotRDPActive"]["RDPList"].pop(inRDPSessionKeyStr,None)
|
||||||
|
# Run CMD
|
||||||
|
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
|
||||||
|
return lResult
|
||||||
|
|
||||||
|
# Check RDP Session responsibility TODO NEED DEV + TEST
|
||||||
|
def RDPSessionResponsibilityCheck(inRDPSessionKeyStr):
|
||||||
|
global gSettings
|
||||||
|
inGlobalDict = gSettings
|
||||||
|
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr]["SessionHex"]
|
||||||
|
# set the fullscreen
|
||||||
|
Connector.SessionScreenFull(inSessionHex=lSessionHex)
|
||||||
|
time.sleep(1)
|
||||||
|
# Check RDP responsibility
|
||||||
|
lDoCheckResponsibilityBool = True
|
||||||
|
lDoCheckResponsibilityCountMax = 20
|
||||||
|
lDoCheckResponsibilityCountCurrent = 0
|
||||||
|
while lDoCheckResponsibilityBool:
|
||||||
|
# Check if counter is exceed - raise exception
|
||||||
|
if lDoCheckResponsibilityCountCurrent >= lDoCheckResponsibilityCountMax:
|
||||||
|
pass
|
||||||
|
#raise ConnectorExceptions.SessionWindowNotResponsibleError("Error when initialize the RDP session - RDP window is not responding!")
|
||||||
|
# Check responding
|
||||||
|
lDoCheckResponsibilityBool = not Connector.SystemRDPIsResponsible()
|
||||||
|
# Wait if is not responding
|
||||||
|
if lDoCheckResponsibilityBool:
|
||||||
|
time.sleep(3)
|
||||||
|
# increase the couter
|
||||||
|
lDoCheckResponsibilityCountCurrent+=1
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Start process if it is not running
|
||||||
|
def RDPSessionProcessStartIfNotRunning(inRDPSessionKeyStr, inProcessNameWEXEStr, inFilePathStr, inFlagGetAbsPathBool=True):
|
||||||
|
global gSettings
|
||||||
|
inGlobalDict = gSettings
|
||||||
|
lResult = True
|
||||||
|
lCMDStr = CMDStr.ProcessStartIfNotRunning(inProcessNameWEXEStr, inFilePathStr, inFlagGetAbsPath= inFlagGetAbsPathBool)
|
||||||
|
# Calculate the session Hex
|
||||||
|
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
|
||||||
|
# Run CMD
|
||||||
|
if lSessionHex:
|
||||||
|
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
|
||||||
|
return lResult
|
||||||
|
# Create CMD str to stop process
|
||||||
|
def RDPSessionProcessStop(inRDPSessionKeyStr, inProcessNameWEXEStr, inFlagForceCloseBool):
|
||||||
|
global gSettings
|
||||||
|
inGlobalDict = gSettings
|
||||||
|
lResult = True
|
||||||
|
lCMDStr = f'taskkill /im "{inProcessNameWEXEStr}" /fi "username eq %USERNAME%"'
|
||||||
|
if inFlagForceCloseBool:
|
||||||
|
lCMDStr+= " /F"
|
||||||
|
# Calculate the session Hex
|
||||||
|
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
|
||||||
|
# Run CMD
|
||||||
|
if lSessionHex:
|
||||||
|
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
|
||||||
|
return lResult
|
||||||
|
# Send file from Host to Session RDP using shared drive in RDP
|
||||||
|
def RDPSessionFileStoredSend(inRDPSessionKeyStr, inHostFilePathStr, inRDPFilePathStr):
|
||||||
|
global gSettings
|
||||||
|
inGlobalDict = gSettings
|
||||||
|
lResult = True
|
||||||
|
lCMDStr = CMDStr.FileStoredSend(inHostFilePath = inHostFilePathStr, inRDPFilePath = inRDPFilePathStr)
|
||||||
|
# Calculate the session Hex
|
||||||
|
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr, {}).get("SessionHex", None)
|
||||||
|
#lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr]["SessionHex"]
|
||||||
|
# Run CMD
|
||||||
|
if lSessionHex:
|
||||||
|
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120)
|
||||||
|
return lResult
|
||||||
|
# Recieve file from Session RDP to Host using shared drive in RDP
|
||||||
|
def RDPSessionFileStoredRecieve(inRDPSessionKeyStr, inRDPFilePathStr, inHostFilePathStr):
|
||||||
|
global gSettings
|
||||||
|
inGlobalDict = gSettings
|
||||||
|
lResult = True
|
||||||
|
lCMDStr = CMDStr.FileStoredRecieve(inRDPFilePath = inRDPFilePathStr, inHostFilePath = inHostFilePathStr)
|
||||||
|
# Calculate the session Hex
|
||||||
|
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
|
||||||
|
# Run CMD
|
||||||
|
if lSessionHex:
|
||||||
|
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120)
|
||||||
|
return lResult
|
@ -0,0 +1,142 @@
|
|||||||
|
from pyOpenRPA.Robot import UIDesktop
|
||||||
|
import os
|
||||||
|
import time # Time wait operations
|
||||||
|
from . import ConnectorExceptions # Exceptions classes
|
||||||
|
from . import Connector
|
||||||
|
from . import Processor # Module for process some functions on thr RDP
|
||||||
|
# Main function
|
||||||
|
def RobotRDPActive(inGSettings):
|
||||||
|
# inGSettings = {
|
||||||
|
# ... "RobotRDPActive": {} ...
|
||||||
|
# }
|
||||||
|
#import pdb
|
||||||
|
#pdb.set_trace()
|
||||||
|
lLogger = inGSettings["Logger"] # Synonim
|
||||||
|
Processor.gSettings = inGSettings # Set gSettings in processor module
|
||||||
|
mGSettingsRDPActiveDict = inGSettings["RobotRDPActive"] # Get configuration from global dict settings
|
||||||
|
# Global error handler
|
||||||
|
try:
|
||||||
|
######## Init the RDP List
|
||||||
|
for lRDPSessionKeyStrItem in mGSettingsRDPActiveDict["RDPList"]:
|
||||||
|
lConfigurationItem = mGSettingsRDPActiveDict["RDPList"][lRDPSessionKeyStrItem]
|
||||||
|
lConfigurationItem["SessionIsWindowExistBool"] = False # Flag that session is not started
|
||||||
|
lConfigurationItem["SessionIsWindowResponsibleBool"] = False # Flag that session is not started
|
||||||
|
lConfigurationItem["SessionHex"] = " 77777sdfsdf77777dsfdfsf77777777" # Flag that session is not started
|
||||||
|
##########
|
||||||
|
# Run monitor - main loop
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
inGlobalDict = mGSettingsRDPActiveDict # Compatibility
|
||||||
|
inListUpdateTimeout = 1 # Compatibility
|
||||||
|
lFlagWhile = True
|
||||||
|
lResponsibilityCheckLastSec = time.time() # Get current time for check interval
|
||||||
|
while lFlagWhile:
|
||||||
|
try:
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# Check RDP window is OK - reconnect if connection was lost
|
||||||
|
lUIOSelectorList = []
|
||||||
|
lRDPConfigurationDictList = []
|
||||||
|
# Prepare selectors list for check
|
||||||
|
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
|
||||||
|
lItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
|
||||||
|
lRDPConfigurationDictList.append(lItem) # Add RDP Configuration in list
|
||||||
|
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']}.*", "backend": "win32"}])
|
||||||
|
# Run wait command
|
||||||
|
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
|
||||||
|
for lItem in lRDPDissappearList: # Reconnect if connection was lost
|
||||||
|
lRDPConfigurationDict = lRDPConfigurationDictList[lItem] # Get RDP Configuration list
|
||||||
|
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
|
||||||
|
# Check if RDP window is not ignored
|
||||||
|
if not lRDPConfigurationDict["SessionIsIgnoredBool"]:
|
||||||
|
try:
|
||||||
|
Connector.Session(lRDPConfigurationDict)
|
||||||
|
lRDPConfigurationDict["SessionIsWindowExistBool"] = True # Flag that session is started
|
||||||
|
# Write in logger - info
|
||||||
|
lLogger.info(
|
||||||
|
f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session has been initialized!")
|
||||||
|
# catch ConnectorExceptions.SessionWindowNotExistError
|
||||||
|
except ConnectorExceptions.SessionWindowNotExistError as e:
|
||||||
|
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
|
||||||
|
# Write in logger - warning
|
||||||
|
lLogger.warning(
|
||||||
|
f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session is not exist!")
|
||||||
|
# general exceptions
|
||||||
|
except Exception as e:
|
||||||
|
# Write in logger - warning
|
||||||
|
lLogger.exception(f"!!! ATTENTION !!! Unrecognized error")
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# Safe turn off the - no need because of Orchestrator control
|
||||||
|
#if inGlobalDict.get("OrchestratorToRobotResetStorage", {}).get("SafeTurnOff", False):
|
||||||
|
# lFlagWhile = False
|
||||||
|
# # Set status disconnected for all RDP List
|
||||||
|
# for lItem in inGlobalDict["RDPList"]:
|
||||||
|
# lItem["SessionIsWindowExistBool"] = False
|
||||||
|
# lItem["SessionIsWindowResponsibleBool"] = False
|
||||||
|
# # Kill all RDP sessions
|
||||||
|
# os.system('taskkill /F /im mstsc.exe')
|
||||||
|
# # Return from function
|
||||||
|
# return
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
Connector.SystemRDPWarningClickOk() # Click all warning messages
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# Check if RDP session is full screen (if is not ignored)
|
||||||
|
if inGlobalDict["FullScreenRDPSessionKeyStr"] is not None:
|
||||||
|
lRDPSessionKeyStr = inGlobalDict["FullScreenRDPSessionKeyStr"] # Get the RDPSessionKeyStr
|
||||||
|
if lRDPSessionKeyStr in inGlobalDict["RDPList"]: # Session Key is in dict
|
||||||
|
lRDPConfigurationDict = inGlobalDict["RDPList"][lRDPSessionKeyStr]
|
||||||
|
#if not lRDPConfigurationDict["SessionIsIgnoredBool"]: # Session is not ignored
|
||||||
|
# Check if full screen
|
||||||
|
lIsFullScreenBool = Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDict["SessionHex"])
|
||||||
|
if not lIsFullScreenBool: # If not the full screen
|
||||||
|
# Check all RDP window and minimize it
|
||||||
|
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
|
||||||
|
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
|
||||||
|
if Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]):
|
||||||
|
Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"], inXInt=10, inYInt=10,
|
||||||
|
inWInt=550,
|
||||||
|
inHInt=350) # Prepare little window
|
||||||
|
# Set full screen for new window
|
||||||
|
Connector.SessionScreenFull(inSessionHex=lRDPConfigurationDict["SessionHex"])
|
||||||
|
else:
|
||||||
|
# Check all RDP window and minimize it
|
||||||
|
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
|
||||||
|
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
|
||||||
|
if Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]):
|
||||||
|
Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"],
|
||||||
|
inXInt=10, inYInt=10,
|
||||||
|
inWInt=550,
|
||||||
|
inHInt=350) # Prepare little window
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# Iterate the activity list in robot RDP active
|
||||||
|
lActivityListNew = []
|
||||||
|
lActivityListOld = inGlobalDict["ActivityList"]
|
||||||
|
inGlobalDict["ActivityList"] = []
|
||||||
|
for lActivityItem in lActivityListOld:
|
||||||
|
lSubmoduleFunctionName = lActivityItem["DefNameStr"]
|
||||||
|
if lSubmoduleFunctionName in dir(Processor):
|
||||||
|
# Run SettingUpdate function in submodule
|
||||||
|
# mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
|
||||||
|
lActivityItemResult = getattr(Processor, lSubmoduleFunctionName)(
|
||||||
|
*lActivityItem["ArgList"], **lActivityItem["ArgDict"])
|
||||||
|
lActivityItemResultType = type(lActivityItemResult)
|
||||||
|
# Check if Result is bool
|
||||||
|
if lActivityItemResultType is bool:
|
||||||
|
if not lActivityItemResult:
|
||||||
|
# Activity is not done - add to list (retry in future)
|
||||||
|
lActivityListNew.append(lActivityItem)
|
||||||
|
inGlobalDict["ActivityList"] = lActivityListNew # Override the value
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
except RuntimeError as e:
|
||||||
|
# case noGUI error passed - do nothing
|
||||||
|
# Write in logger - warning
|
||||||
|
lLogger.warning(f"Host session has lost the GUI")
|
||||||
|
finally:
|
||||||
|
# Wait for the next iteration
|
||||||
|
time.sleep(0.7)
|
||||||
|
# Scheduler.Scheduler(mGSettingsRDPActiveDict["Scheduler"]) # Init & Run Scheduler TODO remake in processor list
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
#Monitor.Monitor(mGSettingsRDPActiveDict, 1)
|
||||||
|
except Exception as e:
|
||||||
|
# Write in logger - warning
|
||||||
|
lLogger.exception(f"!!! ATTENTION !!! Global error handler - look at code")
|
@ -0,0 +1,111 @@
|
|||||||
|
from . import Timer # Async thread
|
||||||
|
import threading # Create in another thread
|
||||||
|
import datetime # Datetime class
|
||||||
|
import time # time functions
|
||||||
|
import importlib # import lib functions
|
||||||
|
# Scheduler class - init and work by the configuration
|
||||||
|
# OOP
|
||||||
|
class Scheduler:
|
||||||
|
# Class properties
|
||||||
|
mSchedulerDict = None
|
||||||
|
mGSettings = None
|
||||||
|
#########################
|
||||||
|
# Init class
|
||||||
|
def __init__(self,inSchedulerDict, inGSettings = None):
|
||||||
|
self.Init(inSchedulerDict = inSchedulerDict, inGSettings = inGSettings)
|
||||||
|
# Init the class instance
|
||||||
|
def Init(self,inSchedulerDict, inGSettings):
|
||||||
|
self.mGSettings = inGSettings
|
||||||
|
self.mSchedulerDict = inSchedulerDict
|
||||||
|
# Init the threads
|
||||||
|
lTimerMainThread = threading.Thread(target = self.TimerMainThreadRun)
|
||||||
|
lTimerMainThread.start() # Start the Timer main thread
|
||||||
|
#print (f"Class instance configuration: {self.mSchedulerDict}, Init has been completed")
|
||||||
|
########################
|
||||||
|
# Main timer thread - run when init class instance
|
||||||
|
def TimerMainThreadRun(self):
|
||||||
|
lDaemonStartDateTime=datetime.datetime.now()
|
||||||
|
lDaemonLoopSeconds=self.mSchedulerDict["ActivityTimeCheckLoopSeconds"]
|
||||||
|
lDaemonActivityLogDict={} #Словарь отработанных активностей, ключ - кортеж (<activityType>, <datetime>, <processPath || processName>, <processArgs>)
|
||||||
|
#Вечный цикл
|
||||||
|
while True:
|
||||||
|
lCurrentDateTime = datetime.datetime.now()
|
||||||
|
#Циклический обход правил
|
||||||
|
lFlagSearchActivityType=True
|
||||||
|
for lIndex, lItem in enumerate(self.mSchedulerDict["ActivityTimeList"]):
|
||||||
|
#Проверка дней недели, в рамках которых можно запускать активность
|
||||||
|
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>=lDaemonStartDateTime and
|
||||||
|
lCurrentDateTime>=lActivityDateTime and
|
||||||
|
(lIndex,lActivityDateTime) not in lDaemonActivityLogDict):
|
||||||
|
#Выполнить операцию
|
||||||
|
#Запись в массив отработанных активностей
|
||||||
|
lDaemonActivityLogDict[(lIndex,lActivityDateTime)]={"ActivityStartDateTime":lCurrentDateTime}
|
||||||
|
#Запустить процесс - new code
|
||||||
|
#################
|
||||||
|
#Call function from Activity structure
|
||||||
|
################################################
|
||||||
|
lSubmoduleFunctionName = lItem["Activity"]["DefName"]
|
||||||
|
lFileFullPath = lItem["Activity"]["ModulePath"] # "path\\to\\module.py"
|
||||||
|
lModuleName = (lFileFullPath.split("\\")[-1])[0:-3]
|
||||||
|
lTechSpecification = importlib.util.spec_from_file_location(lModuleName, lFileFullPath)
|
||||||
|
lTechModuleFromSpec = importlib.util.module_from_spec(lTechSpecification)
|
||||||
|
lTechSpecificationModuleLoader = lTechSpecification.loader.exec_module(lTechModuleFromSpec)
|
||||||
|
# Set gSettings in module
|
||||||
|
lTechModuleFromSpec.gSettings = self.mGSettings
|
||||||
|
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
|
||||||
|
# Run SettingUpdate function in submodule
|
||||||
|
#mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
|
||||||
|
getattr(lTechModuleFromSpec, lSubmoduleFunctionName)(*lItem["Activity"]["ArgList"],**lItem["Activity"]["ArgDict"])
|
||||||
|
#################################################
|
||||||
|
#######################################################################
|
||||||
|
#Branch 2 - if TimeHH:MMStart, TimeHH:MMStop, ActivityIntervalSeconds
|
||||||
|
#######################################################################
|
||||||
|
if "TimeHH:MMStart" in lItem and "TimeHH:MMStop" in lItem and "ActivityIntervalSeconds" in lItem:
|
||||||
|
#Сформировать временной штамп, относительно которого надо будет проверять время
|
||||||
|
#часовой пояс пока не учитываем
|
||||||
|
lActivityDateTime=datetime.datetime.strptime(lItem["TimeHH:MMStart"],"%H:%M")
|
||||||
|
lActivityDateTime=lActivityDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day)
|
||||||
|
lActivityTimeEndDateTime=datetime.datetime.strptime(lItem["TimeHH:MMStop"],"%H:%M")
|
||||||
|
lActivityTimeEndDateTime=lActivityTimeEndDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day)
|
||||||
|
#Убедиться в том, что время наступило
|
||||||
|
if (
|
||||||
|
lCurrentDateTime<lActivityTimeEndDateTime and
|
||||||
|
lCurrentDateTime>=lActivityDateTime and
|
||||||
|
(lIndex,lActivityDateTime) not in lDaemonActivityLogDict):
|
||||||
|
#Запись в массив отработанных активностей
|
||||||
|
lDaemonActivityLogDict[(lIndex,lActivityDateTime)]={"ActivityStartDateTime":lCurrentDateTime}
|
||||||
|
#Call function from Activity structure
|
||||||
|
################################################
|
||||||
|
lSubmoduleFunctionName = lItem["Activity"]["DefName"]
|
||||||
|
lFileFullPath = lItem["Activity"]["ModulePath"] # "path\\to\\module.py"
|
||||||
|
lModuleName = (lFileFullPath.split("\\")[-1])[0:-3]
|
||||||
|
lTechSpecification = importlib.util.spec_from_file_location(lModuleName, lFileFullPath)
|
||||||
|
lTechModuleFromSpec = importlib.util.module_from_spec(lTechSpecification)
|
||||||
|
lTechSpecificationModuleLoader = lTechSpecification.loader.exec_module(lTechModuleFromSpec)
|
||||||
|
# Set gSettings in module
|
||||||
|
lTechModuleFromSpec.gSettings = self.mGSettings
|
||||||
|
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
|
||||||
|
# Run SettingUpdate function in submodule
|
||||||
|
#mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
|
||||||
|
lDef = getattr(lTechModuleFromSpec, lSubmoduleFunctionName) #(*lItem["Activity"]["ArgList"],**lItem["Activity"]["ArgDict"])
|
||||||
|
#################################################
|
||||||
|
#Запуск циклической процедуры
|
||||||
|
#Timer.activityLoopStart(lItem["ActivityIntervalSeconds"], lActivityTimeEndDateTime, lItem["Activity"])
|
||||||
|
lTimer = Timer.RepeatedTimer(lItem["ActivityIntervalSeconds"], lActivityTimeEndDateTime, lDef, *lItem["Activity"]["ArgList"], **lItem["Activity"]["ArgDict"]) # it auto-starts, no need of rt.start()
|
||||||
|
#Уснуть до следующего прогона
|
||||||
|
#print (f"Loop has been completed")
|
||||||
|
time.sleep(lDaemonLoopSeconds)
|
@ -0,0 +1,31 @@
|
|||||||
|
from threading import Timer
|
||||||
|
import datetime
|
||||||
|
class RepeatedTimer(object):
|
||||||
|
def __init__(self, interval, inDateTimeEnd, function, *args, **kwargs):
|
||||||
|
self._timer = None
|
||||||
|
self.interval = interval
|
||||||
|
self.function = function
|
||||||
|
self.args = args
|
||||||
|
self.kwargs = kwargs
|
||||||
|
self.is_running = False
|
||||||
|
self.mDateTimeEnd = inDateTimeEnd # DateTime when stop
|
||||||
|
self.start()
|
||||||
|
def _run(self):
|
||||||
|
self.is_running = False
|
||||||
|
lResultGoLoop=True
|
||||||
|
lCurrentDateTime=datetime.datetime.now()
|
||||||
|
self.function(*self.args, **self.kwargs)
|
||||||
|
if lCurrentDateTime>=self.mDateTimeEnd:
|
||||||
|
lResultGoLoop=False
|
||||||
|
if lResultGoLoop is not None:
|
||||||
|
if lResultGoLoop:
|
||||||
|
self.start()
|
||||||
|
def start(self):
|
||||||
|
if not self.is_running:
|
||||||
|
self._timer = Timer(self.interval, self._run)
|
||||||
|
self._timer.start()
|
||||||
|
self.is_running = True
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self._timer.cancel()
|
||||||
|
self.is_running = False
|
@ -1,55 +0,0 @@
|
|||||||
from pyOpenRPA.Robot import UIDesktop
|
|
||||||
from . import Connector
|
|
||||||
import os
|
|
||||||
import pdb
|
|
||||||
#Check for session is closed. Reopen if detected. Always keep session is active
|
|
||||||
def Monitor(inGlobalDict, inListUpdateTimeout):
|
|
||||||
lFlagWhile = True
|
|
||||||
while lFlagWhile:
|
|
||||||
# UIOSelector list init
|
|
||||||
lUIOSelectorList = []
|
|
||||||
#Prepare selectors list for check
|
|
||||||
for lIndex, lItem in enumerate(inGlobalDict["RDPList"]):
|
|
||||||
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']}.*", "backend": "win32"}])
|
|
||||||
#Run wait command
|
|
||||||
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
|
|
||||||
###########################################
|
|
||||||
#Analyze if flag safeturn off is activated
|
|
||||||
if inGlobalDict.get("OrchestratorToRobotResetStorage",{}).get("SafeTurnOff",False):
|
|
||||||
lFlagWhile=False
|
|
||||||
#Set status disconnected for all RDP List
|
|
||||||
for lItem in inGlobalDict["RDPList"]:
|
|
||||||
lItem["FlagSessionIsActive"]=False
|
|
||||||
#Kill all RDP sessions
|
|
||||||
os.system('taskkill /F /im mstsc.exe')
|
|
||||||
#Return from function
|
|
||||||
return
|
|
||||||
###########################################
|
|
||||||
###########################################
|
|
||||||
for lItem in lRDPDissappearList:
|
|
||||||
inGlobalDict["RDPList"][lItem]["FlagSessionIsActive"] = False # Set flag that session is disconnected
|
|
||||||
#pdb.set_trace()
|
|
||||||
#Session start if it is not in ignore list
|
|
||||||
#add check for selector if it is not in ignoreIndexList
|
|
||||||
if lItem not in inGlobalDict["OrchestratorToRobotStorage"]["IgnoreIndexList"]:
|
|
||||||
try:
|
|
||||||
Connector.Session(inGlobalDict["RDPList"][lItem])
|
|
||||||
inGlobalDict["RDPList"][lItem]["FlagSessionIsActive"] = True # Flag that session is started
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
###########################################
|
|
||||||
#Check if from Orchestrator full screen session is set
|
|
||||||
if inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"] != inGlobalDict["FullScreenSessionIndex"]:
|
|
||||||
#Do some switches
|
|
||||||
#If full screen mode we have now
|
|
||||||
if inGlobalDict["FullScreenSessionIndex"] is not None:
|
|
||||||
if inGlobalDict["RDPList"][inGlobalDict["FullScreenSessionIndex"]]["FlagSessionIsActive"]:
|
|
||||||
Connector.SessionScreen100x550(inGlobalDict["RDPList"][inGlobalDict["FullScreenSessionIndex"]]["SessionHex"])
|
|
||||||
#If new session is setted
|
|
||||||
if inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"] is not None:
|
|
||||||
if inGlobalDict["RDPList"][inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]]["FlagSessionIsActive"]:
|
|
||||||
Connector.SessionScreenFull(inGlobalDict["RDPList"][inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]]["SessionHex"])
|
|
||||||
#Set one to other equal
|
|
||||||
inGlobalDict["FullScreenSessionIndex"] = inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]
|
|
||||||
return None
|
|
||||||
#TODO Def garbage window cleaner (if connection was lost)
|
|
Binary file not shown.
@ -1,6 +1,6 @@
|
|||||||
Metadata-Version: 2.1
|
Metadata-Version: 2.1
|
||||||
Name: pyOpenRPA
|
Name: pyOpenRPA
|
||||||
Version: 1.0.42
|
Version: 1.1.0
|
||||||
Summary: First open source RPA platform for business
|
Summary: First open source RPA platform for business
|
||||||
Home-page: https://gitlab.com/UnicodeLabs/OpenRPA
|
Home-page: https://gitlab.com/UnicodeLabs/OpenRPA
|
||||||
Author: Ivan Maslov
|
Author: Ivan Maslov
|
@ -0,0 +1,26 @@
|
|||||||
|
import os # Get abs path of the file
|
||||||
|
# Create CMD str to run file if process.exe is not running
|
||||||
|
def ProcessStartIfNotRunning(inProcessName, inFilePath, inFlagGetAbsPath=True):
|
||||||
|
lFileAbsPath = inFilePath
|
||||||
|
if inFlagGetAbsPath:
|
||||||
|
lFileAbsPath = os.path.abspath(inFilePath)
|
||||||
|
lResult = f'tasklist /nh /fi "imagename eq {inProcessName}" | find /i "{inProcessName}" > nul || (start {lFileAbsPath})'
|
||||||
|
return lResult
|
||||||
|
# Create CMD str to stop process
|
||||||
|
def ProcessStop(inProcessName, inFlagForceClose):
|
||||||
|
lResult = f'taskkill /im "{inProcessName}" /fi "username eq %USERNAME%"'
|
||||||
|
if inFlagForceClose:
|
||||||
|
lResult+= " /F"
|
||||||
|
return lResult
|
||||||
|
# Send file from Host to Session RDP using shared drive in RDP (force copy)
|
||||||
|
def FileStoredSend(inHostFilePath, inRDPFilePath):
|
||||||
|
lHostFileAbsPath = os.path.join("\\\\tsclient", os.path.abspath(inHostFilePath).replace(":","")) # \\tsclient\C\path\to\file
|
||||||
|
lHostRDPFileAbsPath = os.path.abspath(inRDPFilePath) # File location in RDP
|
||||||
|
lResult = f'copy /Y "{lHostFileAbsPath}" "{lHostRDPFileAbsPath}"'
|
||||||
|
return lResult
|
||||||
|
# Send file from Session RDP to Host using shared drive in RDP (force copy)
|
||||||
|
def FileStoredRecieve(inRDPFilePath, inHostFilePath):
|
||||||
|
lHostFileAbsPath = os.path.join("\\\\tsclient", os.path.abspath(inHostFilePath).replace(":","")) # \\tsclient\C\path\to\file
|
||||||
|
lHostRDPFileAbsPath = os.path.abspath(inRDPFilePath) # File location in RDP
|
||||||
|
lResult = f'copy /Y "{lHostRDPFileAbsPath}" "{lHostFileAbsPath}"'
|
||||||
|
return lResult
|
@ -0,0 +1,40 @@
|
|||||||
|
import win32clipboard
|
||||||
|
import keyboard # keyboard functions
|
||||||
|
import time # Some operations need wait
|
||||||
|
import random # random number for test
|
||||||
|
gWaitTextInClipboardSec = 1 # Second for wait text will be set in clipboard (for get operations)
|
||||||
|
# set clipboard data
|
||||||
|
def TextSet(inTextStr):
|
||||||
|
win32clipboard.OpenClipboard()
|
||||||
|
win32clipboard.EmptyClipboard()
|
||||||
|
win32clipboard.SetClipboardText(inTextStr)
|
||||||
|
win32clipboard.CloseClipboard()
|
||||||
|
# get clipboard data
|
||||||
|
def TextGet(inWaitTextInClipboardSec = gWaitTextInClipboardSec):
|
||||||
|
time.sleep(inWaitTextInClipboardSec) # Wait for clipboard will save
|
||||||
|
win32clipboard.OpenClipboard()
|
||||||
|
data = win32clipboard.GetClipboardData()
|
||||||
|
win32clipboard.CloseClipboard()
|
||||||
|
return data
|
||||||
|
# Test in has text cursor and ready to apply
|
||||||
|
def InputIsFocused():
|
||||||
|
keyboard.press_and_release("ctrl+a")
|
||||||
|
keyboard.press_and_release("backspace") # remove old text
|
||||||
|
lTextForTest = str(random.randrange(100,99999))
|
||||||
|
keyboard.write(lTextForTest)
|
||||||
|
keyboard.press_and_release("ctrl+a")
|
||||||
|
keyboard.press_and_release("ctrl+c")
|
||||||
|
time.sleep(2)
|
||||||
|
keyboard.press_and_release("backspace") # remove old text
|
||||||
|
lClipboardText = TextGet()
|
||||||
|
lResult = lClipboardText == lTextForTest
|
||||||
|
return lResult
|
||||||
|
# Check if cmd is opened
|
||||||
|
def CMDIsOpen():
|
||||||
|
lTextForTest = str(random.randrange(100,99999))
|
||||||
|
keyboard.write(lTextForTest+" |clip")
|
||||||
|
keyboard.press_and_release("enter")
|
||||||
|
time.sleep(2)
|
||||||
|
lClipboardText = TextGet()
|
||||||
|
lResult = lClipboardText == lTextForTest
|
||||||
|
return lResult
|
@ -0,0 +1,10 @@
|
|||||||
|
#####################################
|
||||||
|
# RobotRDPActive Exceptions class
|
||||||
|
#####################################
|
||||||
|
class SessionWindowNotExistError(Exception): pass #Error when Window not exists
|
||||||
|
class SessionWindowNotResponsibleError(Exception): pass # Error when Window not responding
|
||||||
|
class HostNoGUIError(Exception): pass # Orchestrator session has no GUI
|
||||||
|
#try:
|
||||||
|
# raise SessionWindowNotResponsibleError("Test")
|
||||||
|
#except SessionWindowNotResponsibleError as e:
|
||||||
|
# print("Catched")
|
@ -0,0 +1,66 @@
|
|||||||
|
# ATTENTION! HERE IS NO Relative import because it will be imported dynamically
|
||||||
|
# All function check the flag SessionIsWindowResponsibleBool == True else no cammand is processed
|
||||||
|
# All functions can return None, Bool or Dict { "IsSuccessful": True }
|
||||||
|
from pyOpenRPA.Tools.RobotRDPActive import CMDStr # Create CMD Strings
|
||||||
|
from pyOpenRPA.Tools.RobotRDPActive import Connector # RDP API
|
||||||
|
def ProcessStartIfNotRunning(inGlobalDict, inSessionIndex, inProcessName, inFilePath, inFlagGetAbsPath=True):
|
||||||
|
lResult = True
|
||||||
|
lCMDStr = CMDStr.ProcessStartIfNotRunning(inProcessName,inFilePath, inFlagGetAbsPath= inFlagGetAbsPath)
|
||||||
|
# Calculate the session Hex
|
||||||
|
lSessionHex = inGlobalDict["RDPList"][inSessionIndex]["SessionHex"]
|
||||||
|
# Check is Session is responsible
|
||||||
|
if inGlobalDict["RDPList"][inSessionIndex]["SessionIsWindowResponsibleBool"]:
|
||||||
|
# Run CMD
|
||||||
|
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
|
||||||
|
else:
|
||||||
|
# Write in logger - warning
|
||||||
|
inGlobalDict["Logger"].warning(f"GlobalDictSessionIndex_Defs.ProcessStartIfNotRunning: SessionIndex: {str(inSessionIndex)}, ProcessName: {inProcessName}:: Session is not responsible!")
|
||||||
|
lResult = False # Set false result - function has not been done
|
||||||
|
return lResult
|
||||||
|
# Create CMD str to stop process
|
||||||
|
def ProcessStop(inGlobalDict, inSessionIndex, inProcessName, inFlagForceClose):
|
||||||
|
lResult = True
|
||||||
|
lCMDStr = f'taskkill /im "{inProcessName}" /fi "username eq %USERNAME%"'
|
||||||
|
if inFlagForceClose:
|
||||||
|
lCMDStr+= " /F"
|
||||||
|
# Calculate the session Hex
|
||||||
|
lSessionHex = inGlobalDict["RDPList"][inSessionIndex]["SessionHex"]
|
||||||
|
# Check is Session is responsible
|
||||||
|
if inGlobalDict["RDPList"][inSessionIndex]["SessionIsWindowResponsibleBool"]:
|
||||||
|
# Run CMD
|
||||||
|
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
|
||||||
|
else:
|
||||||
|
# TODO Write in logger - warning
|
||||||
|
inGlobalDict["Logger"].warning(f"GlobalDictSessionIndex_Defs.ProcessStop: SessionIndex: {str(inSessionIndex)}, ProcessName: {inProcessName}:: Session is not responsible!")
|
||||||
|
lResult = False # Set false result - function has not been done
|
||||||
|
return lResult
|
||||||
|
# Send file from Host to Session RDP using shared drive in RDP
|
||||||
|
def FileStoredSend(inGlobalDict, inSessionIndex, inHostFilePath, inRDPFilePath):
|
||||||
|
lResult = True
|
||||||
|
lCMDStr = CMDStr.FileStoredSend(inHostFilePath = inHostFilePath, inRDPFilePath = inRDPFilePath)
|
||||||
|
# Calculate the session Hex
|
||||||
|
lSessionHex = inGlobalDict["RDPList"][inSessionIndex]["SessionHex"]
|
||||||
|
# Check is Session is responsible
|
||||||
|
if inGlobalDict["RDPList"][inSessionIndex]["SessionIsWindowResponsibleBool"]:
|
||||||
|
# Run CMD
|
||||||
|
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120)
|
||||||
|
else:
|
||||||
|
# Write in logger - warning
|
||||||
|
inGlobalDict["Logger"].warning(f"GlobalDictSessionIndex_Defs.FileStoredSend: SessionIndex: {str(inSessionIndex)}, HostFilePath: {inHostFilePath}:: Session is not responsible!")
|
||||||
|
lResult = False # Set false result - function has not been done
|
||||||
|
return lResult
|
||||||
|
# Recieve file from Session RDP to Host using shared drive in RDP
|
||||||
|
def FileStoredRecieve(inGlobalDict, inSessionIndex, inRDPFilePath, inHostFilePath):
|
||||||
|
lResult = True
|
||||||
|
lCMDStr = CMDStr.FileStoredRecieve(inRDPFilePath = inRDPFilePath, inHostFilePath = inHostFilePath)
|
||||||
|
# Calculate the session Hex
|
||||||
|
lSessionHex = inGlobalDict["RDPList"][inSessionIndex]["SessionHex"]
|
||||||
|
# Check is Session is responsible
|
||||||
|
if inGlobalDict["RDPList"][inSessionIndex]["SessionIsWindowResponsibleBool"]:
|
||||||
|
# Run CMD
|
||||||
|
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120)
|
||||||
|
else:
|
||||||
|
# Write in logger - warning
|
||||||
|
inGlobalDict["Logger"].warning(f"GlobalDictSessionIndex_Defs.FileStoredRecieve: SessionIndex: {str(inSessionIndex)}, HostFilePath: {inHostFilePath}:: Session is not responsible!")
|
||||||
|
lResult = False # Set false result - function has not been done
|
||||||
|
return lResult
|
@ -0,0 +1,158 @@
|
|||||||
|
from pyOpenRPA.Robot import UIDesktop
|
||||||
|
from . import Connector
|
||||||
|
import os
|
||||||
|
import time # Time wait operations
|
||||||
|
import importlib # from dynamic import module
|
||||||
|
from . import ConnectorExceptions # Exceptions classes
|
||||||
|
|
||||||
|
|
||||||
|
#Check for session is closed. Reopen if detected. Always keep session is active
|
||||||
|
def Monitor(inGlobalDict, inListUpdateTimeout):
|
||||||
|
lFlagWhile = True
|
||||||
|
lResponsibilityCheckLastSec = time.time() # Get current time for check interval
|
||||||
|
while lFlagWhile:
|
||||||
|
try:
|
||||||
|
# UIOSelector list init
|
||||||
|
lUIOSelectorList = []
|
||||||
|
#Prepare selectors list for check
|
||||||
|
for lIndex, lItem in enumerate(inGlobalDict["RDPList"]):
|
||||||
|
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']}.*", "backend": "win32"}])
|
||||||
|
#Run wait command
|
||||||
|
#import pdb
|
||||||
|
#pdb.set_trace()
|
||||||
|
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
|
||||||
|
#print(lRDPDissappearList)
|
||||||
|
###########################################
|
||||||
|
#Analyze if flag safeturn off is activated
|
||||||
|
if inGlobalDict.get("OrchestratorToRobotResetStorage",{}).get("SafeTurnOff",False):
|
||||||
|
lFlagWhile=False
|
||||||
|
#Set status disconnected for all RDP List
|
||||||
|
for lItem in inGlobalDict["RDPList"]:
|
||||||
|
lItem["SessionIsWindowExistBool"]=False
|
||||||
|
lItem["SessionIsWindowResponsibleBool"]=False
|
||||||
|
#Kill all RDP sessions
|
||||||
|
os.system('taskkill /F /im mstsc.exe')
|
||||||
|
#Return from function
|
||||||
|
return
|
||||||
|
###########################################
|
||||||
|
###########################################
|
||||||
|
for lItem in lRDPDissappearList:
|
||||||
|
inGlobalDict["RDPList"][lItem]["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
|
||||||
|
inGlobalDict["RDPList"][lItem]["SessionIsWindowResponsibleBool"]=False
|
||||||
|
#pdb.set_trace()
|
||||||
|
#Session start if it is not in ignore list
|
||||||
|
#add check for selector if it is not in ignoreIndexList
|
||||||
|
if lItem not in inGlobalDict["OrchestratorToRobotStorage"]["IgnoreIndexList"]:
|
||||||
|
try:
|
||||||
|
Connector.Session(inGlobalDict["RDPList"][lItem])
|
||||||
|
inGlobalDict["RDPList"][lItem]["SessionIsWindowExistBool"] = True # Flag that session is started
|
||||||
|
inGlobalDict["RDPList"][lItem]["SessionIsWindowResponsibleBool"]= True
|
||||||
|
# Write in logger - info
|
||||||
|
inGlobalDict["Logger"].info(f"SessionHex: {str(inGlobalDict['RDPList'][lItem]['SessionHex'])}:: Session has been initialized!")
|
||||||
|
# catch ConnectorExceptions.SessionWindowNotExistError
|
||||||
|
except ConnectorExceptions.SessionWindowNotExistError as e:
|
||||||
|
inGlobalDict["RDPList"][lItem]["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
|
||||||
|
inGlobalDict["RDPList"][lItem]["SessionIsWindowResponsibleBool"]=False
|
||||||
|
# Write in logger - warning
|
||||||
|
inGlobalDict["Logger"].warning(f"SessionHex: {str(inGlobalDict['RDPList'][lItem]['SessionHex'])}:: Session is not exist!")
|
||||||
|
# catch ConnectorExceptions.SessionWindowNotResponsibleError
|
||||||
|
except ConnectorExceptions.SessionWindowNotResponsibleError as e:
|
||||||
|
inGlobalDict["RDPList"][lItem]["SessionIsWindowExistBool"] = True # Set flag that session is disconnected
|
||||||
|
inGlobalDict["RDPList"][lItem]["SessionIsWindowResponsibleBool"]=False
|
||||||
|
# Write in logger - warning
|
||||||
|
inGlobalDict["Logger"].warning(f"SessionHex: {str(inGlobalDict['RDPList'][lItem]['SessionHex'])}:: Session is not responsible!")
|
||||||
|
# general exceptions
|
||||||
|
except Exception as e:
|
||||||
|
# Write in logger - warning
|
||||||
|
inGlobalDict["Logger"].exception(f"!!! ATTENTION !!! Unrecognized error")
|
||||||
|
#######################
|
||||||
|
# Click all warning messages
|
||||||
|
Connector.SystemRDPWarningClickOk()
|
||||||
|
#######################
|
||||||
|
###########################################
|
||||||
|
#Check if from Orchestrator full screen session is set
|
||||||
|
if inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"] != inGlobalDict["FullScreenSessionIndex"]:
|
||||||
|
#Do some switches
|
||||||
|
#If full screen mode we have now
|
||||||
|
if inGlobalDict["FullScreenSessionIndex"] is not None:
|
||||||
|
if inGlobalDict["RDPList"][inGlobalDict["FullScreenSessionIndex"]]["SessionIsWindowExistBool"]:
|
||||||
|
Connector.SessionScreen100x550(inGlobalDict["RDPList"][inGlobalDict["FullScreenSessionIndex"]]["SessionHex"])
|
||||||
|
#If new session is setted
|
||||||
|
if inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"] is not None:
|
||||||
|
if inGlobalDict["RDPList"][inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]]["SessionIsWindowExistBool"]:
|
||||||
|
Connector.SessionScreenFull(inGlobalDict["RDPList"][inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]]["SessionHex"])
|
||||||
|
#Set one to other equal
|
||||||
|
inGlobalDict["FullScreenSessionIndex"] = inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]
|
||||||
|
###########################################
|
||||||
|
####################################
|
||||||
|
##### Block check responsibility interval [ResponsibilityCheckIntervalSec]
|
||||||
|
if inGlobalDict['ResponsibilityCheckIntervalSec']: # Do check if ResponsibilityCheckIntervalSec is not None
|
||||||
|
if (time.time - lResponsibilityCheckLastSec()) > inGlobalDict['ResponsibilityCheckIntervalSec']:
|
||||||
|
# Set new time
|
||||||
|
lResponsibilityCheckLastSec = time.time()
|
||||||
|
# Do responsibility check
|
||||||
|
for lIndex, lItem in enumerate(inGlobalDict["RDPList"]):
|
||||||
|
# Check RDP responsibility
|
||||||
|
lDoCheckResponsibilityBool = True
|
||||||
|
lDoCheckResponsibilityCountMax = 20
|
||||||
|
lDoCheckResponsibilityCountCurrent = 0
|
||||||
|
while lDoCheckResponsibilityBool:
|
||||||
|
# Enter full screen mode
|
||||||
|
Connector.SessionScreenFull(lItem['SessionHex'])
|
||||||
|
time.sleep(2)
|
||||||
|
# Check responding
|
||||||
|
lDoCheckResponsibilityBool = not Connector.SystemRDPIsResponsible()
|
||||||
|
# Check if counter is exceed - raise exception
|
||||||
|
if lDoCheckResponsibilityCountCurrent >= lDoCheckResponsibilityCountMax:
|
||||||
|
lItem["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
|
||||||
|
lItem["SessionIsWindowResponsibleBool"]=False
|
||||||
|
# Session window is not responsible - restart RDP (close window here - next loop will reconnect)
|
||||||
|
Connector.SessionClose(lItem['SessionHex'])
|
||||||
|
# Turn off the loop
|
||||||
|
lDoCheckResponsibilityBool = False
|
||||||
|
else:
|
||||||
|
# Exit fullscreen mode
|
||||||
|
Connector.SessionScreen100x550(lItem['SessionHex'])
|
||||||
|
# Wait if is not responding
|
||||||
|
if lDoCheckResponsibilityBool:
|
||||||
|
time.sleep(3)
|
||||||
|
# increase the couter
|
||||||
|
lDoCheckResponsibilityCountCurrent+=1
|
||||||
|
####################################
|
||||||
|
# Check ActivityList from orchestrator
|
||||||
|
lActivityListNew = []
|
||||||
|
lActivityListOld = inGlobalDict["OrchestratorToRobotResetStorage"]["ActivityList"]+inGlobalDict["ActivityListStart"]
|
||||||
|
inGlobalDict["ActivityListStart"] = []
|
||||||
|
for lActivityItem in lActivityListOld:
|
||||||
|
#################
|
||||||
|
#Call function from Activity structure
|
||||||
|
################################################
|
||||||
|
lSubmoduleFunctionName = lActivityItem["DefName"]
|
||||||
|
lFileFullPath = lActivityItem["ModulePath"] # "path\\to\\module.py"
|
||||||
|
lModuleName = (lFileFullPath.split("\\")[-1])[0:-3]
|
||||||
|
lTechSpecification = importlib.util.spec_from_file_location(lModuleName, lFileFullPath)
|
||||||
|
lTechModuleFromSpec = importlib.util.module_from_spec(lTechSpecification)
|
||||||
|
lTechSpecificationModuleLoader = lTechSpecification.loader.exec_module(lTechModuleFromSpec)
|
||||||
|
# Set gSettings in module
|
||||||
|
lTechModuleFromSpec.gSettings = inGlobalDict
|
||||||
|
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
|
||||||
|
# Run SettingUpdate function in submodule
|
||||||
|
#mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
|
||||||
|
lActivityItemResult=getattr(lTechModuleFromSpec, lSubmoduleFunctionName)(*lActivityItem["ArgList"],**lActivityItem["ArgDict"])
|
||||||
|
lActivityItemResultType = type(lActivityItemResult)
|
||||||
|
# Check if Result is bool
|
||||||
|
if lActivityItemResultType is bool:
|
||||||
|
if not lActivityItemResult:
|
||||||
|
# Activity is not done - add to list (retry in future)
|
||||||
|
lActivityListNew.append(lActivityItem)
|
||||||
|
#################################################
|
||||||
|
inGlobalDict["OrchestratorToRobotResetStorage"]["ActivityList"] = lActivityListNew # Override the value
|
||||||
|
except RuntimeError as e:
|
||||||
|
# case noGUI error passed - do nothing
|
||||||
|
# Write in logger - warning
|
||||||
|
inGlobalDict["Logger"].warning(f"Host session has lost the GUI")
|
||||||
|
finally:
|
||||||
|
# Wait for the next iteration
|
||||||
|
time.sleep(0.7)
|
||||||
|
return None
|
||||||
|
#TODO Def garbage window cleaner (if connection was lost)
|
@ -0,0 +1,147 @@
|
|||||||
|
# ATTENTION! HERE IS NO Relative import because it will be imported dynamically
|
||||||
|
# All function check the flag SessionIsWindowResponsibleBool == True else no cammand is processed
|
||||||
|
# All functions can return None, Bool or Dict { "IsSuccessful": True }
|
||||||
|
from . import CMDStr # Create CMD Strings
|
||||||
|
from . import Connector # RDP API
|
||||||
|
from . import ConnectorExceptions # Exceptions
|
||||||
|
import time # sleep function
|
||||||
|
# ATTENTION
|
||||||
|
gSettings = None # Gsettings will be initialized after the import module
|
||||||
|
|
||||||
|
# Create new RDPSession in RobotRDPActive
|
||||||
|
def RDPSessionConnect(inRDPSessionKeyStr, inHostStr, inPortStr, inLoginStr, inPasswordStr):
|
||||||
|
lRDPConfigurationItem = { # Init the configuration item
|
||||||
|
"Host": inHostStr, # Host address, example "77.77.22.22"
|
||||||
|
"Port": inPortStr, # RDP Port, example "3389"
|
||||||
|
"Login": inLoginStr, # Login, example "test"
|
||||||
|
"Password": inPasswordStr, # Password, example "test"
|
||||||
|
"Screen": {
|
||||||
|
"Width": 1680, # Width of the remote desktop in pixels, example 1680
|
||||||
|
"Height": 1050, # Height of the remote desktop in pixels, example 1050
|
||||||
|
# "640x480" or "1680x1050" or "FullScreen". If Resolution not exists set full screen, example
|
||||||
|
"FlagUseAllMonitors": False, # True or False, example False
|
||||||
|
"DepthBit": "32" # "32" or "24" or "16" or "15", example "32"
|
||||||
|
},
|
||||||
|
"SharedDriveList": ["c"], # List of the Root sesion hard drives, example ["c"]
|
||||||
|
###### Will updated in program ############
|
||||||
|
"SessionHex": "77777sdfsdf77777dsfdfsf77777777", # Hex is created when robot runs, example ""
|
||||||
|
"SessionIsWindowExistBool": False, # Flag if the RDP window is exist, old name "FlagSessionIsActive". Check every n seconds , example False
|
||||||
|
"SessionIsWindowResponsibleBool": False, # Flag if RDP window is responsible (recieve commands). Check every nn seconds. If window is Responsible - window is Exist too , example False
|
||||||
|
"SessionIsIgnoredBool": False # Flag to ignore RDP window False - dont ignore, True - ignore, example False
|
||||||
|
}
|
||||||
|
# Add item in RDPList
|
||||||
|
gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr] = lRDPConfigurationItem
|
||||||
|
# Create the RDP session
|
||||||
|
Connector.Session(lRDPConfigurationItem)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Disconnect the RDP session
|
||||||
|
def RDPSessionDisconnect(inRDPSessionKeyStr):
|
||||||
|
global gSettings
|
||||||
|
lSessionHex = gSettings["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
|
||||||
|
if lSessionHex:
|
||||||
|
gSettings["RobotRDPActive"]["RDPList"].pop(inRDPSessionKeyStr,None)
|
||||||
|
Connector.SessionClose(inSessionHexStr=lSessionHex)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# RDP Session reconnect
|
||||||
|
def RDPSessionReconnect(inRDPSessionKeyStr):
|
||||||
|
global gSettings
|
||||||
|
lRDPConfigurationItem = gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr]
|
||||||
|
RDPSessionDisconnect(inRDPSessionKeyStr=inRDPSessionKeyStr) # Disconnect the RDP
|
||||||
|
# Add item in RDPList
|
||||||
|
gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr] = lRDPConfigurationItem
|
||||||
|
# Create the RDP session
|
||||||
|
Connector.Session(lRDPConfigurationItem)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Logoff the RDP session
|
||||||
|
def RDPSessionLogoff(inRDPSessionKeyStr):
|
||||||
|
global gSettings
|
||||||
|
lResult = True
|
||||||
|
lCMDStr = "shutdown -L" # CMD logoff command
|
||||||
|
# Calculate the session Hex
|
||||||
|
lSessionHex = gSettings["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
|
||||||
|
if lSessionHex:
|
||||||
|
gSettings["RobotRDPActive"]["RDPList"].pop(inRDPSessionKeyStr,None)
|
||||||
|
# Run CMD
|
||||||
|
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
|
||||||
|
return lResult
|
||||||
|
|
||||||
|
# Check RDP Session responsibility TODO NEED DEV + TEST
|
||||||
|
def RDPSessionResponsibilityCheck(inRDPSessionKeyStr):
|
||||||
|
global gSettings
|
||||||
|
inGlobalDict = gSettings
|
||||||
|
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr]["SessionHex"]
|
||||||
|
# set the fullscreen
|
||||||
|
Connector.SessionScreenFull(inSessionHex=lSessionHex)
|
||||||
|
time.sleep(1)
|
||||||
|
# Check RDP responsibility
|
||||||
|
lDoCheckResponsibilityBool = True
|
||||||
|
lDoCheckResponsibilityCountMax = 20
|
||||||
|
lDoCheckResponsibilityCountCurrent = 0
|
||||||
|
while lDoCheckResponsibilityBool:
|
||||||
|
# Check if counter is exceed - raise exception
|
||||||
|
if lDoCheckResponsibilityCountCurrent >= lDoCheckResponsibilityCountMax:
|
||||||
|
pass
|
||||||
|
#raise ConnectorExceptions.SessionWindowNotResponsibleError("Error when initialize the RDP session - RDP window is not responding!")
|
||||||
|
# Check responding
|
||||||
|
lDoCheckResponsibilityBool = not Connector.SystemRDPIsResponsible()
|
||||||
|
# Wait if is not responding
|
||||||
|
if lDoCheckResponsibilityBool:
|
||||||
|
time.sleep(3)
|
||||||
|
# increase the couter
|
||||||
|
lDoCheckResponsibilityCountCurrent+=1
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Start process if it is not running
|
||||||
|
def RDPSessionProcessStartIfNotRunning(inRDPSessionKeyStr, inProcessNameWEXEStr, inFilePathStr, inFlagGetAbsPathBool=True):
|
||||||
|
global gSettings
|
||||||
|
inGlobalDict = gSettings
|
||||||
|
lResult = True
|
||||||
|
lCMDStr = CMDStr.ProcessStartIfNotRunning(inProcessNameWEXEStr, inFilePathStr, inFlagGetAbsPath= inFlagGetAbsPathBool)
|
||||||
|
# Calculate the session Hex
|
||||||
|
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
|
||||||
|
# Run CMD
|
||||||
|
if lSessionHex:
|
||||||
|
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
|
||||||
|
return lResult
|
||||||
|
# Create CMD str to stop process
|
||||||
|
def RDPSessionProcessStop(inRDPSessionKeyStr, inProcessNameWEXEStr, inFlagForceCloseBool):
|
||||||
|
global gSettings
|
||||||
|
inGlobalDict = gSettings
|
||||||
|
lResult = True
|
||||||
|
lCMDStr = f'taskkill /im "{inProcessNameWEXEStr}" /fi "username eq %USERNAME%"'
|
||||||
|
if inFlagForceCloseBool:
|
||||||
|
lCMDStr+= " /F"
|
||||||
|
# Calculate the session Hex
|
||||||
|
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
|
||||||
|
# Run CMD
|
||||||
|
if lSessionHex:
|
||||||
|
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
|
||||||
|
return lResult
|
||||||
|
# Send file from Host to Session RDP using shared drive in RDP
|
||||||
|
def RDPSessionFileStoredSend(inRDPSessionKeyStr, inHostFilePathStr, inRDPFilePathStr):
|
||||||
|
global gSettings
|
||||||
|
inGlobalDict = gSettings
|
||||||
|
lResult = True
|
||||||
|
lCMDStr = CMDStr.FileStoredSend(inHostFilePath = inHostFilePathStr, inRDPFilePath = inRDPFilePathStr)
|
||||||
|
# Calculate the session Hex
|
||||||
|
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr, {}).get("SessionHex", None)
|
||||||
|
#lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr]["SessionHex"]
|
||||||
|
# Run CMD
|
||||||
|
if lSessionHex:
|
||||||
|
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120)
|
||||||
|
return lResult
|
||||||
|
# Recieve file from Session RDP to Host using shared drive in RDP
|
||||||
|
def RDPSessionFileStoredRecieve(inRDPSessionKeyStr, inRDPFilePathStr, inHostFilePathStr):
|
||||||
|
global gSettings
|
||||||
|
inGlobalDict = gSettings
|
||||||
|
lResult = True
|
||||||
|
lCMDStr = CMDStr.FileStoredRecieve(inRDPFilePath = inRDPFilePathStr, inHostFilePath = inHostFilePathStr)
|
||||||
|
# Calculate the session Hex
|
||||||
|
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
|
||||||
|
# Run CMD
|
||||||
|
if lSessionHex:
|
||||||
|
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120)
|
||||||
|
return lResult
|
@ -0,0 +1,142 @@
|
|||||||
|
from pyOpenRPA.Robot import UIDesktop
|
||||||
|
import os
|
||||||
|
import time # Time wait operations
|
||||||
|
from . import ConnectorExceptions # Exceptions classes
|
||||||
|
from . import Connector
|
||||||
|
from . import Processor # Module for process some functions on thr RDP
|
||||||
|
# Main function
|
||||||
|
def RobotRDPActive(inGSettings):
|
||||||
|
# inGSettings = {
|
||||||
|
# ... "RobotRDPActive": {} ...
|
||||||
|
# }
|
||||||
|
#import pdb
|
||||||
|
#pdb.set_trace()
|
||||||
|
lLogger = inGSettings["Logger"] # Synonim
|
||||||
|
Processor.gSettings = inGSettings # Set gSettings in processor module
|
||||||
|
mGSettingsRDPActiveDict = inGSettings["RobotRDPActive"] # Get configuration from global dict settings
|
||||||
|
# Global error handler
|
||||||
|
try:
|
||||||
|
######## Init the RDP List
|
||||||
|
for lRDPSessionKeyStrItem in mGSettingsRDPActiveDict["RDPList"]:
|
||||||
|
lConfigurationItem = mGSettingsRDPActiveDict["RDPList"][lRDPSessionKeyStrItem]
|
||||||
|
lConfigurationItem["SessionIsWindowExistBool"] = False # Flag that session is not started
|
||||||
|
lConfigurationItem["SessionIsWindowResponsibleBool"] = False # Flag that session is not started
|
||||||
|
lConfigurationItem["SessionHex"] = " 77777sdfsdf77777dsfdfsf77777777" # Flag that session is not started
|
||||||
|
##########
|
||||||
|
# Run monitor - main loop
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
inGlobalDict = mGSettingsRDPActiveDict # Compatibility
|
||||||
|
inListUpdateTimeout = 1 # Compatibility
|
||||||
|
lFlagWhile = True
|
||||||
|
lResponsibilityCheckLastSec = time.time() # Get current time for check interval
|
||||||
|
while lFlagWhile:
|
||||||
|
try:
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# Check RDP window is OK - reconnect if connection was lost
|
||||||
|
lUIOSelectorList = []
|
||||||
|
lRDPConfigurationDictList = []
|
||||||
|
# Prepare selectors list for check
|
||||||
|
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
|
||||||
|
lItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
|
||||||
|
lRDPConfigurationDictList.append(lItem) # Add RDP Configuration in list
|
||||||
|
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']}.*", "backend": "win32"}])
|
||||||
|
# Run wait command
|
||||||
|
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
|
||||||
|
for lItem in lRDPDissappearList: # Reconnect if connection was lost
|
||||||
|
lRDPConfigurationDict = lRDPConfigurationDictList[lItem] # Get RDP Configuration list
|
||||||
|
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
|
||||||
|
# Check if RDP window is not ignored
|
||||||
|
if not lRDPConfigurationDict["SessionIsIgnoredBool"]:
|
||||||
|
try:
|
||||||
|
Connector.Session(lRDPConfigurationDict)
|
||||||
|
lRDPConfigurationDict["SessionIsWindowExistBool"] = True # Flag that session is started
|
||||||
|
# Write in logger - info
|
||||||
|
lLogger.info(
|
||||||
|
f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session has been initialized!")
|
||||||
|
# catch ConnectorExceptions.SessionWindowNotExistError
|
||||||
|
except ConnectorExceptions.SessionWindowNotExistError as e:
|
||||||
|
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
|
||||||
|
# Write in logger - warning
|
||||||
|
lLogger.warning(
|
||||||
|
f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session is not exist!")
|
||||||
|
# general exceptions
|
||||||
|
except Exception as e:
|
||||||
|
# Write in logger - warning
|
||||||
|
lLogger.exception(f"!!! ATTENTION !!! Unrecognized error")
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# Safe turn off the - no need because of Orchestrator control
|
||||||
|
#if inGlobalDict.get("OrchestratorToRobotResetStorage", {}).get("SafeTurnOff", False):
|
||||||
|
# lFlagWhile = False
|
||||||
|
# # Set status disconnected for all RDP List
|
||||||
|
# for lItem in inGlobalDict["RDPList"]:
|
||||||
|
# lItem["SessionIsWindowExistBool"] = False
|
||||||
|
# lItem["SessionIsWindowResponsibleBool"] = False
|
||||||
|
# # Kill all RDP sessions
|
||||||
|
# os.system('taskkill /F /im mstsc.exe')
|
||||||
|
# # Return from function
|
||||||
|
# return
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
Connector.SystemRDPWarningClickOk() # Click all warning messages
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# Check if RDP session is full screen (if is not ignored)
|
||||||
|
if inGlobalDict["FullScreenRDPSessionKeyStr"] is not None:
|
||||||
|
lRDPSessionKeyStr = inGlobalDict["FullScreenRDPSessionKeyStr"] # Get the RDPSessionKeyStr
|
||||||
|
if lRDPSessionKeyStr in inGlobalDict["RDPList"]: # Session Key is in dict
|
||||||
|
lRDPConfigurationDict = inGlobalDict["RDPList"][lRDPSessionKeyStr]
|
||||||
|
#if not lRDPConfigurationDict["SessionIsIgnoredBool"]: # Session is not ignored
|
||||||
|
# Check if full screen
|
||||||
|
lIsFullScreenBool = Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDict["SessionHex"])
|
||||||
|
if not lIsFullScreenBool: # If not the full screen
|
||||||
|
# Check all RDP window and minimize it
|
||||||
|
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
|
||||||
|
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
|
||||||
|
if Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]):
|
||||||
|
Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"], inXInt=10, inYInt=10,
|
||||||
|
inWInt=550,
|
||||||
|
inHInt=350) # Prepare little window
|
||||||
|
# Set full screen for new window
|
||||||
|
Connector.SessionScreenFull(inSessionHex=lRDPConfigurationDict["SessionHex"])
|
||||||
|
else:
|
||||||
|
# Check all RDP window and minimize it
|
||||||
|
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
|
||||||
|
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
|
||||||
|
if Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]):
|
||||||
|
Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"],
|
||||||
|
inXInt=10, inYInt=10,
|
||||||
|
inWInt=550,
|
||||||
|
inHInt=350) # Prepare little window
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# Iterate the activity list in robot RDP active
|
||||||
|
lActivityListNew = []
|
||||||
|
lActivityListOld = inGlobalDict["ActivityList"]
|
||||||
|
inGlobalDict["ActivityList"] = []
|
||||||
|
for lActivityItem in lActivityListOld:
|
||||||
|
lSubmoduleFunctionName = lActivityItem["DefNameStr"]
|
||||||
|
if lSubmoduleFunctionName in dir(Processor):
|
||||||
|
# Run SettingUpdate function in submodule
|
||||||
|
# mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
|
||||||
|
lActivityItemResult = getattr(Processor, lSubmoduleFunctionName)(
|
||||||
|
*lActivityItem["ArgList"], **lActivityItem["ArgDict"])
|
||||||
|
lActivityItemResultType = type(lActivityItemResult)
|
||||||
|
# Check if Result is bool
|
||||||
|
if lActivityItemResultType is bool:
|
||||||
|
if not lActivityItemResult:
|
||||||
|
# Activity is not done - add to list (retry in future)
|
||||||
|
lActivityListNew.append(lActivityItem)
|
||||||
|
inGlobalDict["ActivityList"] = lActivityListNew # Override the value
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
except RuntimeError as e:
|
||||||
|
# case noGUI error passed - do nothing
|
||||||
|
# Write in logger - warning
|
||||||
|
lLogger.warning(f"Host session has lost the GUI")
|
||||||
|
finally:
|
||||||
|
# Wait for the next iteration
|
||||||
|
time.sleep(0.7)
|
||||||
|
# Scheduler.Scheduler(mGSettingsRDPActiveDict["Scheduler"]) # Init & Run Scheduler TODO remake in processor list
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
#Monitor.Monitor(mGSettingsRDPActiveDict, 1)
|
||||||
|
except Exception as e:
|
||||||
|
# Write in logger - warning
|
||||||
|
lLogger.exception(f"!!! ATTENTION !!! Global error handler - look at code")
|
@ -0,0 +1,111 @@
|
|||||||
|
from . import Timer # Async thread
|
||||||
|
import threading # Create in another thread
|
||||||
|
import datetime # Datetime class
|
||||||
|
import time # time functions
|
||||||
|
import importlib # import lib functions
|
||||||
|
# Scheduler class - init and work by the configuration
|
||||||
|
# OOP
|
||||||
|
class Scheduler:
|
||||||
|
# Class properties
|
||||||
|
mSchedulerDict = None
|
||||||
|
mGSettings = None
|
||||||
|
#########################
|
||||||
|
# Init class
|
||||||
|
def __init__(self,inSchedulerDict, inGSettings = None):
|
||||||
|
self.Init(inSchedulerDict = inSchedulerDict, inGSettings = inGSettings)
|
||||||
|
# Init the class instance
|
||||||
|
def Init(self,inSchedulerDict, inGSettings):
|
||||||
|
self.mGSettings = inGSettings
|
||||||
|
self.mSchedulerDict = inSchedulerDict
|
||||||
|
# Init the threads
|
||||||
|
lTimerMainThread = threading.Thread(target = self.TimerMainThreadRun)
|
||||||
|
lTimerMainThread.start() # Start the Timer main thread
|
||||||
|
#print (f"Class instance configuration: {self.mSchedulerDict}, Init has been completed")
|
||||||
|
########################
|
||||||
|
# Main timer thread - run when init class instance
|
||||||
|
def TimerMainThreadRun(self):
|
||||||
|
lDaemonStartDateTime=datetime.datetime.now()
|
||||||
|
lDaemonLoopSeconds=self.mSchedulerDict["ActivityTimeCheckLoopSeconds"]
|
||||||
|
lDaemonActivityLogDict={} #Словарь отработанных активностей, ключ - кортеж (<activityType>, <datetime>, <processPath || processName>, <processArgs>)
|
||||||
|
#Вечный цикл
|
||||||
|
while True:
|
||||||
|
lCurrentDateTime = datetime.datetime.now()
|
||||||
|
#Циклический обход правил
|
||||||
|
lFlagSearchActivityType=True
|
||||||
|
for lIndex, lItem in enumerate(self.mSchedulerDict["ActivityTimeList"]):
|
||||||
|
#Проверка дней недели, в рамках которых можно запускать активность
|
||||||
|
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>=lDaemonStartDateTime and
|
||||||
|
lCurrentDateTime>=lActivityDateTime and
|
||||||
|
(lIndex,lActivityDateTime) not in lDaemonActivityLogDict):
|
||||||
|
#Выполнить операцию
|
||||||
|
#Запись в массив отработанных активностей
|
||||||
|
lDaemonActivityLogDict[(lIndex,lActivityDateTime)]={"ActivityStartDateTime":lCurrentDateTime}
|
||||||
|
#Запустить процесс - new code
|
||||||
|
#################
|
||||||
|
#Call function from Activity structure
|
||||||
|
################################################
|
||||||
|
lSubmoduleFunctionName = lItem["Activity"]["DefName"]
|
||||||
|
lFileFullPath = lItem["Activity"]["ModulePath"] # "path\\to\\module.py"
|
||||||
|
lModuleName = (lFileFullPath.split("\\")[-1])[0:-3]
|
||||||
|
lTechSpecification = importlib.util.spec_from_file_location(lModuleName, lFileFullPath)
|
||||||
|
lTechModuleFromSpec = importlib.util.module_from_spec(lTechSpecification)
|
||||||
|
lTechSpecificationModuleLoader = lTechSpecification.loader.exec_module(lTechModuleFromSpec)
|
||||||
|
# Set gSettings in module
|
||||||
|
lTechModuleFromSpec.gSettings = self.mGSettings
|
||||||
|
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
|
||||||
|
# Run SettingUpdate function in submodule
|
||||||
|
#mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
|
||||||
|
getattr(lTechModuleFromSpec, lSubmoduleFunctionName)(*lItem["Activity"]["ArgList"],**lItem["Activity"]["ArgDict"])
|
||||||
|
#################################################
|
||||||
|
#######################################################################
|
||||||
|
#Branch 2 - if TimeHH:MMStart, TimeHH:MMStop, ActivityIntervalSeconds
|
||||||
|
#######################################################################
|
||||||
|
if "TimeHH:MMStart" in lItem and "TimeHH:MMStop" in lItem and "ActivityIntervalSeconds" in lItem:
|
||||||
|
#Сформировать временной штамп, относительно которого надо будет проверять время
|
||||||
|
#часовой пояс пока не учитываем
|
||||||
|
lActivityDateTime=datetime.datetime.strptime(lItem["TimeHH:MMStart"],"%H:%M")
|
||||||
|
lActivityDateTime=lActivityDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day)
|
||||||
|
lActivityTimeEndDateTime=datetime.datetime.strptime(lItem["TimeHH:MMStop"],"%H:%M")
|
||||||
|
lActivityTimeEndDateTime=lActivityTimeEndDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day)
|
||||||
|
#Убедиться в том, что время наступило
|
||||||
|
if (
|
||||||
|
lCurrentDateTime<lActivityTimeEndDateTime and
|
||||||
|
lCurrentDateTime>=lActivityDateTime and
|
||||||
|
(lIndex,lActivityDateTime) not in lDaemonActivityLogDict):
|
||||||
|
#Запись в массив отработанных активностей
|
||||||
|
lDaemonActivityLogDict[(lIndex,lActivityDateTime)]={"ActivityStartDateTime":lCurrentDateTime}
|
||||||
|
#Call function from Activity structure
|
||||||
|
################################################
|
||||||
|
lSubmoduleFunctionName = lItem["Activity"]["DefName"]
|
||||||
|
lFileFullPath = lItem["Activity"]["ModulePath"] # "path\\to\\module.py"
|
||||||
|
lModuleName = (lFileFullPath.split("\\")[-1])[0:-3]
|
||||||
|
lTechSpecification = importlib.util.spec_from_file_location(lModuleName, lFileFullPath)
|
||||||
|
lTechModuleFromSpec = importlib.util.module_from_spec(lTechSpecification)
|
||||||
|
lTechSpecificationModuleLoader = lTechSpecification.loader.exec_module(lTechModuleFromSpec)
|
||||||
|
# Set gSettings in module
|
||||||
|
lTechModuleFromSpec.gSettings = self.mGSettings
|
||||||
|
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
|
||||||
|
# Run SettingUpdate function in submodule
|
||||||
|
#mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
|
||||||
|
lDef = getattr(lTechModuleFromSpec, lSubmoduleFunctionName) #(*lItem["Activity"]["ArgList"],**lItem["Activity"]["ArgDict"])
|
||||||
|
#################################################
|
||||||
|
#Запуск циклической процедуры
|
||||||
|
#Timer.activityLoopStart(lItem["ActivityIntervalSeconds"], lActivityTimeEndDateTime, lItem["Activity"])
|
||||||
|
lTimer = Timer.RepeatedTimer(lItem["ActivityIntervalSeconds"], lActivityTimeEndDateTime, lDef, *lItem["Activity"]["ArgList"], **lItem["Activity"]["ArgDict"]) # it auto-starts, no need of rt.start()
|
||||||
|
#Уснуть до следующего прогона
|
||||||
|
#print (f"Loop has been completed")
|
||||||
|
time.sleep(lDaemonLoopSeconds)
|
@ -0,0 +1,31 @@
|
|||||||
|
from threading import Timer
|
||||||
|
import datetime
|
||||||
|
class RepeatedTimer(object):
|
||||||
|
def __init__(self, interval, inDateTimeEnd, function, *args, **kwargs):
|
||||||
|
self._timer = None
|
||||||
|
self.interval = interval
|
||||||
|
self.function = function
|
||||||
|
self.args = args
|
||||||
|
self.kwargs = kwargs
|
||||||
|
self.is_running = False
|
||||||
|
self.mDateTimeEnd = inDateTimeEnd # DateTime when stop
|
||||||
|
self.start()
|
||||||
|
def _run(self):
|
||||||
|
self.is_running = False
|
||||||
|
lResultGoLoop=True
|
||||||
|
lCurrentDateTime=datetime.datetime.now()
|
||||||
|
self.function(*self.args, **self.kwargs)
|
||||||
|
if lCurrentDateTime>=self.mDateTimeEnd:
|
||||||
|
lResultGoLoop=False
|
||||||
|
if lResultGoLoop is not None:
|
||||||
|
if lResultGoLoop:
|
||||||
|
self.start()
|
||||||
|
def start(self):
|
||||||
|
if not self.is_running:
|
||||||
|
self._timer = Timer(self.interval, self._run)
|
||||||
|
self._timer.start()
|
||||||
|
self.is_running = True
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self._timer.cancel()
|
||||||
|
self.is_running = False
|
@ -1,55 +0,0 @@
|
|||||||
from pyOpenRPA.Robot import UIDesktop
|
|
||||||
from . import Connector
|
|
||||||
import os
|
|
||||||
import pdb
|
|
||||||
#Check for session is closed. Reopen if detected. Always keep session is active
|
|
||||||
def Monitor(inGlobalDict, inListUpdateTimeout):
|
|
||||||
lFlagWhile = True
|
|
||||||
while lFlagWhile:
|
|
||||||
# UIOSelector list init
|
|
||||||
lUIOSelectorList = []
|
|
||||||
#Prepare selectors list for check
|
|
||||||
for lIndex, lItem in enumerate(inGlobalDict["RDPList"]):
|
|
||||||
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']}.*", "backend": "win32"}])
|
|
||||||
#Run wait command
|
|
||||||
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
|
|
||||||
###########################################
|
|
||||||
#Analyze if flag safeturn off is activated
|
|
||||||
if inGlobalDict.get("OrchestratorToRobotResetStorage",{}).get("SafeTurnOff",False):
|
|
||||||
lFlagWhile=False
|
|
||||||
#Set status disconnected for all RDP List
|
|
||||||
for lItem in inGlobalDict["RDPList"]:
|
|
||||||
lItem["FlagSessionIsActive"]=False
|
|
||||||
#Kill all RDP sessions
|
|
||||||
os.system('taskkill /F /im mstsc.exe')
|
|
||||||
#Return from function
|
|
||||||
return
|
|
||||||
###########################################
|
|
||||||
###########################################
|
|
||||||
for lItem in lRDPDissappearList:
|
|
||||||
inGlobalDict["RDPList"][lItem]["FlagSessionIsActive"] = False # Set flag that session is disconnected
|
|
||||||
#pdb.set_trace()
|
|
||||||
#Session start if it is not in ignore list
|
|
||||||
#add check for selector if it is not in ignoreIndexList
|
|
||||||
if lItem not in inGlobalDict["OrchestratorToRobotStorage"]["IgnoreIndexList"]:
|
|
||||||
try:
|
|
||||||
Connector.Session(inGlobalDict["RDPList"][lItem])
|
|
||||||
inGlobalDict["RDPList"][lItem]["FlagSessionIsActive"] = True # Flag that session is started
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
###########################################
|
|
||||||
#Check if from Orchestrator full screen session is set
|
|
||||||
if inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"] != inGlobalDict["FullScreenSessionIndex"]:
|
|
||||||
#Do some switches
|
|
||||||
#If full screen mode we have now
|
|
||||||
if inGlobalDict["FullScreenSessionIndex"] is not None:
|
|
||||||
if inGlobalDict["RDPList"][inGlobalDict["FullScreenSessionIndex"]]["FlagSessionIsActive"]:
|
|
||||||
Connector.SessionScreen100x550(inGlobalDict["RDPList"][inGlobalDict["FullScreenSessionIndex"]]["SessionHex"])
|
|
||||||
#If new session is setted
|
|
||||||
if inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"] is not None:
|
|
||||||
if inGlobalDict["RDPList"][inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]]["FlagSessionIsActive"]:
|
|
||||||
Connector.SessionScreenFull(inGlobalDict["RDPList"][inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]]["SessionHex"])
|
|
||||||
#Set one to other equal
|
|
||||||
inGlobalDict["FullScreenSessionIndex"] = inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]
|
|
||||||
return None
|
|
||||||
#TODO Def garbage window cleaner (if connection was lost)
|
|
Binary file not shown.
Loading…
Reference in new issue