Prepare for release 1.2.2

dev-linux
Ivan Maslov 4 years ago
parent 938e36f8a7
commit 97d5e2bc3a

@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: pyOpenRPA
Version: 1.2.1
Version: 1.2.2
Summary: First open source RPA platform for business
Home-page: https://gitlab.com/UnicodeLabs/OpenRPA
Author: Ivan Maslov
@ -11,6 +11,8 @@ Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: License :: OSI Approved :: MIT License
Classifier: Intended Audience :: Developers
Classifier: Environment :: Win32 (MS Windows)
Classifier: Environment :: X11 Applications
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.7
Classifier: Topic :: Software Development :: Libraries :: Python Modules
@ -19,13 +21,13 @@ Classifier: Topic :: Software Development :: User Interfaces
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Home Automation
Description-Content-Type: text/markdown
Requires-Dist: pywinauto (>=0.6.8)
Requires-Dist: WMI (>=1.4.9)
Requires-Dist: pillow (>=6.0.0)
Requires-Dist: keyboard (>=0.13.3)
Requires-Dist: pyautogui (>=0.9.44)
Requires-Dist: pywin32 (>=224)
Requires-Dist: crypto (>=1.4.1)
Requires-Dist: pywin32 (>=224) ; platform_system == "Linux" and python_version >= "3.0"
Requires-Dist: pywinauto (>=0.6.8) ; platform_system == "win32" and python_version >= "3.0"
Requires-Dist: WMI (>=1.4.9) ; platform_system == "win32" and python_version >= "3.0"
# OpenRPA
First open source RPA platform for business is released!

@ -1,13 +1,19 @@
pyOpenRPA-1.2.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pyOpenRPA-1.2.1.dist-info/METADATA,sha256=aGWBieAGB-PR9Na_bh8FhdPn3YzwX3vK7HMtIzU2YeE,3351
pyOpenRPA-1.2.1.dist-info/RECORD,,
pyOpenRPA-1.2.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA-1.2.1.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97
pyOpenRPA-1.2.1.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10
pyOpenRPA/Agent/A2O.py,sha256=Ee72BuVpmXgoNTUInqAj1xVdC4JoWCQ0d0lTlijKyuA,1225
pyOpenRPA/Agent/O2A.py,sha256=IONoht1jb2b7JFT5syelVPq88z7TTLPZjcdH7SrR7rk,2612
pyOpenRPA/Agent/Processor.py,sha256=FtU7IGIev2_po_fkJTH2KNYZap6IVFODM30qiqBNsm4,4146
pyOpenRPA/Agent/__Agent__.py,sha256=VxQsuyItFvgXaDKahEKbG6hGgmpNGJFHRTYGGdP7J-A,4916
pyOpenRPA-1.2.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pyOpenRPA-1.2.2.dist-info/METADATA,sha256=Oy6DxZeOruRyWkROJ9if7MI8zheBqEqlBEFBhj1zRbU,3612
pyOpenRPA-1.2.2.dist-info/RECORD,,
pyOpenRPA-1.2.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA-1.2.2.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97
pyOpenRPA-1.2.2.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10
pyOpenRPA/.idea/inspectionProfiles/profiles_settings.xml,sha256=YXLFmX7rPNGcnKK1uX1uKYPN0fpgskYNe7t0BV7cqkY,174
pyOpenRPA/.idea/misc.xml,sha256=V-fQnOz-bYEZULgfbFgm-8mURphZrKfXMSd0wKjeEyA,188
pyOpenRPA/.idea/modules.xml,sha256=Q__U1JIA2cjxbLRXAv-SfYY00fZA0TNlpkkbY4s3ncg,277
pyOpenRPA/.idea/pyOpenRPA.iml,sha256=EXh41F8lqRiSBMVg-n2tKaEaHC6_3gGSuKkPJA12Na0,408
pyOpenRPA/.idea/vcs.xml,sha256=2HygA1oRAwc3VBf-irxHrX5JJG9DXuQwrN0BlubhoKY,191
pyOpenRPA/.idea/workspace.xml,sha256=6tJZehshdK4And6tEoUvkIB0KE7waL_NnTSkTYYAeFA,3802
pyOpenRPA/Agent/A2O.py,sha256=ZVXNamhKOB1y3j9b4gp_rzJq55Nr5pBGeoBgMnCtNKc,1657
pyOpenRPA/Agent/O2A.py,sha256=4W2bbU34MBmuveXkPvkCzmzKAryR_YB-gnA013fxMoY,3356
pyOpenRPA/Agent/Processor.py,sha256=Co8nWpffgsnEE_TpG9WrpKxz3N0sDF7eFnKxDOk1sd8,4653
pyOpenRPA/Agent/__Agent__.py,sha256=Id75cxA6kwed1r8NaLWHfYIyUrTZx7RPlxw1PdzropI,10006
pyOpenRPA/Agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Agent/__pycache__/A2O.cpython-37.pyc,,
pyOpenRPA/Agent/__pycache__/O2A.cpython-37.pyc,,
@ -16,17 +22,18 @@ pyOpenRPA/Agent/__pycache__/__Agent__.cpython-37.pyc,,
pyOpenRPA/Agent/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Agent/readme.md,sha256=QF_Bnv204OK3t1JUEhjfICkxFmSdX6bvaRl_HI6lH9I,19
pyOpenRPA/Info.md,sha256=u4Nv-PjniSF0Zlbtr6jEJX2vblK3_1zhSLNUgOdtDaA,85
pyOpenRPA/Orchestrator/BackwardCompatibility.py,sha256=lzV3kinWlde5Fs4tBYqyKWetBLM4yEo6nbXmLC-fFaA,30159
pyOpenRPA/Orchestrator/BackwardCompatibility.py,sha256=3EhSlSMoDB9Po7lfllmgXn4LbwhVuPzLszR6P1pHU_M,32440
pyOpenRPA/Orchestrator/ControlPanel.py,sha256=OzS8HjG__8OZgqhajr8L8owyugXPuSLWHLtXuKdEP78,103
pyOpenRPA/Orchestrator/Core.py,sha256=Q0n05GuySXDPy3V7qeYQON0kYEyWogZWhYevSjY4q2s,189
pyOpenRPA/Orchestrator/Processor.py,sha256=8T10Qos4_GT7Qvhh8q59JPCuUyHbic087y_xBK9lM_4,6645
pyOpenRPA/Orchestrator/Core.py,sha256=Kjphtu0g6iaS4D_fIWmzRaLLgBQ9fcwccpQJhOETTAc,521
pyOpenRPA/Orchestrator/Processor.py,sha256=Z1SglmX6ykTLifD3M1mzWEJQUgweWo6HjjCjHldjGyM,8594
pyOpenRPA/Orchestrator/ProcessorOld.py,sha256=Vh5zLRpWWf-vt9CCYI8nDY7oaefiufnu6Pnl4tp27pY,13749
pyOpenRPA/Orchestrator/RobotRDPActive/CMDStr.py,sha256=6otw1WnR2_evvQ5LGyOVh0BLk_nTdilViGub7p56fXQ,1531
pyOpenRPA/Orchestrator/RobotRDPActive/Clipboard.py,sha256=YB5HJL-Qf4IlVrFHyRv_ZMJ0Vo4vjyYqWKjvrTnf1k4,1564
pyOpenRPA/Orchestrator/RobotRDPActive/Connector.py,sha256=Qwf194uO_wcO3kBe2hTI0py90ZC1ejDUGeh6UWEfavc,27789
pyOpenRPA/Orchestrator/RobotRDPActive/ConnectorExceptions.py,sha256=wwH9JOoMFFxDKQ7IyNyh1OkFkZ23o1cD8Jm3n31ycII,657
pyOpenRPA/Orchestrator/RobotRDPActive/Processor.py,sha256=AQ_u9QVSLpce9hhSacm3UT98bErc636MXza4Q6mHsSc,12264
pyOpenRPA/Orchestrator/RobotRDPActive/RobotRDPActive.py,sha256=pbffSPsUzzaFMevNQ0P24NA0cdJg9KwtyHscnWYQc_M,10769
pyOpenRPA/Orchestrator/RobotRDPActive/Recovery.py,sha256=jneD474V-ZBYnmQFxWoY_feGNMSL0lGaRK6TEfQ6gOc,2954
pyOpenRPA/Orchestrator/RobotRDPActive/RobotRDPActive.py,sha256=5FX48HlIn8NKfs7q_rp3lpumWtNcwdHq7J8ygnOwU_g,12284
pyOpenRPA/Orchestrator/RobotRDPActive/Scheduler.py,sha256=21N0ilFzWI1mj3X5S9tPMgwvG7BviuBxfTuqBY85Hy4,9144
pyOpenRPA/Orchestrator/RobotRDPActive/Template.rdp,sha256=JEMVYkEmNcfg_p8isdIyvj9E-2ZB5mj-R3MkcNMKxkA,2426
pyOpenRPA/Orchestrator/RobotRDPActive/Timer.py,sha256=y8--fUvg10qEFomecl_cmdWpdGjarZBlFpMbs_GvzoQ,1077
@ -37,6 +44,7 @@ pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Clipboard.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Connector.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/ConnectorExceptions.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Processor.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Recovery.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/RobotRDPActive.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Scheduler.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Timer.cpython-37.pyc,,
@ -51,20 +59,20 @@ pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/Monitor.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/Screen.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Server.py,sha256=mx4AXf5xEoi9LLKgrJ4s0h20ElcBmsntzZbI99LfboU,28462
pyOpenRPA/Orchestrator/ServerSettings.py,sha256=TZMoxB090UkNOCQ3ve0KBcrdM7YH6LTFz3ErVU42wTQ,28499
pyOpenRPA/Orchestrator/SettingsTemplate.py,sha256=p7J8xXSN6xdyMTd-OrkTu7JQGLn6t7tJpPp2CPybA-w,19955
pyOpenRPA/Orchestrator/Server.py,sha256=301ws0BtUhz_HIghP7alHkotLCUXbJhi8fb2Wn0H8EU,29345
pyOpenRPA/Orchestrator/ServerSettings.py,sha256=-WiQXhfSdS4-eKbFp4U6NBylyRtJ0a6AVdds3KT3H9Q,31004
pyOpenRPA/Orchestrator/SettingsTemplate.py,sha256=R8o3_4z2TavV3i0KSz-d_oQx-U4qsrQFHvVmZFOnmnQ,20238
pyOpenRPA/Orchestrator/Timer.py,sha256=HvYtEeH2Q5WVVjgds9XaBpWRmvZgwgBXurJDdVVq_T0,2097
pyOpenRPA/Orchestrator/Utils/LoggerHandlerDumpLogList.py,sha256=hD47TiOuKR-G8IWu9lJD2kG28qlH7YZV63i3qv1N5Dk,681
pyOpenRPA/Orchestrator/Utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Orchestrator/Utils/__pycache__/LoggerHandlerDumpLogList.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Utils/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Web/Basic.py,sha256=UUiV3Rp__i8EVADK-SvIhlVmLzOzW4gpCq1eBpqU4cA,6482
pyOpenRPA/Orchestrator/Web/Index.js,sha256=DtvpHDBT3_XvJpdKUREpGT1NR3lKdBs9ER4HPvlfwhE,39036
pyOpenRPA/Orchestrator/Web/Basic.py,sha256=pPH55rPwZz1ktpzNIcC51jeV2MgZI10Zf0Q0DncihDw,7757
pyOpenRPA/Orchestrator/Web/Index.js,sha256=Blo3LHe_a3zrW7MqYo4BSIwoOx7nlO7Ko9LWxfeqU_o,39090
pyOpenRPA/Orchestrator/Web/Index.xhtml,sha256=a4N_reLA6_Zb2KXiL73a7cWtJwO0W0Dr5lZ-RpUwuI0,16428
pyOpenRPA/Orchestrator/Web/__pycache__/Basic.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Web/favicon.ico,sha256=6S8XwSQ_3FXPpaX6zYkf8uUewVXO9bHnrrDHEoWrEgw,112922
pyOpenRPA/Orchestrator/__Orchestrator__.py,sha256=QSbaJT1U5L3UE_yNBsPzqJfwdy6Xycb8Tvf6r8OUbSQ,90464
pyOpenRPA/Orchestrator/__Orchestrator__.py,sha256=WTPCLcAGunuIJ-6fAfMTXtboAvhuZUCHm2vf3h6kS8U,109030
pyOpenRPA/Orchestrator/__init__.py,sha256=f1RFDzOkL3IVorCtqogjGdXYPtHH-P-y-5CqT7PGy7A,183
pyOpenRPA/Orchestrator/__main__.py,sha256=czJrc7_57WiO3EPIYfPeF_LG3pZsQVmuAYgbl_YXcVU,273
pyOpenRPA/Orchestrator/__pycache__/BackwardCompatibility.cpython-37.pyc,,
@ -333,6 +341,6 @@ pyOpenRPA/Tools/Terminator.py,sha256=VcjX3gFXiCGu3MMCidhrTNsmC9wsAqfjRJdTSU9fLnU
pyOpenRPA/Tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Tools/__pycache__/Terminator.cpython-37.pyc,,
pyOpenRPA/Tools/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/__init__.py,sha256=F-Q2H4aCcjl9IIkTWH_9aXSwQnCjgjm7DSSRyKV9MbM,174
pyOpenRPA/__init__.py,sha256=ZiHtLttT3HWPDuXjwYNe06oadFPTLrVMTKyaMXZAmBE,174
pyOpenRPA/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/test.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0

@ -25,3 +25,9 @@ def _A2ODataSend(inGSettings, inDataDict):
def LogListSend(inGSettings, inLogList):
lDataDict = { "HostNameUpperStr": inGSettings["AgentDict"]["HostNameUpperStr"], "UserUpperStr": inGSettings["AgentDict"]["UserUpperStr"], "LogList": inLogList}
_A2ODataSend(inGSettings=inGSettings, inDataDict=lDataDict)
# Send some def result to the orchestrator by the Activity Item GUID str
def ActivityReturnDictSend(inGSettings, inActivityItemGUIDStr, inReturn):
lDataDict = {"HostNameUpperStr": inGSettings["AgentDict"]["HostNameUpperStr"],
"UserUpperStr": inGSettings["AgentDict"]["UserUpperStr"], "ActivityReturnDict": {inActivityItemGUIDStr:inReturn}}
_A2ODataSend(inGSettings=inGSettings, inDataDict=lDataDict)

@ -1,4 +1,4 @@
import requests, time
import requests, time, json
# O2A - Data flow Orchestrator to Agent
# f"{lProtocolStr}://{lHostStr}:{lPortInt}/pyOpenRPA/Agent/O2A"
@ -16,26 +16,36 @@ import requests, time
def O2A_Loop(inGSettings):
lL = inGSettings["Logger"]
lActivityLastGUIDStr = "" # Init empty ActivityLastGUIDStr
while inGSettings["O2ADict"]["IsOnlineBool"]:
# Send request to the orchestrator server
lRequestBody = None
try:
lProtocolStr= "https" if inGSettings["OrchestratorDict"]["IsHTTPSBool"] else "http"
lHostStr = inGSettings["OrchestratorDict"]["HostStr"]
lPortInt = inGSettings["OrchestratorDict"]["PortInt"]
lURLStr=f"{lProtocolStr}://{lHostStr}:{lPortInt}/pyOpenRPA/Agent/O2A"
lDataDict = { "HostNameUpperStr": inGSettings["AgentDict"]["HostNameUpperStr"], "UserUpperStr": inGSettings["AgentDict"]["UserUpperStr"]}
lDataDict = { "HostNameUpperStr": inGSettings["AgentDict"]["HostNameUpperStr"], "UserUpperStr": inGSettings["AgentDict"]["UserUpperStr"], "ActivityLastGUIDStr": lActivityLastGUIDStr}
lResponse = requests.post(url= lURLStr, cookies = {"AuthToken":inGSettings["OrchestratorDict"]["SuperTokenStr"]}, json=lDataDict)
if lResponse.status_code != 200:
if lL: lL.warning(f"Agent can not connect to Orchestrator. Below the response from the orchestrator:{lResponse}")
time.sleep(inGSettings["O2ADict"]["RetryTimeoutSecFloat"])
else:
lRequestBody = lResponse.text
lQueueItem = lResponse.json() # Try to get JSON
# Append QUEUE item in ProcessorDict > ActivityList
lActivityLastGUIDStr = lQueueItem["GUIDStr"]
inGSettings["ProcessorDict"]["ActivityList"].append(lQueueItem)
if lL: lL.debug(f"ActivityItem was recieved from orchestrator: {lQueueItem}");
except Exception as e:
if lL: lL.exception(f"A2O Error handler. Sleep for {inGSettings['A2ODict']['RetryTimeoutSecFloat']} s.")
time.sleep(inGSettings["O2ADict"]["RetryTimeoutSecFloat"])
if lL: lL.debug(f"ActivityItem was received from orchestrator: {lQueueItem}");
except requests.exceptions.ConnectionError as e:
if lL: lL.error(f"A2O Connection error - orchestrator is not available. Sleep for {inGSettings['A2ODict']['RetryTimeoutSecFloat']} s.")
if lL: lL.error(f"O2A Connection error - orchestrator is not available. Sleep for {inGSettings['A2ODict']['RetryTimeoutSecFloat']} s.")
time.sleep(inGSettings["O2ADict"]["RetryTimeoutSecFloat"])
except ConnectionResetError as e:
if lL: lL.error(f"O2A Connection error - orchestrator is not available. Sleep for {inGSettings['A2ODict']['RetryTimeoutSecFloat']} s.")
time.sleep(inGSettings["O2ADict"]["RetryTimeoutSecFloat"])
except json.decoder.JSONDecodeError as e:
if lL: lL.error(f"See body of the recieved content from the Orchestrator: {lRequestBody}")
time.sleep(inGSettings["O2ADict"]["RetryTimeoutSecFloat"])
except Exception as e:
if lL: lL.exception(f"O2A Error handler. Sleep for {inGSettings['A2ODict']['RetryTimeoutSecFloat']} s.")
time.sleep(inGSettings["O2ADict"]["RetryTimeoutSecFloat"])

