diff --git a/Orchestrator/Settings/SettingsOrchestratorExample.py b/Orchestrator/Settings/SettingsOrchestratorExample.py index e5959cf9..e758444a 100644 --- a/Orchestrator/Settings/SettingsOrchestratorExample.py +++ b/Orchestrator/Settings/SettingsOrchestratorExample.py @@ -1,7 +1,7 @@ import psutil import datetime import logging - +import sys # stdout fro logging def RenderRobotR01(inGlobalConfiguration): #Subheader Variants lSubheaderRunTrueText="Состояние: Работает" @@ -74,12 +74,12 @@ def Settings(): mDict = { "Server": { "ListenPort_": "Порт, по которому можно подключиться к демону", - "ListenPort": 8081, + "ListenPort": 80, "ListenURLList": [ { "Description": "Local machine test", "URL_": "Сетевое расположение сервера демона", - "URL": "http://127.0.0.1:8081" + "URL": "" } ], "AccessUsers": { #Default - all URL is blocked @@ -144,7 +144,32 @@ def Settings(): # "CheckTaskName": "notepad.exe", #Python function module name # "Path": "notepad", #Python function name # "ArgList": [] #Input python function args - #} + #}, + # { + # "Type": "RDPSessionConnect", #Activity type - start/connect RDP Session + # "RDPSessionKeyStr": "notepad.exe", #Python function module name + # "RDPConfigurationDict": {} + # }, + # { + # "Type": "RDPSessionLogoff", #Activity type - logoff RDP Session + # "RDPSessionKeyStr": "notepad.exe", #Python function module name + # }, + # { + # "Type": "RDPSessionDisconnect", #Activity type - disconnect the RDP Session without logoff + # "RDPSessionKeyStr": "notepad.exe", #Python function module name + # }, + # { + # "Type": "RDPSessionFileSend", #Activity type - send file to RDP session + # ... + # }, + # { + # "Type": "RDPSessionFileRecieve", #Activity type - recieve file from rdp session + # ... + # }, + # { + # "Type": "RDPSessionProcessStart", #Activity type - + # ... + # }, ] }, "Scheduler": { @@ -196,6 +221,57 @@ def Settings(): } ] }, + # # # # # # # # # # # # # # + "RobotRDPActive":{ + "RDPList": { + "RDPSessionKey":{ + "Host": "77.77.22.22", # Host address + "Port": "3389", # RDP Port + "Login": "test", # Login + "Password": "test", # Password + "Screen": { + "Width": 1680, # Width of the remote desktop in pixels + "Height": 1050, # Height of the remote desktop in pixels + # "640x480" or "1680x1050" or "FullScreen". If Resolution not exists set full screen + "FlagUseAllMonitors": False, # True or False + "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 + "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 + "SessionIsIgnoredBool": False # Flag to ignore RDP window False - dont ignore, True - ignore + } + }, + "ResponsibilityCheckIntervalSec": None, + # Seconds interval when Robot check the RDP responsibility. if None - dont check + "FullScreenRDPSessionKeyStr": None, # RDPSessionKeyStr of the current session which is full screened, None is no session in fullscreen + "ActivityList":[ # Technical Activity list for RobotRDPActive thread - equal to Main activity list, apply only RDP activity + # { + # "DefNameStr":"test", # Function name in RobotRDPActive.Processor + # "ArgList":[1,2,3], # Args list + # "ArgDict":{"ttt":1,"222":2,"dsd":3} # Args dictionary + # }, + #{ + # "DefNameStr": "RDPSessionConnect", # Function name in RobotRDPActive.Processor + # "ArgList": [], # Args list + # "ArgDict": {"inRDPSessionKeyStr": "TestRDP", "inHostStr": "77.44.33.22", "inPortStr": "3389", + # "inLoginStr": "login", "inPasswordStr": "pass"} # Args dictionary + #}, + # { + # "DefNameStr": "RDPSessionDisconnect", # Disconnect the RDP session without logoff. Function name in RobotRDPActive.Processor + # "ArgList": [], # Args list + # "ArgDict": {"inRDPSessionKeyStr": "TestRDP"} + # }, + # { + # "DefNameStr": "RDPSessionReconnect", # Disconnect the RDP session without logoff. Function name in RobotRDPActive.Processor + # "ArgList": [], # Args list + # "ArgDict": {"inRDPSessionKeyStr": "TestRDP"} + # } + ] + }, + # # # # # # # # # # # # # # "FileManager": { "FileURLFilePathDict_help": "https://localhost:8081/filemanager/. All FileURL s must be set in lowercase", "FileURLFilePathDict": { @@ -224,6 +300,10 @@ def Settings(): mRobotLoggerFH.setFormatter(mRobotLoggerFormatter) # add handler to logger object mRobotLogger.addHandler(mRobotLoggerFH) + ####################Add console output + handler = logging.StreamHandler(sys.stdout) + handler.setFormatter(mRobotLoggerFormatter) + mRobotLogger.addHandler(handler) ############################################ ################################### #Init .py files from Settings folder diff --git a/Sources/pyOpenRPA/Tools/RobotRDPActive/__init__.py b/Sources/__init__.py similarity index 100% rename from Sources/pyOpenRPA/Tools/RobotRDPActive/__init__.py rename to Sources/__init__.py diff --git a/Sources/pyOpenRPA/Orchestrator/Orchestrator.py b/Sources/pyOpenRPA/Orchestrator/Orchestrator.py index c99c8192..93d99081 100644 --- a/Sources/pyOpenRPA/Orchestrator/Orchestrator.py +++ b/Sources/pyOpenRPA/Orchestrator/Orchestrator.py @@ -15,9 +15,11 @@ import copy #from .Settings import Settings import importlib from importlib import util +import threading # Multi-threading for RobotRDPActive +from .RobotRDPActive import RobotRDPActive #Start robot rdp active #Единый глобальный словарь (За основу взять из Settings.py) -global mGlobalDict +global gSettingsDict #Call Settings function from argv[1] file ################################################ lSubmoduleFunctionName = "Settings" @@ -26,37 +28,41 @@ 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) -mGlobalDict = None +gSettingsDict = None if lSubmoduleFunctionName in dir(lTechModuleFromSpec): # Run SettingUpdate function in submodule - mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)() + gSettingsDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)() ################################################# #mGlobalDict = Settings.Settings(sys.argv[1]) -Processor.mGlobalDict = mGlobalDict -Timer.mGlobalDict = mGlobalDict -Timer.Processor.mGlobalDict = mGlobalDict -Server.mGlobalDict = mGlobalDict -Server.Processor.mGlobalDict = mGlobalDict +Processor.gSettingsDict = gSettingsDict +Timer.gSettingsDict = gSettingsDict +Timer.Processor.gSettingsDict = gSettingsDict +Server.gSettingsDict = gSettingsDict +Server.Processor.gSettingsDict = gSettingsDict #Инициализация настроечных параметров -lDaemonLoopSeconds=mGlobalDict["Scheduler"]["ActivityTimeCheckLoopSeconds"] +lDaemonLoopSeconds=gSettingsDict["Scheduler"]["ActivityTimeCheckLoopSeconds"] lDaemonActivityLogDict={} #Словарь отработанных активностей, ключ - кортеж (, , , ) lDaemonStartDateTime=datetime.datetime.now() #Инициализация сервера -lThreadServer = Server.RobotDaemonServer("ServerThread", mGlobalDict) +lThreadServer = Server.RobotDaemonServer("ServerThread", gSettingsDict) lThreadServer.start() +# Init the RobotRDPActive in another thread +lRobotRDPActiveThread = threading.Thread(target= RobotRDPActive.RobotRDPActive, kwargs={"inGSettings":gSettingsDict}) +lRobotRDPActiveThread.daemon = True # Run the thread in daemon mode. +lRobotRDPActiveThread.start() # Start the thread execution. #Logging -mGlobalDict["Logger"].info("Scheduler loop init") +gSettingsDict["Logger"].info("Scheduler loop init") # Выполнить активности при старте -for lActivityItem in mGlobalDict["OrchestratorStart"]["ActivityList"]: +for lActivityItem in gSettingsDict["OrchestratorStart"]["ActivityList"]: Processor.ActivityListOrDict(lActivityItem) #Вечный цикл while True: lCurrentDateTime = datetime.datetime.now() #Циклический обход правил lFlagSearchActivityType=True - for lIndex, lItem in enumerate(mGlobalDict["Scheduler"]["ActivityTimeList"]): + for lIndex, lItem in enumerate(gSettingsDict["Scheduler"]["ActivityTimeList"]): #Проверка дней недели, в рамках которых можно запускать активность lItemWeekdayList=lItem.get("WeekdayList", [0, 1, 2, 3, 4, 5, 6]) if lCurrentDateTime.weekday() in lItemWeekdayList: @@ -64,7 +70,7 @@ while True: #Лог lItemCopy = copy.deepcopy(lItem) lItemCopy["DateTimeUTCStringStart"]=datetime.datetime.strftime(datetime.datetime.now(),"%Y-%m-%dT%H:%M:%S.%f") - mGlobalDict["Scheduler"]["LogList"].append(lItemCopy) + gSettingsDict["Scheduler"]["LogList"].append(lItemCopy) ####################################################################### #Branch 1 - if has TimeHH:MM ####################################################################### diff --git a/Sources/pyOpenRPA/Orchestrator/Processor.py b/Sources/pyOpenRPA/Orchestrator/Processor.py index 7c10775e..c9ff0fcb 100644 --- a/Sources/pyOpenRPA/Orchestrator/Processor.py +++ b/Sources/pyOpenRPA/Orchestrator/Processor.py @@ -29,6 +29,11 @@ import psutil # "Value": # }, # { +# "Type": "GlobalDictKeyListValueAppend", +# "KeyList": ["key1","key2",...], +# "Value": +# }, +# { # "Type": "GlobalDictKeyListValueGet", # "KeyList": ["key1","key2",...] # }, @@ -72,9 +77,10 @@ import psutil # "DateTimeUTCStringStart" # "DateTimeUTCStringStop" # "Result" +gSettingsDict = None def Activity(inActivity): #Глобальная переменная - глобальный словарь унаследованный от Settings.py - global mGlobalDict + global gSettingsDict #Fill DateTimeUTCStringStart inActivity["DateTimeUTCStringStart"] = datetime.datetime.strftime(datetime.datetime.now(),"%Y-%m-%dT%H:%M:%S.%f") #Alias (compatibility) @@ -113,7 +119,7 @@ def Activity(inActivity): #Обработка команды GlobalDictKeyListValueSet ########################################################### if lItem["Type"]=="GlobalDictKeyListValueSet": - lDict = mGlobalDict + lDict = gSettingsDict for lItem2 in lItem["KeyList"][:-1]: #Check if key - value exists if lItem2 in lDict: @@ -125,10 +131,25 @@ def Activity(inActivity): lDict[lItem["KeyList"][-1]]=lItem["Value"] lItem["Result"] = True ########################################################### + # Обработка команды GlobalDictKeyListValueAppend + ########################################################### + if lItem["Type"] == "GlobalDictKeyListValueAppend": + lDict = gSettingsDict + for lItem2 in lItem["KeyList"][:-1]: + # Check if key - value exists + if lItem2 in lDict: + pass + else: + lDict[lItem2] = {} + lDict = lDict[lItem2] + # Set value + lDict[lItem["KeyList"][-1]].append(lItem["Value"]) + lItem["Result"] = True + ########################################################### #Обработка команды GlobalDictKeyListValueGet ########################################################### if lItem["Type"]=="GlobalDictKeyListValueGet": - lDict = mGlobalDict + lDict = gSettingsDict for lItem2 in lItem["KeyList"][:-1]: #Check if key - value exists if lItem2 in lDict: @@ -147,7 +168,7 @@ def Activity(inActivity): #Вид активности - запуск процесса #Запись в массив отработанных активностей #Лог - mGlobalDict["Processor"]["LogList"].append({"activityType":lItem["Type"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["Path"], "activityStartDateTime":str(lCurrentDateTime)}) + gSettingsDict["Processor"]["LogList"].append({"activityType":lItem["Type"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["Path"], "activityStartDateTime":str(lCurrentDateTime)}) #Запустить процесс lItemArgs=[lItem["Path"]] lItemArgs.extend(lItem["ArgList"]) @@ -169,7 +190,7 @@ def Activity(inActivity): #Вид активности - запуск процесса #Запись в массив отработанных активностей #Лог - mGlobalDict["Processor"]["LogList"].append({"activityType":lItem["Type"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["Path"], "activityStartDateTime":str(lCurrentDateTime)}) + gSettingsDict["Processor"]["LogList"].append({"activityType":lItem["Type"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["Path"], "activityStartDateTime":str(lCurrentDateTime)}) #Запустить процесс lItemArgs=[lItem["Path"]] lItemArgs.extend(lItem["ArgList"]) @@ -189,7 +210,7 @@ def Activity(inActivity): if lItem.get('User',"")!="": lActivityCloseCommand+=f' /fi "username eq {lItem["User"]}"' #Лог - mGlobalDict["Processor"]["LogList"].append({"activityType":lItem["Type"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["Name"], "activityStartDateTime":str(lCurrentDateTime)}) + gSettingsDict["Processor"]["LogList"].append({"activityType":lItem["Type"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["Name"], "activityStartDateTime":str(lCurrentDateTime)}) #Завершить процесс os.system(lActivityCloseCommand) ################################# @@ -228,9 +249,9 @@ def Activity(inActivity): #Trace activity ################## #print(mGlobalDict) - if mGlobalDict["Processor"].get(f"LogType_{lItem['Type']}",True): + if gSettingsDict["Processor"].get(f"LogType_{lItem['Type']}", True): #Add activity in TransactionList if it is applicable - mGlobalDict["Processor"]["LogList"].append(copy.deepcopy(lItem)) + gSettingsDict["Processor"]["LogList"].append(copy.deepcopy(lItem)) #Вернуть результат return lItem diff --git a/Sources/pyOpenRPA/Tools/RobotRDPActive/CMDStr.py b/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/CMDStr.py similarity index 100% rename from Sources/pyOpenRPA/Tools/RobotRDPActive/CMDStr.py rename to Sources/pyOpenRPA/Orchestrator/RobotRDPActive/CMDStr.py diff --git a/Sources/pyOpenRPA/Tools/RobotRDPActive/Clipboard.py b/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/Clipboard.py similarity index 100% rename from Sources/pyOpenRPA/Tools/RobotRDPActive/Clipboard.py rename to Sources/pyOpenRPA/Orchestrator/RobotRDPActive/Clipboard.py diff --git a/Sources/pyOpenRPA/Tools/RobotRDPActive/Connector.py b/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/Connector.py similarity index 90% rename from Sources/pyOpenRPA/Tools/RobotRDPActive/Connector.py rename to Sources/pyOpenRPA/Orchestrator/RobotRDPActive/Connector.py index f2f7c757..3b1284be 100644 --- a/Sources/pyOpenRPA/Tools/RobotRDPActive/Connector.py +++ b/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/Connector.py @@ -4,7 +4,6 @@ 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 # Keyboard functions @@ -140,31 +139,16 @@ def SessionRDPStart(inRDPFilePath): raise ConnectorExceptions.SessionWindowNotExistError("Error when initialize the RDP session - No RDP windows has appreared!") # Wait for init time.sleep(3) - # set the fullscreen - SessionScreenFull(inSessionHex=lRDPFileName) - time.sleep(1) - # 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) + SessionScreenSize_X_Y_W_H(inSessionHex = lRDPFileName, inXInt = 10, inYInt = 10, inWInt = 550, inHInt = 350) #Prepare little window return None + #Set fullscreen for app def SessionScreenFull(inSessionHex): #Prepare little window - lRDPWindow = UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHex}.*", "backend": "win32"}]) + try: + lRDPWindow = UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHex}.*", "backend": "win32"}]) + except Exception as e: + return None lRDPWindow.set_focus() lRDPWindow.maximize() #time.sleep(0.5) @@ -172,22 +156,34 @@ def SessionScreenFull(inSessionHex): lRDPWindow.type_keys("^%{BREAK}") time.sleep(0.5) return None -#Set Little window of the session -def SessionScreen100x550(inSessionHex): + +# Set the screen size +def SessionScreenSize_X_Y_W_H(inSessionHex, inXInt, inYInt, inWInt, inHInt): #Prepare little window - lRDPWindow = UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHex}.*", "backend": "win32"}]) + try: + lRDPWindow = UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHex}.*", "backend": "win32"}]) + except Exception as e: + return None lRDPWindow.set_focus() if SessionIsFullScreen(inSessionHex): lRDPWindow.type_keys("^%{BREAK}") time.sleep(0.5) lRDPWindow.restore() time.sleep(0.5) - lRDPWindow.move_window(10,10,550,100) + lRDPWindow.move_window(inXInt,inYInt,inWInt,inHInt) + return None + +# Set Little window of the session +def SessionScreen100x550(inSessionHex): + SessionScreenSize_X_Y_W_H(inSessionHex = inSessionHex, inXInt = 10, inYInt = 10, inWInt = 550, inHInt = 100) return None # Session - close window def SessionClose(inSessionHexStr): #Close window - UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHexStr}.*", "backend": "win32"}]).close() + try: + UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHexStr}.*", "backend": "win32"}]).close() + except Exception as e: + pass #Type command in CMD # inSessionHex - SessionHex to catch window # inModeStr "LISTEN", "CROSSCHECK", "RUN" @@ -208,7 +204,8 @@ def SessionCMDRun(inSessionHex,inCMDCommandStr = "echo 1", inModeStr="CROSSCHECK # Run CMD operations lResult = SystemCMDRun(inCMDCommandStr = inCMDCommandStr, inModeStr = inModeStr, inClipboardTimeoutSec = inClipboardTimeoutSec) # Exit fullscreen mode - SessionScreen100x550(inSessionHex) + SessionScreenSize_X_Y_W_H(inSessionHex=inSessionHex, inXInt=10, inYInt=10, inWInt=550, + inHInt=350) # Prepare little window # Check if session is in Full screen mode # Return True - is in fullscreen # example print(Connector.SessionIsFullScreen("")) @@ -218,7 +215,10 @@ def SessionIsFullScreen(inSessionHexStr): lWeight = GetSystemMetrics(0) lHeight = GetSystemMetrics(1) #Get window screen - lRectangle = UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHexStr}.*", "backend": "win32"}]).rectangle() + try: + lRectangle = UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHexStr}.*", "backend": "win32"}]).rectangle() + except Exception as e: + return lResult # Get Height/Weight lSessionWeight = lRectangle.right - lRectangle.left lSessionHeight = lRectangle.bottom - lRectangle.top diff --git a/Sources/pyOpenRPA/Tools/RobotRDPActive/ConnectorExceptions.py b/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/ConnectorExceptions.py similarity index 100% rename from Sources/pyOpenRPA/Tools/RobotRDPActive/ConnectorExceptions.py rename to Sources/pyOpenRPA/Orchestrator/RobotRDPActive/ConnectorExceptions.py diff --git a/Sources/pyOpenRPA/Tools/RobotRDPActive/GlobalDictSessionIndex_Defs.py b/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/GlobalDictSessionIndex_Defs.py similarity index 100% rename from Sources/pyOpenRPA/Tools/RobotRDPActive/GlobalDictSessionIndex_Defs.py rename to Sources/pyOpenRPA/Orchestrator/RobotRDPActive/GlobalDictSessionIndex_Defs.py diff --git a/Sources/pyOpenRPA/Tools/RobotRDPActive/Monitor.py b/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/Monitor.py similarity index 99% rename from Sources/pyOpenRPA/Tools/RobotRDPActive/Monitor.py rename to Sources/pyOpenRPA/Orchestrator/RobotRDPActive/Monitor.py index ed7b9fc5..2f7777de 100644 --- a/Sources/pyOpenRPA/Tools/RobotRDPActive/Monitor.py +++ b/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/Monitor.py @@ -2,10 +2,10 @@ from pyOpenRPA.Robot import UIDesktop from . import Connector import os import time # Time wait operations -import pdb import importlib # from dynamic import module from . import ConnectorExceptions # Exceptions classes -import copy + + #Check for session is closed. Reopen if detected. Always keep session is active def Monitor(inGlobalDict, inListUpdateTimeout): lFlagWhile = True diff --git a/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/Processor.py b/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/Processor.py new file mode 100644 index 00000000..8f1789f2 --- /dev/null +++ b/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/Processor.py @@ -0,0 +1,152 @@ +# 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"][inRDPSessionKeyStr]["SessionHex"] + 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 + +# 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(inRDPSessionKey, inProcessName, inFilePath, inFlagGetAbsPath=True): + global gSettings + inGlobalDict = gSettings + lResult = True + lCMDStr = CMDStr.ProcessStartIfNotRunning(inProcessName,inFilePath, inFlagGetAbsPath= inFlagGetAbsPath) + # Calculate the session Hex + lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKey]["SessionHex"] + # Check is Session is responsible + if inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKey]["SessionIsWindowResponsibleBool"]: + # Run CMD + Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN") + else: + # Write in logger - warning + inGlobalDict["Logger"].warning(f"Defs_SessionIndex.ProcessStartIfNotRunning: SessionIndex: {str(inRDPSessionKey)}, 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 RDPSessionProcessStop(inRDPSessionKey, inProcessName, inFlagForceClose): + global gSettings + inGlobalDict = gSettings + lResult = True + lCMDStr = f'taskkill /im "{inProcessName}" /fi "username eq %USERNAME%"' + if inFlagForceClose: + lCMDStr+= " /F" + # Calculate the session Hex + lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKey]["SessionHex"] + # Check is Session is responsible + if inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKey]["SessionIsWindowResponsibleBool"]: + # Run CMD + Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN") + else: + # TODO Write in logger - warning + inGlobalDict["Logger"].warning(f"Defs_SessionIndex.ProcessStop: SessionIndex: {str(inRDPSessionKey)}, 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 RDPSessionFileStoredSend(inRDPSessionKey, inHostFilePath, inRDPFilePath): + global gSettings + inGlobalDict = gSettings + lResult = True + lCMDStr = CMDStr.FileStoredSend(inHostFilePath = inHostFilePath, inRDPFilePath = inRDPFilePath) + # Calculate the session Hex + lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKey]["SessionHex"] + # Check is Session is responsible + if inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKey]["SessionIsWindowResponsibleBool"]: + # Run CMD + Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120) + else: + # Write in logger - warning + inGlobalDict["Logger"].warning(f"Defs_SessionIndex.FileStoredSend: SessionIndex: {str(inRDPSessionKey)}, 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 RDPSessionFileStoredRecieve(inRDPSessionKey, inRDPFilePath, inHostFilePath): + global gSettings + inGlobalDict = gSettings + lResult = True + lCMDStr = CMDStr.FileStoredRecieve(inRDPFilePath = inRDPFilePath, inHostFilePath = inHostFilePath) + # Calculate the session Hex + lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKey]["SessionHex"] + # Check is Session is responsible + if inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKey]["SessionIsWindowResponsibleBool"]: + # Run CMD + Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120) + else: + # Write in logger - warning + inGlobalDict["Logger"].warning(f"Defs_SessionIndex.FileStoredRecieve: SessionIndex: {str(inRDPSessionKey)}, 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/Orchestrator/RobotRDPActive/RobotRDPActive.py b/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/RobotRDPActive.py new file mode 100644 index 00000000..bcb3e76f --- /dev/null +++ b/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/RobotRDPActive.py @@ -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") \ No newline at end of file diff --git a/Sources/pyOpenRPA/Tools/RobotRDPActive/Scheduler.py b/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/Scheduler.py similarity index 99% rename from Sources/pyOpenRPA/Tools/RobotRDPActive/Scheduler.py rename to Sources/pyOpenRPA/Orchestrator/RobotRDPActive/Scheduler.py index bf67287b..dca0651a 100644 --- a/Sources/pyOpenRPA/Tools/RobotRDPActive/Scheduler.py +++ b/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/Scheduler.py @@ -1,7 +1,6 @@ from . import Timer # Async thread import threading # Create in another thread import datetime # Datetime class -import copy # Copy struct functions import time # time functions import importlib # import lib functions # Scheduler class - init and work by the configuration diff --git a/Sources/pyOpenRPA/Tools/RobotRDPActive/Template.rdp b/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/Template.rdp similarity index 100% rename from Sources/pyOpenRPA/Tools/RobotRDPActive/Template.rdp rename to Sources/pyOpenRPA/Orchestrator/RobotRDPActive/Template.rdp diff --git a/Sources/pyOpenRPA/Tools/RobotRDPActive/Timer.py b/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/Timer.py similarity index 100% rename from Sources/pyOpenRPA/Tools/RobotRDPActive/Timer.py rename to Sources/pyOpenRPA/Orchestrator/RobotRDPActive/Timer.py diff --git a/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/__init__.py b/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/Sources/pyOpenRPA/Tools/RobotRDPActive/__main__.py b/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/__main__.py similarity index 82% rename from Sources/pyOpenRPA/Tools/RobotRDPActive/__main__.py rename to Sources/pyOpenRPA/Orchestrator/RobotRDPActive/__main__.py index 21d3244e..b6ffa9e4 100644 --- a/Sources/pyOpenRPA/Tools/RobotRDPActive/__main__.py +++ b/Sources/pyOpenRPA/Orchestrator/RobotRDPActive/__main__.py @@ -13,7 +13,7 @@ import importlib lFolderPath = "/".join(__file__.split("/")[:-4]) sys.path.insert(0, lFolderPath) #Единый глобальный словарь (За основу взять из Settings.py) -global mGlobalDict +global gSettingsDict #Call Settings function from argv[1] file ################################################ lSubmoduleFunctionName = "Settings" @@ -22,10 +22,10 @@ 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) -mGlobalDict = None +gSettingsDict = None if lSubmoduleFunctionName in dir(lTechModuleFromSpec): # Run SettingUpdate function in submodule - mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)() + gSettingsDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)() ################################################# ######################################################### from pyOpenRPA.Tools.RobotRDPActive import Connector @@ -35,17 +35,17 @@ from pyOpenRPA.Tools.RobotRDPActive import Scheduler # Scheduler operations try: #time.sleep() ######## Init the RDP List - for lConfigurationItem in mGlobalDict["RDPList"]: + for lConfigurationItem in gSettingsDict["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) + Scheduler.Scheduler(gSettingsDict["Scheduler"]) # Init & Run Scheduler + Monitor.Monitor(gSettingsDict, 1) except Exception as e: # Write in logger - warning - mGlobalDict["Logger"].exception(f"!!! ATTENTION !!! Global error handler - look at code") + gSettingsDict["Logger"].exception(f"!!! ATTENTION !!! Global error handler - look at code") finally: #Close all thread from OrchestratorConnection - mGlobalDict["OrchestratorConnectorTerminateAll"]() \ No newline at end of file + gSettingsDict["OrchestratorConnectorTerminateAll"]() \ No newline at end of file diff --git a/Sources/pyOpenRPA/Orchestrator/Server.py b/Sources/pyOpenRPA/Orchestrator/Server.py index 4a970585..cf146b98 100644 --- a/Sources/pyOpenRPA/Orchestrator/Server.py +++ b/Sources/pyOpenRPA/Orchestrator/Server.py @@ -11,8 +11,9 @@ import uuid import datetime import os #for path operations from http import cookies -global mGlobalDict +global gSettingsDict from . import ServerSettings +import copy #Authenticate function () # return dict # { @@ -26,17 +27,21 @@ def AuthenticateVerify(inRequest): lCookies = cookies.SimpleCookie(inRequest.headers.get("Cookie", "")) inRequest.OpenRPA = {} inRequest.OpenRPA["AuthToken"] = None + inRequest.OpenRPA["Domain"] = None + inRequest.OpenRPA["User"] = None #pdb.set_trace() if "AuthToken" in lCookies: lCookieAuthToken = lCookies.get("AuthToken", "").value if lCookieAuthToken: #Find AuthToken in GlobalDict - if lCookieAuthToken in mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("AuthTokensDict", {}): + if lCookieAuthToken in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("AuthTokensDict", {}): #Auth Token Has Been Founded - lResult["Domain"] = mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"] - lResult["User"] = mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"] + lResult["Domain"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"] + lResult["User"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"] #Set auth token inRequest.OpenRPA["AuthToken"] = lCookieAuthToken + inRequest.OpenRPA["Domain"] = lResult["Domain"] + inRequest.OpenRPA["User"] = lResult["User"] #Exit earlier return lResult ###################################### @@ -66,11 +71,11 @@ def AuthenticateVerify(inRequest): lResult["User"] = lLogonResult["User"] #Create token lAuthToken=str(uuid.uuid1()) - mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {} - mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"] - mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"] - mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False - mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now() + gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {} + gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"] + gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"] + gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False + gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now() #Set-cookie inRequest.OpenRPA["AuthToken"] = lAuthToken inRequest.OpenRPASetCookie = {} @@ -109,13 +114,13 @@ def UserAccessCheckBefore(inMethod, inRequest): #go next if user is identified lUserDict = None if lAuthToken: - lUserDict = mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] + lUserDict = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] #pdb.set_trace() ######################################## ######################################## #Check general before rule (without User domain) #Check rules - for lAccessRuleItem in mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("RuleMethodMatchURLBeforeList", []): + for lAccessRuleItem in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleMethodMatchURLBeforeList", []): #Go next execution if flag is false if not lResult: #Check if Method is identical @@ -125,21 +130,21 @@ def UserAccessCheckBefore(inMethod, inRequest): lURLPath = inRequest.path lURLPath = lURLPath.upper() if lURLPath.startswith(lAccessRuleItem["URL"].upper()): - lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict) + lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) # check Match type variant: Contains elif lAccessRuleItem["MatchType"].upper() == "CONTAINS": lURLPath = inRequest.path lURLPath = lURLPath.upper() if lURLPath.contains(lAccessRuleItem["URL"].upper()): - lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict) + lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) # check Match type variant: Equal elif lAccessRuleItem["MatchType"].upper() == "EQUAL": if lAccessRuleItem["URL"].upper() == inRequest.path.upper(): - lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict) + lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) # check Match type variant: EqualCase elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE": if lAccessRuleItem["URL"] == inRequest.path: - lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict) + lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) ######################################### ######################################### #Do check if lResult is false @@ -147,7 +152,7 @@ def UserAccessCheckBefore(inMethod, inRequest): #Check access by User Domain #Check rules to find first appicable #Check rules - for lAccessRuleItem in mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", []): + for lAccessRuleItem in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", []): #Go next execution if flag is false if not lResult: #Check if Method is identical @@ -157,21 +162,21 @@ def UserAccessCheckBefore(inMethod, inRequest): lURLPath = inRequest.path lURLPath = lURLPath.upper() if lURLPath.startswith(lAccessRuleItem["URL"].upper()): - lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict) + lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) #check Match type variant: Contains elif lAccessRuleItem["MatchType"].upper() == "CONTAINS": lURLPath = inRequest.path lURLPath = lURLPath.upper() if lURLPath.contains(lAccessRuleItem["URL"].upper()): - lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict) + lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) # check Match type variant: Equal elif lAccessRuleItem["MatchType"].upper() == "EQUAL": if lAccessRuleItem["URL"].upper() == inRequest.path.upper(): - lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict) + lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) # check Match type variant: EqualCase elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE": if lAccessRuleItem["URL"] == inRequest.path: - lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict) + lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) ##################################### ##################################### #Return lResult @@ -221,24 +226,24 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): lURLPath = self.path lURLPath = lURLPath.upper() if lURLPath.startswith(inURLItem["URL"].upper()): - URLItemDo(inURLItem, self, mGlobalDict) + URLItemDo(inURLItem, self, gSettingsDict) return True # check Match type variant: Contains elif inURLItem["MatchType"].upper() == "CONTAINS": lURLPath = self.path lURLPath = lURLPath.upper() if lURLPath.contains(inURLItem["URL"].upper()): - URLItemDo(inURLItem, self, mGlobalDict) + URLItemDo(inURLItem, self, gSettingsDict) return True # check Match type variant: Equal elif inURLItem["MatchType"].upper() == "EQUAL": if inURLItem["URL"].upper() == self.path.upper(): - URLItemDo(inURLItem, self, mGlobalDict) + URLItemDo(inURLItem, self, gSettingsDict) return True # check Match type variant: EqualCase elif inURLItem["MatchType"].upper() == "EQUALCASE": if inURLItem["URL"] == self.path: - URLItemDo(inURLItem, self, mGlobalDict) + URLItemDo(inURLItem, self, gSettingsDict) return True return False #ResponseContentTypeFile @@ -281,12 +286,12 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): ##################################### lFlagAccessUserBlock=False lAuthenticateDict = {"Domain": "", "User": ""} - if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): + if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): lAuthenticateDict = AuthenticateVerify(self) if not lAuthenticateDict["User"]: lFlagAccessUserBlock=True # Logging - mGlobalDict["Logger"].info(f"HTTP request /. Domain: {lAuthenticateDict['Domain']}, User: {lAuthenticateDict['User']}") + # gSettingsDict["Logger"].info(f"HTTP request /. Domain: {lAuthenticateDict['Domain']}, User: {lAuthenticateDict['User']}") if lFlagAccessUserBlock: AuthenticateBlock(self) ##################################### @@ -295,7 +300,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): #################################### lFlagUserAccess = True #If need user authentication - if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): + if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): lFlagUserAccess = UserAccessCheckBefore("GET", self) ###################################### if lFlagUserAccess: @@ -303,7 +308,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): ############################ #New server engine (url from global dict (URLList)) ############################ - for lURLItem in mGlobalDict["Server"]["URLList"]: + for lURLItem in gSettingsDict["Server"]["URLList"]: #Check if all condition are applied lFlagURLIsApplied=False lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "GET") @@ -318,15 +323,15 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): self.send_header('Content-type','application/json') self.end_headers() # Send message back to client - message = json.dumps(mGlobalDict) + message = json.dumps(gSettingsDict) # Write content as utf-8 data self.wfile.write(bytes(message, "utf8")) #Filemanager function if self.path.lower().startswith('/filemanager/'): lFileURL=self.path[13:] # check if file in FileURL - File Path Mapping Dict - if lFileURL.lower() in mGlobalDict["FileManager"]["FileURLFilePathDict"]: - self.SendResponseContentTypeFile('application/octet-stream',mGlobalDict["FileManager"]["FileURLFilePathDict"][lFileURL]) + if lFileURL.lower() in gSettingsDict["FileManager"]["FileURLFilePathDict"]: + self.SendResponseContentTypeFile('application/octet-stream', gSettingsDict["FileManager"]["FileURLFilePathDict"][lFileURL]) else: #Set access denied code # Send response status code @@ -345,7 +350,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): ##################################### lFlagAccessUserBlock=False lAuthenticateDict = {"Domain": "", "User": ""} - if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): + if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): lAuthenticateDict = AuthenticateVerify(self) if not lAuthenticateDict["User"]: lFlagAccessUserBlock=True @@ -357,7 +362,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): #################################### lFlagUserAccess = True #If need user authentication - if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): + if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): lFlagUserAccess = UserAccessCheckBefore("POST", self) ###################################### if lFlagUserAccess: @@ -365,7 +370,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): ############################ #New server engine (url from global dict (URLList)) ############################ - for lURLItem in mGlobalDict["Server"]["URLList"]: + for lURLItem in gSettingsDict["Server"]["URLList"]: #Check if all condition are applied lFlagURLIsApplied=False lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "POST") @@ -416,16 +421,16 @@ class RobotDaemonServer(Thread): Thread.__init__(self) self.name = name # Update the global dict - ServerSettings.SettingsUpdate(mGlobalDict) + ServerSettings.SettingsUpdate(inGlobalDict) def run(self): inServerAddress=""; - inPort = mGlobalDict["Server"]["ListenPort"]; + inPort = gSettingsDict["Server"]["ListenPort"]; # Server settings # Choose port 8080, for port 80, which is normally used for a http server, you need root access server_address = (inServerAddress, inPort) #httpd = HTTPServer(server_address, testHTTPServer_RequestHandler) # Logging - mGlobalDict["Logger"].info(f"Server init. Listen URL: {inServerAddress}, Listen port: {inPort}") + gSettingsDict["Logger"].info(f"Server init. Listen URL: {inServerAddress}, Listen port: {inPort}") #httpd.serve_forever() httpd = ThreadedHTTPServer(server_address, testHTTPServer_RequestHandler) #print('Starting server, use to stop') diff --git a/Sources/pyOpenRPA/Orchestrator/ServerSettings.py b/Sources/pyOpenRPA/Orchestrator/ServerSettings.py index 881a799c..4dffd798 100644 --- a/Sources/pyOpenRPA/Orchestrator/ServerSettings.py +++ b/Sources/pyOpenRPA/Orchestrator/ServerSettings.py @@ -3,6 +3,29 @@ import json from desktopmagic.screengrab_win32 import ( getDisplayRects, saveScreenToBmp, saveRectToBmp, getScreenAsImage, getRectAsImage, getDisplaysAsImages) + +# /Orchestrator/RobotRDPActive/ControlPanelDictGet +def RobotRDPActive_ControlPanelDictGet(inRequest,inGlobalDict): + inResponseDict = inRequest.OpenRPAResponseDict + lResultDict = { + "DataList":[ + # {"SessionKeyStr":"", "SessionHexStr": "", "IsFullScreenBool": False, "IsIgnoredBool": False} + ] + } + # Iterate throught the RDP List + for lRDPSessionKeyStrItem in inGlobalDict["RobotRDPActive"]["RDPList"]: + lRDPConfiguration = inGlobalDict["RobotRDPActive"]["RDPList"][lRDPSessionKeyStrItem] # Get the configuration dict + lDataItemDict = {"SessionKeyStr":"", "SessionHexStr": "", "IsFullScreenBool": False, "IsIgnoredBool": False} # Template + lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str + lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex + lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGlobalDict["RobotRDPActive"]["FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window + lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored + lResultDict["DataList"].append(lDataItemDict) + # Send message back to client + message = json.dumps(lResultDict) + # Write content as utf-8 data + inResponseDict["Body"] = bytes(message, "utf8") + def Monitor_ControlPanelDictGet(inRequest,inGlobalDict): inResponseDict = inRequest.OpenRPAResponseDict # Create result JSON @@ -60,7 +83,8 @@ def SettingsUpdate(inGlobalConfiguration): {"Method":"GET", "URL": "/favicon.ico", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "Web\\favicon.ico"), "ResponseContentType": "image/x-icon"}, {"Method":"GET", "URL": "/3rdParty/Handlebars/handlebars-v4.1.2.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Handlebars\\handlebars-v4.1.2.js"), "ResponseContentType": "application/javascript"}, {"Method": "GET", "URL": "/Monitor/ControlPanelDictGet", "MatchType": "Equal", "ResponseDefRequestGlobal": Monitor_ControlPanelDictGet, "ResponseContentType": "application/json"}, - {"Method": "GET", "URL": "/GetScreenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": GetScreenshot, "ResponseContentType": "image/png"} - ] + {"Method": "GET", "URL": "/GetScreenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": GetScreenshot, "ResponseContentType": "image/png"}, + {"Method": "GET", "URL": "/Orchestrator/RobotRDPActive/ControlPanelDictGet", "MatchType": "Equal","ResponseDefRequestGlobal": RobotRDPActive_ControlPanelDictGet, "ResponseContentType": "application/json"} + ] inGlobalConfiguration["Server"]["URLList"]=inGlobalConfiguration["Server"]["URLList"]+lURLList return inGlobalConfiguration \ No newline at end of file diff --git a/Sources/pyOpenRPA/Orchestrator/Timer.py b/Sources/pyOpenRPA/Orchestrator/Timer.py index 9449f1a6..28f4dfd5 100644 --- a/Sources/pyOpenRPA/Orchestrator/Timer.py +++ b/Sources/pyOpenRPA/Orchestrator/Timer.py @@ -5,7 +5,7 @@ import importlib import logging from . import Processor -global mGlobalDict +global gSettingsDict class RepeatedTimer(object): def __init__(self, interval, function, *args, **kwargs): diff --git a/Sources/pyOpenRPA/Orchestrator/Web/Index.xhtml b/Sources/pyOpenRPA/Orchestrator/Web/Index.xhtml index f2efeae6..12a061d7 100644 --- a/Sources/pyOpenRPA/Orchestrator/Web/Index.xhtml +++ b/Sources/pyOpenRPA/Orchestrator/Web/Index.xhtml @@ -292,7 +292,49 @@ } mGlobal.Monitor.fControlPanelRefresh() mGlobal.Monitor.fControlPanelAutoUpdateRun(3); - + //////////////////////////////// + /////// /Orchestrator/RobotRDPActive/ControlPanelDictGet + /////////////////////////////// + mGlobal.RobotRDPActive = {} + ///Refresh control panel + mGlobal.RobotRDPActive.fControlPanelRefresh=function() { + ///Загрузка данных + $.ajax({ + type: "GET", + url: 'Orchestrator/RobotRDPActive/ControlPanelDictGet', + data: '', + success: + function(lData,l2,l3) + { + var lResponseJSON=JSON.parse(lData) + ///Сформировать HTML код новой таблицы + lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-robotrdpactive-control-panel",lResponseJSON) + //Присвоить ответ в mGlobal.RobotRDPActive.mResponseList + mGlobal.RobotRDPActive.mResponseList = lResponseJSON + ///Прогрузить новую таблицу + $(".openrpa-robotrdpactive-control-panel").html(lHTMLCode) + }, + dataType: "text" + }); + } + /// + mGlobal.RobotRDPActive.mControlPanelAutoUpdateSeconds=3; + mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent=3; + mGlobal.RobotRDPActive.fControlPanelAutoUpdateRun=function(inRefreshSeconds) { + mGlobal.RobotRDPActive.mControlPanelAutoUpdateSeconds=inRefreshSeconds; + //Функция обновления текста кнопки обновления + lControlPanelUpdate=function() { + mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent=mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent-1 + if (mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent==-1) { + mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent=mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent=mGlobal.RobotRDPActive.mControlPanelAutoUpdateSeconds; + mGlobal.RobotRDPActive.fControlPanelRefresh() + } + $(".openrpa-robotrdpactive-control-panel-general .openrpa-refresh-button").html("Refresh "+mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent); + } + mGlobal.RobotRDPActive.mControlPanelAutoUpdateTimerId=setInterval(lControlPanelUpdate,1000) + } + mGlobal.RobotRDPActive.fControlPanelRefresh() + mGlobal.RobotRDPActive.fControlPanelAutoUpdateRun(3); mGlobal.Test=function() { ///Обнулить таблицу lData = [ @@ -339,9 +381,9 @@ function(lData,l2,l3) { var lResponseJSON=JSON.parse(lData) - lResponseJSON["actionListResult"][0]["result"].forEach(function(lItem){lItem["processPathName"]=("processPath" in lItem ? lItem["processPath"] : lItem["processName"])}) + lResponseJSON[0]["Result"].forEach(function(lItem){lItem["processPathName"]=("processPath" in lItem ? lItem["processPath"] : lItem["processName"])}) ///Отправить запрос на формирование таблицы - lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-info-table-planloglist",lResponseJSON["actionListResult"][0]); + lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-info-table-planloglist",lResponseJSON[0]); ///Установить HTML код $('.ui.modal.basic .content').html(lHTMLCode); $('.ui.modal.basic').modal('show'); @@ -349,12 +391,33 @@ dataType: "text" }); } - /////////////////////////////// ///Processor functions /////////////////////////////// - mGlobal.Processor = {} + mGlobal.Processor.ServerValueAppend = function(inKeyList,inValue) { + lData = [ + { + "Type":"GlobalDictKeyListValueAppend", + "KeyList": inKeyList, + "Value": inValue + } + ] + ///Обнулить таблицу + $('.ui.modal.basic .content').html(""); + $.ajax({ + type: "POST", + url: 'Utils/Processor', + data: JSON.stringify(lData), + success: + function(lData,l2,l3) + { + var lResponseJSON=JSON.parse(lData) + ///TODO Show error if exist error + }, + dataType: "text" + }); + } mGlobal.Processor.ServerValueSet = function(inKeyList,inValue) { lData = [ { @@ -532,58 +595,17 @@ ///Установить HTML код lElementParentElement.insertAdjacentHTML("beforeend",lHTMLCode); } - ///Test - lTestDataTable = { - "Title":"Test", - "Columns":["Дата/Время","Статус","Клиент","Файл"], - "Rows":[ - ["2019.10.31 13:21","Успешно", "ООО БалтКам", "test.xml"], - ["2019.10.31 13:21","Успешно", "ООО Гренодер", "test.xml"], - ["2019.10.31 13:21","Успешно", "ООО БалтКам", "test.xml"], - ["2019.10.31 13:21","Успешно", "ООО Гренодер", "test.xml"], - ["2019.10.31 13:21","Отказ", "ООО Сударь", "test.xml"], - ["2019.10.31 13:21","Успешно", "ООО БалтКам", "test.xml"], - ["2019.10.31 13:21","Отказ", "ООО Гренодер", "test.xml"], - ["2019.10.31 13:21","Успешно", "ООО Гренодер", "test.xml"], - ["2019.10.31 13:21","Успешно", "ООО Сударь", "test.xml"], - ["2019.10.31 13:21","Успешно", "ООО БалтКам", "test.xml"], - ["2019.10.31 13:21","Успешно", "ООО Гренодер", "test.xml"], - ["2019.10.31 13:21","Отказ", "ООО Сударь", "test.xml"], - ["2019.10.31 13:21","Успешно", "ООО БалтКам", "test.xml"], - ["f","s"] - ] - } - //mGlobal.Modal.TableFilter.Show(lTestData) - ///Test - lTestData = { - "Title":"Test", - "List":[ - {"Header":"Head 09","Description":"Test 21.02.2019"}, - {"Header":"Head 09","Description":"Test 21.02.2019"}, - {"Header":"Head 09","Description":"Test 21.02.2019"}, - {"Header":"Head 09","Description":"TestNew 21.02.2019"}, - {"Header":"Head 09","Description":"Test 21.02.2019"}, - {"Header":"Head 09","Description":"TestNew 21.02.2019"}, - {"Header":"Head 09","Description":"Test 21.02.2019"}, - {"Header":"Head 09","Description":"Test 21.02.2019"} - ] - } - // mGlobal.Modal.ListFilter.Show(lTestData) }) ;