import psutil, datetime, logging, os, json # # # # # # # ORCHESTRATOR CONTROL PANEL # # # # # # # # Init parameters gProcessNameWOEXE = "OpenRPA_RobotRDPActive_" gRDPOrchestratorStorageKey = "" 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 = "" gRobotProcessFilePath = r"path\to\start\link" # Function, which is generate Dict for front-endswith def ControlPanelRenderDict(inGSettings): """result={ "HeaderLeftText":"", "HeaderRightText":"
", "DataStorageKey":"Robot_Name", #Use key for set current dict in mGlobal.DataStorage["DataStorageKey"] on client side "SubheaderText": "State: Turned on", "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'Start' lBodyKeyValue_r3_stop=f'Stop' lBodyKeyValue_r3_restart=f'restart' lResultDict={ "HeaderLeftText":"ROBOT r4", "HeaderRightText":"r4", "DataStorageKey":gRDPOrchestratorStorageKey, #Use key for set current dict in mGlobal.DataStorage["DataStorageKey"] on client side "SubheaderText":"", "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'Set fullscreen' if lRDPListIndex == lFullScreenSessionIndex: lLabelSessionFullScreen = '[Fullscreen]' lOnClickSetFullScreen = f"mGlobal.Processor.ServerValueSet(['Storage','{gRDPOrchestratorStorageKey}','OrchestratorToRobotStorage','FullScreenSessionIndex'],null);" lSetFullScreenA = f'Set minimized' lIgnoreIndexListOnClick = "$.ajax({type: 'POST', url: '{gRDPOrchestratorStorageKey}/IgnoreIndexListAppend', data: '"+str(lRDPListIndex)+"', success: function(lData,l2,l3){}, dataType: 'text'});" lIgnoreIndexListLink = f'Ignore' ### Check if in ignore if lRDPListIndex in inGSettings.get("Storage",{}).get(gRDPOrchestratorStorageKey,{}).get("OrchestratorToRobotStorage",{}).get("IgnoreIndexList",[]): lLabelIsIgnored = '[Ignored]' lIgnoreIndexListOnClick = "$.ajax({type: 'POST', url: '"+gRDPOrchestratorStorageKey+"/IgnoreIndexListRemove', data: '"+str(lRDPListIndex)+"', success: function(lData,l2,l3){}, dataType: 'text'});" lIgnoreIndexListLink = f'Unignore' ### Session state lItemSessionState='Disconnected' if lItem.get("SessionIsWindowResponsibleBool",False): lItemSessionState='Connected' 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: Turned on" lSubheaderRunFalseText="State: Turned off" 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