@ -1,5 +1,6 @@
# 1.2.0 - general processor - contains old orchestrator processor + RDPActive processor
import time, copy, threading
from . import A2O
# Run processor synchronious
def ProcessorRunSync(inGSettings):
"""
@ -10,7 +11,8 @@ def ProcessorRunSync(inGSettings):
# "ArgList":[1,2,3], # Args list
# "ArgDict":{"ttt":1,"222":2,"dsd":3}, # Args dictionary
# "ArgGSettings": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "ArgLogger": None, # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "GUIDStr": "sadasd-asdas-d-asdasd", # ActivityItem GUID which identify the Activity
# },
],
"AliasDefDict": {}, # Storage for def with Str alias. To use it see pyOpenRPA.Orchestrator.ControlPanel
@ -24,7 +26,13 @@ def ProcessorRunSync(inGSettings):
if len(lActivityList)>0:
if lL: lL.debug(f'Processor ActivityList len: {len(lActivityList)}')
lActivityItem = inGSettings["ProcessorDict"]["ActivityList"].pop(0) # Extract the first item from processor queue
ActivityListExecute(inGSettings = inGSettings, inActivityList = [lActivityItem]) # execute the activity item
lResultList = ActivityListExecute(inGSettings = inGSettings, inActivityList = [lActivityItem]) # execute the activity item
#Some help code
if len(lResultList) == 0: lResultList= [None]
# Send result to Orc if we have GUIDStr
if "GUIDStr" in lActivityItem:
# Def to send to Orc
A2O.ActivityReturnDictSend(inGSettings=inGSettings, inActivityItemGUIDStr=lActivityItem["GUIDStr"],inReturn=lResultList[0])
else:
time.sleep(inGSettings["ProcessorDict"]["CheckIntervalSecFloat"]) # Sleep when list is empty
@ -61,5 +69,5 @@ def ActivityListExecute(inGSettings, inActivityList):
lResultList.append(lActivityItemResult) # return the result
except Exception as e:
if lL: lL.exception(f"Processor.ActivityListExecute: Exception in def execution - activity will be ignored. Activity item: {lActivityItem}") # Logging
lResultList.append(e) # return the generated exception
lResultList.append(None) # return the generated exception
return lResultList # return the result list

@ -1,10 +1,14 @@
import threading, socket, getpass, sys, uuid, subprocess, base64
import threading, socket, getpass, sys, uuid, subprocess, base64, psutil, getpass, time
from . import O2A, A2O # Data flow Orchestrator To Agent
from . import Processor # Processor Queue
from subprocess import CREATE_NEW_CONSOLE # Flag to create new process in another CMD
# Create binary file by the base64 string (safe for JSON transmition)
def OSFileBinaryDataBase64StrCreate(inFilePathStr, inFileDataBase64Str,inGSettings = None):
""" Create binary file by the base64 string (safe for JSON transmition)"""
"""
Create binary file by the base64 string (safe for JSON transmition)
"""
lFile = open(inFilePathStr, "wb")
lFile.write(base64.b64decode(inFileDataBase64Str))
lFile.close()
@ -15,6 +19,15 @@ def OSFileBinaryDataBase64StrCreate(inFilePathStr, inFileDataBase64Str,inGSettin
# Create text file by the string
def OSFileTextDataStrCreate(inFilePathStr, inFileDataStr, inEncodingStr = "utf-8",inGSettings = None):
"""
Create text file in the agent GUI session
:param inFilePathStr: File abs path
:param inFileDataStr: File data text content
:param inEncodingStr: Write file encoding
:param inGSettings: global settings of the Agent (singleton)
:return:
"""
lFile = open(inFilePathStr, "w", encoding=inEncodingStr)
lFile.write(inFileDataStr)
lFile.close()
@ -23,15 +36,67 @@ def OSFileTextDataStrCreate(inFilePathStr, inFileDataStr, inEncodingStr = "utf-8
if lL: lL.info(lMessageStr)
A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
def OSFileBinaryDataBase64StrReceive(inFilePathStr, inGSettings=None):
"""
Read binary file and encode in base64 to transmit (safe for JSON transmition)
:param inFilePathStr: File path to read
:param inGSettings: global settings of the Agent (singleton)
:return: File content in string base64 format (use base64.b64decode to decode data). Return None if file is not exist
"""
lFile = open(inFilePathStr, "rb")
lFileDataBytes = lFile.read()
lFile.close()
lFileDataBase64Str = base64.b64encode(lFileDataBytes).decode("utf-8")
lL = inGSettings.get("Logger", None) if type(inGSettings) is dict else None
lMessageStr = f"AGENT Binary file {inFilePathStr} has been read."
if lL: lL.info(lMessageStr)
A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
return lFileDataBase64Str
def OSFileTextDataStrReceive(inFilePathStr, inEncodingStr="utf-8", inGSettings=None):
"""
Read text file in the agent GUI session
:param inFilePathStr: File abs path
:param inEncodingStr: Read file encoding. Default utf-8
:param inGSettings: global settings of the Agent (singleton)
:return: File text content in string format (use base64.b64decode to decode data). Return None if file is not exist
"""
lFile = open(inFilePathStr, "r", encoding=inEncodingStr)
lFileDataStr = lFile.read()
lFile.close()
lL = inGSettings.get("Logger", None) if type(inGSettings) is dict else None
lMessageStr = f"AGENT Text file {inFilePathStr} has been read."
if lL: lL.info(lMessageStr)
A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
return lFileDataStr
# Send CMD to OS. Result return to log + Orchestrator by the A2O connection
def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None):
def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None, inSendOutputToOrchestratorLogsBool = True, inCMDEncodingStr = "cp1251"):
"""
Execute CMD on the Agent daemonic process
:param inCMDStr: command to execute on the Agent session
:param inRunAsyncBool: True - Agent processor don't wait execution; False - Agent processor wait cmd execution
:param inGSettings: Agent global settings dict
:param inSendOutputToOrchestratorLogsBool: True - catch cmd execution output and send it to the Orchestrator logs; Flase - else case; Default True
!ATTENTION! If you need to start absolutely encapsulated app - set this flag as False. If you set True - the app output will come to Agent
:param inCMDEncodingStr: Set the encoding of the DOS window on the Agent server session. Windows is beautiful :) . Default is "cp1251" early was "cp866" - need test
:return:
"""
lResultStr = ""
# Subdef to listen OS result
def _CMDRunAndListenLogs(inCMDStr, inGSettings = None):
def _CMDRunAndListenLogs(inCMDStr, inSendOutputToOrchestratorLogsBool, inCMDEncodingStr, inGSettings = None):
lL = inGSettings.get("Logger",None) if type(inGSettings) is dict else None
lResultStr = ""
lOSCMDKeyStr = str(uuid.uuid4())[0:4].upper()
lCMDProcess = None
if inSendOutputToOrchestratorLogsBool == True:
lCMDProcess = subprocess.Popen(f'cmd /c {inCMDStr}', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
else:
lCMDProcess = subprocess.Popen(f'cmd /c {inCMDStr}', stdout=None, stderr=None,
creationflags=CREATE_NEW_CONSOLE)
lListenBool = True
lMessageStr = f"{lOSCMDKeyStr}: # # # # AGENT CMD Process has been STARTED # # # # "
if lL: lL.info(lMessageStr)
@ -40,32 +105,64 @@ def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None):
if lL: lL.info(lMessageStr)
A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
while lListenBool:
if inSendOutputToOrchestratorLogsBool == True: # Capturing can be turned on!
lOutputLineBytes = lCMDProcess.stdout.readline()
if lOutputLineBytes == b"":
lListenBool = False
lStr = lOutputLineBytes.decode('cp866')
lStr = lOutputLineBytes.decode(inCMDEncodingStr) # was cp866, on win server don't work properly - set cp1251
if lStr.endswith("\n"): lStr = lStr[:-1]
lMessageStr = f"{lOSCMDKeyStr}: {lStr}"
if lL: lL.info(lMessageStr)
A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
lResultStr+=lStr
else: #Capturing is not turned on - wait until process will be closed
lCMDProcessPoll = lCMDProcess.poll()
if lCMDProcessPoll is None: # Process is alive - wait
time.sleep(2)
else:
lListenBool = False
lMessageStr = f"{lOSCMDKeyStr}: # # # # AGENT CMD Process has been FINISHED # # # # "
if lL: lL.info(lMessageStr)
A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
return lResultStr
# New call
if inRunAsyncBool:
lThread = threading.Thread(target=_CMDRunAndListenLogs, kwargs={"inCMDStr":inCMDStr, "inGSettings":inGSettings})
lThread = threading.Thread(target=_CMDRunAndListenLogs, kwargs={"inCMDStr":inCMDStr, "inGSettings":inGSettings, "inSendOutputToOrchestratorLogsBool":inSendOutputToOrchestratorLogsBool, "inCMDEncodingStr":inCMDEncodingStr })
lThread.start()
lResultStr="ActivityList has been started in async mode - no output is available here."
else:
lResultStr = _CMDRunAndListenLogs(inCMDStr=inCMDStr, inGSettings=inGSettings)
lResultStr = _CMDRunAndListenLogs(inCMDStr=inCMDStr, inGSettings=inGSettings, inSendOutputToOrchestratorLogsBool = inSendOutputToOrchestratorLogsBool, inCMDEncodingStr = inCMDEncodingStr)
#lCMDCode = "cmd /c " + inCMDStr
#subprocess.Popen(lCMDCode)
#lResultCMDRun = 1 # os.system(lCMDCode)
return lResultStr
def ProcessWOExeUpperUserListGet():
"""
Return the process list only for the current user (where Agent is running) without .EXE in upper case. Can use in ActivityItem from Orchestrator to Agent
:param inProcessNameWOExeList:
:return: list of the agent user process in upper case without .EXE. Example ["NOTEPAD","..."],
"""
lUserNameStr = getpass.getuser()
lResult = []
# Create updated list for quick check
lProcessNameWOExeList = []
# Iterate over the list
for proc in psutil.process_iter():
try:
# Fetch process details as dict
pinfo = proc.as_dict(attrs=['pid', 'name', 'username'])
# Add if empty inProcessNameWOExeList or if process in inProcessNameWOExeList
lUserNameWODomainStr = proc.username().split('\\')[-1]
if lUserNameWODomainStr == lUserNameStr:
lResult.append(pinfo['name'][:-4].upper())
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
pass
return lResult
# Main def
def Agent(inGSettings):
lL = inGSettings["Logger"]

@ -421,4 +421,37 @@ def Update(inGSettings):
# Remove old structure Scheduler
del inGSettings["Scheduler"]
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Convert Scheduler to SchedulerDict with new features") # Log about compatibility
# # Convert to Storage to StorageDict
if "Storage" in inGSettings:
# Check if Server is active > convert to ServerDict
inGSettings["StorageDict"] = inGSettings["Storage"]
if lL: lL.warning(
f"Backward compatibility (v1.2.1 to v1.2.2): Convert Storage to StorageDict") # Log about compatibility
# Remove old structure Scheduler
del inGSettings["Storage"]
# Add new key WarningExecutionMoreThanSecFloat in ProcessorDict
if "WarningExecutionMoreThanSecFloat" not in inGSettings["ProcessorDict"]:
inGSettings["ProcessorDict"]["WarningExecutionMoreThanSecFloat"] = 60.0
if lL: lL.warning(
f"Backward compatibility (v1.2.1 to v1.2.2): Add key WarningExecutionMoreThanSecFloat in ProcessorDict") # Log about compatibility
# Add new key AgentActivityLifetimeSecFloat, AgentConnectionLifetimeSecFloat, AgentLoopSleepSecFloat in ProcessorDict > ServerDict
if "AgentActivityLifetimeSecFloat" not in inGSettings["ServerDict"]:
inGSettings["ServerDict"]["AgentActivityLifetimeSecFloat"] = 1200.0
inGSettings["ServerDict"]["AgentConnectionLifetimeSecFloat"] = 300.0
inGSettings["ServerDict"]["AgentLoopSleepSecFloat"] = 2.0
if lL: lL.warning(
f"Backward compatibility (v1.2.1 to v1.2.2): Add key AgentActivityLifetimeSecFloat, AgentConnectionLifetimeSecFloat, AgentLoopSleepSecFloat in ProcessorDict > ServerDict") # Log about compatibility
# Add new key RecoveryDict in ProcessorDict > RobotRDPActive
if "RecoveryDict" not in inGSettings["RobotRDPActive"]:
inGSettings["RobotRDPActive"]["RecoveryDict"] = {
"CatchPeriodSecFloat": 1200, # Catch last 10 minutes
"TriggerCountInt": 10, # Activate trigger if for the period orch will catch the reconnect RDP n times
"DoDict": {
"OSRemotePCRestart": True # Do powershell remote restart
},
"__StatisticsDict__": {
# RDPSessionKeyStr : [time.time(), time.time()],
}
}
if lL: lL.warning(
f"Backward compatibility (v1.2.1 to v1.2.2): Add new key RecoveryDict in ProcessorDict > RobotRDPActive") # Log about compatibility

@ -3,3 +3,13 @@ import threading
# Check if current execution is in Processor thread
def IsProcessorThread(inGSettings):
return inGSettings["ProcessorDict"]["ThreadIdInt"] == threading.get_ident()
def IsOrchestratorInitialized(inGSettings):
"""
Check if Orchestrator will be successfully initialized
:param inGSettings: global settings (singleton)
:return:
"""
# Check if gSettings has flag "HiddenOrchestratorInitBool"
return inGSettings.get("HiddenIsOrchestratorInitializedBool", False)

@ -1,5 +1,5 @@
# 1.2.0 - general processor - contains old orchestrator processor + RDPActive processor
import time, copy, threading
import time, copy, threading, uuid
# Run processor synchronious
# inThreadControlDict = {"ThreadExecuteBool":True}
def ProcessorRunSync(inGSettings, inRobotRDPThreadControlDict):
@ -11,7 +11,8 @@ def ProcessorRunSync(inGSettings, inRobotRDPThreadControlDict):
# "ArgList":[1,2,3], # Args list
# "ArgDict":{"ttt":1,"222":2,"dsd":3}, # Args dictionary
# "ArgGSettings": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "ArgLogger": None ,# Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "GUIDStr": ""
# },
],
"AliasDefDict": {}, # Storage for def with Str alias. To use it see pyOpenRPA.Orchestrator.ControlPanel
@ -20,6 +21,7 @@ def ProcessorRunSync(inGSettings, inRobotRDPThreadControlDict):
"""
lL = inGSettings["Logger"] # Logger alias
inGSettings["ProcessorDict"]["ThreadIdInt"] = threading.get_ident() # fill Processor thread id
try:
while inGSettings["ProcessorDict"]["ExecuteBool"]:
lActivityList = inGSettings["ProcessorDict"]["ActivityList"] # Alias
if len(lActivityList)>0:
@ -30,6 +32,8 @@ def ProcessorRunSync(inGSettings, inRobotRDPThreadControlDict):
inRobotRDPThreadControlDict["ThreadExecuteBool"] = True # Continue the RobotRDPActive monitoring
else:
time.sleep(inGSettings["ProcessorDict"]["CheckIntervalSecFloat"]) # Sleep when list is empty
except Exception as e:
if lL: lL.exception(f"Processor.ProcessorRunSync. Something goes very wrong in processor queue. See traceback")
# Execute ActivityItem list
# return the def result
@ -98,3 +102,34 @@ def __ActivityListVerify__(inActivityList):
#CASE NOT LIST
else:
raise Exception(f"pyOpenRPA Processor.__ActivityListVerify__: inActivityList has wrong structure! Details: Your ActivityList is not a list.")
def ProcessorMonitorRunSync(inGSettings):
"""
Periodically check processor queue if task is updating. If one task is more than ... sec - send warning in log
"""
lL = inGSettings["Logger"] # Logger alias
lActiveGUIDStr = None
lActiveTimeStart = time.time()
try:
while True:
if len(inGSettings["ProcessorDict"]["ActivityList"])>0:
lItemDict = inGSettings["ProcessorDict"]["ActivityList"][0]
if "GUIDStr" not in lItemDict:
lGUIDStr = str(uuid.uuid4()) # generate new GUID
lItemDict["GUIDStr"] = lGUIDStr
# Check if GUID is identical
if lItemDict["GUIDStr"]==lActiveGUIDStr:
# Check time
lActiveTimeDeltaSec = time.time() - lActiveTimeStart
# If delta more than Warning limit sec float
lWaitTimeSecFloat = inGSettings["ProcessorDict"]["WarningExecutionMoreThanSecFloat"]
if lActiveTimeDeltaSec > lWaitTimeSecFloat:
if lL: lL.warning(f"Processor.ProcessorMonitorRunSync: Processor wait more than {lWaitTimeSecFloat} sec. Activity def: {lItemDict['Def']}; GUID: {lItemDict['GUIDStr']}")
else:
lActiveGUIDStr = lItemDict["GUIDStr"]
lActiveTimeStart = time.time()
time.sleep(inGSettings["ProcessorDict"]["WarningExecutionMoreThanSecFloat"]) # Sleep when list is empty
except Exception as e:
if lL: lL.exception(
f"Processor.ProcessorMonitorRunSync. Something goes very wrong in processor queue. See traceback")

@ -0,0 +1,60 @@
import time
def RetryMark(inRDPSessionKeyStr, inGSettings):
"""
Set mark that Orch will try to reconnect to RDP
:param inRDPSessionKeyStr: RDP Session key string - to monitor retry count by the RDP Session key
:param inGSettings: Orchestrator global settings dict (singleton)
:return: None
"""
lL = inGSettings.get("Logger", None) # Get the logger instance
# Create List by the RDP Session key if not exists
if inRDPSessionKeyStr not in inGSettings["RobotRDPActive"]["RecoveryDict"]["__StatisticsDict__"]:
inGSettings["RobotRDPActive"]["RecoveryDict"]["__StatisticsDict__"][inRDPSessionKeyStr] = []
inGSettings["RobotRDPActive"]["RecoveryDict"]["__StatisticsDict__"][inRDPSessionKeyStr].append(time.time())
def RetryIsTriggered(inRDPSessionKeyStr, inGSettings):
"""
Check if you can need to init recovery mode for the RDP
:param inRDPSessionKeyStr: RDP Session key string - to monitor retry count by the RDP Session key
:param inGSettings: Orchestrator global settings dict (singleton)
:return: True - Ready to start recovery mode - remotely restart PC; Falsew - else case
"""
lTimeNowFloat = time.time()
lResultBool = False
if inRDPSessionKeyStr in inGSettings["RobotRDPActive"]["RecoveryDict"]["__StatisticsDict__"]:
lTimeNewList = []
lCatchCounterInt = 0
for inTimeItemFloat in inGSettings["RobotRDPActive"]["RecoveryDict"]["__StatisticsDict__"][inRDPSessionKeyStr]:
lTimeDeltaFloat = lTimeNowFloat - inTimeItemFloat
# Remove item if very old
if lTimeDeltaFloat < inGSettings["RobotRDPActive"]["RecoveryDict"]["CatchPeriodSecFloat"]:
lTimeNewList.append(inTimeItemFloat)
lCatchCounterInt = lCatchCounterInt+1
# Set updated list
inGSettings["RobotRDPActive"]["RecoveryDict"]["__StatisticsDict__"][inRDPSessionKeyStr] = lTimeNewList
# Check if counter equal or more
if lCatchCounterInt>= inGSettings["RobotRDPActive"]["RecoveryDict"]["TriggerCountInt"]:
lResultBool = True
return lResultBool
def RetryHostClear(inHostStr, inGSettings):
"""
Clear retry stat by the host str
:param inHostStr: PC host str to be cleared (search the RDPSession keys)
:param inGSettings: Orchestrator global settings dict (singleton)
:return:
"""
for lRDPSessionKeyStr in inGSettings["RobotRDPActive"]["RDPList"]:
lRDPDict = inGSettings["RobotRDPActive"]["RDPList"][lRDPSessionKeyStr]
# Check if HOST in UPPER is equal
if lRDPDict["Host"].upper() == inHostStr.upper():
#Check if RDPSession key exist in stat
if lRDPSessionKeyStr in inGSettings["RobotRDPActive"]["RecoveryDict"]["__StatisticsDict__"]:
del inGSettings["RobotRDPActive"]["RecoveryDict"]["__StatisticsDict__"][lRDPSessionKeyStr]

