diff --git a/Orchestrator/Settings/ControlPanel_RobotRDPActive.py b/Orchestrator/Settings/ControlPanel_RobotRDPActive.py
index 2ecce44f..1e76458b 100644
--- a/Orchestrator/Settings/ControlPanel_RobotRDPActive.py
+++ b/Orchestrator/Settings/ControlPanel_RobotRDPActive.py
@@ -63,7 +63,7 @@ def RenderRobotRDPActive(inGlobalConfiguration):
################################
#Session state
lItemSessionState='Disconnected'
- if lItem.get("FlagSessionIsActive",False):
+ if lItem.get("SessionIsWindowExistBool",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
diff --git a/Sources/pyOpenRPA/Tools/RobotRDPActive/CMDStr.py b/Sources/pyOpenRPA/Tools/RobotRDPActive/CMDStr.py
index 02a2651a..992e28e1 100644
--- a/Sources/pyOpenRPA/Tools/RobotRDPActive/CMDStr.py
+++ b/Sources/pyOpenRPA/Tools/RobotRDPActive/CMDStr.py
@@ -11,4 +11,14 @@ def ProcessStop(inProcessName, inFlagForceClose):
lResult = f'taskkill /im "{inProcessName}" /fi "username eq %USERNAME%"'
if inFlagForceClose:
lResult+= " /F"
- return lResult
\ No newline at end of file
+ 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}"'
+# 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}"'
\ No newline at end of file
diff --git a/Sources/pyOpenRPA/Tools/RobotRDPActive/Clipboard.py b/Sources/pyOpenRPA/Tools/RobotRDPActive/Clipboard.py
index 1af5ea76..aa0c1a8c 100644
--- a/Sources/pyOpenRPA/Tools/RobotRDPActive/Clipboard.py
+++ b/Sources/pyOpenRPA/Tools/RobotRDPActive/Clipboard.py
@@ -2,15 +2,16 @@ 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():
+def TextGet(inWaitTextInClipboardSec = gWaitTextInClipboardSec):
+ time.sleep(inWaitTextInClipboardSec) # Wait for clipboard will save
win32clipboard.OpenClipboard()
data = win32clipboard.GetClipboardData()
win32clipboard.CloseClipboard()
diff --git a/Sources/pyOpenRPA/Tools/RobotRDPActive/Connector.py b/Sources/pyOpenRPA/Tools/RobotRDPActive/Connector.py
index 72e37915..a024d535 100644
--- a/Sources/pyOpenRPA/Tools/RobotRDPActive/Connector.py
+++ b/Sources/pyOpenRPA/Tools/RobotRDPActive/Connector.py
@@ -1,12 +1,13 @@
#Import parent folder to import current / other packages
from pyOpenRPA.Robot import UIDesktop #Lib to access RDP window
+from . import ConnectorExceptions # Exceptions classes
import os #os for process run
import uuid #temp id for Template.rdp
import tempfile #Temporary location
import time
import subprocess
from . import Clipboard # Clipboard functions get/set
-import keyboard
+import keyboard # Keyboard functions
import time
import random # random integers
from win32api import GetSystemMetrics # Get Screen rect
@@ -37,6 +38,7 @@ def Session(inRDPSessionConfiguration):
#Remove temp file
time.sleep(4) #Delete file after some delay - one way to delete and run the RDP before because RDP is not read file in one moment
os.remove(lRDPFile) # delete the temp rdp
+ # Set the result
return inRDPSessionConfiguration
#Add login/ password to the windows credentials to run RDP
def SessionLoginPasswordSet(inHost, inLogin, inPassword):
@@ -79,6 +81,9 @@ def SessionConfigurationCreate(inConfiguration):
return (lRDPCurrentFileFullPath, (lRDPCurrentFileFullPath.split("\\")[-1])[0:-4])
#RDPSessionStart
def SessionRDPStart(inRDPFilePath):
+ #Disable certificate warning
+ lCMDString = 'reg add "HKEY_CURRENT_USER\\Software\\Microsoft\\Terminal Server Client" /v "AuthenticationLevelOverride" /t "REG_DWORD" /d 0 /f'
+ os.system(lCMDString)
#run rdp session
lItemArgs = [inRDPFilePath]
subprocess.Popen(lItemArgs, shell=True)
@@ -92,10 +97,13 @@ def SessionRDPStart(inRDPFilePath):
{"title": "D&on't ask me again for connections to this computer",
"friendly_class_name": "CheckBox"}],
[{"title_re": f"{lRDPFileName}.*",
- "class_name": "TscShellContainerClass", "backend": "win32"}]
+ "class_name": "TscShellContainerClass", "backend": "win32"},{"depth_start":3, "depth_end": 3, "class_name":"UIMainClass"}]
],
30
- )
+ )
+ #Enable certificate warning
+ lCMDString = 'reg add "HKEY_CURRENT_USER\\Software\\Microsoft\\Terminal Server Client" /v "AuthenticationLevelOverride" /t "REG_DWORD" /d 2 /f'
+ os.system(lCMDString)
#Click if 0 is appear (RUS)
if 0 in lWaitResult:
#Check the box do not retry
@@ -129,7 +137,24 @@ def SessionRDPStart(inRDPFilePath):
)
# Raise exception if RDP is not active
if len(lWaitResult) == 0:
- raise Exception("Error when initialize the RDP session!")
+ raise ConnectorExceptions.SessionWindowNotExistError("Error when initialize the RDP session - No RDP windows has appreared!")
+ # Wait for init
+ time.sleep(3)
+ # Check RDP responsibility
+ lDoCheckResponsibilityBool = True
+ lDoCheckResponsibilityCountMax = 20
+ lDoCheckResponsibilityCountCurrent = 0
+ while lDoCheckResponsibilityBool:
+ # Check if counter is exceed - raise exception
+ if lDoCheckResponsibilityCountCurrent >= lDoCheckResponsibilityCountMax:
+ raise ConnectorExceptions.SessionWindowNotResponsibleError("Error when initialize the RDP session - RDP window is not responding!")
+ # Check responding
+ lDoCheckResponsibilityBool = not SystemRDPIsResponsible()
+ # Wait if is not responding
+ if lDoCheckResponsibilityBool:
+ time.sleep(3)
+ # increase the couter
+ lDoCheckResponsibilityCountCurrent+=1
#Prepare little window
SessionScreen100x550(lRDPFileName)
return None
@@ -139,6 +164,7 @@ def SessionScreenFull(inSessionHex):
lRDPWindow = UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHex}.*", "backend": "win32"}])
lRDPWindow.set_focus()
lRDPWindow.maximize()
+ #time.sleep(0.5)
if not SessionIsFullScreen(inSessionHex):
lRDPWindow.type_keys("^%{BREAK}")
time.sleep(0.5)
@@ -155,29 +181,30 @@ def SessionScreen100x550(inSessionHex):
time.sleep(0.5)
lRDPWindow.move_window(10,10,550,100)
return None
+# Session - close window
+def SessionClose(inSessionHexStr):
+ #Close window
+ UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHexStr}.*", "backend": "win32"}]).close()
#Type command in CMD
-# inFlagDoCrossCheck: True - Do check that CMD is executed (the text response will not be available)
+# inSessionHex - SessionHex to catch window
# inModeStr "LISTEN", "CROSSCHECK", "RUN"
# "LISTEN" - Get result of the cmd command in result TODO get home script
# "CROSSCHECK" - Check if the command was successufully sent TODO get home script
# "RUN" - Run without crosscheck and get clipboard
-# return ...
+# return {
+# "OutStr": <> # Result string
+# "IsResponsibleBool": True|False # Flag is RDP is responsible - works only when inModeStr = CROSSCHECK
+# }
# example Connector.SessionCMDRun("4d1e48f3ff6c45cc810ea25d8adbeb50","start notepad", "RUN")
-def SessionCMDRun(inSessionHex,inCMDCommandStr, inModeStr="RUN"):
- lCMDPostFixStr = "" # Case default "RUN"
- if inModeStr == "CROSSCHECK":
- lCMDPostFixStr = f"| echo {str(random.randrange(999,9999999))} | clip"
- elif inModeStr == "LISTEN":
- lCMDPostFixStr = f"| clip"
+def SessionCMDRun(inSessionHex,inCMDCommandStr = "echo 1", inModeStr="CROSSCHECK"):
+ # Init the result dict
+ lResult = {"OutStr": None,"IsResponsibleBool":True}
+ # Enter full screen mode
SessionScreenFull(inSessionHex)
time.sleep(2)
- UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHex}.*", "backend": "win32"}])
- keyboard.press_and_release('win+r')
- time.sleep(1)
- keyboard.write(f"cmd /c {inCMDCommandStr} {lCMDPostFixStr}")
- time.sleep(1)
- # TODo cross check from clipboard
- keyboard.press_and_release('enter')
+ # Run CMD operations
+ lResult = SystemCMDRun(inCMDCommandStr = inCMDCommandStr, inModeStr = inModeStr)
+ # Exit fullscreen mode
SessionScreen100x550(inSessionHex)
# Check if session is in Full screen mode
# Return True - is in fullscreen
@@ -196,3 +223,76 @@ def SessionIsFullScreen(inSessionHexStr):
if lSessionHeight == lHeight and lSessionWeight == lWeight:
lResult = True
return lResult
+# Check if RDP session is responsible (check with random combination in cmd)
+# Attention - function will be work fine if RDP will be in full screen mode!!! (see def SessionScreenFull)
+# Return True - is responsible; False - is not responsible
+#Type command in CMD
+# inFlagDoCrossCheck: True - Do check that CMD is executed (the text response will not be available)
+# inModeStr "LISTEN", "CROSSCHECK", "RUN"
+# "LISTEN" - Get result of the cmd command in result TODO get home script
+# "CROSSCHECK" - Check if the command was successufully sent TODO get home script
+# "RUN" - Run without crosscheck and get clipboard
+# inClipboardTimeoutSec # Second for wait when clipboard will changed
+# return {
+# "OutStr": <> # Result string
+# "IsResponsibleBool": True|False # Flag is RDP is responsible - works only when inModeStr = CROSSCHECK
+# }
+# example Connector.SessionCMDRun("4d1e48f3ff6c45cc810ea25d8adbeb50","start notepad", "RUN")
+def SystemCMDRun(inCMDCommandStr = "echo 1", inModeStr="CROSSCHECK", inClipboardTimeoutSec = 5):
+ # Set random text to clipboard (for check purposes that clipboard text has been changed)
+ lClipboardTextOld = str(random.randrange(999,9999999))
+ Clipboard.TextSet(lClipboardTextOld)
+ # Init the result dict
+ lResult = {"OutStr": None,"IsResponsibleBool":True}
+ lCrosscheckKeyStr = str(random.randrange(999,9999999))
+ lCMDPostFixStr = "" # Case default "RUN"
+ if inModeStr == "CROSSCHECK":
+ lCMDPostFixStr = f"| echo {lCrosscheckKeyStr} | clip"
+ elif inModeStr == "LISTEN":
+ lCMDPostFixStr = f"| clip"
+ keyboard.press_and_release('win+r')
+ time.sleep(1)
+ # Remove old text
+ keyboard.press_and_release("ctrl+a")
+ keyboard.press_and_release("backspace")
+ # Write new text
+ keyboard.write(f"cmd /c {inCMDCommandStr} {lCMDPostFixStr}")
+ time.sleep(1)
+ # TODo cross check from clipboard
+ keyboard.press_and_release('enter')
+ # Get OutStr (Case CROSSCHECK and LISTEN)
+ if inModeStr == "CROSSCHECK" or inModeStr == "LISTEN":
+ lClipboardWaitTimeStartSec = time.time()
+ lResult["OutStr"] = Clipboard.TextGet() # Get text from clipboard
+ while lResult["OutStr"] == lClipboardTextOld and (time.time() - lClipboardWaitTimeStartSec) <= inClipboardTimeoutSec
+ lResult["OutStr"] = Clipboard.TextGet() # Get text from clipboard
+ time.sleep(0.5) # wait some time for the next operation
+ # Do crosscheck
+ if inModeStr == "CROSSCHECK":
+ if lResult["OutStr"] == f"{lCrosscheckKeyStr} \r\n\x00\x00\x00\x00\x00":
+ lResult["IsResponsibleBool"] = True
+ else:
+ lResult["IsResponsibleBool"] = False
+ # return the result
+ return lResult
+# Check if current RDP is responsible
+def SystemRDPIsResponsible():
+ return SystemCMDRun(inCMDCommandStr = "echo 1", inModeStr="CROSSCHECK")["IsResponsibleBool"]
+# Click OK on error messages
+def SystemRDPWarningClickOk():
+ # Try to click OK Error window in RUS version
+ while UIDesktop.UIOSelector_Exist_Bool([{"title": "Подключение к удаленному рабочему столу", "class_name": "#32770", "backend": "win32"},
+ {"title": "ОК", "class_name": "Button"}]):
+ try:
+ UIDesktop.UIOSelector_Get_UIO([{"title": "Подключение к удаленному рабочему столу", "class_name": "#32770", "backend": "win32"},
+ {"title": "ОК", "class_name": "Button"}]).click()
+ except Exception as e:
+ pass
+ # Try to click OK Error window in ENG version
+ while UIDesktop.UIOSelector_Exist_Bool([{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
+ {"title": "OK", "class_name": "Button"}]):
+ try:
+ UIDesktop.UIOSelector_Get_UIO([{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
+ {"title": "OK", "class_name": "Button"}]).click()
+ except Exception as e:
+ pass
\ No newline at end of file
diff --git a/Sources/pyOpenRPA/Tools/RobotRDPActive/ConnectorExceptions.py b/Sources/pyOpenRPA/Tools/RobotRDPActive/ConnectorExceptions.py
new file mode 100644
index 00000000..3ae91409
--- /dev/null
+++ b/Sources/pyOpenRPA/Tools/RobotRDPActive/ConnectorExceptions.py
@@ -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")
diff --git a/Sources/pyOpenRPA/Tools/RobotRDPActive/GlobalDictSessionIndex_Defs.py b/Sources/pyOpenRPA/Tools/RobotRDPActive/GlobalDictSessionIndex_Defs.py
index 9ddcc3ee..bc7d5e8f 100644
--- a/Sources/pyOpenRPA/Tools/RobotRDPActive/GlobalDictSessionIndex_Defs.py
+++ b/Sources/pyOpenRPA/Tools/RobotRDPActive/GlobalDictSessionIndex_Defs.py
@@ -1,18 +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"]
- # Run CMD
- Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
+ # 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"]
- # Run CMD
- Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
\ No newline at end of file
+ # 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
\ No newline at end of file
diff --git a/Sources/pyOpenRPA/Tools/RobotRDPActive/Monitor.py b/Sources/pyOpenRPA/Tools/RobotRDPActive/Monitor.py
index 025cf231..c1eb11b9 100644
--- a/Sources/pyOpenRPA/Tools/RobotRDPActive/Monitor.py
+++ b/Sources/pyOpenRPA/Tools/RobotRDPActive/Monitor.py
@@ -4,73 +4,150 @@ import os
import time # Time wait operations
import pdb
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:
- # 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
+ 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()
- #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"]
- ###########################################
- # Check ActivityList from orchestrator
- for lActivityItem in inGlobalDict["OrchestratorToRobotResetStorage"]["ActivityList"]:
- #################
- #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)
- if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
- # Run SettingUpdate function in submodule
- #mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
- getattr(lTechModuleFromSpec, lSubmoduleFunctionName)(*lActivityItem["ArgList"],**lActivityItem["ArgDict"])
- #################################################
- inGlobalDict["OrchestratorToRobotResetStorage"]["ActivityList"] = [] # Override the value
- time.sleep(2)
+ 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 = []
+ for lActivityItem in inGlobalDict["OrchestratorToRobotResetStorage"]["ActivityList"]:
+ #################
+ #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)
+ 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(2)
return None
#TODO Def garbage window cleaner (if connection was lost)
\ No newline at end of file
diff --git a/Sources/pyOpenRPA/Tools/RobotRDPActive/Scheduler.py b/Sources/pyOpenRPA/Tools/RobotRDPActive/Scheduler.py
index 4eb0e5f0..2f48aa9f 100644
--- a/Sources/pyOpenRPA/Tools/RobotRDPActive/Scheduler.py
+++ b/Sources/pyOpenRPA/Tools/RobotRDPActive/Scheduler.py
@@ -19,7 +19,7 @@ class Scheduler:
# 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")
+ #print (f"Class instance configuration: {self.mSchedulerDict}, Init has been completed")
########################
# Main timer thread - run when init class instance
def TimerMainThreadRun(self):
@@ -102,5 +102,5 @@ class Scheduler:
#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")
+ #print (f"Loop has been completed")
time.sleep(lDaemonLoopSeconds)
\ No newline at end of file
diff --git a/Sources/pyOpenRPA/Tools/RobotRDPActive/__main__.py b/Sources/pyOpenRPA/Tools/RobotRDPActive/__main__.py
index 06e7b5c3..21d3244e 100644
--- a/Sources/pyOpenRPA/Tools/RobotRDPActive/__main__.py
+++ b/Sources/pyOpenRPA/Tools/RobotRDPActive/__main__.py
@@ -31,22 +31,21 @@ if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
from pyOpenRPA.Tools.RobotRDPActive import Connector
from pyOpenRPA.Tools.RobotRDPActive import Monitor
from pyOpenRPA.Tools.RobotRDPActive import Scheduler # Scheduler operations
-#Disable certificate warning
-lCMDString = 'reg add "HKEY_CURRENT_USER\\Software\\Microsoft\\Terminal Server Client" /v "AuthenticationLevelOverride" /t "REG_DWORD" /d 0 /f'
-os.system(lCMDString)
-#time.sleep()
-for lConfigurationItem in mGlobalDict["RDPList"]:
- try:
- Connector.Session(lConfigurationItem)
- lConfigurationItem["FlagSessionIsActive"]=True #Flag that session is started
- except Exception:
- pass
-#Run monitor
-#print(mGlobalDict)
-Scheduler.Scheduler(mGlobalDict["Scheduler"]) # Init & Run Scheduler
-Monitor.Monitor(mGlobalDict, 1)
-#Enable certificate warning
-lCMDString = 'reg add "HKEY_CURRENT_USER\\Software\\Microsoft\\Terminal Server Client" /v "AuthenticationLevelOverride" /t "REG_DWORD" /d 2 /f'
-os.system(lCMDString)
-#Close all thread from OrchestratorConnection
-mGlobalDict["OrchestratorConnectorTerminateAll"]()
\ No newline at end of file
+#### Global error handler
+try:
+ #time.sleep()
+ ######## Init the RDP List
+ for lConfigurationItem in mGlobalDict["RDPList"]:
+ 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
+ Scheduler.Scheduler(mGlobalDict["Scheduler"]) # Init & Run Scheduler
+ Monitor.Monitor(mGlobalDict, 1)
+except Exception as e:
+ # Write in logger - warning
+ mGlobalDict["Logger"].exception(f"!!! ATTENTION !!! Global error handler - look at code")
+finally:
+ #Close all thread from OrchestratorConnection
+ mGlobalDict["OrchestratorConnectorTerminateAll"]()
\ No newline at end of file
diff --git a/Utils/RobotRDPActive/SettingsRobotRDPActiveExample.py b/Utils/RobotRDPActive/SettingsRobotRDPActiveExample.py
index 94c7e5be..30827e68 100644
--- a/Utils/RobotRDPActive/SettingsRobotRDPActiveExample.py
+++ b/Utils/RobotRDPActive/SettingsRobotRDPActiveExample.py
@@ -4,6 +4,7 @@ from pyOpenRPA.Tools import RobotRDPActive # For RobotRDPActive folder purposes
import os
import logging
import datetime
+import sys
#Definitions
lOrchestratorHost="localhost"
lOrchestratorPort=8081
@@ -29,10 +30,13 @@ def Settings():
"DepthBit": "32" # "32" or "24" or "16" or "15"
},
"SharedDriveList":["c"], # List of the Root sesion hard drives
+ ###### Will updated in program ############
"SessionHex":"", # Hex is created when robot runs
- "FlagSessionIsActive": False
+ "SessionIsWindowExistBool": False , # Flag if the RDP window is exist, old name "FlagSessionIsActive". Check every n seconds
+ "SessionIsWindowResponsibleBool": False # Flag if RDP window is responsible (recieve commands). Check every nn seconds. If window is Responsible - window is Exist too
}
],
+ "ResponsibilityCheckIntervalSec": None, # Seconds interval when Robot check the RDP responsibility. if None - dont check
"FullScreenSessionIndex": None, #Index of the current session which is full screened, None is no session in fullscreen
"Logger": logging.getLogger("RobotRDPActive"),
"OrchestratorToRobotStorage": {
@@ -151,12 +155,17 @@ def Settings():
#Подготовка логгера Robot
#########################
mRobotLogger=mDict["Logger"]
- mRobotLogger.setLevel(logging.INFO)
+ mRobotLogger.setLevel(logging.INFO) #logging.DEBUG
# create the logging file handler
mRobotLoggerFH = logging.FileHandler("Reports\ReportRobotRDPActive_"+datetime.datetime.now().strftime("%Y_%m_%d")+".log")
mRobotLoggerFormatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
mRobotLoggerFH.setFormatter(mRobotLoggerFormatter)
# add handler to logger object
mRobotLogger.addHandler(mRobotLoggerFH)
+ ####################Add console output
+ if mDict["Logs"]["FlagShowInConsole"]:
+ handler = logging.StreamHandler(sys.stdout)
+ handler.setFormatter(lRobotLoggerFormatter)
+ mRobotLogger.addHandler(handler)
############################################
return mDict
\ No newline at end of file