You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ORPA-pyOpenRPA/Orchestrator/ControlPanel_RobotRDPActive...

207 lines
12 KiB

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