@ -4,6 +4,8 @@ import time # Time wait operations
from . import ConnectorExceptions # Exceptions classes
from . import Connector
from . import Processor # Module for process some functions on thr RDP
from . import Recovery
from .. import __Orchestrator__
# Main function
# inThreadControlDict = {"ThreadExecuteBool":True}
def RobotRDPActive(inGSettings, inThreadControlDict):
@ -42,14 +44,17 @@ def RobotRDPActive(inGSettings, inThreadControlDict):
# Check RDP window is OK - reconnect if connection was lost
lUIOSelectorList = []
lRDPConfigurationDictList = []
lRDPSessionKeyList = []
# Prepare selectors list for check
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lRDPSessionKeyList.append(lRDPSessionKeyStrItem)
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
lRDPSessionKeyStr = lRDPSessionKeyList[lItem]
lRDPConfigurationDict = lRDPConfigurationDictList[lItem] # Get RDP Configuration list
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
# Check if RDP window is not ignored
@ -57,11 +62,19 @@ def RobotRDPActive(inGSettings, inThreadControlDict):
try:
Connector.Session(lRDPConfigurationDict, inScreenSize550x350Bool = True)
lRDPConfigurationDict["SessionIsWindowExistBool"] = True # Flag that session is started
if lL: lL.info(f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session has been initialized!") #Logging
if lL: lL.info(f"Host: {lRDPConfigurationDict['Host']}, Login: {lRDPConfigurationDict['Login']}, SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session has been initialized!") #Logging
# catch ConnectorExceptions.SessionWindowNotExistError
except ConnectorExceptions.SessionWindowNotExistError as e:
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
if lL: lL.warning(f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session is not exist!") #Logging
if lL: lL.warning(f"Host: {lRDPConfigurationDict['Host']}, Login: {lRDPConfigurationDict['Login']}, SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session is not exist! Mark the retry") #Logging
# Recovery operations
Recovery.RetryMark(inRDPSessionKeyStr=lRDPSessionKeyStr,inGSettings=inGSettings)
if Recovery.RetryIsTriggered(inRDPSessionKeyStr=lRDPSessionKeyStr,inGSettings=inGSettings) == True:
if lL: lL.warning(f"!ATTENTION! Host: {lRDPConfigurationDict['Host']}, Login: {lRDPConfigurationDict['Login']}; RDP is not responsible for many times - run recovery mode")
Recovery.RetryHostClear(inHostStr=lRDPConfigurationDict['Host'],inGSettings=inGSettings) # Clear the stat about current host
if inGSettings["RobotRDPActive"]["RecoveryDict"]["DoDict"]["OSRemotePCRestart"] == True:
if lL: lL.warning(f"!ATTENTION! Host: {lRDPConfigurationDict['Host']}, Send signal to restart remote PC.")
__Orchestrator__.OSRemotePCRestart(inLogger=lL,inHostStr=lRDPConfigurationDict['Host'],inForceBool=True)
# general exceptions
except Exception as e:
if lL: lL.exception(f"!!! ATTENTION !!! Unrecognized error") #Logging

@ -43,6 +43,20 @@ def __ComplexDictMerge2to1__(in1Dict, in2Dict):
in1Dict[lKeyStr] = in2Dict[lKeyStr]
return in1Dict
# Tool to merge complex dictionaries - no exceptions, just overwrite dict 2 in dict 1
def __ComplexDictMerge2to1Overwrite__(in1Dict, in2Dict):
lPathList=None
if lPathList is None: lPathList = []
for lKeyStr in in2Dict:
if lKeyStr in in1Dict:
if isinstance(in1Dict[lKeyStr], dict) and isinstance(in2Dict[lKeyStr], dict):
__ComplexDictMerge2to1Overwrite__(in1Dict[lKeyStr], in2Dict[lKeyStr])
else:
in1Dict[lKeyStr] = in2Dict[lKeyStr]
else:
in1Dict[lKeyStr] = in2Dict[lKeyStr]
return in1Dict
#Authenticate function ()
# return dict
# {
@ -319,6 +333,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
lFileObject.close()
# ResponseContentTypeFile
def ResponseDictSend(self):
lL = gSettingsDict["Logger"]
inResponseDict = self.OpenRPAResponseDict
# Send response status code
self.send_response(inResponseDict["StatusCode"])
@ -329,9 +344,12 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
for lItemKey, lItemValue in inResponseDict["SetCookies"].items():
self.send_header("Set-Cookie", f"{lItemKey}={lItemValue}")
#Close headers section in response
try:
self.end_headers()
# Write content as utf-8 data
self.wfile.write(inResponseDict["Body"])
except ConnectionResetError as e:
if lL: lL.warning(f"An existing connection was forcibly closed by the remote host - OK for the network interactions (ConnectionResetError: [WinError 10054])")
def do_GET(self):
try:
self.OpenRPA = {}

@ -151,10 +151,13 @@ def HiddenAgentDictGenerate(inRequest, inGSettings):
lKeyStr = f"{lAgentItemKeyStrItem[0]};{lAgentItemKeyStrItem[1]}" # turple ("HostNameUpperStr","UserUpperStr") > Str "HostNameUpperStr;UserUpperStr"
if dUAC(inRoleKeyList=lUACAgentTemplateKeyList+[lKeyStr]):
lDataItemDict = inGSettings["AgentDict"][lAgentItemKeyStrItem]
lAgentDict[lKeyStr]=lDataItemDict
lDataItemAgentDict = copy.deepcopy(lDataItemDict)
lDataItemAgentDict["ActivityList"] = []
lAgentDict[lKeyStr]=lDataItemAgentDict
lHandlebarsDataItemDict = copy.deepcopy(lDataItemDict)
lHandlebarsDataItemDict["HostnameUpperStr"]=lAgentItemKeyStrItem[0]
lHandlebarsDataItemDict["UserUpperStr"]=lAgentItemKeyStrItem[1]
lHandlebarsDataItemDict["ActivityList"] = []
lAgentDict["HandlebarsList"].append(lHandlebarsDataItemDict)
return lAgentDict
@ -330,7 +333,9 @@ def pyOpenRPA_ActivityListExecute(inRequest, inGSettings):
# See docs in Agent (pyOpenRPA.Agent.O2A)
def pyOpenRPA_Agent_O2A(inRequest, inGSettings):
lL = inGSettings["Logger"] # Alias
lConnectionLifetimeSecFloat = 3600.0 # 60 min * 60 sec 3600.0
lConnectionLifetimeSecFloat = inGSettings["ServerDict"]["AgentConnectionLifetimeSecFloat"] # 300.0 # 5 min * 60 sec 300.0
lActivityItemLifetimeLimitSecFloat = inGSettings["ServerDict"]["AgentActivityLifetimeSecFloat"]
lAgentLoopSleepSecFloat = inGSettings["ServerDict"]["AgentLoopSleepSecFloat"]
lTimeStartFloat = time.time()
# Recieve the data
lValueStr = None
@ -348,6 +353,7 @@ def pyOpenRPA_Agent_O2A(inRequest, inGSettings):
lThisAgentDict["ConnectionCountInt"] += 1 # increment connection count
# Test solution
lDoLoopBool = True
try:
while lDoLoopBool:
# Check if lifetime is over
if time.time() - lTimeStartFloat > lConnectionLifetimeSecFloat: # Lifetime is over
@ -357,26 +363,47 @@ def pyOpenRPA_Agent_O2A(inRequest, inGSettings):
lThisAgentDict["IsListenBool"] = True # Set is online
lQueueList = lThisAgentDict["ActivityList"]
if len(lQueueList)>0:# Do some operations if has queue items
if lL: lL.debug(f'O2A BEFORE: ConnectionCountInt: {lThisAgentDict["ConnectionCountInt"]};ConnectionFirstQueueItemCountInt {lThisAgentDict["ConnectionFirstQueueItemCountInt"]}')
if lThisAgentDict["ConnectionCountInt"] == lThisAgentDict["ConnectionFirstQueueItemCountInt"] + 1:
# POP QUEUE ITEM CONDITION ConnectionCountInt == ConnectionFirstQueueItemCountInt + 1
if lL: lL.debug(f'O2A: ConnectionCountInt: {lThisAgentDict["ConnectionCountInt"]};ConnectionFirstQueueItemCountInt {lThisAgentDict["ConnectionFirstQueueItemCountInt"]}')
# check if delta datetime is < than ActivityLifeTimeSecFloat
lActivityItem = lThisAgentDict["ActivityList"][0]
lActivityLifetimeSecFloat = (datetime.datetime.now() - lActivityItem["CreatedByDatetime"]).total_seconds()
# Check case if limit is expired - remove item
if lActivityLifetimeSecFloat > lActivityItemLifetimeLimitSecFloat:
lActivityItem = lThisAgentDict["ActivityList"].pop(0)
lThisAgentDict["ConnectionFirstQueueItemCountInt"] = 0
if lL: lL.debug(f"Activity was deleted from the list: {lThisAgentDict['ActivityList']}")
else:
lActivityItem = lThisAgentDict["ActivityList"][0]
lThisAgentDict["ConnectionFirstQueueItemCountInt"] += 1
if lL: lL.debug(f"Activity was !not! deleted from the list: {lThisAgentDict['ActivityList']}")
if lL: lL.debug(f'O2A AFTER: ConnectionCountInt: {lThisAgentDict["ConnectionCountInt"]};ConnectionFirstQueueItemCountInt {lThisAgentDict["ConnectionFirstQueueItemCountInt"]}')
lReturnActivityItemDict = None
# If lInput['ActivityLastGUIDStr'] is '' > return 0 element for send in Agent
if lInput['ActivityLastGUIDStr'] == "":
lReturnActivityItemDict = lThisAgentDict["ActivityList"][0]
else:
# go from the end - search element with GUIDStr
lForTriggerGetNextItem = False
for lForActivityItemDict in lQueueList:
if lForTriggerGetNextItem == True:
lReturnActivityItemDict = lForActivityItemDict
break
if lForActivityItemDict['GUIDStr'] == lInput['ActivityLastGUIDStr']: lForTriggerGetNextItem = True
# CASE if GUID is not detected - return 0 element
if lReturnActivityItemDict == None and lForTriggerGetNextItem == False:
lReturnActivityItemDict = lThisAgentDict["ActivityList"][0]
# Send QUEUE ITEM
if lL: lL.info(f"Activity item to agent Hostname {lInput['HostNameUpperStr']}, User {lInput['UserUpperStr']}. Activity item: {lActivityItem}")
inRequest.OpenRPAResponseDict["Body"] = bytes(json.dumps(lActivityItem), "utf8")
if lReturnActivityItemDict is not None:
lReturnActivityItemDict = copy.deepcopy(lReturnActivityItemDict)
if "CreatedByDatetime" in lReturnActivityItemDict:
del lReturnActivityItemDict["CreatedByDatetime"]
if lL: lL.info(f"Activity item to agent Hostname {lInput['HostNameUpperStr']}, User {lInput['UserUpperStr']}. Activity item: {lReturnActivityItemDict}")
inRequest.OpenRPAResponseDict["Body"] = bytes(json.dumps(lReturnActivityItemDict), "utf8")
lDoLoopBool = False # CLose the connection
else: # Nothing to send - sleep for the next iteration
time.sleep(lAgentLoopSleepSecFloat)
else: # no queue item - sleep for the next iteration
time.sleep(1)
time.sleep(lAgentLoopSleepSecFloat)
except Exception as e:
if lL: lL.exception("pyOpenRPA_Agent_O2A Exception!")
lThisAgentDict["ConnectionCountInt"] -= 1 # Connection go to be closed - decrement the connection count
# See docs in Agent (pyOpenRPA.Agent.A2O)
def pyOpenRPA_Agent_A2O(inRequest, inGSettings):
lL = inGSettings["Logger"]
# Recieve the data
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
@ -387,6 +414,12 @@ def pyOpenRPA_Agent_A2O(inRequest, inGSettings):
if "LogList" in lInput:
for lLogItemStr in lInput["LogList"]:
inGSettings["Logger"].info(lLogItemStr)
if "ActivityReturnDict" in lInput:
for lActivityReturnItemKeyStr in lInput["ActivityReturnDict"]:
lActivityReturnItemValue = lInput["ActivityReturnDict"][lActivityReturnItemKeyStr]
# Create item in gSettings
inGSettings["AgentActivityReturnDict"][lActivityReturnItemKeyStr]=SettingsTemplate.__AgentActivityReturnDictItemCreate__(inReturn=lActivityReturnItemValue)
if lL: lL.debug(f"SERVER: pyOpenRPA_Agent_A2O:: Has recieved result of the activity items from agent! ActivityItem GUID Str: {lActivityReturnItemKeyStr}; Return value: {lActivityReturnItemValue}")
def SettingsUpdate(inGlobalConfiguration):
import os

@ -7,6 +7,7 @@ def __Create__():
"Autocleaner": {
# Some gurbage is collecting in g settings. So you can configure autocleaner to periodically clear gSettings
"IntervalSecFloat": 3600.0, # Sec float to periodically clear gsettings
"AgentActivityReturnLifetimeSecFloat": 300.0 # Time in seconds to life for activity result recieved from the agent
},
"Client": { # Settings about client web orchestrator
"Session": {
@ -14,7 +15,7 @@ def __Create__():
"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,
"ControlPanelRefreshIntervalSecFloat": 2.0, # 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
@ -38,6 +39,9 @@ def __Create__():
# # # # # # # # # # # # # # # # # #
},
"ServerDict": {
"AgentActivityLifetimeSecFloat": 1200.0, # Time in seconds to life for activity for the agent
"AgentConnectionLifetimeSecFloat": 300.0, # Time in seconds to handle the open connection to the Agent
"AgentLoopSleepSecFloat": 2.0, # Time in seconds to sleep between loops when check to send some activity to the agent
"WorkingDirectoryPathStr": None, # Will be filled automatically
"RequestTimeoutSecFloat": 300, # Time to handle request in seconds
"ListenPort_": "Порт, по которому можно подключиться к демону",
@ -115,45 +119,7 @@ def __Create__():
"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 -
# ...
# },
]
"ActivityList": []
},
"SchedulerDict": {
"CheckIntervalSecFloat": 5.0, # Check interval in seconds
@ -162,11 +128,14 @@ def __Create__():
# "TimeHH:MMStr": "22:23", # Time [HH:MM] to trigger activity
# "WeekdayList": [0, 1, 2, 3, 4, 5, 6], #List of the weekday index when activity is applicable, Default [0,1,2,3,4,5,6]
# "ActivityList": [
# {
# "Type": "ProcessStart", # Activity type
# "Path": "start", # Executable file path
# "ArgList": ["cmd.exe", "/c", "PIPUpgrade.cmd"] # List of the arguments
# }
# # {
# # "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)
# # "ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# # "GUIDStr": ..., # GUID of the activity
# # },
# ],
# "GUID": None # Will be filled in Orchestrator automatically - is needed for detect activity completion
# },
@ -180,12 +149,14 @@ def __Create__():
# "ArgDict":{"ttt":1,"222":2,"dsd":3} # Args dictionary
# "ArgGSettings": # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "GUIDStr": ..., # GUID of the activity
# },
],
"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
"ThreadIdInt": None # Technical field - will be setup when processor init
"ThreadIdInt": None, # Technical field - will be setup when processor init
"WarningExecutionMoreThanSecFloat": 60.0 # Push warning if execution more than n seconds
},
"ControlPanelDict": { # Old structure > CPDict
"RefreshSeconds": 5, # deprecated parameter
@ -201,6 +172,16 @@ def __Create__():
},
# # # # # # # # # # # # # #
"RobotRDPActive": {
"RecoveryDict": {
"CatchPeriodSecFloat": 1200, # Catch last 10 minutes
"TriggerCountInt": 10, # Activate trigger if for the period orch will catch the reconnect RDP n times
"DoDict": {
"OSRemotePCRestart": True # Do powershell remote restart
},
"__StatisticsDict__": {
# RDPSessionKeyStr : [time.time(), time.time()],
}
},
"RDPList": {
# "RDPSessionKey":{
# "Host": "77.77.22.22", # Host address
@ -259,19 +240,29 @@ def __Create__():
}
},
"Logger": logging.getLogger("Orchestrator"),
"Storage": {
"StorageDict": {
"Robot_R01_help": "Robot data storage in orchestrator env",
"Robot_R01": {},
"R01_OrchestratorToRobot": {"Test2": "Test2"}
},
"AgentDict": { # Will be filled when program runs
#("HostNameUpperStr", "UserUpperStr"): { "IsListenBool": True, "QueueList": [] }
},
"AgentActivityReturnDict": { # Will be filled when programs run - fill result of the Activity execution on the agent
# Key - Activity Item GUID str, Value {"Return": ..., "ReturnedByDatetime": datetime.datetime}
# If key exists - def has been completed
}
# "HiddenIsOrchestratorInitialized" - will be inited when orchestrator will be initialized
}
# Create full configuration for
def __AgentDictItemCreate__():
return {"IsListenBool":False, "ConnectionCountInt":0, "ConnectionFirstQueueItemCountInt":0, "ActivityList":[]}
# Create full configuration for AgentActivityReturnDict
def __AgentActivityReturnDictItemCreate__(inReturn):
return {"Return": inReturn, "ReturnedByDatetime": datetime.datetime.now()}
# Create full configuration for
def __UACClientAdminCreate__():
lResultDict = {

@ -1,4 +1,4 @@
import json
import json, copy
from .. import __Orchestrator__
from .. import Processor
# Escape JS to the safe JS for the inline JS in HTML tags ATTENTION! Use it only if want to paste JS into HTML tag - not in <script>
@ -7,22 +7,42 @@ def JSEscapeForHTMLInline(inJSStr):
lResult = inJSStr.replace("\"","&quot;")
return lResult
# Create JS for send activity list/ activity to the processor
# USAGE: Orchestrator.Web.Basic.JSProcessorActivityListAdd(inActivityList)
def JSProcessorActivityListAdd(inActivityList):
def JSProcessorActivityListAdd(inActivityList, inGUIDRemoveBool = True):
"""
# Create JS for send activity list/ activity to the processor
# USAGE: Orchestrator.Web.Basic.JSProcessorActivityListAdd(inActivityList)
:param inActivityList: List of the activities (See __Orchestrator__.ProcessorActivityItemCreate)
:param inGUIDRemoveBool: True - remove GUID before generate JS (if GUID is not important)
:return: JavaScript string for the front end
"""
Processor.__ActivityListVerify__(inActivityList=inActivityList) # DO VERIFICATION FOR THE inActivityList
inActivityList = copy.deepcopy(inActivityList)
# Check if no def function is here - if exist - replace to alias
for lActivityItem in inActivityList:
if "GUIDStr" in lActivityItem and inGUIDRemoveBool == True: del lActivityItem["GUIDStr"] # Remove GUID from activity items if exists
lDef = lActivityItem["Def"]
if callable(lDef): raise Exception(f"pyOpenRPA Exception: You can't send ActivityList with def to JS. Use Def Alias (see Orchestrator.ProcessorAliasDefUpdate)")
if type(inActivityList) is not list: inActivityList = [inActivityList]
lJSStr = f"""mGlobal.pyOpenRPA.ProcessorQueueAdd({json.dumps(inActivityList)});"""
return lJSStr
# Create JS for execute activity list/ activity permanent
# USAGE: Orchestrator.Web.Basic.JSActivityListExecute(inActivityList)
def JSActivityListExecute(inActivityList):
def JSActivityListExecute(inActivityList, inGUIDRemoveBool = True):
"""
Create JS for execute activity list/ activity permanent
USAGE: Orchestrator.Web.Basic.JSActivityListExecute(inActivityList, inGUIDRemoveBool = True)
:param inActivityList: List of the activities (See __Orchestrator__.ProcessorActivityItemCreate)
:param inGUIDRemoveBool: True - remove GUID before generate JS (if GUID is not important)
:return: JavaScript string for the front end
"""
Processor.__ActivityListVerify__(inActivityList=inActivityList) # DO VERIFICATION FOR THE inActivityList
inActivityList = copy.deepcopy(inActivityList)
# Check if no def function is here - if exist - replace to alias
for lActivityItem in inActivityList:
if "GUIDStr" in lActivityItem and inGUIDRemoveBool == True: del lActivityItem["GUIDStr"] # Remove GUID from activity items if exists
lDef = lActivityItem["Def"]
if callable(lDef): raise Exception(f"pyOpenRPA Exception: You can't send ActivityList with def to JS. Use Def Alias (see Orchestrator.ProcessorAliasDefUpdate)")
lJSStr = f"""mGlobal.pyOpenRPA.ActivityListExecute({json.dumps(inActivityList)});"""
return lJSStr

@ -176,6 +176,7 @@ $(document).ready(function() {
}
///Restart PC
mGlobal.Controller.PCRestart = function () {
mGlobal.Controller.OrchestratorSessionSave()
mGlobal.Controller.CMDRunText("shutdown -r")
}
///Orchestrator save session

@ -1,9 +1,14 @@
import subprocess, json, psutil, time, os, win32security, sys, base64, logging, ctypes #Get input argument
import subprocess, json, psutil, time, os, win32security, sys, base64, logging, ctypes, copy #Get input argument
import pickle
from partd import Server
from . import Server
from . import Timer
from . import Processor
from . import BackwardCompatibility # Backward compatibility from v1.1.13
from . import Core
from subprocess import CREATE_NEW_CONSOLE
from .Utils import LoggerHandlerDumpLogList
# ATTENTION! HERE IS NO Relative import because it will be imported dynamically
@ -23,7 +28,7 @@ import uuid # Generate uuid
import datetime # datetime
#Единый глобальный словарь (За основу взять из Settings.py)
global gSettingsDict
gSettingsDict = None
# AGENT DEFS
@ -35,34 +40,82 @@ def AgentActivityItemAdd(inGSettings, inHostNameStr, inUserStr, inActivityItemDi
:param inHostNameStr: Agent host name
:param inUserStr: User login, where agent is based
:param inActivityItemDict: ActivityItem
:return: None
"""
:return: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
"""
lActivityItemDict = copy.deepcopy(inActivityItemDict)
# Add GUIDStr if not exist
lGUIDStr = None
if "GUIDStr" not in lActivityItemDict:
lGUIDStr = str(uuid.uuid4()) # generate new GUID
lActivityItemDict["GUIDStr"] = lGUIDStr
else: lGUIDStr = lActivityItemDict["GUIDStr"]
# Add CreatedByDatetime
lActivityItemDict["CreatedByDatetime"] = datetime.datetime.now()
# Main alg
lAgentDictItemKeyTurple = (inHostNameStr.upper(),inUserStr.upper())
if lAgentDictItemKeyTurple not in inGSettings["AgentDict"]:
inGSettings["AgentDict"][lAgentDictItemKeyTurple] = SettingsTemplate.__AgentDictItemCreate__()
lThisAgentDict = inGSettings["AgentDict"][lAgentDictItemKeyTurple]
lThisAgentDict["ActivityList"].append(inActivityItemDict)
lThisAgentDict["ActivityList"].append(lActivityItemDict)
# Return the result
return lGUIDStr
def AgentActivityItemReturnExists(inGSettings, inGUIDStr):
"""
Check by GUID if ActivityItem has been executed and result has come to the Orchestrator
:param inGSettings: Global settings dict (singleton)
:param inGUIDStr: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
:return: True - result has been received from the Agent to orc; False - else case
"""
# Check if GUID is exists in dict - has been recieved
return inGUIDStr in inGSettings["AgentActivityReturnDict"]
def AgentOSCMD(inGSettings, inHostNameStr, inUserStr, inCMDStr, inRunAsyncBool=True):
def AgentActivityItemReturnGet(inGSettings, inGUIDStr, inCheckIntervalSecFloat = 0.5):
"""
Work synchroniously! Wait while result will be recieved. Get the result of the ActivityItem execution on the Agent side. Before this please check by the def AgentActivityItemReturnExists that result has come to the Orchestrator
!ATTENTION! Use only after Orchestrator initialization! Before orchestrator init exception will be raised.
:param inGSettings: Global settings dict (singleton)
:param inGUIDStr: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
:param inCheckIntervalSecFloat: Interval in sec of the check Activity Item result
:return: Result of the ActivityItem executed on the Agent side anr transmitted to the Orchestrator. IMPORTANT! ONLY JSON ENABLED Types CAN BE TRANSMITTED TO ORCHESTRATOR!
"""
#Check if Orchestrator has been initialized - else raise exception
if Core.IsOrchestratorInitialized(inGSettings=inGSettings) == True:
# Wait while result will not come here
while not AgentActivityItemReturnExists(inGSettings=inGSettings, inGUIDStr=inGUIDStr):
time.sleep(inCheckIntervalSecFloat)
# Return the result
return inGSettings["AgentActivityReturnDict"][inGUIDStr]["Return"]
else:
raise Exception(f"__Orchestrator__.AgentActivityItemReturnGet !ATTENTION! Use this function only after Orchestrator initialization! Before orchestrator init exception will be raised.")
def AgentOSCMD(inGSettings, inHostNameStr, inUserStr, inCMDStr, inRunAsyncBool=True, inSendOutputToOrchestratorLogsBool=True, inCMDEncodingStr="cp1251"):
"""
Send CMD to OS thought the pyOpenRPA.Agent daemon. Result return to log + Orchestrator by the A2O connection
:param inGSettings: Global settings dict (singleton)
:param inHostNameStr:
:param inUserStr:
:param inCMDStr:
:param inRunAsyncBool:
:param inHostNameStr: Agent host name in upper case (example "RPA01", "RPA_99" and so on). Active agent session you can see on the orchestrator dashboard as Orchestrator admin
:param inUserStr: Agent user name in upper case (example "UserRPA"). Active agent session you can see on the orchestrator dashboard as Orchestrator admin
:param inCMDStr: command to execute on the Agent session
:param inRunAsyncBool: True - Agent processor don't wait execution; False - Agent processor wait cmd execution
:param inSendOutputToOrchestratorLogsBool: True - catch cmd execution output and send it to the Orchestrator logs; Flase - else case; Default True
:param inCMDEncodingStr: Set the encoding of the DOS window on the Agent server session. Windows is beautiful :) . Default is "cp1251" early was "cp866" - need test
:return: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
"""
lActivityItemDict = {
"Def":"OSCMD", # def alias (look pyOpeRPA.Agent gSettings["ProcessorDict"]["AliasDefDict"])
"ArgList":[], # Args list
"ArgDict":{"inCMDStr":inCMDStr,"inRunAsyncBool":inRunAsyncBool}, # Args dictionary
"ArgDict":{"inCMDStr":inCMDStr,"inRunAsyncBool":inRunAsyncBool, "inSendOutputToOrchestratorLogsBool": inSendOutputToOrchestratorLogsBool, "inCMDEncodingStr": inCMDEncodingStr}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
#Send item in AgentDict for the futher data transmition
AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
return AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
def AgentOSFileBinaryDataBytesCreate(inGSettings, inHostNameStr, inUserStr, inFilePathStr, inFileDataBytes):
"""
@ -73,6 +126,7 @@ def AgentOSFileBinaryDataBytesCreate(inGSettings, inHostNameStr, inUserStr, inFi
:param inUserStr:
:param inFilePathStr:
:param inFileDataBytes:
:return: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
"""
lFileDataBase64Str = base64.b64encode(inFileDataBytes).decode("utf-8")
@ -84,7 +138,7 @@ def AgentOSFileBinaryDataBytesCreate(inGSettings, inHostNameStr, inUserStr, inFi
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
#Send item in AgentDict for the futher data transmition
AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
return AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
def AgentOSFileBinaryDataBase64StrCreate(inGSettings, inHostNameStr, inUserStr, inFilePathStr, inFileDataBase64Str):
@ -96,6 +150,7 @@ def AgentOSFileBinaryDataBase64StrCreate(inGSettings, inHostNameStr, inUserStr,
:param inUserStr:
:param inFilePathStr:
:param inFileDataBase64Str:
:return: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
"""
lActivityItemDict = {
@ -106,7 +161,7 @@ def AgentOSFileBinaryDataBase64StrCreate(inGSettings, inHostNameStr, inUserStr,
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
#Send item in AgentDict for the futher data transmition
AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
return AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
# Send text file to Agent (string)
def AgentOSFileTextDataStrCreate(inGSettings, inHostNameStr, inUserStr, inFilePathStr, inFileDataStr, inEncodingStr = "utf-8"):
@ -119,6 +174,7 @@ def AgentOSFileTextDataStrCreate(inGSettings, inHostNameStr, inUserStr, inFilePa
:param inFilePathStr:
:param inFileDataStr:
:param inEncodingStr:
:return: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
"""
lActivityItemDict = {
@ -129,7 +185,70 @@ def AgentOSFileTextDataStrCreate(inGSettings, inHostNameStr, inUserStr, inFilePa
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
#Send item in AgentDict for the futher data transmition
AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
return AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
def AgentOSFileBinaryDataBase64StrReceive(inGSettings, inHostNameStr, inUserStr, inFilePathStr):
"""
Read binary file and encode in base64 to transmit (safe for JSON transmition)
:param inGSettings: Global settings dict (singleton)
:param inHostNameStr:
:param inUserStr:
:param inFilePathStr: File path to read
:return: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
"""
lActivityItemDict = {
"Def":"OSFileBinaryDataBase64StrReceive", # def alias (look pyOpeRPA.Agent gSettings["ProcessorDict"]["AliasDefDict"])
"ArgList":[], # Args list
"ArgDict":{"inFilePathStr":inFilePathStr}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
#Send item in AgentDict for the futher data transmition
return AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
def AgentOSFileTextDataStrReceive(inGSettings, inHostNameStr, inUserStr, inFilePathStr, inEncodingStr="utf-8"):
"""
Read text file in the agent GUI session
:param inGSettings: Global settings dict (singleton)
:param inHostNameStr:
:param inUserStr:
:param inFilePathStr: File path to read
:param inEncodingStr: Text file encoding. Default 'utf-8'
:return: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
"""
lActivityItemDict = {
"Def":"OSFileTextDataStrReceive", # def alias (look pyOpeRPA.Agent gSettings["ProcessorDict"]["AliasDefDict"])
"ArgList":[], # Args list
"ArgDict":{"inFilePathStr":inFilePathStr, "inEncodingStr": inEncodingStr}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
#Send item in AgentDict for the futher data transmition
return AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
def AgentProcessWOExeUpperUserListGet(inGSettings, inHostNameStr, inUserStr):
"""
Return the process list only for the current user (where Agent is running) without .EXE in upper case. Can use in ActivityItem from Orchestrator to Agent
:param inGSettings: Global settings dict (singleton)
:param inHostNameStr:
:param inUserStr:
:return: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
"""
lActivityItemDict = {
"Def":"ProcessWOExeUpperUserListGet", # def alias (look pyOpeRPA.Agent gSettings["ProcessorDict"]["AliasDefDict"])
"ArgList":[], # Args list
"ArgDict":{}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
#Send item in AgentDict for the futher data transmition
return AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
# OS DEFS
def OSCredentialsVerify(inUserStr, inPasswordStr, inDomainStr=""): ##
@ -151,6 +270,20 @@ def OSCredentialsVerify(inUserStr, inPasswordStr, inDomainStr=""): ##
else:
return True
def OSRemotePCRestart(inLogger, inHostStr, inForceBool=True):
"""
Send signal via power shell to restart remote PC
ATTENTION: Orchestrator user need to have restart right on the Remote machine to restart PC.
:param inLogger: logger to log powershell result in logs
:param inHostStr: PC hostname which you need to restart.
:param inForceBool: True - send signal to force retart PC; False - else case
:return:
"""
lCMDStr = f"powershell -Command Restart-Computer -ComputerName {inHostStr}"
if inForceBool == True: lCMDStr = lCMDStr + " -Force"
OSCMD(inCMDStr=lCMDStr,inLogger=inLogger)
def OSCMD(inCMDStr, inRunAsyncBool=True, inLogger = None):
"""
OS send command in shell locally
@ -165,7 +298,7 @@ def OSCMD(inCMDStr, inRunAsyncBool=True, inLogger = None):
def _CMDRunAndListenLogs(inCMDStr, inLogger):
lResultStr = ""
lOSCMDKeyStr = str(uuid.uuid4())[0:4].upper()
lCMDProcess = subprocess.Popen(f'cmd /c {inCMDStr}', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
lCMDProcess = subprocess.Popen(f'cmd /c {inCMDStr}', stdout=subprocess.PIPE, stderr=subprocess.STDOUT, creationflags=CREATE_NEW_CONSOLE)
if inLogger:
lListenBool = True
inLogger.info(f"{lOSCMDKeyStr}: # # # # CMD Process has been STARTED # # # # ")
@ -206,33 +339,106 @@ def OrchestratorRestart(inGSettings=None):
os.execl(sys.executable, os.path.abspath(__file__), *sys.argv)
sys.exit(0)
def OrchestratorSessionSave(inGSettings=None):
def OrchestratorIsAdmin():
"""
Orchestrator session save in file _SessionLast_RDPList.json (encoding = "utf-8")
Check if Orchestrator process is running as administrator
:return: True - run as administrator; False - not as administrator
"""
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except:
return False
def OrchestratorRerunAsAdmin():
"""
Check if not admin - then rerun orchestrator as administrator
:return: True - run as administrator; False - not as administrator
"""
if not OrchestratorIsAdmin():
# Re-run the program with admin rights
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
else:
print(f"!SKIPPED! Already run as administrator!")
def OrchestratorSessionSave(inGSettings):
"""
Orchestrator session save in file
_SessionLast_RDPList.json (encoding = "utf-8")
_SessionLast_StorageDict.pickle (binary)
:param inGSettings: Global settings dict (singleton)
:return: True every time
"""
lL = inGSettings["Logger"]
try:
# Dump RDP List in file json
lFile = open("_SessionLast_RDPList.json", "w", encoding="utf-8")
lFile.write(json.dumps(inGSettings["RobotRDPActive"]["RDPList"])) # dump json to file
lFile.close() # Close the file
if inGSettings is not None:
lL = inGSettings["Logger"]
if lL: lL.info(
f"Orchestrator has dump the RDP list before the restart.")
# _SessionLast_StorageDict.pickle (binary)
if "StorageDict" in inGSettings:
with open('_SessionLast_StorageDict.pickle', 'wb') as lFile:
pickle.dump(inGSettings["StorageDict"], lFile)
if lL: lL.info(
f"Orchestrator has dump the StorageDict before the restart.")
except Exception as e:
if lL: lL.exception(f"Exception when dump data before restart the Orchestrator")
return True
def OrchestratorSessionRestore(inGSettings):
"""
Check _SessionLast_RDPList.json and _SessionLast_StorageDict.pickle in working directory. if exist - load into gsettings
# _SessionLast_StorageDict.pickle (binary)
_SessionLast_RDPList.json (encoding = "utf-8")
_SessionLast_StorageDict.pickle (binary)
:param inGSettings: Global settings dict (singleton)
:return:
"""
lL = inGSettings.get("Logger",None)
# _SessionLast_RDPList.json (encoding = "utf-8")
if os.path.exists("_SessionLast_RDPList.json"):
lFile = open("_SessionLast_RDPList.json", "r", encoding="utf-8")
lSessionLastRDPList = json.loads(lFile.read())
lFile.close() # Close the file
os.remove("_SessionLast_RDPList.json") # remove the temp file
inGSettings["RobotRDPActive"]["RDPList"] = lSessionLastRDPList # Set the last session dict
if lL: lL.warning(f"RDP Session List was restored from previous Orchestrator session")
# _SessionLast_StorageDict.pickle (binary)
if os.path.exists("_SessionLast_StorageDict.pickle"):
if "StorageDict" not in inGSettings:
inGSettings["StorageDict"] = {}
with open('_SessionLast_StorageDict.pickle', 'rb') as lFile:
lStorageDictDumpDict = pickle.load(lFile)
Server.__ComplexDictMerge2to1Overwrite__(in1Dict=inGSettings["StorageDict"],
in2Dict=lStorageDictDumpDict) # Merge dict 2 into dict 1
if lL: lL.warning(f"StorageDict was restored from previous Orchestrator session")
os.remove("_SessionLast_StorageDict.pickle") # remove the temp file
def UACKeyListCheck(inRequest, inRoleKeyList) -> bool:
"""
Check is client is has access for the key list
:param inRequest:
:param inRequest: request handler (from http.server import BaseHTTPRequestHandler)
:param inRoleKeyList:
:return: bool
"""
return inRequest.UACClientCheck(inRoleKeyList=inRoleKeyList)
def UACUserDictGet(inRequest) -> dict:
"""
Return user UAC hierarchy dict of the inRequest object. Empty dict - superuser access
:param inRequest: request handler (from http.server import BaseHTTPRequestHandler)
:return: user UAC hierarchy dict
"""
return inRequest.UserRoleHierarchyGet() # get the Hierarchy
def UACUpdate(inGSettings, inADLoginStr, inADStr="", inADIsDefaultBool=True, inURLList=None, inRoleHierarchyAllowedDict=None):
"""
Update user access (UAC)
@ -609,7 +815,7 @@ def ProcessorAliasDefUpdate(inGSettings, inDef, inAliasStr):
else: raise Exception(f"pyOpenRPA Exception: You can't use Orchestrator.ProcessorAliasDefUpdate with arg 'inDef' string value. inDef is '{inDef}', inAliasStr is '{inAliasStr}'")
return inAliasStr
def ProcessorActivityItemCreate(inDef, inArgList=None, inArgDict=None, inArgGSettingsStr=None, inArgLoggerStr=None):
def ProcessorActivityItemCreate(inDef, inArgList=None, inArgDict=None, inArgGSettingsStr=None, inArgLoggerStr=None, inGUIDStr = None):
"""
Create activity item. Activity item can be used as list item in ProcessorActivityItemAppend or in Processor.ActivityListExecute.
@ -663,8 +869,12 @@ def ProcessorActivityItemCreate(inDef, inArgList=None, inArgDict=None, inArgGSet
:param inArgDict: Args dict for the def
:param inArgGSettingsStr: Name of def argument of the GSettings dict
:param inArgLoggerStr: Name of def argument of the logging object
:param inGUIDStr: GUID which you can specify. If None the GUID will be generated
:return: {}
"""
# Work about GUID in Activity items
if inGUIDStr is None:
inGUIDStr = str(uuid.uuid4()) # generate new GUID
if inArgList is None: inArgList=[]
if inArgDict is None: inArgDict={}
lActivityItemDict= {
@ -672,7 +882,8 @@ def ProcessorActivityItemCreate(inDef, inArgList=None, inArgDict=None, inArgGSet
"ArgList":inArgList, # Args list
"ArgDict":inArgDict, # Args dictionary
"ArgGSettings": inArgGSettingsStr, # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": inArgLoggerStr # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": inArgLoggerStr, # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"GUIDStr": inGUIDStr
}
return lActivityItemDict
@ -722,6 +933,7 @@ def ProcessorActivityItemAppend(inGSettings, inDef=None, inArgList=None, inArgDi
:param inArgGSettingsStr: Name of def argument of the GSettings dict
:param inArgLoggerStr: Name of def argument of the logging object
:param inActivityItemDict: Fill if you already have ActivityItemDict (don't fill inDef, inArgList, inArgDict, inArgGSettingsStr, inArgLoggerStr)
:return ActivityItem GUIDStr
"""
if inActivityItemDict is None:
if inArgList is None: inArgList=[]
@ -738,7 +950,16 @@ def ProcessorActivityItemAppend(inGSettings, inDef=None, inArgList=None, inArgDi
]
else:
lActivityList = [inActivityItemDict]
# Work about GUID in Activity items
lGUIDStr = None
for lItemDict in lActivityList:
# Add GUIDStr if not exist
if "GUIDStr" not in lItemDict:
lGUIDStr = str(uuid.uuid4()) # generate new GUID
lItemDict["GUIDStr"] = lGUIDStr
# Add activity list in ProcessorDict
inGSettings["ProcessorDict"]["ActivityList"]+=lActivityList
return lGUIDStr
## Process defs
def ProcessIsStarted(inProcessNameWOExeStr): # Check if process is started
@ -897,6 +1118,85 @@ def ProcessListGet(inProcessNameWOExeList=None):
pass
return lResult
def ProcessDefIntervalCall(inGSettings, inDef, inIntervalSecFloat, inIntervalAsyncBool=False, inDefArgList=None, inDefArgDict=None, inDefArgGSettingsNameStr=None, inDefArgLoggerNameStr=None, inExecuteInNewThreadBool=True, inLogger=None):
"""
Use this procedure if you need to run periodically some def. Set def, args, interval and enjoy :)
:param inGSettings: global settings
:param inDef: def link, which will be called with interval inIntervalSecFloat
:param inIntervalSecFloat: Interval in seconds between call
:param inIntervalAsyncBool: False - wait interval before next call after the previous iteration result; True - wait interval after previous iteration call
:param inDefArgList: List of the args in def. Default None (empty list)
:param inDefArgDict: Dict of the args in def. Default None (empty dict)
:param inDefArgGSettingsNameStr: Name of the GSettings arg name for def (optional)
:param inDefArgLoggerNameStr: Name of the Logger arg name for def (optional). If Use - please check fill of the inLogger arg.
:param inExecuteInNewThreadBool: True - create new thread for the periodic execution; False - execute in current thread. Default: True
:param inLogger: logging def if some case is appear
:return:
"""
#Some edits on start
if inDefArgDict is None: inDefArgDict = {}
if inDefArgList is None: inDefArgList = []
# Check if inDefArgLogger is set and inLogger is exist
if inDefArgLoggerNameStr=="": inDefArgLoggerNameStr=None
if inDefArgGSettingsNameStr=="": inDefArgGSettingsNameStr=None
if inDefArgLoggerNameStr is not None and not inLogger:
raise Exception(f"!ERROR! ProcessDefIntervalCall - You need to send logger in def because your def is require logger. Raise error!")
# Check thread
if not Core.IsProcessorThread(inGSettings=inGSettings):
if inGSettings["Logger"]: inGSettings["Logger"].warning(f"__Orchestrator__.ProcessDefIntervalCall def was called not from processor queue - activity will be append in the processor queue.")
lProcessorActivityDict = {
"Def": ProcessDefIntervalCall, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {"inDef": inDef, "inIntervalSecFloat": inIntervalSecFloat,
"inIntervalAsyncBool":inIntervalAsyncBool, "inDefArgList": inDefArgList,
"inDefArgDict": inDefArgDict, "inDefArgGSettingsNameStr":inDefArgGSettingsNameStr,
"inDefArgLoggerNameStr": inDefArgLoggerNameStr, "inExecuteInNewThreadBool": inExecuteInNewThreadBool}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": "inLogger" # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
inGSettings["ProcessorDict"]["ActivityList"].append(lProcessorActivityDict)
else:
# Internal def to execute periodically
def __Execute__(inGSettings, inDef, inIntervalSecFloat, inIntervalAsyncBool, inDefArgList, inDefArgDict, inLogger, inDefArgGSettingsNameStr, inDefArgLoggerNameStr):
if inLogger: inLogger.info(f"__Orchestrator__.ProcessDefIntervalCall: Interval execution has been started. Def: {str(inDef)}")
# Prepare gSettings and logger args
if inDefArgGSettingsNameStr is not None:
inDefArgDict[inDefArgGSettingsNameStr] = inGSettings
if inDefArgLoggerNameStr is not None:
inDefArgDict[inDefArgLoggerNameStr] = inLogger
while True:
try:
# Call async if needed
if inIntervalAsyncBool == False: # Case wait result then wait
inDef(*inDefArgList, **inDefArgDict)
else: # Case dont wait result - run sleep then new iteration (use many threads)
lThread2 = threading.Thread(target=inDef,
args=inDefArgList,
kwargs=inDefArgDict)
lThread2.start()
except Exception as e:
if inLogger: inLogger.exception(
f"ProcessDefIntervalCall: Interval call has been failed. Traceback is below. Code will sleep for the next call")
# Sleep interval
time.sleep(inIntervalSecFloat)
# Check to call in new thread
if inExecuteInNewThreadBool:
lThread = threading.Thread(target=__Execute__,
kwargs={"inGSettings":inGSettings, "inDef": inDef, "inIntervalSecFloat": inIntervalSecFloat,
"inIntervalAsyncBool": inIntervalAsyncBool, "inDefArgList": inDefArgList,
"inDefArgDict": inDefArgDict, "inLogger": inLogger,
"inDefArgGSettingsNameStr":inDefArgGSettingsNameStr , "inDefArgLoggerNameStr":inDefArgLoggerNameStr})
lThread.start()
else:
__Execute__(inGSettings=inGSettings, inDef=inDef, inIntervalSecFloat=inIntervalSecFloat, inIntervalAsyncBool=inIntervalAsyncBool,
inDefArgList=inDefArgList, inDefArgDict=inDefArgDict, inLogger=inLogger,
inDefArgGSettingsNameStr=inDefArgGSettingsNameStr , inDefArgLoggerNameStr=inDefArgLoggerNameStr)
# Python def - start module function
def PythonStart(inModulePathStr, inDefNameStr, inArgList=None, inArgDict=None, inLogger = None):
"""
@ -1602,24 +1902,28 @@ def GSettingsAutocleaner(inGSettings):
else:
if lL: lL.debug(f"Client > Session > TechnicalSessionGUIDCache > lItemKeyStr: Lifetime is expired. Remove from gSettings") # Info
inGSettings["Client"]["Session"]["TechnicalSessionGUIDCache"] = lTechnicalSessionGUIDCacheNew # Set updated Cache
# Clean old items in AgentActivityReturnDict > GUIDStr > ReturnedByDatetime
lTechnicalAgentActivityReturnDictNew = {}
for lItemKeyStr in inGSettings["AgentActivityReturnDict"]:
lItemValue = inGSettings["AgentActivityReturnDict"][lItemKeyStr]
if (lNowDatetime - lItemValue["ReturnedByDatetime"]).total_seconds() < inGSettings["Autocleaner"]["AgentActivityReturnLifetimeSecFloat"]: # Add if lifetime is ok
lTechnicalAgentActivityReturnDictNew[lItemKeyStr]=lItemValue # Lifetime is ok - set
else:
if lL: lL.debug(f"AgentActivityReturnDict lItemKeyStr: Lifetime is expired. Remove from gSettings") # Info
inGSettings["AgentActivityReturnDict"] = lTechnicalAgentActivityReturnDictNew # Set updated Cache
# # # # # # # # # # # # # # # # # # # # # # # # # #
from .. import __version__ # Get version from the package
def Orchestrator(inGSettings):
def Orchestrator(inGSettings, inDumpRestoreBool = True, inRunAsAdministratorBool = True):
lL = inGSettings["Logger"]
# https://stackoverflow.com/questions/130763/request-uac-elevation-from-within-a-python-script
def is_admin():
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except:
return False
if not is_admin():
# Re-run the program with admin rights
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
if not OrchestratorIsAdmin() and inRunAsAdministratorBool==True:
OrchestratorRerunAsAdmin()
else:
# Code of your program here
#mGlobalDict = Settings.Settings(sys.argv[1])
global gSettingsDict
gSettingsDict = inGSettings # Alias for old name in alg
inGSettings["VersionStr"] = __version__
#Logger alias
@ -1632,17 +1936,9 @@ def Orchestrator(inGSettings):
Server.gSettingsDict = gSettingsDict
Server.ProcessorOld.gSettingsDict = gSettingsDict # Backward compatibility
# Check _SessionLast_RDPList.json in working directory. if exist - load into gsettings
# GSettings
#"RobotRDPActive": {
# "RDPList": {
if os.path.exists("_SessionLast_RDPList.json"):
lFile = open("_SessionLast_RDPList.json", "r", encoding="utf-8")
lSessionLastRDPList = json.loads(lFile.read())
lFile.close() # Close the file
os.remove("_SessionLast_RDPList.json") # remove the temp file
gSettingsDict["RobotRDPActive"]["RDPList"]=lSessionLastRDPList # Set the last session dict
if lL: lL.warning(f"RDP Session List was restored from previous Orchestrator session")
#Backward compatibility - restore in Orc def if old def
if inDumpRestoreBool == True:
OrchestratorSessionRestore(inGSettings=inGSettings)
# Init SettingsUpdate defs from file list (after RDP restore)
lSettingsUpdateFilePathList = gSettingsDict.get("OrchestratorStart", {}).get("DefSettingsUpdatePathList",[])
@ -1714,10 +2010,19 @@ def Orchestrator(inGSettings):
lProcessorThread.start() # Start the thread execution.
if lL: lL.info("Processor has been started (ProcessorDict)") #Logging
# Processor monitor thread
lProcessorMonitorThread = threading.Thread(target= Processor.ProcessorMonitorRunSync, kwargs={"inGSettings":gSettingsDict})
lProcessorMonitorThread.daemon = True # Run the thread in daemon mode.
lProcessorMonitorThread.start() # Start the thread execution.
if lL: lL.info("Processor monitor has been started") #Logging
if lL: lL.info("Scheduler loop start") #Logging
gDaemonActivityLogDictRefreshSecInt = 10 # The second period for clear lDaemonActivityLogDict from old items
gDaemonActivityLogDictLastTime = time.time() # The second perioad for clean lDaemonActivityLogDict from old items
# Set flag that orchestrator has been initialized
inGSettings["HiddenIsOrchestratorInitializedBool"] = True
while True:
try:
lCurrentDateTime = datetime.datetime.now()

@ -3,7 +3,7 @@ r"""
The OpenRPA package (from UnicodeLabs)
"""
__version__ = 'v1.2.1'
__version__ = 'v1.2.2'
__all__ = []
__author__ = 'Ivan Maslov <ivan.maslov@unicodelabs.ru>'
#from .Core import Robot

@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: pyOpenRPA
Version: 1.2.1
Version: 1.2.2
Summary: First open source RPA platform for business
Home-page: https://gitlab.com/UnicodeLabs/OpenRPA
Author: Ivan Maslov
@ -11,6 +11,8 @@ Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: License :: OSI Approved :: MIT License
Classifier: Intended Audience :: Developers
Classifier: Environment :: Win32 (MS Windows)
Classifier: Environment :: X11 Applications
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.7
Classifier: Topic :: Software Development :: Libraries :: Python Modules
@ -19,13 +21,13 @@ Classifier: Topic :: Software Development :: User Interfaces
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Home Automation
Description-Content-Type: text/markdown
Requires-Dist: pywinauto (>=0.6.8)
Requires-Dist: WMI (>=1.4.9)
Requires-Dist: pillow (>=6.0.0)
Requires-Dist: keyboard (>=0.13.3)
Requires-Dist: pyautogui (>=0.9.44)
Requires-Dist: pywin32 (>=224)
Requires-Dist: crypto (>=1.4.1)
Requires-Dist: pywin32 (>=224) ; platform_system == "Linux" and python_version >= "3.0"
Requires-Dist: pywinauto (>=0.6.8) ; platform_system == "win32" and python_version >= "3.0"
Requires-Dist: WMI (>=1.4.9) ; platform_system == "win32" and python_version >= "3.0"
# OpenRPA
First open source RPA platform for business is released!

@ -1,13 +1,19 @@
pyOpenRPA-1.2.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pyOpenRPA-1.2.1.dist-info/METADATA,sha256=aGWBieAGB-PR9Na_bh8FhdPn3YzwX3vK7HMtIzU2YeE,3351
pyOpenRPA-1.2.1.dist-info/RECORD,,
pyOpenRPA-1.2.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA-1.2.1.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97
pyOpenRPA-1.2.1.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10
pyOpenRPA/Agent/A2O.py,sha256=Ee72BuVpmXgoNTUInqAj1xVdC4JoWCQ0d0lTlijKyuA,1225
pyOpenRPA/Agent/O2A.py,sha256=IONoht1jb2b7JFT5syelVPq88z7TTLPZjcdH7SrR7rk,2612
pyOpenRPA/Agent/Processor.py,sha256=FtU7IGIev2_po_fkJTH2KNYZap6IVFODM30qiqBNsm4,4146
pyOpenRPA/Agent/__Agent__.py,sha256=VxQsuyItFvgXaDKahEKbG6hGgmpNGJFHRTYGGdP7J-A,4916
pyOpenRPA-1.2.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pyOpenRPA-1.2.2.dist-info/METADATA,sha256=Oy6DxZeOruRyWkROJ9if7MI8zheBqEqlBEFBhj1zRbU,3612
pyOpenRPA-1.2.2.dist-info/RECORD,,
pyOpenRPA-1.2.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA-1.2.2.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97
pyOpenRPA-1.2.2.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10
pyOpenRPA/.idea/inspectionProfiles/profiles_settings.xml,sha256=YXLFmX7rPNGcnKK1uX1uKYPN0fpgskYNe7t0BV7cqkY,174
pyOpenRPA/.idea/misc.xml,sha256=V-fQnOz-bYEZULgfbFgm-8mURphZrKfXMSd0wKjeEyA,188
pyOpenRPA/.idea/modules.xml,sha256=Q__U1JIA2cjxbLRXAv-SfYY00fZA0TNlpkkbY4s3ncg,277
pyOpenRPA/.idea/pyOpenRPA.iml,sha256=EXh41F8lqRiSBMVg-n2tKaEaHC6_3gGSuKkPJA12Na0,408
pyOpenRPA/.idea/vcs.xml,sha256=2HygA1oRAwc3VBf-irxHrX5JJG9DXuQwrN0BlubhoKY,191
pyOpenRPA/.idea/workspace.xml,sha256=6tJZehshdK4And6tEoUvkIB0KE7waL_NnTSkTYYAeFA,3802
pyOpenRPA/Agent/A2O.py,sha256=ZVXNamhKOB1y3j9b4gp_rzJq55Nr5pBGeoBgMnCtNKc,1657
pyOpenRPA/Agent/O2A.py,sha256=4W2bbU34MBmuveXkPvkCzmzKAryR_YB-gnA013fxMoY,3356
pyOpenRPA/Agent/Processor.py,sha256=Co8nWpffgsnEE_TpG9WrpKxz3N0sDF7eFnKxDOk1sd8,4653
pyOpenRPA/Agent/__Agent__.py,sha256=Id75cxA6kwed1r8NaLWHfYIyUrTZx7RPlxw1PdzropI,10006
pyOpenRPA/Agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Agent/__pycache__/A2O.cpython-37.pyc,,
pyOpenRPA/Agent/__pycache__/O2A.cpython-37.pyc,,
@ -16,17 +22,18 @@ pyOpenRPA/Agent/__pycache__/__Agent__.cpython-37.pyc,,
pyOpenRPA/Agent/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Agent/readme.md,sha256=QF_Bnv204OK3t1JUEhjfICkxFmSdX6bvaRl_HI6lH9I,19
pyOpenRPA/Info.md,sha256=u4Nv-PjniSF0Zlbtr6jEJX2vblK3_1zhSLNUgOdtDaA,85
pyOpenRPA/Orchestrator/BackwardCompatibility.py,sha256=lzV3kinWlde5Fs4tBYqyKWetBLM4yEo6nbXmLC-fFaA,30159
pyOpenRPA/Orchestrator/BackwardCompatibility.py,sha256=3EhSlSMoDB9Po7lfllmgXn4LbwhVuPzLszR6P1pHU_M,32440
pyOpenRPA/Orchestrator/ControlPanel.py,sha256=OzS8HjG__8OZgqhajr8L8owyugXPuSLWHLtXuKdEP78,103
pyOpenRPA/Orchestrator/Core.py,sha256=Q0n05GuySXDPy3V7qeYQON0kYEyWogZWhYevSjY4q2s,189
pyOpenRPA/Orchestrator/Processor.py,sha256=8T10Qos4_GT7Qvhh8q59JPCuUyHbic087y_xBK9lM_4,6645
pyOpenRPA/Orchestrator/Core.py,sha256=Kjphtu0g6iaS4D_fIWmzRaLLgBQ9fcwccpQJhOETTAc,521
pyOpenRPA/Orchestrator/Processor.py,sha256=Z1SglmX6ykTLifD3M1mzWEJQUgweWo6HjjCjHldjGyM,8594
pyOpenRPA/Orchestrator/ProcessorOld.py,sha256=Vh5zLRpWWf-vt9CCYI8nDY7oaefiufnu6Pnl4tp27pY,13749
pyOpenRPA/Orchestrator/RobotRDPActive/CMDStr.py,sha256=6otw1WnR2_evvQ5LGyOVh0BLk_nTdilViGub7p56fXQ,1531
pyOpenRPA/Orchestrator/RobotRDPActive/Clipboard.py,sha256=YB5HJL-Qf4IlVrFHyRv_ZMJ0Vo4vjyYqWKjvrTnf1k4,1564
pyOpenRPA/Orchestrator/RobotRDPActive/Connector.py,sha256=Qwf194uO_wcO3kBe2hTI0py90ZC1ejDUGeh6UWEfavc,27789
pyOpenRPA/Orchestrator/RobotRDPActive/ConnectorExceptions.py,sha256=wwH9JOoMFFxDKQ7IyNyh1OkFkZ23o1cD8Jm3n31ycII,657
pyOpenRPA/Orchestrator/RobotRDPActive/Processor.py,sha256=AQ_u9QVSLpce9hhSacm3UT98bErc636MXza4Q6mHsSc,12264
pyOpenRPA/Orchestrator/RobotRDPActive/RobotRDPActive.py,sha256=pbffSPsUzzaFMevNQ0P24NA0cdJg9KwtyHscnWYQc_M,10769
pyOpenRPA/Orchestrator/RobotRDPActive/Recovery.py,sha256=jneD474V-ZBYnmQFxWoY_feGNMSL0lGaRK6TEfQ6gOc,2954
pyOpenRPA/Orchestrator/RobotRDPActive/RobotRDPActive.py,sha256=5FX48HlIn8NKfs7q_rp3lpumWtNcwdHq7J8ygnOwU_g,12284
pyOpenRPA/Orchestrator/RobotRDPActive/Scheduler.py,sha256=21N0ilFzWI1mj3X5S9tPMgwvG7BviuBxfTuqBY85Hy4,9144
pyOpenRPA/Orchestrator/RobotRDPActive/Template.rdp,sha256=JEMVYkEmNcfg_p8isdIyvj9E-2ZB5mj-R3MkcNMKxkA,2426
pyOpenRPA/Orchestrator/RobotRDPActive/Timer.py,sha256=y8--fUvg10qEFomecl_cmdWpdGjarZBlFpMbs_GvzoQ,1077
@ -37,6 +44,7 @@ pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Clipboard.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Connector.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/ConnectorExceptions.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Processor.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Recovery.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/RobotRDPActive.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Scheduler.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Timer.cpython-37.pyc,,
@ -51,20 +59,20 @@ pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/Monitor.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/Screen.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Server.py,sha256=mx4AXf5xEoi9LLKgrJ4s0h20ElcBmsntzZbI99LfboU,28462
pyOpenRPA/Orchestrator/ServerSettings.py,sha256=TZMoxB090UkNOCQ3ve0KBcrdM7YH6LTFz3ErVU42wTQ,28499
pyOpenRPA/Orchestrator/SettingsTemplate.py,sha256=p7J8xXSN6xdyMTd-OrkTu7JQGLn6t7tJpPp2CPybA-w,19955
pyOpenRPA/Orchestrator/Server.py,sha256=301ws0BtUhz_HIghP7alHkotLCUXbJhi8fb2Wn0H8EU,29345
pyOpenRPA/Orchestrator/ServerSettings.py,sha256=-WiQXhfSdS4-eKbFp4U6NBylyRtJ0a6AVdds3KT3H9Q,31004
pyOpenRPA/Orchestrator/SettingsTemplate.py,sha256=R8o3_4z2TavV3i0KSz-d_oQx-U4qsrQFHvVmZFOnmnQ,20238
pyOpenRPA/Orchestrator/Timer.py,sha256=HvYtEeH2Q5WVVjgds9XaBpWRmvZgwgBXurJDdVVq_T0,2097
pyOpenRPA/Orchestrator/Utils/LoggerHandlerDumpLogList.py,sha256=hD47TiOuKR-G8IWu9lJD2kG28qlH7YZV63i3qv1N5Dk,681
pyOpenRPA/Orchestrator/Utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Orchestrator/Utils/__pycache__/LoggerHandlerDumpLogList.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Utils/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Web/Basic.py,sha256=UUiV3Rp__i8EVADK-SvIhlVmLzOzW4gpCq1eBpqU4cA,6482
pyOpenRPA/Orchestrator/Web/Index.js,sha256=DtvpHDBT3_XvJpdKUREpGT1NR3lKdBs9ER4HPvlfwhE,39036
pyOpenRPA/Orchestrator/Web/Basic.py,sha256=pPH55rPwZz1ktpzNIcC51jeV2MgZI10Zf0Q0DncihDw,7757
pyOpenRPA/Orchestrator/Web/Index.js,sha256=Blo3LHe_a3zrW7MqYo4BSIwoOx7nlO7Ko9LWxfeqU_o,39090
pyOpenRPA/Orchestrator/Web/Index.xhtml,sha256=a4N_reLA6_Zb2KXiL73a7cWtJwO0W0Dr5lZ-RpUwuI0,16428
pyOpenRPA/Orchestrator/Web/__pycache__/Basic.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Web/favicon.ico,sha256=6S8XwSQ_3FXPpaX6zYkf8uUewVXO9bHnrrDHEoWrEgw,112922
pyOpenRPA/Orchestrator/__Orchestrator__.py,sha256=QSbaJT1U5L3UE_yNBsPzqJfwdy6Xycb8Tvf6r8OUbSQ,90464
pyOpenRPA/Orchestrator/__Orchestrator__.py,sha256=WTPCLcAGunuIJ-6fAfMTXtboAvhuZUCHm2vf3h6kS8U,109030
pyOpenRPA/Orchestrator/__init__.py,sha256=f1RFDzOkL3IVorCtqogjGdXYPtHH-P-y-5CqT7PGy7A,183
pyOpenRPA/Orchestrator/__main__.py,sha256=czJrc7_57WiO3EPIYfPeF_LG3pZsQVmuAYgbl_YXcVU,273
pyOpenRPA/Orchestrator/__pycache__/BackwardCompatibility.cpython-37.pyc,,
@ -333,6 +341,6 @@ pyOpenRPA/Tools/Terminator.py,sha256=VcjX3gFXiCGu3MMCidhrTNsmC9wsAqfjRJdTSU9fLnU
pyOpenRPA/Tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Tools/__pycache__/Terminator.cpython-37.pyc,,
pyOpenRPA/Tools/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/__init__.py,sha256=F-Q2H4aCcjl9IIkTWH_9aXSwQnCjgjm7DSSRyKV9MbM,174
pyOpenRPA/__init__.py,sha256=ZiHtLttT3HWPDuXjwYNe06oadFPTLrVMTKyaMXZAmBE,174
pyOpenRPA/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/test.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0

@ -25,3 +25,9 @@ def _A2ODataSend(inGSettings, inDataDict):
def LogListSend(inGSettings, inLogList):
lDataDict = { "HostNameUpperStr": inGSettings["AgentDict"]["HostNameUpperStr"], "UserUpperStr": inGSettings["AgentDict"]["UserUpperStr"], "LogList": inLogList}
_A2ODataSend(inGSettings=inGSettings, inDataDict=lDataDict)
# Send some def result to the orchestrator by the Activity Item GUID str
def ActivityReturnDictSend(inGSettings, inActivityItemGUIDStr, inReturn):
lDataDict = {"HostNameUpperStr": inGSettings["AgentDict"]["HostNameUpperStr"],
"UserUpperStr": inGSettings["AgentDict"]["UserUpperStr"], "ActivityReturnDict": {inActivityItemGUIDStr:inReturn}}
_A2ODataSend(inGSettings=inGSettings, inDataDict=lDataDict)

@ -1,4 +1,4 @@
import requests, time
import requests, time, json
# O2A - Data flow Orchestrator to Agent
# f"{lProtocolStr}://{lHostStr}:{lPortInt}/pyOpenRPA/Agent/O2A"
@ -16,26 +16,36 @@ import requests, time
def O2A_Loop(inGSettings):
lL = inGSettings["Logger"]
lActivityLastGUIDStr = "" # Init empty ActivityLastGUIDStr
while inGSettings["O2ADict"]["IsOnlineBool"]:
# Send request to the orchestrator server
lRequestBody = None
try:
lProtocolStr= "https" if inGSettings["OrchestratorDict"]["IsHTTPSBool"] else "http"
lHostStr = inGSettings["OrchestratorDict"]["HostStr"]
lPortInt = inGSettings["OrchestratorDict"]["PortInt"]
lURLStr=f"{lProtocolStr}://{lHostStr}:{lPortInt}/pyOpenRPA/Agent/O2A"
lDataDict = { "HostNameUpperStr": inGSettings["AgentDict"]["HostNameUpperStr"], "UserUpperStr": inGSettings["AgentDict"]["UserUpperStr"]}
lDataDict = { "HostNameUpperStr": inGSettings["AgentDict"]["HostNameUpperStr"], "UserUpperStr": inGSettings["AgentDict"]["UserUpperStr"], "ActivityLastGUIDStr": lActivityLastGUIDStr}
lResponse = requests.post(url= lURLStr, cookies = {"AuthToken":inGSettings["OrchestratorDict"]["SuperTokenStr"]}, json=lDataDict)
if lResponse.status_code != 200:
if lL: lL.warning(f"Agent can not connect to Orchestrator. Below the response from the orchestrator:{lResponse}")
time.sleep(inGSettings["O2ADict"]["RetryTimeoutSecFloat"])
else:
lRequestBody = lResponse.text
lQueueItem = lResponse.json() # Try to get JSON
# Append QUEUE item in ProcessorDict > ActivityList
lActivityLastGUIDStr = lQueueItem["GUIDStr"]
inGSettings["ProcessorDict"]["ActivityList"].append(lQueueItem)
if lL: lL.debug(f"ActivityItem was recieved from orchestrator: {lQueueItem}");
except Exception as e:
if lL: lL.exception(f"A2O Error handler. Sleep for {inGSettings['A2ODict']['RetryTimeoutSecFloat']} s.")
time.sleep(inGSettings["O2ADict"]["RetryTimeoutSecFloat"])
if lL: lL.debug(f"ActivityItem was received from orchestrator: {lQueueItem}");
except requests.exceptions.ConnectionError as e:
if lL: lL.error(f"A2O Connection error - orchestrator is not available. Sleep for {inGSettings['A2ODict']['RetryTimeoutSecFloat']} s.")
if lL: lL.error(f"O2A Connection error - orchestrator is not available. Sleep for {inGSettings['A2ODict']['RetryTimeoutSecFloat']} s.")
time.sleep(inGSettings["O2ADict"]["RetryTimeoutSecFloat"])
except ConnectionResetError as e:
if lL: lL.error(f"O2A Connection error - orchestrator is not available. Sleep for {inGSettings['A2ODict']['RetryTimeoutSecFloat']} s.")
time.sleep(inGSettings["O2ADict"]["RetryTimeoutSecFloat"])
except json.decoder.JSONDecodeError as e:
if lL: lL.error(f"See body of the recieved content from the Orchestrator: {lRequestBody}")
time.sleep(inGSettings["O2ADict"]["RetryTimeoutSecFloat"])
except Exception as e:
if lL: lL.exception(f"O2A Error handler. Sleep for {inGSettings['A2ODict']['RetryTimeoutSecFloat']} s.")
time.sleep(inGSettings["O2ADict"]["RetryTimeoutSecFloat"])

@ -1,5 +1,6 @@
# 1.2.0 - general processor - contains old orchestrator processor + RDPActive processor
import time, copy, threading
from . import A2O
# Run processor synchronious
def ProcessorRunSync(inGSettings):
"""
@ -10,7 +11,8 @@ def ProcessorRunSync(inGSettings):
# "ArgList":[1,2,3], # Args list
# "ArgDict":{"ttt":1,"222":2,"dsd":3}, # Args dictionary
# "ArgGSettings": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "ArgLogger": None, # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "GUIDStr": "sadasd-asdas-d-asdasd", # ActivityItem GUID which identify the Activity
# },
],
"AliasDefDict": {}, # Storage for def with Str alias. To use it see pyOpenRPA.Orchestrator.ControlPanel
@ -24,7 +26,13 @@ def ProcessorRunSync(inGSettings):
if len(lActivityList)>0:
if lL: lL.debug(f'Processor ActivityList len: {len(lActivityList)}')
lActivityItem = inGSettings["ProcessorDict"]["ActivityList"].pop(0) # Extract the first item from processor queue
ActivityListExecute(inGSettings = inGSettings, inActivityList = [lActivityItem]) # execute the activity item
lResultList = ActivityListExecute(inGSettings = inGSettings, inActivityList = [lActivityItem]) # execute the activity item
#Some help code
if len(lResultList) == 0: lResultList= [None]
# Send result to Orc if we have GUIDStr
if "GUIDStr" in lActivityItem:
# Def to send to Orc
A2O.ActivityReturnDictSend(inGSettings=inGSettings, inActivityItemGUIDStr=lActivityItem["GUIDStr"],inReturn=lResultList[0])
else:
time.sleep(inGSettings["ProcessorDict"]["CheckIntervalSecFloat"]) # Sleep when list is empty
@ -61,5 +69,5 @@ def ActivityListExecute(inGSettings, inActivityList):
lResultList.append(lActivityItemResult) # return the result
except Exception as e:
if lL: lL.exception(f"Processor.ActivityListExecute: Exception in def execution - activity will be ignored. Activity item: {lActivityItem}") # Logging
lResultList.append(e) # return the generated exception
lResultList.append(None) # return the generated exception
return lResultList # return the result list

@ -1,10 +1,14 @@
import threading, socket, getpass, sys, uuid, subprocess, base64
import threading, socket, getpass, sys, uuid, subprocess, base64, psutil, getpass, time
from . import O2A, A2O # Data flow Orchestrator To Agent
from . import Processor # Processor Queue
from subprocess import CREATE_NEW_CONSOLE # Flag to create new process in another CMD
# Create binary file by the base64 string (safe for JSON transmition)
def OSFileBinaryDataBase64StrCreate(inFilePathStr, inFileDataBase64Str,inGSettings = None):
""" Create binary file by the base64 string (safe for JSON transmition)"""
"""
Create binary file by the base64 string (safe for JSON transmition)
"""
lFile = open(inFilePathStr, "wb")
lFile.write(base64.b64decode(inFileDataBase64Str))
lFile.close()
@ -15,6 +19,15 @@ def OSFileBinaryDataBase64StrCreate(inFilePathStr, inFileDataBase64Str,inGSettin
# Create text file by the string
def OSFileTextDataStrCreate(inFilePathStr, inFileDataStr, inEncodingStr = "utf-8",inGSettings = None):
"""
Create text file in the agent GUI session
:param inFilePathStr: File abs path
:param inFileDataStr: File data text content
:param inEncodingStr: Write file encoding
:param inGSettings: global settings of the Agent (singleton)
:return:
"""
lFile = open(inFilePathStr, "w", encoding=inEncodingStr)
lFile.write(inFileDataStr)
lFile.close()
@ -23,15 +36,67 @@ def OSFileTextDataStrCreate(inFilePathStr, inFileDataStr, inEncodingStr = "utf-8
if lL: lL.info(lMessageStr)
A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
def OSFileBinaryDataBase64StrReceive(inFilePathStr, inGSettings=None):
"""
Read binary file and encode in base64 to transmit (safe for JSON transmition)
:param inFilePathStr: File path to read
:param inGSettings: global settings of the Agent (singleton)
:return: File content in string base64 format (use base64.b64decode to decode data). Return None if file is not exist
"""
lFile = open(inFilePathStr, "rb")
lFileDataBytes = lFile.read()
lFile.close()
lFileDataBase64Str = base64.b64encode(lFileDataBytes).decode("utf-8")
lL = inGSettings.get("Logger", None) if type(inGSettings) is dict else None
lMessageStr = f"AGENT Binary file {inFilePathStr} has been read."
if lL: lL.info(lMessageStr)
A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
return lFileDataBase64Str
def OSFileTextDataStrReceive(inFilePathStr, inEncodingStr="utf-8", inGSettings=None):
"""
Read text file in the agent GUI session
:param inFilePathStr: File abs path
:param inEncodingStr: Read file encoding. Default utf-8
:param inGSettings: global settings of the Agent (singleton)
:return: File text content in string format (use base64.b64decode to decode data). Return None if file is not exist
"""
lFile = open(inFilePathStr, "r", encoding=inEncodingStr)
lFileDataStr = lFile.read()
lFile.close()
lL = inGSettings.get("Logger", None) if type(inGSettings) is dict else None
lMessageStr = f"AGENT Text file {inFilePathStr} has been read."
if lL: lL.info(lMessageStr)
A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
return lFileDataStr
# Send CMD to OS. Result return to log + Orchestrator by the A2O connection
def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None):
def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None, inSendOutputToOrchestratorLogsBool = True, inCMDEncodingStr = "cp1251"):
"""
Execute CMD on the Agent daemonic process
:param inCMDStr: command to execute on the Agent session
:param inRunAsyncBool: True - Agent processor don't wait execution; False - Agent processor wait cmd execution
:param inGSettings: Agent global settings dict
:param inSendOutputToOrchestratorLogsBool: True - catch cmd execution output and send it to the Orchestrator logs; Flase - else case; Default True
!ATTENTION! If you need to start absolutely encapsulated app - set this flag as False. If you set True - the app output will come to Agent
:param inCMDEncodingStr: Set the encoding of the DOS window on the Agent server session. Windows is beautiful :) . Default is "cp1251" early was "cp866" - need test
:return:
"""
lResultStr = ""
# Subdef to listen OS result
def _CMDRunAndListenLogs(inCMDStr, inGSettings = None):
def _CMDRunAndListenLogs(inCMDStr, inSendOutputToOrchestratorLogsBool, inCMDEncodingStr, inGSettings = None):
lL = inGSettings.get("Logger",None) if type(inGSettings) is dict else None
lResultStr = ""
lOSCMDKeyStr = str(uuid.uuid4())[0:4].upper()
lCMDProcess = None
if inSendOutputToOrchestratorLogsBool == True:
lCMDProcess = subprocess.Popen(f'cmd /c {inCMDStr}', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
else:
lCMDProcess = subprocess.Popen(f'cmd /c {inCMDStr}', stdout=None, stderr=None,
creationflags=CREATE_NEW_CONSOLE)
lListenBool = True
lMessageStr = f"{lOSCMDKeyStr}: # # # # AGENT CMD Process has been STARTED # # # # "
if lL: lL.info(lMessageStr)
@ -40,32 +105,64 @@ def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None):
if lL: lL.info(lMessageStr)
A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
while lListenBool:
if inSendOutputToOrchestratorLogsBool == True: # Capturing can be turned on!
lOutputLineBytes = lCMDProcess.stdout.readline()
if lOutputLineBytes == b"":
lListenBool = False
lStr = lOutputLineBytes.decode('cp866')
lStr = lOutputLineBytes.decode(inCMDEncodingStr) # was cp866, on win server don't work properly - set cp1251
if lStr.endswith("\n"): lStr = lStr[:-1]
lMessageStr = f"{lOSCMDKeyStr}: {lStr}"
if lL: lL.info(lMessageStr)
A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
lResultStr+=lStr
else: #Capturing is not turned on - wait until process will be closed
lCMDProcessPoll = lCMDProcess.poll()
if lCMDProcessPoll is None: # Process is alive - wait
time.sleep(2)
else:
lListenBool = False
lMessageStr = f"{lOSCMDKeyStr}: # # # # AGENT CMD Process has been FINISHED # # # # "
if lL: lL.info(lMessageStr)
A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
return lResultStr
# New call
if inRunAsyncBool:
lThread = threading.Thread(target=_CMDRunAndListenLogs, kwargs={"inCMDStr":inCMDStr, "inGSettings":inGSettings})
lThread = threading.Thread(target=_CMDRunAndListenLogs, kwargs={"inCMDStr":inCMDStr, "inGSettings":inGSettings, "inSendOutputToOrchestratorLogsBool":inSendOutputToOrchestratorLogsBool, "inCMDEncodingStr":inCMDEncodingStr })
lThread.start()
lResultStr="ActivityList has been started in async mode - no output is available here."
else:
lResultStr = _CMDRunAndListenLogs(inCMDStr=inCMDStr, inGSettings=inGSettings)
lResultStr = _CMDRunAndListenLogs(inCMDStr=inCMDStr, inGSettings=inGSettings, inSendOutputToOrchestratorLogsBool = inSendOutputToOrchestratorLogsBool, inCMDEncodingStr = inCMDEncodingStr)
#lCMDCode = "cmd /c " + inCMDStr
#subprocess.Popen(lCMDCode)
#lResultCMDRun = 1 # os.system(lCMDCode)
return lResultStr
def ProcessWOExeUpperUserListGet():
"""
Return the process list only for the current user (where Agent is running) without .EXE in upper case. Can use in ActivityItem from Orchestrator to Agent
:param inProcessNameWOExeList:
:return: list of the agent user process in upper case without .EXE. Example ["NOTEPAD","..."],
"""
lUserNameStr = getpass.getuser()
lResult = []
# Create updated list for quick check
lProcessNameWOExeList = []
# Iterate over the list
for proc in psutil.process_iter():
try:
# Fetch process details as dict
pinfo = proc.as_dict(attrs=['pid', 'name', 'username'])
# Add if empty inProcessNameWOExeList or if process in inProcessNameWOExeList
lUserNameWODomainStr = proc.username().split('\\')[-1]
if lUserNameWODomainStr == lUserNameStr:
lResult.append(pinfo['name'][:-4].upper())
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
pass
return lResult
# Main def
def Agent(inGSettings):
lL = inGSettings["Logger"]

@ -421,4 +421,37 @@ def Update(inGSettings):
# Remove old structure Scheduler
del inGSettings["Scheduler"]
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Convert Scheduler to SchedulerDict with new features") # Log about compatibility
# # Convert to Storage to StorageDict
if "Storage" in inGSettings:
# Check if Server is active > convert to ServerDict
inGSettings["StorageDict"] = inGSettings["Storage"]
if lL: lL.warning(
f"Backward compatibility (v1.2.1 to v1.2.2): Convert Storage to StorageDict") # Log about compatibility
# Remove old structure Scheduler
del inGSettings["Storage"]
# Add new key WarningExecutionMoreThanSecFloat in ProcessorDict
if "WarningExecutionMoreThanSecFloat" not in inGSettings["ProcessorDict"]:
inGSettings["ProcessorDict"]["WarningExecutionMoreThanSecFloat"] = 60.0
if lL: lL.warning(
f"Backward compatibility (v1.2.1 to v1.2.2): Add key WarningExecutionMoreThanSecFloat in ProcessorDict") # Log about compatibility
# Add new key AgentActivityLifetimeSecFloat, AgentConnectionLifetimeSecFloat, AgentLoopSleepSecFloat in ProcessorDict > ServerDict
if "AgentActivityLifetimeSecFloat" not in inGSettings["ServerDict"]:
inGSettings["ServerDict"]["AgentActivityLifetimeSecFloat"] = 1200.0
inGSettings["ServerDict"]["AgentConnectionLifetimeSecFloat"] = 300.0
inGSettings["ServerDict"]["AgentLoopSleepSecFloat"] = 2.0
if lL: lL.warning(
f"Backward compatibility (v1.2.1 to v1.2.2): Add key AgentActivityLifetimeSecFloat, AgentConnectionLifetimeSecFloat, AgentLoopSleepSecFloat in ProcessorDict > ServerDict") # Log about compatibility
# Add new key RecoveryDict in ProcessorDict > RobotRDPActive
if "RecoveryDict" not in inGSettings["RobotRDPActive"]:
inGSettings["RobotRDPActive"]["RecoveryDict"] = {
"CatchPeriodSecFloat": 1200, # Catch last 10 minutes
"TriggerCountInt": 10, # Activate trigger if for the period orch will catch the reconnect RDP n times
"DoDict": {
"OSRemotePCRestart": True # Do powershell remote restart
},
"__StatisticsDict__": {
# RDPSessionKeyStr : [time.time(), time.time()],
}
}
if lL: lL.warning(
f"Backward compatibility (v1.2.1 to v1.2.2): Add new key RecoveryDict in ProcessorDict > RobotRDPActive") # Log about compatibility

@ -3,3 +3,13 @@ import threading
# Check if current execution is in Processor thread
def IsProcessorThread(inGSettings):
return inGSettings["ProcessorDict"]["ThreadIdInt"] == threading.get_ident()
def IsOrchestratorInitialized(inGSettings):
"""
Check if Orchestrator will be successfully initialized
:param inGSettings: global settings (singleton)
:return:
"""
# Check if gSettings has flag "HiddenOrchestratorInitBool"
return inGSettings.get("HiddenIsOrchestratorInitializedBool", False)

@ -1,5 +1,5 @@
# 1.2.0 - general processor - contains old orchestrator processor + RDPActive processor
import time, copy, threading
import time, copy, threading, uuid
# Run processor synchronious
# inThreadControlDict = {"ThreadExecuteBool":True}
def ProcessorRunSync(inGSettings, inRobotRDPThreadControlDict):
@ -11,7 +11,8 @@ def ProcessorRunSync(inGSettings, inRobotRDPThreadControlDict):
# "ArgList":[1,2,3], # Args list
# "ArgDict":{"ttt":1,"222":2,"dsd":3}, # Args dictionary
# "ArgGSettings": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "ArgLogger": None ,# Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "GUIDStr": ""
# },
],
"AliasDefDict": {}, # Storage for def with Str alias. To use it see pyOpenRPA.Orchestrator.ControlPanel
@ -20,6 +21,7 @@ def ProcessorRunSync(inGSettings, inRobotRDPThreadControlDict):
"""
lL = inGSettings["Logger"] # Logger alias
inGSettings["ProcessorDict"]["ThreadIdInt"] = threading.get_ident() # fill Processor thread id
try:
while inGSettings["ProcessorDict"]["ExecuteBool"]:
lActivityList = inGSettings["ProcessorDict"]["ActivityList"] # Alias
if len(lActivityList)>0:
@ -30,6 +32,8 @@ def ProcessorRunSync(inGSettings, inRobotRDPThreadControlDict):
inRobotRDPThreadControlDict["ThreadExecuteBool"] = True # Continue the RobotRDPActive monitoring
else:
time.sleep(inGSettings["ProcessorDict"]["CheckIntervalSecFloat"]) # Sleep when list is empty
except Exception as e:
if lL: lL.exception(f"Processor.ProcessorRunSync. Something goes very wrong in processor queue. See traceback")
# Execute ActivityItem list
# return the def result
@ -98,3 +102,34 @@ def __ActivityListVerify__(inActivityList):
#CASE NOT LIST
else:
raise Exception(f"pyOpenRPA Processor.__ActivityListVerify__: inActivityList has wrong structure! Details: Your ActivityList is not a list.")
def ProcessorMonitorRunSync(inGSettings):
"""
Periodically check processor queue if task is updating. If one task is more than ... sec - send warning in log
"""
lL = inGSettings["Logger"] # Logger alias
lActiveGUIDStr = None
lActiveTimeStart = time.time()
try:
while True:
if len(inGSettings["ProcessorDict"]["ActivityList"])>0:
lItemDict = inGSettings["ProcessorDict"]["ActivityList"][0]
if "GUIDStr" not in lItemDict:
lGUIDStr = str(uuid.uuid4()) # generate new GUID
lItemDict["GUIDStr"] = lGUIDStr
# Check if GUID is identical
if lItemDict["GUIDStr"]==lActiveGUIDStr:
# Check time
lActiveTimeDeltaSec = time.time() - lActiveTimeStart
# If delta more than Warning limit sec float
lWaitTimeSecFloat = inGSettings["ProcessorDict"]["WarningExecutionMoreThanSecFloat"]
if lActiveTimeDeltaSec > lWaitTimeSecFloat:
if lL: lL.warning(f"Processor.ProcessorMonitorRunSync: Processor wait more than {lWaitTimeSecFloat} sec. Activity def: {lItemDict['Def']}; GUID: {lItemDict['GUIDStr']}")
else:
lActiveGUIDStr = lItemDict["GUIDStr"]
lActiveTimeStart = time.time()
time.sleep(inGSettings["ProcessorDict"]["WarningExecutionMoreThanSecFloat"]) # Sleep when list is empty
except Exception as e:
if lL: lL.exception(
f"Processor.ProcessorMonitorRunSync. Something goes very wrong in processor queue. See traceback")

@ -0,0 +1,60 @@
import time
def RetryMark(inRDPSessionKeyStr, inGSettings):
"""
Set mark that Orch will try to reconnect to RDP
:param inRDPSessionKeyStr: RDP Session key string - to monitor retry count by the RDP Session key
:param inGSettings: Orchestrator global settings dict (singleton)
:return: None
"""
lL = inGSettings.get("Logger", None) # Get the logger instance
# Create List by the RDP Session key if not exists
if inRDPSessionKeyStr not in inGSettings["RobotRDPActive"]["RecoveryDict"]["__StatisticsDict__"]:
inGSettings["RobotRDPActive"]["RecoveryDict"]["__StatisticsDict__"][inRDPSessionKeyStr] = []
inGSettings["RobotRDPActive"]["RecoveryDict"]["__StatisticsDict__"][inRDPSessionKeyStr].append(time.time())
def RetryIsTriggered(inRDPSessionKeyStr, inGSettings):
"""
Check if you can need to init recovery mode for the RDP
:param inRDPSessionKeyStr: RDP Session key string - to monitor retry count by the RDP Session key
:param inGSettings: Orchestrator global settings dict (singleton)
:return: True - Ready to start recovery mode - remotely restart PC; Falsew - else case
"""
lTimeNowFloat = time.time()
lResultBool = False
if inRDPSessionKeyStr in inGSettings["RobotRDPActive"]["RecoveryDict"]["__StatisticsDict__"]:
lTimeNewList = []
lCatchCounterInt = 0
for inTimeItemFloat in inGSettings["RobotRDPActive"]["RecoveryDict"]["__StatisticsDict__"][inRDPSessionKeyStr]:
lTimeDeltaFloat = lTimeNowFloat - inTimeItemFloat
# Remove item if very old
if lTimeDeltaFloat < inGSettings["RobotRDPActive"]["RecoveryDict"]["CatchPeriodSecFloat"]:
lTimeNewList.append(inTimeItemFloat)
lCatchCounterInt = lCatchCounterInt+1
# Set updated list
inGSettings["RobotRDPActive"]["RecoveryDict"]["__StatisticsDict__"][inRDPSessionKeyStr] = lTimeNewList
# Check if counter equal or more
if lCatchCounterInt>= inGSettings["RobotRDPActive"]["RecoveryDict"]["TriggerCountInt"]:
lResultBool = True
return lResultBool
def RetryHostClear(inHostStr, inGSettings):
"""
Clear retry stat by the host str
:param inHostStr: PC host str to be cleared (search the RDPSession keys)
:param inGSettings: Orchestrator global settings dict (singleton)
:return:
"""
for lRDPSessionKeyStr in inGSettings["RobotRDPActive"]["RDPList"]:
lRDPDict = inGSettings["RobotRDPActive"]["RDPList"][lRDPSessionKeyStr]
# Check if HOST in UPPER is equal
if lRDPDict["Host"].upper() == inHostStr.upper():
#Check if RDPSession key exist in stat
if lRDPSessionKeyStr in inGSettings["RobotRDPActive"]["RecoveryDict"]["__StatisticsDict__"]:
del inGSettings["RobotRDPActive"]["RecoveryDict"]["__StatisticsDict__"][lRDPSessionKeyStr]

@ -4,6 +4,8 @@ import time # Time wait operations
from . import ConnectorExceptions # Exceptions classes
from . import Connector
from . import Processor # Module for process some functions on thr RDP
from . import Recovery
from .. import __Orchestrator__
# Main function
# inThreadControlDict = {"ThreadExecuteBool":True}
def RobotRDPActive(inGSettings, inThreadControlDict):
@ -42,14 +44,17 @@ def RobotRDPActive(inGSettings, inThreadControlDict):
# Check RDP window is OK - reconnect if connection was lost
lUIOSelectorList = []
lRDPConfigurationDictList = []
lRDPSessionKeyList = []
# Prepare selectors list for check
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lRDPSessionKeyList.append(lRDPSessionKeyStrItem)
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
lRDPSessionKeyStr = lRDPSessionKeyList[lItem]
lRDPConfigurationDict = lRDPConfigurationDictList[lItem] # Get RDP Configuration list
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
# Check if RDP window is not ignored
@ -57,11 +62,19 @@ def RobotRDPActive(inGSettings, inThreadControlDict):
try:
Connector.Session(lRDPConfigurationDict, inScreenSize550x350Bool = True)
lRDPConfigurationDict["SessionIsWindowExistBool"] = True # Flag that session is started
if lL: lL.info(f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session has been initialized!") #Logging
if lL: lL.info(f"Host: {lRDPConfigurationDict['Host']}, Login: {lRDPConfigurationDict['Login']}, SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session has been initialized!") #Logging
# catch ConnectorExceptions.SessionWindowNotExistError
except ConnectorExceptions.SessionWindowNotExistError as e:
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
if lL: lL.warning(f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session is not exist!") #Logging
if lL: lL.warning(f"Host: {lRDPConfigurationDict['Host']}, Login: {lRDPConfigurationDict['Login']}, SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session is not exist! Mark the retry") #Logging
# Recovery operations
Recovery.RetryMark(inRDPSessionKeyStr=lRDPSessionKeyStr,inGSettings=inGSettings)
if Recovery.RetryIsTriggered(inRDPSessionKeyStr=lRDPSessionKeyStr,inGSettings=inGSettings) == True:
if lL: lL.warning(f"!ATTENTION! Host: {lRDPConfigurationDict['Host']}, Login: {lRDPConfigurationDict['Login']}; RDP is not responsible for many times - run recovery mode")
Recovery.RetryHostClear(inHostStr=lRDPConfigurationDict['Host'],inGSettings=inGSettings) # Clear the stat about current host
if inGSettings["RobotRDPActive"]["RecoveryDict"]["DoDict"]["OSRemotePCRestart"] == True:
if lL: lL.warning(f"!ATTENTION! Host: {lRDPConfigurationDict['Host']}, Send signal to restart remote PC.")
__Orchestrator__.OSRemotePCRestart(inLogger=lL,inHostStr=lRDPConfigurationDict['Host'],inForceBool=True)
# general exceptions
except Exception as e:
if lL: lL.exception(f"!!! ATTENTION !!! Unrecognized error") #Logging

@ -43,6 +43,20 @@ def __ComplexDictMerge2to1__(in1Dict, in2Dict):
in1Dict[lKeyStr] = in2Dict[lKeyStr]
return in1Dict
# Tool to merge complex dictionaries - no exceptions, just overwrite dict 2 in dict 1
def __ComplexDictMerge2to1Overwrite__(in1Dict, in2Dict):
lPathList=None
if lPathList is None: lPathList = []
for lKeyStr in in2Dict:
if lKeyStr in in1Dict:
if isinstance(in1Dict[lKeyStr], dict) and isinstance(in2Dict[lKeyStr], dict):
__ComplexDictMerge2to1Overwrite__(in1Dict[lKeyStr], in2Dict[lKeyStr])
else:
in1Dict[lKeyStr] = in2Dict[lKeyStr]
else:
in1Dict[lKeyStr] = in2Dict[lKeyStr]
return in1Dict
#Authenticate function ()
# return dict
# {
@ -319,6 +333,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
lFileObject.close()
# ResponseContentTypeFile
def ResponseDictSend(self):
lL = gSettingsDict["Logger"]
inResponseDict = self.OpenRPAResponseDict
# Send response status code
self.send_response(inResponseDict["StatusCode"])
@ -329,9 +344,12 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
for lItemKey, lItemValue in inResponseDict["SetCookies"].items():
self.send_header("Set-Cookie", f"{lItemKey}={lItemValue}")
#Close headers section in response
try:
self.end_headers()
# Write content as utf-8 data
self.wfile.write(inResponseDict["Body"])
except ConnectionResetError as e:
if lL: lL.warning(f"An existing connection was forcibly closed by the remote host - OK for the network interactions (ConnectionResetError: [WinError 10054])")
def do_GET(self):
try:
self.OpenRPA = {}

@ -151,10 +151,13 @@ def HiddenAgentDictGenerate(inRequest, inGSettings):
lKeyStr = f"{lAgentItemKeyStrItem[0]};{lAgentItemKeyStrItem[1]}" # turple ("HostNameUpperStr","UserUpperStr") > Str "HostNameUpperStr;UserUpperStr"
if dUAC(inRoleKeyList=lUACAgentTemplateKeyList+[lKeyStr]):
lDataItemDict = inGSettings["AgentDict"][lAgentItemKeyStrItem]
lAgentDict[lKeyStr]=lDataItemDict
lDataItemAgentDict = copy.deepcopy(lDataItemDict)
lDataItemAgentDict["ActivityList"] = []
lAgentDict[lKeyStr]=lDataItemAgentDict
lHandlebarsDataItemDict = copy.deepcopy(lDataItemDict)
lHandlebarsDataItemDict["HostnameUpperStr"]=lAgentItemKeyStrItem[0]
lHandlebarsDataItemDict["UserUpperStr"]=lAgentItemKeyStrItem[1]
lHandlebarsDataItemDict["ActivityList"] = []
lAgentDict["HandlebarsList"].append(lHandlebarsDataItemDict)
return lAgentDict
@ -330,7 +333,9 @@ def pyOpenRPA_ActivityListExecute(inRequest, inGSettings):
# See docs in Agent (pyOpenRPA.Agent.O2A)
def pyOpenRPA_Agent_O2A(inRequest, inGSettings):
lL = inGSettings["Logger"] # Alias
lConnectionLifetimeSecFloat = 3600.0 # 60 min * 60 sec 3600.0
lConnectionLifetimeSecFloat = inGSettings["ServerDict"]["AgentConnectionLifetimeSecFloat"] # 300.0 # 5 min * 60 sec 300.0
lActivityItemLifetimeLimitSecFloat = inGSettings["ServerDict"]["AgentActivityLifetimeSecFloat"]
lAgentLoopSleepSecFloat = inGSettings["ServerDict"]["AgentLoopSleepSecFloat"]
lTimeStartFloat = time.time()
# Recieve the data
lValueStr = None
@ -348,6 +353,7 @@ def pyOpenRPA_Agent_O2A(inRequest, inGSettings):
lThisAgentDict["ConnectionCountInt"] += 1 # increment connection count
# Test solution
lDoLoopBool = True
try:
while lDoLoopBool:
# Check if lifetime is over
if time.time() - lTimeStartFloat > lConnectionLifetimeSecFloat: # Lifetime is over
@ -357,26 +363,47 @@ def pyOpenRPA_Agent_O2A(inRequest, inGSettings):
lThisAgentDict["IsListenBool"] = True # Set is online
lQueueList = lThisAgentDict["ActivityList"]
if len(lQueueList)>0:# Do some operations if has queue items
if lL: lL.debug(f'O2A BEFORE: ConnectionCountInt: {lThisAgentDict["ConnectionCountInt"]};ConnectionFirstQueueItemCountInt {lThisAgentDict["ConnectionFirstQueueItemCountInt"]}')
if lThisAgentDict["ConnectionCountInt"] == lThisAgentDict["ConnectionFirstQueueItemCountInt"] + 1:
# POP QUEUE ITEM CONDITION ConnectionCountInt == ConnectionFirstQueueItemCountInt + 1
if lL: lL.debug(f'O2A: ConnectionCountInt: {lThisAgentDict["ConnectionCountInt"]};ConnectionFirstQueueItemCountInt {lThisAgentDict["ConnectionFirstQueueItemCountInt"]}')
# check if delta datetime is < than ActivityLifeTimeSecFloat
lActivityItem = lThisAgentDict["ActivityList"][0]
lActivityLifetimeSecFloat = (datetime.datetime.now() - lActivityItem["CreatedByDatetime"]).total_seconds()
# Check case if limit is expired - remove item
if lActivityLifetimeSecFloat > lActivityItemLifetimeLimitSecFloat:
lActivityItem = lThisAgentDict["ActivityList"].pop(0)
lThisAgentDict["ConnectionFirstQueueItemCountInt"] = 0
if lL: lL.debug(f"Activity was deleted from the list: {lThisAgentDict['ActivityList']}")
else:
lActivityItem = lThisAgentDict["ActivityList"][0]
lThisAgentDict["ConnectionFirstQueueItemCountInt"] += 1
if lL: lL.debug(f"Activity was !not! deleted from the list: {lThisAgentDict['ActivityList']}")
if lL: lL.debug(f'O2A AFTER: ConnectionCountInt: {lThisAgentDict["ConnectionCountInt"]};ConnectionFirstQueueItemCountInt {lThisAgentDict["ConnectionFirstQueueItemCountInt"]}')
lReturnActivityItemDict = None
# If lInput['ActivityLastGUIDStr'] is '' > return 0 element for send in Agent
if lInput['ActivityLastGUIDStr'] == "":
lReturnActivityItemDict = lThisAgentDict["ActivityList"][0]
else:
# go from the end - search element with GUIDStr
lForTriggerGetNextItem = False
for lForActivityItemDict in lQueueList:
if lForTriggerGetNextItem == True:
lReturnActivityItemDict = lForActivityItemDict
break
if lForActivityItemDict['GUIDStr'] == lInput['ActivityLastGUIDStr']: lForTriggerGetNextItem = True
# CASE if GUID is not detected - return 0 element
if lReturnActivityItemDict == None and lForTriggerGetNextItem == False:
lReturnActivityItemDict = lThisAgentDict["ActivityList"][0]
# Send QUEUE ITEM
if lL: lL.info(f"Activity item to agent Hostname {lInput['HostNameUpperStr']}, User {lInput['UserUpperStr']}. Activity item: {lActivityItem}")
inRequest.OpenRPAResponseDict["Body"] = bytes(json.dumps(lActivityItem), "utf8")
if lReturnActivityItemDict is not None:
lReturnActivityItemDict = copy.deepcopy(lReturnActivityItemDict)
if "CreatedByDatetime" in lReturnActivityItemDict:
del lReturnActivityItemDict["CreatedByDatetime"]
if lL: lL.info(f"Activity item to agent Hostname {lInput['HostNameUpperStr']}, User {lInput['UserUpperStr']}. Activity item: {lReturnActivityItemDict}")
inRequest.OpenRPAResponseDict["Body"] = bytes(json.dumps(lReturnActivityItemDict), "utf8")
lDoLoopBool = False # CLose the connection
else: # Nothing to send - sleep for the next iteration
time.sleep(lAgentLoopSleepSecFloat)
else: # no queue item - sleep for the next iteration
time.sleep(1)
time.sleep(lAgentLoopSleepSecFloat)
except Exception as e:
if lL: lL.exception("pyOpenRPA_Agent_O2A Exception!")
lThisAgentDict["ConnectionCountInt"] -= 1 # Connection go to be closed - decrement the connection count
# See docs in Agent (pyOpenRPA.Agent.A2O)
def pyOpenRPA_Agent_A2O(inRequest, inGSettings):
lL = inGSettings["Logger"]
# Recieve the data
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
@ -387,6 +414,12 @@ def pyOpenRPA_Agent_A2O(inRequest, inGSettings):
if "LogList" in lInput:
for lLogItemStr in lInput["LogList"]:
inGSettings["Logger"].info(lLogItemStr)
if "ActivityReturnDict" in lInput:
for lActivityReturnItemKeyStr in lInput["ActivityReturnDict"]:
lActivityReturnItemValue = lInput["ActivityReturnDict"][lActivityReturnItemKeyStr]
# Create item in gSettings
inGSettings["AgentActivityReturnDict"][lActivityReturnItemKeyStr]=SettingsTemplate.__AgentActivityReturnDictItemCreate__(inReturn=lActivityReturnItemValue)
if lL: lL.debug(f"SERVER: pyOpenRPA_Agent_A2O:: Has recieved result of the activity items from agent! ActivityItem GUID Str: {lActivityReturnItemKeyStr}; Return value: {lActivityReturnItemValue}")
def SettingsUpdate(inGlobalConfiguration):
import os

@ -7,6 +7,7 @@ def __Create__():
"Autocleaner": {
# Some gurbage is collecting in g settings. So you can configure autocleaner to periodically clear gSettings
"IntervalSecFloat": 3600.0, # Sec float to periodically clear gsettings
"AgentActivityReturnLifetimeSecFloat": 300.0 # Time in seconds to life for activity result recieved from the agent
},
"Client": { # Settings about client web orchestrator
"Session": {
@ -14,7 +15,7 @@ def __Create__():
"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,
"ControlPanelRefreshIntervalSecFloat": 2.0, # 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
@ -38,6 +39,9 @@ def __Create__():
# # # # # # # # # # # # # # # # # #
},
"ServerDict": {
"AgentActivityLifetimeSecFloat": 1200.0, # Time in seconds to life for activity for the agent
"AgentConnectionLifetimeSecFloat": 300.0, # Time in seconds to handle the open connection to the Agent
"AgentLoopSleepSecFloat": 2.0, # Time in seconds to sleep between loops when check to send some activity to the agent
"WorkingDirectoryPathStr": None, # Will be filled automatically
"RequestTimeoutSecFloat": 300, # Time to handle request in seconds
"ListenPort_": "Порт, по которому можно подключиться к демону",
@ -115,45 +119,7 @@ def __Create__():
"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 -
# ...
# },
]
"ActivityList": []
},
"SchedulerDict": {
"CheckIntervalSecFloat": 5.0, # Check interval in seconds
@ -162,11 +128,14 @@ def __Create__():
# "TimeHH:MMStr": "22:23", # Time [HH:MM] to trigger activity
# "WeekdayList": [0, 1, 2, 3, 4, 5, 6], #List of the weekday index when activity is applicable, Default [0,1,2,3,4,5,6]
# "ActivityList": [
# {
# "Type": "ProcessStart", # Activity type
# "Path": "start", # Executable file path
# "ArgList": ["cmd.exe", "/c", "PIPUpgrade.cmd"] # List of the arguments
# }
# # {
# # "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)
# # "ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# # "GUIDStr": ..., # GUID of the activity
# # },
# ],
# "GUID": None # Will be filled in Orchestrator automatically - is needed for detect activity completion
# },
@ -180,12 +149,14 @@ def __Create__():
# "ArgDict":{"ttt":1,"222":2,"dsd":3} # Args dictionary
# "ArgGSettings": # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "GUIDStr": ..., # GUID of the activity
# },
],
"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
"ThreadIdInt": None # Technical field - will be setup when processor init
"ThreadIdInt": None, # Technical field - will be setup when processor init
"WarningExecutionMoreThanSecFloat": 60.0 # Push warning if execution more than n seconds
},
"ControlPanelDict": { # Old structure > CPDict
"RefreshSeconds": 5, # deprecated parameter
@ -201,6 +172,16 @@ def __Create__():
},
# # # # # # # # # # # # # #
"RobotRDPActive": {
"RecoveryDict": {
"CatchPeriodSecFloat": 1200, # Catch last 10 minutes
"TriggerCountInt": 10, # Activate trigger if for the period orch will catch the reconnect RDP n times
"DoDict": {
"OSRemotePCRestart": True # Do powershell remote restart
},
"__StatisticsDict__": {
# RDPSessionKeyStr : [time.time(), time.time()],
}
},
"RDPList": {
# "RDPSessionKey":{
# "Host": "77.77.22.22", # Host address
@ -259,19 +240,29 @@ def __Create__():
}
},
"Logger": logging.getLogger("Orchestrator"),
"Storage": {
"StorageDict": {
"Robot_R01_help": "Robot data storage in orchestrator env",
"Robot_R01": {},
"R01_OrchestratorToRobot": {"Test2": "Test2"}
},
"AgentDict": { # Will be filled when program runs
#("HostNameUpperStr", "UserUpperStr"): { "IsListenBool": True, "QueueList": [] }
},
"AgentActivityReturnDict": { # Will be filled when programs run - fill result of the Activity execution on the agent
# Key - Activity Item GUID str, Value {"Return": ..., "ReturnedByDatetime": datetime.datetime}
# If key exists - def has been completed
}
# "HiddenIsOrchestratorInitialized" - will be inited when orchestrator will be initialized
}
# Create full configuration for
def __AgentDictItemCreate__():
return {"IsListenBool":False, "ConnectionCountInt":0, "ConnectionFirstQueueItemCountInt":0, "ActivityList":[]}
# Create full configuration for AgentActivityReturnDict
def __AgentActivityReturnDictItemCreate__(inReturn):
return {"Return": inReturn, "ReturnedByDatetime": datetime.datetime.now()}
# Create full configuration for
def __UACClientAdminCreate__():
lResultDict = {

@ -1,4 +1,4 @@
import json
import json, copy
from .. import __Orchestrator__
from .. import Processor
# Escape JS to the safe JS for the inline JS in HTML tags ATTENTION! Use it only if want to paste JS into HTML tag - not in <script>
@ -7,22 +7,42 @@ def JSEscapeForHTMLInline(inJSStr):
lResult = inJSStr.replace("\"","&quot;")
return lResult
# Create JS for send activity list/ activity to the processor
# USAGE: Orchestrator.Web.Basic.JSProcessorActivityListAdd(inActivityList)
def JSProcessorActivityListAdd(inActivityList):
def JSProcessorActivityListAdd(inActivityList, inGUIDRemoveBool = True):
"""
# Create JS for send activity list/ activity to the processor
# USAGE: Orchestrator.Web.Basic.JSProcessorActivityListAdd(inActivityList)
:param inActivityList: List of the activities (See __Orchestrator__.ProcessorActivityItemCreate)
:param inGUIDRemoveBool: True - remove GUID before generate JS (if GUID is not important)
:return: JavaScript string for the front end
"""
Processor.__ActivityListVerify__(inActivityList=inActivityList) # DO VERIFICATION FOR THE inActivityList
inActivityList = copy.deepcopy(inActivityList)
# Check if no def function is here - if exist - replace to alias
for lActivityItem in inActivityList:
if "GUIDStr" in lActivityItem and inGUIDRemoveBool == True: del lActivityItem["GUIDStr"] # Remove GUID from activity items if exists
lDef = lActivityItem["Def"]
if callable(lDef): raise Exception(f"pyOpenRPA Exception: You can't send ActivityList with def to JS. Use Def Alias (see Orchestrator.ProcessorAliasDefUpdate)")
if type(inActivityList) is not list: inActivityList = [inActivityList]
lJSStr = f"""mGlobal.pyOpenRPA.ProcessorQueueAdd({json.dumps(inActivityList)});"""
return lJSStr
# Create JS for execute activity list/ activity permanent
# USAGE: Orchestrator.Web.Basic.JSActivityListExecute(inActivityList)
def JSActivityListExecute(inActivityList):
def JSActivityListExecute(inActivityList, inGUIDRemoveBool = True):
"""
Create JS for execute activity list/ activity permanent
USAGE: Orchestrator.Web.Basic.JSActivityListExecute(inActivityList, inGUIDRemoveBool = True)
:param inActivityList: List of the activities (See __Orchestrator__.ProcessorActivityItemCreate)
:param inGUIDRemoveBool: True - remove GUID before generate JS (if GUID is not important)
:return: JavaScript string for the front end
"""
Processor.__ActivityListVerify__(inActivityList=inActivityList) # DO VERIFICATION FOR THE inActivityList
inActivityList = copy.deepcopy(inActivityList)
# Check if no def function is here - if exist - replace to alias
for lActivityItem in inActivityList:
if "GUIDStr" in lActivityItem and inGUIDRemoveBool == True: del lActivityItem["GUIDStr"] # Remove GUID from activity items if exists
lDef = lActivityItem["Def"]
if callable(lDef): raise Exception(f"pyOpenRPA Exception: You can't send ActivityList with def to JS. Use Def Alias (see Orchestrator.ProcessorAliasDefUpdate)")
lJSStr = f"""mGlobal.pyOpenRPA.ActivityListExecute({json.dumps(inActivityList)});"""
return lJSStr

@ -176,6 +176,7 @@ $(document).ready(function() {
}
///Restart PC
mGlobal.Controller.PCRestart = function () {
mGlobal.Controller.OrchestratorSessionSave()
mGlobal.Controller.CMDRunText("shutdown -r")
}
///Orchestrator save session

@ -1,9 +1,14 @@
import subprocess, json, psutil, time, os, win32security, sys, base64, logging, ctypes #Get input argument
import subprocess, json, psutil, time, os, win32security, sys, base64, logging, ctypes, copy #Get input argument
import pickle
from partd import Server
from . import Server
from . import Timer
from . import Processor
from . import BackwardCompatibility # Backward compatibility from v1.1.13
from . import Core
from subprocess import CREATE_NEW_CONSOLE
from .Utils import LoggerHandlerDumpLogList
# ATTENTION! HERE IS NO Relative import because it will be imported dynamically
@ -23,7 +28,7 @@ import uuid # Generate uuid
import datetime # datetime
#Единый глобальный словарь (За основу взять из Settings.py)
global gSettingsDict
gSettingsDict = None
# AGENT DEFS
@ -35,34 +40,82 @@ def AgentActivityItemAdd(inGSettings, inHostNameStr, inUserStr, inActivityItemDi
:param inHostNameStr: Agent host name
:param inUserStr: User login, where agent is based
:param inActivityItemDict: ActivityItem
:return: None
"""
:return: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
"""
lActivityItemDict = copy.deepcopy(inActivityItemDict)
# Add GUIDStr if not exist
lGUIDStr = None
if "GUIDStr" not in lActivityItemDict:
lGUIDStr = str(uuid.uuid4()) # generate new GUID
lActivityItemDict["GUIDStr"] = lGUIDStr
else: lGUIDStr = lActivityItemDict["GUIDStr"]
# Add CreatedByDatetime
lActivityItemDict["CreatedByDatetime"] = datetime.datetime.now()
# Main alg
lAgentDictItemKeyTurple = (inHostNameStr.upper(),inUserStr.upper())
if lAgentDictItemKeyTurple not in inGSettings["AgentDict"]:
inGSettings["AgentDict"][lAgentDictItemKeyTurple] = SettingsTemplate.__AgentDictItemCreate__()
lThisAgentDict = inGSettings["AgentDict"][lAgentDictItemKeyTurple]
lThisAgentDict["ActivityList"].append(inActivityItemDict)
lThisAgentDict["ActivityList"].append(lActivityItemDict)
# Return the result
return lGUIDStr
def AgentActivityItemReturnExists(inGSettings, inGUIDStr):
"""
Check by GUID if ActivityItem has been executed and result has come to the Orchestrator
:param inGSettings: Global settings dict (singleton)
:param inGUIDStr: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
:return: True - result has been received from the Agent to orc; False - else case
"""
# Check if GUID is exists in dict - has been recieved
return inGUIDStr in inGSettings["AgentActivityReturnDict"]
def AgentOSCMD(inGSettings, inHostNameStr, inUserStr, inCMDStr, inRunAsyncBool=True):
def AgentActivityItemReturnGet(inGSettings, inGUIDStr, inCheckIntervalSecFloat = 0.5):
"""
Work synchroniously! Wait while result will be recieved. Get the result of the ActivityItem execution on the Agent side. Before this please check by the def AgentActivityItemReturnExists that result has come to the Orchestrator
!ATTENTION! Use only after Orchestrator initialization! Before orchestrator init exception will be raised.
:param inGSettings: Global settings dict (singleton)
:param inGUIDStr: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
:param inCheckIntervalSecFloat: Interval in sec of the check Activity Item result
:return: Result of the ActivityItem executed on the Agent side anr transmitted to the Orchestrator. IMPORTANT! ONLY JSON ENABLED Types CAN BE TRANSMITTED TO ORCHESTRATOR!
"""
#Check if Orchestrator has been initialized - else raise exception
if Core.IsOrchestratorInitialized(inGSettings=inGSettings) == True:
# Wait while result will not come here
while not AgentActivityItemReturnExists(inGSettings=inGSettings, inGUIDStr=inGUIDStr):
time.sleep(inCheckIntervalSecFloat)
# Return the result
return inGSettings["AgentActivityReturnDict"][inGUIDStr]["Return"]
else:
raise Exception(f"__Orchestrator__.AgentActivityItemReturnGet !ATTENTION! Use this function only after Orchestrator initialization! Before orchestrator init exception will be raised.")
def AgentOSCMD(inGSettings, inHostNameStr, inUserStr, inCMDStr, inRunAsyncBool=True, inSendOutputToOrchestratorLogsBool=True, inCMDEncodingStr="cp1251"):
"""
Send CMD to OS thought the pyOpenRPA.Agent daemon. Result return to log + Orchestrator by the A2O connection
:param inGSettings: Global settings dict (singleton)
:param inHostNameStr:
:param inUserStr:
:param inCMDStr:
:param inRunAsyncBool:
:param inHostNameStr: Agent host name in upper case (example "RPA01", "RPA_99" and so on). Active agent session you can see on the orchestrator dashboard as Orchestrator admin
:param inUserStr: Agent user name in upper case (example "UserRPA"). Active agent session you can see on the orchestrator dashboard as Orchestrator admin
:param inCMDStr: command to execute on the Agent session
:param inRunAsyncBool: True - Agent processor don't wait execution; False - Agent processor wait cmd execution
:param inSendOutputToOrchestratorLogsBool: True - catch cmd execution output and send it to the Orchestrator logs; Flase - else case; Default True
:param inCMDEncodingStr: Set the encoding of the DOS window on the Agent server session. Windows is beautiful :) . Default is "cp1251" early was "cp866" - need test
:return: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
"""
lActivityItemDict = {
"Def":"OSCMD", # def alias (look pyOpeRPA.Agent gSettings["ProcessorDict"]["AliasDefDict"])
"ArgList":[], # Args list
"ArgDict":{"inCMDStr":inCMDStr,"inRunAsyncBool":inRunAsyncBool}, # Args dictionary
"ArgDict":{"inCMDStr":inCMDStr,"inRunAsyncBool":inRunAsyncBool, "inSendOutputToOrchestratorLogsBool": inSendOutputToOrchestratorLogsBool, "inCMDEncodingStr": inCMDEncodingStr}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
#Send item in AgentDict for the futher data transmition
AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
return AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
def AgentOSFileBinaryDataBytesCreate(inGSettings, inHostNameStr, inUserStr, inFilePathStr, inFileDataBytes):
"""
@ -73,6 +126,7 @@ def AgentOSFileBinaryDataBytesCreate(inGSettings, inHostNameStr, inUserStr, inFi
:param inUserStr:
:param inFilePathStr:
:param inFileDataBytes:
:return: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
"""
lFileDataBase64Str = base64.b64encode(inFileDataBytes).decode("utf-8")
@ -84,7 +138,7 @@ def AgentOSFileBinaryDataBytesCreate(inGSettings, inHostNameStr, inUserStr, inFi
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
#Send item in AgentDict for the futher data transmition
AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
return AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
def AgentOSFileBinaryDataBase64StrCreate(inGSettings, inHostNameStr, inUserStr, inFilePathStr, inFileDataBase64Str):
@ -96,6 +150,7 @@ def AgentOSFileBinaryDataBase64StrCreate(inGSettings, inHostNameStr, inUserStr,
:param inUserStr:
:param inFilePathStr:
:param inFileDataBase64Str:
:return: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
"""
lActivityItemDict = {
@ -106,7 +161,7 @@ def AgentOSFileBinaryDataBase64StrCreate(inGSettings, inHostNameStr, inUserStr,
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
#Send item in AgentDict for the futher data transmition
AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
return AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
# Send text file to Agent (string)
def AgentOSFileTextDataStrCreate(inGSettings, inHostNameStr, inUserStr, inFilePathStr, inFileDataStr, inEncodingStr = "utf-8"):
@ -119,6 +174,7 @@ def AgentOSFileTextDataStrCreate(inGSettings, inHostNameStr, inUserStr, inFilePa
:param inFilePathStr:
:param inFileDataStr:
:param inEncodingStr:
:return: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
"""
lActivityItemDict = {
@ -129,7 +185,70 @@ def AgentOSFileTextDataStrCreate(inGSettings, inHostNameStr, inUserStr, inFilePa
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
#Send item in AgentDict for the futher data transmition
AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
return AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
def AgentOSFileBinaryDataBase64StrReceive(inGSettings, inHostNameStr, inUserStr, inFilePathStr):
"""
Read binary file and encode in base64 to transmit (safe for JSON transmition)
:param inGSettings: Global settings dict (singleton)
:param inHostNameStr:
:param inUserStr:
:param inFilePathStr: File path to read
:return: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
"""
lActivityItemDict = {
"Def":"OSFileBinaryDataBase64StrReceive", # def alias (look pyOpeRPA.Agent gSettings["ProcessorDict"]["AliasDefDict"])
"ArgList":[], # Args list
"ArgDict":{"inFilePathStr":inFilePathStr}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
#Send item in AgentDict for the futher data transmition
return AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
def AgentOSFileTextDataStrReceive(inGSettings, inHostNameStr, inUserStr, inFilePathStr, inEncodingStr="utf-8"):
"""
Read text file in the agent GUI session
:param inGSettings: Global settings dict (singleton)
:param inHostNameStr:
:param inUserStr:
:param inFilePathStr: File path to read
:param inEncodingStr: Text file encoding. Default 'utf-8'
:return: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
"""
lActivityItemDict = {
"Def":"OSFileTextDataStrReceive", # def alias (look pyOpeRPA.Agent gSettings["ProcessorDict"]["AliasDefDict"])
"ArgList":[], # Args list
"ArgDict":{"inFilePathStr":inFilePathStr, "inEncodingStr": inEncodingStr}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
#Send item in AgentDict for the futher data transmition
return AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
def AgentProcessWOExeUpperUserListGet(inGSettings, inHostNameStr, inUserStr):
"""
Return the process list only for the current user (where Agent is running) without .EXE in upper case. Can use in ActivityItem from Orchestrator to Agent
:param inGSettings: Global settings dict (singleton)
:param inHostNameStr:
:param inUserStr:
:return: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
"""
lActivityItemDict = {
"Def":"ProcessWOExeUpperUserListGet", # def alias (look pyOpeRPA.Agent gSettings["ProcessorDict"]["AliasDefDict"])
"ArgList":[], # Args list
"ArgDict":{}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
#Send item in AgentDict for the futher data transmition
return AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict)
# OS DEFS
def OSCredentialsVerify(inUserStr, inPasswordStr, inDomainStr=""): ##
@ -151,6 +270,20 @@ def OSCredentialsVerify(inUserStr, inPasswordStr, inDomainStr=""): ##
else:
return True
def OSRemotePCRestart(inLogger, inHostStr, inForceBool=True):
"""
Send signal via power shell to restart remote PC
ATTENTION: Orchestrator user need to have restart right on the Remote machine to restart PC.
:param inLogger: logger to log powershell result in logs
:param inHostStr: PC hostname which you need to restart.
:param inForceBool: True - send signal to force retart PC; False - else case
:return:
"""
lCMDStr = f"powershell -Command Restart-Computer -ComputerName {inHostStr}"
if inForceBool == True: lCMDStr = lCMDStr + " -Force"
OSCMD(inCMDStr=lCMDStr,inLogger=inLogger)
def OSCMD(inCMDStr, inRunAsyncBool=True, inLogger = None):
"""
OS send command in shell locally
@ -165,7 +298,7 @@ def OSCMD(inCMDStr, inRunAsyncBool=True, inLogger = None):
def _CMDRunAndListenLogs(inCMDStr, inLogger):
lResultStr = ""
lOSCMDKeyStr = str(uuid.uuid4())[0:4].upper()
lCMDProcess = subprocess.Popen(f'cmd /c {inCMDStr}', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
lCMDProcess = subprocess.Popen(f'cmd /c {inCMDStr}', stdout=subprocess.PIPE, stderr=subprocess.STDOUT, creationflags=CREATE_NEW_CONSOLE)
if inLogger:
lListenBool = True
inLogger.info(f"{lOSCMDKeyStr}: # # # # CMD Process has been STARTED # # # # ")
@ -206,33 +339,106 @@ def OrchestratorRestart(inGSettings=None):
os.execl(sys.executable, os.path.abspath(__file__), *sys.argv)
sys.exit(0)
def OrchestratorSessionSave(inGSettings=None):
def OrchestratorIsAdmin():
"""
Orchestrator session save in file _SessionLast_RDPList.json (encoding = "utf-8")
Check if Orchestrator process is running as administrator
:return: True - run as administrator; False - not as administrator
"""
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except:
return False
def OrchestratorRerunAsAdmin():
"""
Check if not admin - then rerun orchestrator as administrator
:return: True - run as administrator; False - not as administrator
"""
if not OrchestratorIsAdmin():
# Re-run the program with admin rights
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
else:
print(f"!SKIPPED! Already run as administrator!")
def OrchestratorSessionSave(inGSettings):
"""
Orchestrator session save in file
_SessionLast_RDPList.json (encoding = "utf-8")
_SessionLast_StorageDict.pickle (binary)
:param inGSettings: Global settings dict (singleton)
:return: True every time
"""
lL = inGSettings["Logger"]
try:
# Dump RDP List in file json
lFile = open("_SessionLast_RDPList.json", "w", encoding="utf-8")
lFile.write(json.dumps(inGSettings["RobotRDPActive"]["RDPList"])) # dump json to file
lFile.close() # Close the file
if inGSettings is not None:
lL = inGSettings["Logger"]
if lL: lL.info(
f"Orchestrator has dump the RDP list before the restart.")
# _SessionLast_StorageDict.pickle (binary)
if "StorageDict" in inGSettings:
with open('_SessionLast_StorageDict.pickle', 'wb') as lFile:
pickle.dump(inGSettings["StorageDict"], lFile)
if lL: lL.info(
f"Orchestrator has dump the StorageDict before the restart.")
except Exception as e:
if lL: lL.exception(f"Exception when dump data before restart the Orchestrator")
return True
def OrchestratorSessionRestore(inGSettings):
"""
Check _SessionLast_RDPList.json and _SessionLast_StorageDict.pickle in working directory. if exist - load into gsettings
# _SessionLast_StorageDict.pickle (binary)
_SessionLast_RDPList.json (encoding = "utf-8")
_SessionLast_StorageDict.pickle (binary)
:param inGSettings: Global settings dict (singleton)
:return:
"""
lL = inGSettings.get("Logger",None)
# _SessionLast_RDPList.json (encoding = "utf-8")
if os.path.exists("_SessionLast_RDPList.json"):
lFile = open("_SessionLast_RDPList.json", "r", encoding="utf-8")
lSessionLastRDPList = json.loads(lFile.read())
lFile.close() # Close the file
os.remove("_SessionLast_RDPList.json") # remove the temp file
inGSettings["RobotRDPActive"]["RDPList"] = lSessionLastRDPList # Set the last session dict
if lL: lL.warning(f"RDP Session List was restored from previous Orchestrator session")
# _SessionLast_StorageDict.pickle (binary)
if os.path.exists("_SessionLast_StorageDict.pickle"):
if "StorageDict" not in inGSettings:
inGSettings["StorageDict"] = {}
with open('_SessionLast_StorageDict.pickle', 'rb') as lFile:
lStorageDictDumpDict = pickle.load(lFile)
Server.__ComplexDictMerge2to1Overwrite__(in1Dict=inGSettings["StorageDict"],
in2Dict=lStorageDictDumpDict) # Merge dict 2 into dict 1
if lL: lL.warning(f"StorageDict was restored from previous Orchestrator session")
os.remove("_SessionLast_StorageDict.pickle") # remove the temp file
def UACKeyListCheck(inRequest, inRoleKeyList) -> bool:
"""
Check is client is has access for the key list
:param inRequest:
:param inRequest: request handler (from http.server import BaseHTTPRequestHandler)
:param inRoleKeyList:
:return: bool
"""
return inRequest.UACClientCheck(inRoleKeyList=inRoleKeyList)
def UACUserDictGet(inRequest) -> dict:
"""
Return user UAC hierarchy dict of the inRequest object. Empty dict - superuser access
:param inRequest: request handler (from http.server import BaseHTTPRequestHandler)
:return: user UAC hierarchy dict
"""
return inRequest.UserRoleHierarchyGet() # get the Hierarchy
def UACUpdate(inGSettings, inADLoginStr, inADStr="", inADIsDefaultBool=True, inURLList=None, inRoleHierarchyAllowedDict=None):
"""
Update user access (UAC)
@ -609,7 +815,7 @@ def ProcessorAliasDefUpdate(inGSettings, inDef, inAliasStr):
else: raise Exception(f"pyOpenRPA Exception: You can't use Orchestrator.ProcessorAliasDefUpdate with arg 'inDef' string value. inDef is '{inDef}', inAliasStr is '{inAliasStr}'")
return inAliasStr
def ProcessorActivityItemCreate(inDef, inArgList=None, inArgDict=None, inArgGSettingsStr=None, inArgLoggerStr=None):
def ProcessorActivityItemCreate(inDef, inArgList=None, inArgDict=None, inArgGSettingsStr=None, inArgLoggerStr=None, inGUIDStr = None):
"""
Create activity item. Activity item can be used as list item in ProcessorActivityItemAppend or in Processor.ActivityListExecute.
@ -663,8 +869,12 @@ def ProcessorActivityItemCreate(inDef, inArgList=None, inArgDict=None, inArgGSet
:param inArgDict: Args dict for the def
:param inArgGSettingsStr: Name of def argument of the GSettings dict
:param inArgLoggerStr: Name of def argument of the logging object
:param inGUIDStr: GUID which you can specify. If None the GUID will be generated
:return: {}
"""
# Work about GUID in Activity items
if inGUIDStr is None:
inGUIDStr = str(uuid.uuid4()) # generate new GUID
if inArgList is None: inArgList=[]
if inArgDict is None: inArgDict={}
lActivityItemDict= {
@ -672,7 +882,8 @@ def ProcessorActivityItemCreate(inDef, inArgList=None, inArgDict=None, inArgGSet
"ArgList":inArgList, # Args list
"ArgDict":inArgDict, # Args dictionary
"ArgGSettings": inArgGSettingsStr, # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": inArgLoggerStr # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": inArgLoggerStr, # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"GUIDStr": inGUIDStr
}
return lActivityItemDict
@ -722,6 +933,7 @@ def ProcessorActivityItemAppend(inGSettings, inDef=None, inArgList=None, inArgDi
:param inArgGSettingsStr: Name of def argument of the GSettings dict
:param inArgLoggerStr: Name of def argument of the logging object
:param inActivityItemDict: Fill if you already have ActivityItemDict (don't fill inDef, inArgList, inArgDict, inArgGSettingsStr, inArgLoggerStr)
:return ActivityItem GUIDStr
"""
if inActivityItemDict is None:
if inArgList is None: inArgList=[]
@ -738,7 +950,16 @@ def ProcessorActivityItemAppend(inGSettings, inDef=None, inArgList=None, inArgDi
]
else:
lActivityList = [inActivityItemDict]
# Work about GUID in Activity items
lGUIDStr = None
for lItemDict in lActivityList:
# Add GUIDStr if not exist
if "GUIDStr" not in lItemDict:
lGUIDStr = str(uuid.uuid4()) # generate new GUID
lItemDict["GUIDStr"] = lGUIDStr
# Add activity list in ProcessorDict
inGSettings["ProcessorDict"]["ActivityList"]+=lActivityList
return lGUIDStr
## Process defs
def ProcessIsStarted(inProcessNameWOExeStr): # Check if process is started
@ -897,6 +1118,85 @@ def ProcessListGet(inProcessNameWOExeList=None):
pass
return lResult
def ProcessDefIntervalCall(inGSettings, inDef, inIntervalSecFloat, inIntervalAsyncBool=False, inDefArgList=None, inDefArgDict=None, inDefArgGSettingsNameStr=None, inDefArgLoggerNameStr=None, inExecuteInNewThreadBool=True, inLogger=None):
"""
Use this procedure if you need to run periodically some def. Set def, args, interval and enjoy :)
:param inGSettings: global settings
:param inDef: def link, which will be called with interval inIntervalSecFloat
:param inIntervalSecFloat: Interval in seconds between call
:param inIntervalAsyncBool: False - wait interval before next call after the previous iteration result; True - wait interval after previous iteration call
:param inDefArgList: List of the args in def. Default None (empty list)
:param inDefArgDict: Dict of the args in def. Default None (empty dict)
:param inDefArgGSettingsNameStr: Name of the GSettings arg name for def (optional)
:param inDefArgLoggerNameStr: Name of the Logger arg name for def (optional). If Use - please check fill of the inLogger arg.
:param inExecuteInNewThreadBool: True - create new thread for the periodic execution; False - execute in current thread. Default: True
:param inLogger: logging def if some case is appear
:return:
"""
#Some edits on start
if inDefArgDict is None: inDefArgDict = {}
if inDefArgList is None: inDefArgList = []
# Check if inDefArgLogger is set and inLogger is exist
if inDefArgLoggerNameStr=="": inDefArgLoggerNameStr=None
if inDefArgGSettingsNameStr=="": inDefArgGSettingsNameStr=None
if inDefArgLoggerNameStr is not None and not inLogger:
raise Exception(f"!ERROR! ProcessDefIntervalCall - You need to send logger in def because your def is require logger. Raise error!")
# Check thread
if not Core.IsProcessorThread(inGSettings=inGSettings):
if inGSettings["Logger"]: inGSettings["Logger"].warning(f"__Orchestrator__.ProcessDefIntervalCall def was called not from processor queue - activity will be append in the processor queue.")
lProcessorActivityDict = {
"Def": ProcessDefIntervalCall, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {"inDef": inDef, "inIntervalSecFloat": inIntervalSecFloat,
"inIntervalAsyncBool":inIntervalAsyncBool, "inDefArgList": inDefArgList,
"inDefArgDict": inDefArgDict, "inDefArgGSettingsNameStr":inDefArgGSettingsNameStr,
"inDefArgLoggerNameStr": inDefArgLoggerNameStr, "inExecuteInNewThreadBool": inExecuteInNewThreadBool}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": "inLogger" # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
inGSettings["ProcessorDict"]["ActivityList"].append(lProcessorActivityDict)
else:
# Internal def to execute periodically
def __Execute__(inGSettings, inDef, inIntervalSecFloat, inIntervalAsyncBool, inDefArgList, inDefArgDict, inLogger, inDefArgGSettingsNameStr, inDefArgLoggerNameStr):
if inLogger: inLogger.info(f"__Orchestrator__.ProcessDefIntervalCall: Interval execution has been started. Def: {str(inDef)}")
# Prepare gSettings and logger args
if inDefArgGSettingsNameStr is not None:
inDefArgDict[inDefArgGSettingsNameStr] = inGSettings
if inDefArgLoggerNameStr is not None:
inDefArgDict[inDefArgLoggerNameStr] = inLogger
while True:
try:
# Call async if needed
if inIntervalAsyncBool == False: # Case wait result then wait
inDef(*inDefArgList, **inDefArgDict)
else: # Case dont wait result - run sleep then new iteration (use many threads)
lThread2 = threading.Thread(target=inDef,
args=inDefArgList,
kwargs=inDefArgDict)
lThread2.start()
except Exception as e:
if inLogger: inLogger.exception(
f"ProcessDefIntervalCall: Interval call has been failed. Traceback is below. Code will sleep for the next call")
# Sleep interval
time.sleep(inIntervalSecFloat)
# Check to call in new thread
if inExecuteInNewThreadBool:
lThread = threading.Thread(target=__Execute__,
kwargs={"inGSettings":inGSettings, "inDef": inDef, "inIntervalSecFloat": inIntervalSecFloat,
"inIntervalAsyncBool": inIntervalAsyncBool, "inDefArgList": inDefArgList,
"inDefArgDict": inDefArgDict, "inLogger": inLogger,
"inDefArgGSettingsNameStr":inDefArgGSettingsNameStr , "inDefArgLoggerNameStr":inDefArgLoggerNameStr})
lThread.start()
else:
__Execute__(inGSettings=inGSettings, inDef=inDef, inIntervalSecFloat=inIntervalSecFloat, inIntervalAsyncBool=inIntervalAsyncBool,
inDefArgList=inDefArgList, inDefArgDict=inDefArgDict, inLogger=inLogger,
inDefArgGSettingsNameStr=inDefArgGSettingsNameStr , inDefArgLoggerNameStr=inDefArgLoggerNameStr)
# Python def - start module function
def PythonStart(inModulePathStr, inDefNameStr, inArgList=None, inArgDict=None, inLogger = None):
"""
@ -1602,24 +1902,28 @@ def GSettingsAutocleaner(inGSettings):
else:
if lL: lL.debug(f"Client > Session > TechnicalSessionGUIDCache > lItemKeyStr: Lifetime is expired. Remove from gSettings") # Info
inGSettings["Client"]["Session"]["TechnicalSessionGUIDCache"] = lTechnicalSessionGUIDCacheNew # Set updated Cache
# Clean old items in AgentActivityReturnDict > GUIDStr > ReturnedByDatetime
lTechnicalAgentActivityReturnDictNew = {}
for lItemKeyStr in inGSettings["AgentActivityReturnDict"]:
lItemValue = inGSettings["AgentActivityReturnDict"][lItemKeyStr]
if (lNowDatetime - lItemValue["ReturnedByDatetime"]).total_seconds() < inGSettings["Autocleaner"]["AgentActivityReturnLifetimeSecFloat"]: # Add if lifetime is ok
lTechnicalAgentActivityReturnDictNew[lItemKeyStr]=lItemValue # Lifetime is ok - set
else:
if lL: lL.debug(f"AgentActivityReturnDict lItemKeyStr: Lifetime is expired. Remove from gSettings") # Info
inGSettings["AgentActivityReturnDict"] = lTechnicalAgentActivityReturnDictNew # Set updated Cache
# # # # # # # # # # # # # # # # # # # # # # # # # #
from .. import __version__ # Get version from the package
def Orchestrator(inGSettings):
def Orchestrator(inGSettings, inDumpRestoreBool = True, inRunAsAdministratorBool = True):
lL = inGSettings["Logger"]
# https://stackoverflow.com/questions/130763/request-uac-elevation-from-within-a-python-script
def is_admin():
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except:
return False
if not is_admin():
# Re-run the program with admin rights
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
if not OrchestratorIsAdmin() and inRunAsAdministratorBool==True:
OrchestratorRerunAsAdmin()
else:
# Code of your program here
#mGlobalDict = Settings.Settings(sys.argv[1])
global gSettingsDict
gSettingsDict = inGSettings # Alias for old name in alg
inGSettings["VersionStr"] = __version__
#Logger alias
@ -1632,17 +1936,9 @@ def Orchestrator(inGSettings):
Server.gSettingsDict = gSettingsDict
Server.ProcessorOld.gSettingsDict = gSettingsDict # Backward compatibility
# Check _SessionLast_RDPList.json in working directory. if exist - load into gsettings
# GSettings
#"RobotRDPActive": {
# "RDPList": {
if os.path.exists("_SessionLast_RDPList.json"):
lFile = open("_SessionLast_RDPList.json", "r", encoding="utf-8")
lSessionLastRDPList = json.loads(lFile.read())
lFile.close() # Close the file
os.remove("_SessionLast_RDPList.json") # remove the temp file
gSettingsDict["RobotRDPActive"]["RDPList"]=lSessionLastRDPList # Set the last session dict
if lL: lL.warning(f"RDP Session List was restored from previous Orchestrator session")
#Backward compatibility - restore in Orc def if old def
if inDumpRestoreBool == True:
OrchestratorSessionRestore(inGSettings=inGSettings)
# Init SettingsUpdate defs from file list (after RDP restore)
lSettingsUpdateFilePathList = gSettingsDict.get("OrchestratorStart", {}).get("DefSettingsUpdatePathList",[])
@ -1714,10 +2010,19 @@ def Orchestrator(inGSettings):
lProcessorThread.start() # Start the thread execution.
if lL: lL.info("Processor has been started (ProcessorDict)") #Logging
# Processor monitor thread
lProcessorMonitorThread = threading.Thread(target= Processor.ProcessorMonitorRunSync, kwargs={"inGSettings":gSettingsDict})
lProcessorMonitorThread.daemon = True # Run the thread in daemon mode.
lProcessorMonitorThread.start() # Start the thread execution.
if lL: lL.info("Processor monitor has been started") #Logging
if lL: lL.info("Scheduler loop start") #Logging
gDaemonActivityLogDictRefreshSecInt = 10 # The second period for clear lDaemonActivityLogDict from old items
gDaemonActivityLogDictLastTime = time.time() # The second perioad for clean lDaemonActivityLogDict from old items
# Set flag that orchestrator has been initialized
inGSettings["HiddenIsOrchestratorInitializedBool"] = True
while True:
try:
lCurrentDateTime = datetime.datetime.now()

@ -3,7 +3,7 @@ r"""
The OpenRPA package (from UnicodeLabs)
"""
__version__ = 'v1.2.1'
__version__ = 'v1.2.2'
__all__ = []
__author__ = 'Ivan Maslov <ivan.maslov@unicodelabs.ru>'
#from .Core import Robot

@ -3,7 +3,7 @@ r"""
The OpenRPA package (from UnicodeLabs)
"""
__version__ = 'v1.2.1'
__version__ = 'v1.2.2'
__all__ = []
__author__ = 'Ivan Maslov <ivan.maslov@unicodelabs.ru>'
#from .Core import Robot

@ -309,124 +309,127 @@
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.OSCredentialsVerify" title="pyOpenRPA.Orchestrator.__Orchestrator__.OSCredentialsVerify"><code class="xref py py-obj docutils literal notranslate"><span class="pre">OSCredentialsVerify</span></code></a>(inUserStr, inPasswordStr)</p></td>
<td><p>Verify user credentials in windows.</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorIsAdmin" title="pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorIsAdmin"><code class="xref py py-obj docutils literal notranslate"><span class="pre">OrchestratorIsAdmin</span></code></a>()</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.OSRemotePCRestart" title="pyOpenRPA.Orchestrator.__Orchestrator__.OSRemotePCRestart"><code class="xref py py-obj docutils literal notranslate"><span class="pre">OSRemotePCRestart</span></code></a>(inLogger, inHostStr[, …])</p></td>
<td><p>Send signal via power shell to restart remote PC ATTENTION: Orchestrator user need to have restart right on the Remote machine to restart PC.</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorIsAdmin" title="pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorIsAdmin"><code class="xref py py-obj docutils literal notranslate"><span class="pre">OrchestratorIsAdmin</span></code></a>()</p></td>
<td><p>Check if Orchestrator process is running as administrator</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorRerunAsAdmin" title="pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorRerunAsAdmin"><code class="xref py py-obj docutils literal notranslate"><span class="pre">OrchestratorRerunAsAdmin</span></code></a>()</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorRerunAsAdmin" title="pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorRerunAsAdmin"><code class="xref py py-obj docutils literal notranslate"><span class="pre">OrchestratorRerunAsAdmin</span></code></a>()</p></td>
<td><p>Check if not admin - then rerun orchestrator as administrator</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorRestart" title="pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorRestart"><code class="xref py py-obj docutils literal notranslate"><span class="pre">OrchestratorRestart</span></code></a>([inGSettings])</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorRestart" title="pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorRestart"><code class="xref py py-obj docutils literal notranslate"><span class="pre">OrchestratorRestart</span></code></a>([inGSettings])</p></td>
<td><p>Orchestrator restart</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorSessionRestore" title="pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorSessionRestore"><code class="xref py py-obj docutils literal notranslate"><span class="pre">OrchestratorSessionRestore</span></code></a>(inGSettings)</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorSessionRestore" title="pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorSessionRestore"><code class="xref py py-obj docutils literal notranslate"><span class="pre">OrchestratorSessionRestore</span></code></a>(inGSettings)</p></td>
<td><p>Check _SessionLast_RDPList.json and _SessionLast_StorageDict.pickle in working directory. if exist - load into gsettings # _SessionLast_StorageDict.pickle (binary) _SessionLast_RDPList.json (encoding = “utf-8”) _SessionLast_StorageDict.pickle (binary).</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorSessionSave" title="pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorSessionSave"><code class="xref py py-obj docutils literal notranslate"><span class="pre">OrchestratorSessionSave</span></code></a>(inGSettings)</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorSessionSave" title="pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorSessionSave"><code class="xref py py-obj docutils literal notranslate"><span class="pre">OrchestratorSessionSave</span></code></a>(inGSettings)</p></td>
<td><p>Orchestrator session save in file</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessDefIntervalCall" title="pyOpenRPA.Orchestrator.__Orchestrator__.ProcessDefIntervalCall"><code class="xref py py-obj docutils literal notranslate"><span class="pre">ProcessDefIntervalCall</span></code></a>(inGSettings, inDef, …)</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessDefIntervalCall" title="pyOpenRPA.Orchestrator.__Orchestrator__.ProcessDefIntervalCall"><code class="xref py py-obj docutils literal notranslate"><span class="pre">ProcessDefIntervalCall</span></code></a>(inGSettings, inDef, …)</p></td>
<td><p>Use this procedure if you need to run periodically some def.</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessIsStarted" title="pyOpenRPA.Orchestrator.__Orchestrator__.ProcessIsStarted"><code class="xref py py-obj docutils literal notranslate"><span class="pre">ProcessIsStarted</span></code></a>(inProcessNameWOExeStr)</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessIsStarted" title="pyOpenRPA.Orchestrator.__Orchestrator__.ProcessIsStarted"><code class="xref py py-obj docutils literal notranslate"><span class="pre">ProcessIsStarted</span></code></a>(inProcessNameWOExeStr)</p></td>
<td><p>Check if there is any running process that contains the given name processName.</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessListGet" title="pyOpenRPA.Orchestrator.__Orchestrator__.ProcessListGet"><code class="xref py py-obj docutils literal notranslate"><span class="pre">ProcessListGet</span></code></a>([inProcessNameWOExeList])</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessListGet" title="pyOpenRPA.Orchestrator.__Orchestrator__.ProcessListGet"><code class="xref py py-obj docutils literal notranslate"><span class="pre">ProcessListGet</span></code></a>([inProcessNameWOExeList])</p></td>
<td><p>Return process list on the orchestrator machine sorted by Memory Usage.</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessStart" title="pyOpenRPA.Orchestrator.__Orchestrator__.ProcessStart"><code class="xref py py-obj docutils literal notranslate"><span class="pre">ProcessStart</span></code></a>(inPathStr, inArgList[, …])</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessStart" title="pyOpenRPA.Orchestrator.__Orchestrator__.ProcessStart"><code class="xref py py-obj docutils literal notranslate"><span class="pre">ProcessStart</span></code></a>(inPathStr, inArgList[, …])</p></td>
<td><p>Start process locally.</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessStop" title="pyOpenRPA.Orchestrator.__Orchestrator__.ProcessStop"><code class="xref py py-obj docutils literal notranslate"><span class="pre">ProcessStop</span></code></a>(inProcessNameWOExeStr, …[, …])</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessStop" title="pyOpenRPA.Orchestrator.__Orchestrator__.ProcessStop"><code class="xref py py-obj docutils literal notranslate"><span class="pre">ProcessStop</span></code></a>(inProcessNameWOExeStr, …[, …])</p></td>
<td><p>Stop process on the orchestrator machine.</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessorActivityItemAppend" title="pyOpenRPA.Orchestrator.__Orchestrator__.ProcessorActivityItemAppend"><code class="xref py py-obj docutils literal notranslate"><span class="pre">ProcessorActivityItemAppend</span></code></a>(inGSettings[, …])</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessorActivityItemAppend" title="pyOpenRPA.Orchestrator.__Orchestrator__.ProcessorActivityItemAppend"><code class="xref py py-obj docutils literal notranslate"><span class="pre">ProcessorActivityItemAppend</span></code></a>(inGSettings[, …])</p></td>
<td><p>Create and add activity item in processor queue.</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessorActivityItemCreate" title="pyOpenRPA.Orchestrator.__Orchestrator__.ProcessorActivityItemCreate"><code class="xref py py-obj docutils literal notranslate"><span class="pre">ProcessorActivityItemCreate</span></code></a>(inDef[, …])</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessorActivityItemCreate" title="pyOpenRPA.Orchestrator.__Orchestrator__.ProcessorActivityItemCreate"><code class="xref py py-obj docutils literal notranslate"><span class="pre">ProcessorActivityItemCreate</span></code></a>(inDef[, …])</p></td>
<td><p>Create activity item.</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessorAliasDefCreate" title="pyOpenRPA.Orchestrator.__Orchestrator__.ProcessorAliasDefCreate"><code class="xref py py-obj docutils literal notranslate"><span class="pre">ProcessorAliasDefCreate</span></code></a>(inGSettings, inDef)</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessorAliasDefCreate" title="pyOpenRPA.Orchestrator.__Orchestrator__.ProcessorAliasDefCreate"><code class="xref py py-obj docutils literal notranslate"><span class="pre">ProcessorAliasDefCreate</span></code></a>(inGSettings, inDef)</p></td>
<td><p>Create alias for def (can be used in ActivityItem in field Def) !WHEN DEF ALIAS IS REQUIRED! - Def alias is required when you try to call Python def from the Orchestrator WEB side (because you cant transmit Python def object out of the Python environment)</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessorAliasDefUpdate" title="pyOpenRPA.Orchestrator.__Orchestrator__.ProcessorAliasDefUpdate"><code class="xref py py-obj docutils literal notranslate"><span class="pre">ProcessorAliasDefUpdate</span></code></a>(inGSettings, inDef, …)</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessorAliasDefUpdate" title="pyOpenRPA.Orchestrator.__Orchestrator__.ProcessorAliasDefUpdate"><code class="xref py py-obj docutils literal notranslate"><span class="pre">ProcessorAliasDefUpdate</span></code></a>(inGSettings, inDef, …)</p></td>
<td><p>Update alias for def (can be used in ActivityItem in field Def).</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.PythonStart" title="pyOpenRPA.Orchestrator.__Orchestrator__.PythonStart"><code class="xref py py-obj docutils literal notranslate"><span class="pre">PythonStart</span></code></a>(inModulePathStr, inDefNameStr[, …])</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.PythonStart" title="pyOpenRPA.Orchestrator.__Orchestrator__.PythonStart"><code class="xref py py-obj docutils literal notranslate"><span class="pre">PythonStart</span></code></a>(inModulePathStr, inDefNameStr[, …])</p></td>
<td><p>Import module and run def in the Orchestrator process.</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionCMDRun" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionCMDRun"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionCMDRun</span></code></a>(inGSettings, …[, inModeStr])</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionCMDRun" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionCMDRun"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionCMDRun</span></code></a>(inGSettings, …[, inModeStr])</p></td>
<td><p>Send CMD command to the RDP session “RUN” window</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionConnect" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionConnect"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionConnect</span></code></a>(inGSettings, …[, …])</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionConnect" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionConnect"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionConnect</span></code></a>(inGSettings, …[, …])</p></td>
<td><p>Create new RDPSession in RobotRDPActive. Attention - activity will be ignored if RDP key is already exists</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionDisconnect" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionDisconnect"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionDisconnect</span></code></a>(inGSettings, …[, …])</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionDisconnect" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionDisconnect"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionDisconnect</span></code></a>(inGSettings, …[, …])</p></td>
<td><p>Disconnect the RDP session and stop monitoring it.</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionDublicatesResolve" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionDublicatesResolve"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionDublicatesResolve</span></code></a>(inGSettings)</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionDublicatesResolve" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionDublicatesResolve"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionDublicatesResolve</span></code></a>(inGSettings)</p></td>
<td><p>DEVELOPING Search duplicates in GSettings RDPlist !def is developing!</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionFileStoredRecieve" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionFileStoredRecieve"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionFileStoredRecieve</span></code></a>(inGSettings, …)</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionFileStoredRecieve" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionFileStoredRecieve"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionFileStoredRecieve</span></code></a>(inGSettings, …)</p></td>
<td><p>Recieve file from RDP session to the Orchestrator session using shared drive in RDP (see RDP Configuration Dict, Shared drive)</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionFileStoredSend" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionFileStoredSend"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionFileStoredSend</span></code></a>(inGSettings, …)</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionFileStoredSend" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionFileStoredSend"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionFileStoredSend</span></code></a>(inGSettings, …)</p></td>
<td><p>Send file from Orchestrator session to the RDP session using shared drive in RDP (see RDP Configuration Dict, Shared drive)</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionLogoff" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionLogoff"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionLogoff</span></code></a>(inGSettings, inRDPSessionKeyStr)</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionLogoff" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionLogoff"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionLogoff</span></code></a>(inGSettings, inRDPSessionKeyStr)</p></td>
<td><p>Logoff the RDP session from the Orchestrator process (close all apps in session when logoff)</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionMonitorStop" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionMonitorStop"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionMonitorStop</span></code></a>(inGSettings, …)</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionMonitorStop" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionMonitorStop"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionMonitorStop</span></code></a>(inGSettings, …)</p></td>
<td><p>Stop monitoring the RDP session by the Orchestrator process.</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionProcessStartIfNotRunning" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionProcessStartIfNotRunning"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionProcessStartIfNotRunning</span></code></a>(…[, …])</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionProcessStartIfNotRunning" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionProcessStartIfNotRunning"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionProcessStartIfNotRunning</span></code></a>(…[, …])</p></td>
<td><p>Start process in RDP if it is not running (check by the arg inProcessNameWEXEStr)</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionProcessStop" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionProcessStop"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionProcessStop</span></code></a>(inGSettings, …)</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionProcessStop" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionProcessStop"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionProcessStop</span></code></a>(inGSettings, …)</p></td>
<td><p>Send CMD command to the RDP session “RUN” window.</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionReconnect" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionReconnect"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionReconnect</span></code></a>(inGSettings, …[, …])</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionReconnect" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionReconnect"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionReconnect</span></code></a>(inGSettings, …[, …])</p></td>
<td><p>Reconnect the RDP session</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionResponsibilityCheck" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionResponsibilityCheck"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionResponsibilityCheck</span></code></a>(inGSettings, …)</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionResponsibilityCheck" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPSessionResponsibilityCheck"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPSessionResponsibilityCheck</span></code></a>(inGSettings, …)</p></td>
<td><p>DEVELOPING, MAYBE NOT USEFUL Check RDP Session responsibility TODO NEED DEV + TEST</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPTemplateCreate" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPTemplateCreate"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPTemplateCreate</span></code></a>(inLoginStr, inPasswordStr)</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.RDPTemplateCreate" title="pyOpenRPA.Orchestrator.__Orchestrator__.RDPTemplateCreate"><code class="xref py py-obj docutils literal notranslate"><span class="pre">RDPTemplateCreate</span></code></a>(inLoginStr, inPasswordStr)</p></td>
<td><p>Create RDP connect dict item/ Use it connect/reconnect (Orchestrator.RDPSessionConnect)</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.SchedulerActivityTimeAddWeekly" title="pyOpenRPA.Orchestrator.__Orchestrator__.SchedulerActivityTimeAddWeekly"><code class="xref py py-obj docutils literal notranslate"><span class="pre">SchedulerActivityTimeAddWeekly</span></code></a>(inGSettings)</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.SchedulerActivityTimeAddWeekly" title="pyOpenRPA.Orchestrator.__Orchestrator__.SchedulerActivityTimeAddWeekly"><code class="xref py py-obj docutils literal notranslate"><span class="pre">SchedulerActivityTimeAddWeekly</span></code></a>(inGSettings)</p></td>
<td><p>Add activity item list in scheduler.</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.UACKeyListCheck" title="pyOpenRPA.Orchestrator.__Orchestrator__.UACKeyListCheck"><code class="xref py py-obj docutils literal notranslate"><span class="pre">UACKeyListCheck</span></code></a>(inRequest, inRoleKeyList)</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.UACKeyListCheck" title="pyOpenRPA.Orchestrator.__Orchestrator__.UACKeyListCheck"><code class="xref py py-obj docutils literal notranslate"><span class="pre">UACKeyListCheck</span></code></a>(inRequest, inRoleKeyList)</p></td>
<td><p>Check is client is has access for the key list</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.UACSuperTokenUpdate" title="pyOpenRPA.Orchestrator.__Orchestrator__.UACSuperTokenUpdate"><code class="xref py py-obj docutils literal notranslate"><span class="pre">UACSuperTokenUpdate</span></code></a>(inGSettings, inSuperTokenStr)</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.UACSuperTokenUpdate" title="pyOpenRPA.Orchestrator.__Orchestrator__.UACSuperTokenUpdate"><code class="xref py py-obj docutils literal notranslate"><span class="pre">UACSuperTokenUpdate</span></code></a>(inGSettings, inSuperTokenStr)</p></td>
<td><p>Add supertoken for the all access (it is need for the robot communication without human)</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.UACUpdate" title="pyOpenRPA.Orchestrator.__Orchestrator__.UACUpdate"><code class="xref py py-obj docutils literal notranslate"><span class="pre">UACUpdate</span></code></a>(inGSettings, inADLoginStr[, …])</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.UACUpdate" title="pyOpenRPA.Orchestrator.__Orchestrator__.UACUpdate"><code class="xref py py-obj docutils literal notranslate"><span class="pre">UACUpdate</span></code></a>(inGSettings, inADLoginStr[, …])</p></td>
<td><p>Update user access (UAC)</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.UACUserDictGet" title="pyOpenRPA.Orchestrator.__Orchestrator__.UACUserDictGet"><code class="xref py py-obj docutils literal notranslate"><span class="pre">UACUserDictGet</span></code></a>(inRequest)</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.UACUserDictGet" title="pyOpenRPA.Orchestrator.__Orchestrator__.UACUserDictGet"><code class="xref py py-obj docutils literal notranslate"><span class="pre">UACUserDictGet</span></code></a>(inRequest)</p></td>
<td><p>Return user UAC hierarchy dict of the inRequest object.</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.WebCPUpdate" title="pyOpenRPA.Orchestrator.__Orchestrator__.WebCPUpdate"><code class="xref py py-obj docutils literal notranslate"><span class="pre">WebCPUpdate</span></code></a>(inGSettings, inCPKeyStr[, …])</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.WebCPUpdate" title="pyOpenRPA.Orchestrator.__Orchestrator__.WebCPUpdate"><code class="xref py py-obj docutils literal notranslate"><span class="pre">WebCPUpdate</span></code></a>(inGSettings, inCPKeyStr[, …])</p></td>
<td><p>Add control panel HTML, JSON generator or JS when page init</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.WebURLConnectDef" title="pyOpenRPA.Orchestrator.__Orchestrator__.WebURLConnectDef"><code class="xref py py-obj docutils literal notranslate"><span class="pre">WebURLConnectDef</span></code></a>(inGSettings, inMethodStr, …)</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.WebURLConnectDef" title="pyOpenRPA.Orchestrator.__Orchestrator__.WebURLConnectDef"><code class="xref py py-obj docutils literal notranslate"><span class="pre">WebURLConnectDef</span></code></a>(inGSettings, inMethodStr, …)</p></td>
<td><p>Connect URL to DEF</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.WebURLConnectFile" title="pyOpenRPA.Orchestrator.__Orchestrator__.WebURLConnectFile"><code class="xref py py-obj docutils literal notranslate"><span class="pre">WebURLConnectFile</span></code></a>(inGSettings, inMethodStr, …)</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.WebURLConnectFile" title="pyOpenRPA.Orchestrator.__Orchestrator__.WebURLConnectFile"><code class="xref py py-obj docutils literal notranslate"><span class="pre">WebURLConnectFile</span></code></a>(inGSettings, inMethodStr, …)</p></td>
<td><p>Connect URL to File</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.WebURLConnectFolder" title="pyOpenRPA.Orchestrator.__Orchestrator__.WebURLConnectFolder"><code class="xref py py-obj docutils literal notranslate"><span class="pre">WebURLConnectFolder</span></code></a>(inGSettings, …)</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.WebURLConnectFolder" title="pyOpenRPA.Orchestrator.__Orchestrator__.WebURLConnectFolder"><code class="xref py py-obj docutils literal notranslate"><span class="pre">WebURLConnectFolder</span></code></a>(inGSettings, …)</p></td>
<td><p>Connect URL to Folder</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.WebUserInfoGet" title="pyOpenRPA.Orchestrator.__Orchestrator__.WebUserInfoGet"><code class="xref py py-obj docutils literal notranslate"><span class="pre">WebUserInfoGet</span></code></a>(inRequest)</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.WebUserInfoGet" title="pyOpenRPA.Orchestrator.__Orchestrator__.WebUserInfoGet"><code class="xref py py-obj docutils literal notranslate"><span class="pre">WebUserInfoGet</span></code></a>(inRequest)</p></td>
<td><p>Return User info about request</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.WebUserIsSuperToken" title="pyOpenRPA.Orchestrator.__Orchestrator__.WebUserIsSuperToken"><code class="xref py py-obj docutils literal notranslate"><span class="pre">WebUserIsSuperToken</span></code></a>(inRequest, inGSettings)</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.WebUserIsSuperToken" title="pyOpenRPA.Orchestrator.__Orchestrator__.WebUserIsSuperToken"><code class="xref py py-obj docutils literal notranslate"><span class="pre">WebUserIsSuperToken</span></code></a>(inRequest, inGSettings)</p></td>
<td><p>Return bool if request is authentificated with supetoken (token which is never expires)</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.WebUserUACHierarchyGet" title="pyOpenRPA.Orchestrator.__Orchestrator__.WebUserUACHierarchyGet"><code class="xref py py-obj docutils literal notranslate"><span class="pre">WebUserUACHierarchyGet</span></code></a>(inRequest)</p></td>
<tr class="row-even"><td><p><a class="reference internal" href="#pyOpenRPA.Orchestrator.__Orchestrator__.WebUserUACHierarchyGet" title="pyOpenRPA.Orchestrator.__Orchestrator__.WebUserUACHierarchyGet"><code class="xref py py-obj docutils literal notranslate"><span class="pre">WebUserUACHierarchyGet</span></code></a>(inRequest)</p></td>
<td><p>Return User UAC Hierarchy DICT Return {…}</p></td>
</tr>
</tbody>
@ -784,6 +787,25 @@
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Orchestrator.__Orchestrator__.OSRemotePCRestart">
<code class="sig-prename descclassname">pyOpenRPA.Orchestrator.__Orchestrator__.</code><code class="sig-name descname">OSRemotePCRestart</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inLogger</span></em>, <em class="sig-param"><span class="n">inHostStr</span></em>, <em class="sig-param"><span class="n">inForceBool</span><span class="o">=</span><span class="default_value">True</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Orchestrator/__Orchestrator__.html#OSRemotePCRestart"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Orchestrator.__Orchestrator__.OSRemotePCRestart" title="Permalink to this definition"></a></dt>
<dd><p>Send signal via power shell to restart remote PC
ATTENTION: Orchestrator user need to have restart right on the Remote machine to restart PC.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>inLogger</strong> logger to log powershell result in logs</p></li>
<li><p><strong>inHostStr</strong> PC hostname which you need to restart.</p></li>
<li><p><strong>inForceBool</strong> True - send signal to force retart PC; False - else case</p></li>
</ul>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p></p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorIsAdmin">
<code class="sig-prename descclassname">pyOpenRPA.Orchestrator.__Orchestrator__.</code><code class="sig-name descname">OrchestratorIsAdmin</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Orchestrator/__Orchestrator__.html#OrchestratorIsAdmin"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorIsAdmin" title="Permalink to this definition"></a></dt>

@ -359,6 +359,16 @@
<span class="p">},</span>
<span class="c1"># # # # # # # # # # # # # #</span>
<span class="s2">&quot;RobotRDPActive&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="s2">&quot;RecoveryDict&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="s2">&quot;CatchPeriodSecFloat&quot;</span><span class="p">:</span> <span class="mi">1200</span><span class="p">,</span> <span class="c1"># Catch last 10 minutes</span>
<span class="s2">&quot;TriggerCountInt&quot;</span><span class="p">:</span> <span class="mi">10</span><span class="p">,</span> <span class="c1"># Activate trigger if for the period orch will catch the reconnect RDP n times</span>
<span class="s2">&quot;DoDict&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="s2">&quot;OSRemotePCRestart&quot;</span><span class="p">:</span> <span class="kc">True</span> <span class="c1"># Do powershell remote restart</span>
<span class="p">},</span>
<span class="s2">&quot;__StatisticsDict__&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="c1"># RDPSessionKeyStr : [time.time(), time.time()],</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="s2">&quot;RDPList&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="c1"># &quot;RDPSessionKey&quot;:{</span>
<span class="c1"># &quot;Host&quot;: &quot;77.77.22.22&quot;, # Host address</span>

@ -451,6 +451,20 @@
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">True</span></div>
<div class="viewcode-block" id="OSRemotePCRestart"><a class="viewcode-back" href="../../../Orchestrator/02_Defs.html#pyOpenRPA.Orchestrator.__Orchestrator__.OSRemotePCRestart">[docs]</a><span class="k">def</span> <span class="nf">OSRemotePCRestart</span><span class="p">(</span><span class="n">inLogger</span><span class="p">,</span> <span class="n">inHostStr</span><span class="p">,</span> <span class="n">inForceBool</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Send signal via power shell to restart remote PC</span>
<span class="sd"> ATTENTION: Orchestrator user need to have restart right on the Remote machine to restart PC.</span>
<span class="sd"> :param inLogger: logger to log powershell result in logs</span>
<span class="sd"> :param inHostStr: PC hostname which you need to restart.</span>
<span class="sd"> :param inForceBool: True - send signal to force retart PC; False - else case</span>
<span class="sd"> :return:</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">lCMDStr</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;powershell -Command Restart-Computer -ComputerName </span><span class="si">{</span><span class="n">inHostStr</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="k">if</span> <span class="n">inForceBool</span> <span class="o">==</span> <span class="kc">True</span><span class="p">:</span> <span class="n">lCMDStr</span> <span class="o">=</span> <span class="n">lCMDStr</span> <span class="o">+</span> <span class="s2">&quot; -Force&quot;</span>
<span class="n">OSCMD</span><span class="p">(</span><span class="n">inCMDStr</span><span class="o">=</span><span class="n">lCMDStr</span><span class="p">,</span><span class="n">inLogger</span><span class="o">=</span><span class="n">inLogger</span><span class="p">)</span></div>
<div class="viewcode-block" id="OSCMD"><a class="viewcode-back" href="../../../Orchestrator/02_Defs.html#pyOpenRPA.Orchestrator.__Orchestrator__.OSCMD">[docs]</a><span class="k">def</span> <span class="nf">OSCMD</span><span class="p">(</span><span class="n">inCMDStr</span><span class="p">,</span> <span class="n">inRunAsyncBool</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">inLogger</span> <span class="o">=</span> <span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> OS send command in shell locally</span>

@ -303,6 +303,8 @@
<li><a href="Agent/02_Defs.html#pyOpenRPA.Agent.__Agent__.OSFileTextDataStrCreate">OSFileTextDataStrCreate() (in module pyOpenRPA.Agent.__Agent__)</a>
</li>
<li><a href="Agent/02_Defs.html#pyOpenRPA.Agent.__Agent__.OSFileTextDataStrReceive">OSFileTextDataStrReceive() (in module pyOpenRPA.Agent.__Agent__)</a>
</li>
<li><a href="Orchestrator/02_Defs.html#pyOpenRPA.Orchestrator.__Orchestrator__.OSRemotePCRestart">OSRemotePCRestart() (in module pyOpenRPA.Orchestrator.__Orchestrator__)</a>
</li>
</ul></td>
</tr></table>

Binary file not shown.

File diff suppressed because one or more lines are too long

@ -138,6 +138,11 @@ Work with activity scheduling.
| Verify user credentials in windows.
|
| `OSRemotePCRestart`(inLogger, inHostStr[, …])
| Send signal via power shell to restart remote PC ATTENTION: Orchestrator user need to have restart right on the Remote machine to restart PC.
|
| `OrchestratorIsAdmin`()
@ -804,6 +809,29 @@ Verify user credentials in windows. Return bool
### pyOpenRPA.Orchestrator.__Orchestrator__.OSRemotePCRestart(inLogger, inHostStr, inForceBool=True)
Send signal via power shell to restart remote PC
ATTENTION: Orchestrator user need to have restart right on the Remote machine to restart PC.
* **Parameters**
* **inLogger** logger to log powershell result in logs
* **inHostStr** PC hostname which you need to restart.
* **inForceBool** True - send signal to force retart PC; False - else case
* **Returns**
### pyOpenRPA.Orchestrator.__Orchestrator__.OrchestratorIsAdmin()
Check if Orchestrator process is running as administrator

@ -177,6 +177,16 @@ def __Create__():
},
# # # # # # # # # # # # # #
"RobotRDPActive": {
"RecoveryDict": {
"CatchPeriodSecFloat": 1200, # Catch last 10 minutes
"TriggerCountInt": 10, # Activate trigger if for the period orch will catch the reconnect RDP n times
"DoDict": {
"OSRemotePCRestart": True # Do powershell remote restart
},
"__StatisticsDict__": {
# RDPSessionKeyStr : [time.time(), time.time()],
}
},
"RDPList": {
# "RDPSessionKey":{
# "Host": "77.77.22.22", # Host address

Loading…
Cancel
Save