diff --git a/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py b/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py index 2320ddc7..9dc39663 100644 --- a/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py +++ b/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py @@ -34,6 +34,26 @@ def v1_2_0_ProcessorOld2NewActivityDict(inActivityOld): else: return True ################################### + # { + # "Type": "GlobalDictKeyListValueGet", + # "KeyList": ["key1","key2",...] + # }, + def GlobalDictKeyListValueGet(inGSettings, inKeyList=[]): + ########################################################### + # Обработка команды GlobalDictKeyListValueGet + ########################################################### + lResult = None + lDict = inGSettings + for lItem2 in inKeyList[:-1]: + # Check if key - value exists + if lItem2 in lDict: + pass + else: + lDict[lItem2] = {} + lDict = lDict[lItem2] + # Return value + lResult = lDict.get(inKeyList[-1], None) + return lResult # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @@ -45,8 +65,15 @@ def v1_2_0_ProcessorOld2NewActivityDict(inActivityOld): "ArgDict":{"inUserStr": inActivityOld["User"],"inPasswordStr":inActivityOld["Password"],"inDomainStr":inActivityOld["Domain"]}, # Args dictionary "ArgGSettings": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList) } + elif inActivityOld["Type"] == "GlobalDictKeyListValueGet": + lResult = { + "Def": GlobalDictKeyListValueGet, # def link or def alias (look gSettings["Processor"]["AliasDefDict"]) + "ArgList":[], # Args list + "ArgDict":{"inKeyList": inActivityOld["KeyList"]}, # Args dictionary + "ArgGSettings": "inGSettings" # Name of GSettings attribute: str (ArgDict) or index (for ArgList) + } else: - raise Exception(f"BackwardCompatibility up to 1.2.0, old processor: No type {inActivityOld['Type']} has been found in old processor.") + raise Exception(f"BackwardCompatibility up to v1.2.0, old processor: No type {inActivityOld['Type']} has been found in old processor.") return lResult # return the result def Update(inGSettings): diff --git a/Sources/pyOpenRPA/Orchestrator/Orchestrator.py b/Sources/pyOpenRPA/Orchestrator/Orchestrator.py index 38874e72..63117108 100644 --- a/Sources/pyOpenRPA/Orchestrator/Orchestrator.py +++ b/Sources/pyOpenRPA/Orchestrator/Orchestrator.py @@ -195,7 +195,7 @@ def Orchestrator(inGSettings): time.sleep(lDaemonLoopSeconds) # Backward compatibility below to 1.2.0 -if __name__ == "__main__": +def __deprecated_run__(): #Call Settings function from argv[1] file ################################################ lSubmoduleFunctionName = "Settings" diff --git a/Sources/pyOpenRPA/Orchestrator/Processor.py b/Sources/pyOpenRPA/Orchestrator/Processor.py index c060db0c..2abadb1d 100644 --- a/Sources/pyOpenRPA/Orchestrator/Processor.py +++ b/Sources/pyOpenRPA/Orchestrator/Processor.py @@ -37,7 +37,7 @@ def ActivityListExecute(inGSettings, inActivityList): lGSettingsDictKey = lActivityItem.pop("ArgGSettings",None) # # Prepare arg dict if type(lGSettingsDictKey) is str: # check if gSetting key is in ArgDict - lActivityItem["ArgDict"]["lGSettingsDictKey"] = inGSettings # Set the gSettings in dict + lActivityItem["ArgDict"][lGSettingsDictKey] = inGSettings # Set the gSettings in dict # # Prepare arg list elif type(lGSettingsDictKey) is int: # check if gSetting key is in ArgDict lActivityItem["ArgList"].insert(lGSettingsDictKey,inGSettings)# Set the gSettings in list by the index diff --git a/Sources/pyOpenRPA/Orchestrator/ProcessorOld.py b/Sources/pyOpenRPA/Orchestrator/ProcessorOld.py index 3bf8da19..aa2eb97c 100644 --- a/Sources/pyOpenRPA/Orchestrator/ProcessorOld.py +++ b/Sources/pyOpenRPA/Orchestrator/ProcessorOld.py @@ -42,6 +42,7 @@ import copy # "KeyList": ["key1","key2",...], # "Value": # }, +# -----BELOW IS UPDATED---------------- # { # "Type": "GlobalDictKeyListValueGet", # "KeyList": ["key1","key2",...] @@ -91,7 +92,7 @@ def Activity(inActivity): # Update 2020.10 - go to the new processor lActivityNew = BackwardCompatibility.v1_2_0_ProcessorOld2NewActivityDict(inActivityOld=inActivity) # Append new activity in list - lItem["Result"] = Processor.ActivityListExecute(inGSettings = gSettingsDict, inActivityList = [inActivity]) + lItem["Result"] = Processor.ActivityListExecute(inGSettings = gSettingsDict, inActivityList = [lActivityNew])[0] """ #Глобальная переменная - глобальный словарь унаследованный от Settings.py lL = gSettingsDict["Logger"] # Alias for logger diff --git a/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py b/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py new file mode 100644 index 00000000..25585b1c --- /dev/null +++ b/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py @@ -0,0 +1,310 @@ +import os, logging, datetime, sys + +# Technical def - return GSettings structure with examples +def __Create__(): + return { + "Autocleaner": { + # Some gurbage is collecting in g settings. So you can configure autocleaner to periodically clear gSettings + "IntervalSecFloat": 600.0, # Sec float to periodically clear gsettings + }, + "Client": { # Settings about client web orchestrator + "Session": { + # Settings about web session. Session algorythms works only for special requests (URL in ServerSettings) + "LifetimeSecFloat": 600.0, + # Client Session lifetime in seconds. after this time server will forget about this client session + "LifetimeRequestSecFloat": 120.0, # 1 client request lifetime in server in seconds + "ControlPanelRefreshIntervalSecFloat": 1.5, # Interval to refresh control panels for session, + "TechnicalSessionGUIDCache": { # TEchnical cache. Fills when web browser is requesting + # "SessionGUIDStr":{ # Session with some GUID str. On client session guid stored in cookie "SessionGUIDStr" + # "InitDatetime": None, # Datetime when session GUID was created + # "DatasetLast": { + # "ControlPanel": { + # "Data": None, # Struct to check with new iterations. None if starts + # "ReturnBool": False # flag to return, close request and return data as json + # } + # }, + # "ClientRequestHandler": None, # Last client request handler + # "UserADStr": None, # User, who connect. None if user is not exists + # "DomainADStr": None, # Domain of the user who connect. None if user is not exists + # } + } + } + }, + "Server": { + "WorkingDirectoryPathStr": None, # Will be filled automatically + "RequestTimeoutSecFloat": 300, # Time to handle request in seconds + "ListenPort_": "Порт, по которому можно подключиться к демону", + "ListenPort": 80, + "ListenURLList": [ + { + "Description": "Local machine test", + "URL_": "Сетевое расположение сервера демона", + "URL": "" + } + ], + "AccessUsers": { # Default - all URL is blocked + "FlagCredentialsAsk": True, # Turn on Authentication + "RuleDomainUserDict": { + # ("DOMAIN", "USER"): { !!!!! only in upper case !!!! + # "MethodMatchURLBeforeList": [ + # { + # "Method":"GET|POST", + # "MatchType":"BeginWith|Contains|Equal|EqualCase", + # "URL":"", + # "FlagAccessDefRequestGlobalAuthenticate": None, #Return bool + # "FlagAccess": True + # } + # ], + # "ControlPanelKeyAllowedList":[], # If empty - all is allowed + # "RoleHierarchyAllowedDict": { + # "Orchestrator":{ + # "Controls": { + # "RestartOrchestrator": {}, # Feature to restart orchestrator on virtual machine + # "LookMachineScreenshots": {} # Feature to look machina screenshots + # }, + # "RDPActive": { # Robot RDP active module + # "ListRead": {} # Access to read RDP session list + # } + # } + # } + # } + }, + "RuleMethodMatchURLBeforeList": [ # General MethodMatchURL list (no domain/user) + # { + # "Method":"GET|POST", + # "MatchType":"BeginWith|Contains|Equal|EqualCase", + # "URL":"", + # "FlagAccessDefRequestGlobalAuthenticate": None, #Return bool + # "FlagAccess": True + # } + ], + "AuthTokensDict": { + # "":{"User":"", "Domain":"", "TokenDatetime":, "FlagDoNotExpire":True} + } + }, + "URLList": [ # List of available URLs with the orchestrator server + # { + # "Method":"GET|POST", + # "URL": "/index", #URL of the request + # "MatchType": "", #"BeginWith|Contains|Equal|EqualCase", + # "ResponseFilePath": "", #Absolute or relative path + # "ResponseFolderPath": "", #Absolute or relative path + # "ResponseContentType": "", #HTTP Content-type + # "ResponseDefRequestGlobal": None #Function with str result + # } + { + "Method": "GET", + "URL": "/test/", # URL of the request + "MatchType": "BeginWith", # "BeginWith|Contains|Equal|EqualCase", + # "ResponseFilePath": "", #Absolute or relative path + "ResponseFolderPath": "C:\Abs\Archive\scopeSrcUL\OpenRPA\Orchestrator\Settings", + # Absolute or relative path + # "ResponseContentType": "", #HTTP Content-type + # "ResponseDefRequestGlobal": None #Function with str result + } + ] + }, + "OrchestratorStart": { + "DefSettingsUpdatePathList": [], + # List of the .py files which should be loaded before init the algorythms + "ActivityList": [ + # { + # "Type": "ProcessStop", #Activity type + # "Name": "OpenRPARobotDaemon.exe", #Process name + # "FlagForce": True, #Force process close + # "User": "%username%" #Empty, user or %username% + # }, + # { + # "Type": "ProcessStartIfTurnedOff", #Activity type + # "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": { + "ActivityTimeCheckLoopSeconds": 5, # Количество секунд, между циклами проверки действий + "ActivityTimeList": [ + #{ + # "TimeHH:MM": "22:23", # Time [HH:MM] to trigger activity + # "WeekdayList": [1, 2, 3, 4, 5, 6, 7], + # # List of the weekday index when activity is applicable, Default [1,2,3,4,5,6,7] + # "Activity": { + # "Type": "ProcessStart", # Activity type + # "Path": "start", # Executable file path + # "ArgList": ["cmd.exe", "/c", "PIPUpgrade.cmd"] # List of the arguments + # }, + # "GUID": None + # # Will be fied in Orchestrator automatically - is needed for detect activity completion + #}, + #{ + # "TimeHH:MM": "19:20", # Time [HH:MM] to trigger activity + # "WeekdayList": [1, 2, 3], + # # List of the weekday index when activity is applicable, Default [1,2,3,4,5,6,7] + # "Activity": { + # "Type": "ProcessStop", # Activity type + # "Name": "OpenRPARobotDaemon.exe", # Process name + # "FlagForce": True, # Force process close + # "User": "%username%" # Empty, user or %username% + # }, + # "GUID": None + # # Will be fied in Orchestrator automatically - is needed for detect activity completion + #}, + #{ + # "TimeHH:MMStart": "12:40", # Time [HH:MM] to trigger activity + # "TimeHH:MMStop": "12:40", + # "ActivityIntervalSeconds": 2, + # "WeekdayList": [1, 2, 3, 4, 5, 6, 7], + # # List of the weekday index when activity is applicable, Default [1,2,3,4,5,6,7] + # "Activity": { + # "Type": "ProcessStartIfTurnedOff", # Activity type + # "CheckTaskName": "notepad.exe", # Python function module name + # "Path": "notepad", # Python function name + # "ArgList": [] # Input python function args + # }, + # "GUID": None + # # Will be fied in Orchestrator automatically - is needed for detect activity completion + #} + ] + }, + "ProcessorDict": { # Has been changed. New general processor (one threaded) v.1.2.0 + "ActivityList": [ # List of the activities + # { + # "Def":"DefAliasTest", # def link or def alias (look gSettings["Processor"]["AliasDefDict"]) + # "ArgList":[1,2,3], # Args list + # "ArgDict":{"ttt":1,"222":2,"dsd":3} # Args dictionary + # "ArgGSettings": # Name of GSettings attribute: str (ArgDict) or index (for ArgList) + # }, + ], + "AliasDefDict": {}, # Storage for def with Str alias. To use it see pyOpenRPA.Orchestrator.ControlPanel + "CheckIntervalSecFloat": 1.0, # Interval for check gSettings in ProcessorDict > ActivityList + "ExecuteBool": True # Flag to execute thread processor + }, + "ControlPanelDict": { + "RefreshSeconds": 5, # deprecated parameter + "RobotList": [ + #{ + # "RenderFunction": RenderRobotR01, + # "KeyStr": "TestControlPanelKey" + #} + ] + }, + # # # # # # # # # # # # # # + "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": { + #"r01/report.xlsx": "C:\\RPA\\R01_IntegrationOrderOut\\Data\\Reestr_otgruzok.xlsx" + } + }, + "Logger": logging.getLogger("Orchestrator"), + "Storage": { + "Robot_R01_help": "Robot data storage in orchestrator env", + "Robot_R01": {}, + "R01_OrchestratorToRobot": {"Test2": "Test2"} + } + } + +# inModeStr: +# "BASIC" - create standart configuration +def Create(inModeStr="BASIC"): + if inModeStr=="BASIC": + lResult = __Create__() # Create settings + # Создать файл логирования + # add filemode="w" to overwrite + if not os.path.exists("Reports"): + os.makedirs("Reports") + ########################## + # Подготовка логгера Robot + ######################### + mRobotLogger = lResult["Logger"] + mRobotLogger.setLevel(logging.DEBUG) + # create the logging file handler + mRobotLoggerFH = logging.FileHandler( + "Reports\ReportOrchestrator_" + datetime.datetime.now().strftime("%Y_%m_%d") + ".log") + mRobotLoggerFormatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') + 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) + ############################################ + return lResult # return the result dict \ No newline at end of file diff --git a/Sources/pyOpenRPA/Orchestrator/__main__.py b/Sources/pyOpenRPA/Orchestrator/__main__.py index c986e54c..c63c1826 100644 --- a/Sources/pyOpenRPA/Orchestrator/__main__.py +++ b/Sources/pyOpenRPA/Orchestrator/__main__.py @@ -1,4 +1,5 @@ import sys lFolderPath = "\\".join(__file__.split("\\")[:-3]) sys.path.insert(0, lFolderPath) -from pyOpenRPA.Orchestrator import Orchestrator \ No newline at end of file +from pyOpenRPA.Orchestrator import Orchestrator +Orchestrator.__deprecated_run__() # Backward compatibility below the v1.2.0. Will be deprecated in 1.3.0 \ No newline at end of file