parent
f6a364518e
commit
90f2b6a568
@ -1,4 +1,4 @@
|
|||||||
cd %~dp0\..\Sources
|
cd %~dp0\..\Sources
|
||||||
copy /Y ..\Resources\WPy64-3720\python-3.7.2.amd64\python.exe ..\Resources\WPy64-3720\python-3.7.2.amd64\OpenRPA_Orchestrator.exe
|
copy /Y ..\Resources\WPy64-3720\python-3.7.2.amd64\python.exe ..\Resources\WPy64-3720\python-3.7.2.amd64\OpenRPA_Orchestrator.exe
|
||||||
.\..\Resources\WPy64-3720\python-3.7.2.amd64\OpenRPA_Orchestrator.exe -m pyOpenRPA.Orchestrator "..\Orchestrator\Settings\Settings.py"
|
.\..\Resources\WPy64-3720\python-3.7.2.amd64\OpenRPA_Orchestrator.exe -m pyOpenRPA.Orchestrator "..\Orchestrator\Settings\SettingsOrchestratorExample.py"
|
||||||
pause >nul
|
pause >nul
|
@ -1,6 +1,6 @@
|
|||||||
Metadata-Version: 2.1
|
Metadata-Version: 2.1
|
||||||
Name: pyOpenRPA
|
Name: pyOpenRPA
|
||||||
Version: 1.0.32
|
Version: 1.0.34
|
||||||
Summary: First open source RPA platform for business
|
Summary: First open source RPA platform for business
|
||||||
Home-page: https://gitlab.com/UnicodeLabs/OpenRPA
|
Home-page: https://gitlab.com/UnicodeLabs/OpenRPA
|
||||||
Author: Ivan Maslov
|
Author: Ivan Maslov
|
@ -1,46 +0,0 @@
|
|||||||
import requests
|
|
||||||
import grequests
|
|
||||||
#from requests import async
|
|
||||||
import json
|
|
||||||
###################################
|
|
||||||
##Orchestrator integration module (safe use when orchestrator is turned off)
|
|
||||||
###################################
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
#Send data to orchestrator (asynchronyous)
|
|
||||||
#Example: t=IntegrationOrchestrator.DataSend(["Storage","Robot_R01"],{"RunDateTimeString":"Test1","StepCurrentName":"Test2","StepCurrentDuration":"Test333","SafeStopSignal":True},"localhost",8081)
|
|
||||||
def DataSend(inKeyList,inValue,inOrchestratorHost="localhost",inOrchestratorPort=80):
|
|
||||||
lURL = f'http://{inOrchestratorHost}:{inOrchestratorPort}/ProcessingRun'
|
|
||||||
lDataJSON = {"actionList":[{"type":"AdministrationGlobalDictSetKeyListValue","key_list":inKeyList,"value":inValue}]}
|
|
||||||
#lAsyncList = []
|
|
||||||
lResultItem = [grequests.post(lURL, json=lDataJSON)]
|
|
||||||
return grequests.map(lResultItem)
|
|
||||||
#lAsyncList.append(lResultItem)
|
|
||||||
#return async.map(lAsyncList)
|
|
||||||
################################################################################
|
|
||||||
#recieve Data from orchestrator
|
|
||||||
#t=IntegrationOrchestrator.DataRecieve(["Storage","Robot_R01"],"localhost",8081)
|
|
||||||
def DataRecieve(inKeyList,inOrchestratorHost="localhost",inOrchestratorPort=80):
|
|
||||||
lURL = f'http://{inOrchestratorHost}:{inOrchestratorPort}/ProcessingRun'
|
|
||||||
lDataJSON = {"actionList":[{"type":"AdministrationGlobalDictGetKeyListValue","key_list":inKeyList}]}
|
|
||||||
try:
|
|
||||||
lResult = requests.post(lURL, json=lDataJSON)
|
|
||||||
lResultJSON = json.loads(lResult.text)
|
|
||||||
return lResultJSON["actionListResult"][0]["value"]
|
|
||||||
except Exception:
|
|
||||||
return None
|
|
||||||
################################################################################
|
|
||||||
#Check if orchestrator has safe stop signal
|
|
||||||
#Example: IntegrationOrchestrator.SafeStopSignalIs(["Storage","Robot_R01","SafeStopSignal"],"localhost",8081)
|
|
||||||
def SafeStopSignalIs(inKeyList,inOrchestratorHost="localhost",inOrchestratorPort=80):
|
|
||||||
lResult=False
|
|
||||||
lResponse=DataRecieve(inKeyList,inOrchestratorHost,inOrchestratorPort)
|
|
||||||
if lResponse is not None:
|
|
||||||
lResult = lResponse
|
|
||||||
return lResult
|
|
||||||
################################################################################
|
|
||||||
#Reset SafeStop signal in orchestrator
|
|
||||||
#Example: t=IntegrationOrchestrator.SafeStopSignalReset(["Storage","Robot_R01","SafeStopSignal"],"localhost",8081)
|
|
||||||
def SafeStopSignalReset(inKeyList,inOrchestratorHost="localhost",inOrchestratorPort=80):
|
|
||||||
lResponse=DataSend(inKeyList,False,inOrchestratorHost,inOrchestratorPort)
|
|
||||||
return lResponse
|
|
@ -0,0 +1,401 @@
|
|||||||
|
import requests
|
||||||
|
#Logging
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import datetime
|
||||||
|
import copy
|
||||||
|
from .Utils import TimerRepeat # Timer which can repeating
|
||||||
|
mLogger=logging.getLogger("OrchestratorConnector")
|
||||||
|
#########################
|
||||||
|
mTimerList=[]
|
||||||
|
def IntervalTerminateAll():
|
||||||
|
for lItem in mTimerList:
|
||||||
|
lItem.stop()
|
||||||
|
#########################
|
||||||
|
# Создать файл логирования
|
||||||
|
# add filemode="w" to overwrite
|
||||||
|
if not os.path.exists("Reports"):
|
||||||
|
os.makedirs("Reports")
|
||||||
|
##########################
|
||||||
|
# Подготовка логгера Robot
|
||||||
|
#########################
|
||||||
|
mLogger.setLevel(logging.INFO)
|
||||||
|
# create the logging file handler
|
||||||
|
mLoggerFH = logging.FileHandler("Reports\ReportOrchestratorConnector_" + datetime.datetime.now().strftime("%Y_%m_%d") + ".log")
|
||||||
|
mLoggerFormatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||||
|
mLoggerFH.setFormatter(mLoggerFormatter)
|
||||||
|
# add handler to logger object
|
||||||
|
mLogger.addHandler(mLoggerFH)
|
||||||
|
############################################
|
||||||
|
#Turn loggin level ERROR
|
||||||
|
def LoggerSetLevelError():
|
||||||
|
mLogger.setLevel(logging.ERROR)
|
||||||
|
#from requests import async
|
||||||
|
import json
|
||||||
|
###################################
|
||||||
|
##Orchestrator integration module (safe use when orchestrator is turned off)
|
||||||
|
###################################
|
||||||
|
################################################################################
|
||||||
|
# Recieve data from orchestrator (synchronyous)
|
||||||
|
# Example:
|
||||||
|
# t=IntegrationOrchestrator.DataRecieveAsync(
|
||||||
|
# RobotStorage=mGlobal["Storage"],
|
||||||
|
# RobotStorageKey="R01_OrchestratorToRobot",
|
||||||
|
# OrchestratorKeyList=["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
# OrchestratorProtocol="http",
|
||||||
|
# OrchestratorHost="localhost",
|
||||||
|
# OrchestratorPort=8081,
|
||||||
|
# OrchestratorAuthToken="1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
# )
|
||||||
|
def DataReceiveSync(
|
||||||
|
OrchestratorKeyList, OrchestratorProtocol="http",
|
||||||
|
OrchestratorHost="localhost", OrchestratorPort=80, OrchestratorAuthToken=None
|
||||||
|
):
|
||||||
|
lCookies = {}
|
||||||
|
# Set auth token if authorization is needed
|
||||||
|
if OrchestratorAuthToken:
|
||||||
|
lCookies["AuthToken"] = OrchestratorAuthToken
|
||||||
|
lURL = f'{OrchestratorProtocol}://{OrchestratorHost}:{OrchestratorPort}/Utils/Processor'
|
||||||
|
lDataJSON = [{"Type": "GlobalDictKeyListValueGet", "KeyList": OrchestratorKeyList}]
|
||||||
|
try:
|
||||||
|
lResult = requests.post(lURL, json=lDataJSON, cookies=lCookies)
|
||||||
|
lResultJSON = json.loads(lResult.text)
|
||||||
|
return (True, lResultJSON[0]["Result"]) # (Flag response is ok, Data)
|
||||||
|
except Exception:
|
||||||
|
mLogger.warning(
|
||||||
|
f"Orchestrator not responding. Def DataRecieveSync, OrchestratorKeyList: {str(OrchestratorKeyList)}, OrchestratorProtocol: {str(OrchestratorProtocol)}, OrchestratorHost: {str(OrchestratorHost)}, OrchestratorPort: {str(OrchestratorPort)}")
|
||||||
|
return (False, None) # (Flag response is not ok, Data None)
|
||||||
|
################################################################################
|
||||||
|
# Recieve data from orchestrator (asynchronyous)
|
||||||
|
# Example:
|
||||||
|
# t=IntegrationOrchestrator.DataRecieveAsync(
|
||||||
|
# RobotStorage=mGlobal["Storage"],
|
||||||
|
# RobotStorageKey="R01_OrchestratorToRobot",
|
||||||
|
# OrchestratorKeyList=["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
# OrchestratorProtocol="http",
|
||||||
|
# OrchestratorHost="localhost",
|
||||||
|
# OrchestratorPort=8081,
|
||||||
|
# OrchestratorAuthToken="1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
# )
|
||||||
|
def DataReceiveAsync(
|
||||||
|
RobotStorage, RobotStorageKey, OrchestratorKeyList, OrchestratorProtocol="http",
|
||||||
|
OrchestratorHost="localhost", OrchestratorPort=80, OrchestratorAuthToken=None
|
||||||
|
):
|
||||||
|
from threading import Thread
|
||||||
|
import uuid
|
||||||
|
global mGlobalDict
|
||||||
|
class ThreadAsync(Thread):
|
||||||
|
def DataRecieveSync(self):
|
||||||
|
lCookies = {}
|
||||||
|
#Set auth token if authorization is needed
|
||||||
|
if OrchestratorAuthToken:
|
||||||
|
lCookies["AuthToken"] = OrchestratorAuthToken
|
||||||
|
lURL = f'{OrchestratorProtocol}://{OrchestratorHost}:{OrchestratorPort}/Utils/Processor'
|
||||||
|
lDataJSON = [{"Type": "GlobalDictKeyListValueGet", "KeyList": OrchestratorKeyList}]
|
||||||
|
try:
|
||||||
|
lResult = requests.post(lURL, json=lDataJSON, cookies = lCookies)
|
||||||
|
lResultJSON = json.loads(lResult.text)
|
||||||
|
return (True,lResultJSON[0]["Result"]) #(Flag response is ok, Data)
|
||||||
|
except Exception:
|
||||||
|
mLogger.warning(
|
||||||
|
f"Orchestrator not responding. Def DataRecieveAsync, OrchestratorKeyList: {str(OrchestratorKeyList)}, OrchestratorProtocol: {str(OrchestratorProtocol)}, OrchestratorHost: {str(OrchestratorHost)}, OrchestratorPort: {str(OrchestratorPort)}")
|
||||||
|
return (False,None) #(Flag response is not ok, Data None)
|
||||||
|
# Thread init
|
||||||
|
def __init__(self, name):
|
||||||
|
Thread.__init__(self)
|
||||||
|
self.name = name
|
||||||
|
#Thread start
|
||||||
|
def run(self):
|
||||||
|
(lFlagResponseOK,lResponseData) = self.DataRecieveSync()
|
||||||
|
if lFlagResponseOK:
|
||||||
|
RobotStorage[RobotStorageKey] = lResponseData
|
||||||
|
ThreadObject = ThreadAsync(f"ThreadAsync{str(uuid.uuid1())}")
|
||||||
|
ThreadObject.start()
|
||||||
|
return True
|
||||||
|
################################################################################
|
||||||
|
#IntervalDataRecieveAsync - Periodic recieve data from orchestrator and update storage
|
||||||
|
def IntervalDataReceiveAsync(*args, **kwargs):
|
||||||
|
lInterval=3
|
||||||
|
#Delete index 0 from args
|
||||||
|
lArgs=copy.copy(args)
|
||||||
|
if len(lArgs)>0:
|
||||||
|
lInterval = lArgs[0]
|
||||||
|
lArgs = lArgs[1:]
|
||||||
|
#Delete Interval from kwargs
|
||||||
|
lKwargs = copy.copy(kwargs)
|
||||||
|
if "Interval" in lKwargs:
|
||||||
|
lInterval = lKwargs["Interval"]
|
||||||
|
del lKwargs["Interval"]
|
||||||
|
lTimer = TimerRepeat.TimerRepeat(lInterval, DataReceiveAsync, lArgs, lKwargs)
|
||||||
|
lTimer.start()
|
||||||
|
#Add timer to general list to stop this when needed
|
||||||
|
mTimerList.append(lTimer)
|
||||||
|
return lTimer
|
||||||
|
################################################################################
|
||||||
|
###################################
|
||||||
|
################################
|
||||||
|
###################################
|
||||||
|
################################################################################
|
||||||
|
# Send data from orchestrator (synchronyous)
|
||||||
|
# Example:
|
||||||
|
# t=IntegrationOrchestrator.DataSendSync(
|
||||||
|
# RobotValue="Value",
|
||||||
|
# OrchestratorKeyList=["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
# OrchestratorProtocol="http",
|
||||||
|
# OrchestratorHost="localhost",
|
||||||
|
# OrchestratorPort=8081,
|
||||||
|
# OrchestratorAuthToken="1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
# )
|
||||||
|
def DataSendSync(
|
||||||
|
RobotValue, OrchestratorKeyList, OrchestratorProtocol="http",
|
||||||
|
OrchestratorHost="localhost", OrchestratorPort=80, OrchestratorAuthToken=None
|
||||||
|
):
|
||||||
|
lCookies = {}
|
||||||
|
# Set auth token if authorization is needed
|
||||||
|
if OrchestratorAuthToken:
|
||||||
|
lCookies["AuthToken"] = OrchestratorAuthToken
|
||||||
|
lURL = f'{OrchestratorProtocol}://{OrchestratorHost}:{OrchestratorPort}/Utils/Processor'
|
||||||
|
lDataJSON = [{"Type": "GlobalDictKeyListValueSet", "KeyList": OrchestratorKeyList, "Value": RobotValue}]
|
||||||
|
try:
|
||||||
|
lResult = requests.post(lURL, json=lDataJSON, cookies=lCookies)
|
||||||
|
lResultJSON = json.loads(lResult.text)
|
||||||
|
return (True, lResultJSON[0]["Result"]) # (Flag response is ok, Data)
|
||||||
|
except Exception:
|
||||||
|
mLogger.warning(
|
||||||
|
f"Orchestrator not responding. Def: DataSendSync, RobotValue: {str(RobotValue)}, OrchestratorKeyList: {str(OrchestratorKeyList)}, OrchestratorProtocol: {str(OrchestratorProtocol)}, OrchestratorHost: {str(OrchestratorHost)}, OrchestratorPort: {str(OrchestratorPort)}")
|
||||||
|
return (False, None) # (Flag response is not ok, Data None)
|
||||||
|
################################################################################
|
||||||
|
# Send data from orchestrator (asynchronyous)
|
||||||
|
# Example:
|
||||||
|
# t=IntegrationOrchestrator.DataSendAsync(
|
||||||
|
# RobotStorage=mGlobal["Storage"],
|
||||||
|
# RobotStorageKey="R01_OrchestratorToRobot",
|
||||||
|
# OrchestratorKeyList=["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
# OrchestratorProtocol="http",
|
||||||
|
# OrchestratorHost="localhost",
|
||||||
|
# OrchestratorPort=8081,
|
||||||
|
# OrchestratorAuthToken="1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
# )
|
||||||
|
def DataSendAsync(
|
||||||
|
RobotStorage, RobotStorageKey, OrchestratorKeyList, OrchestratorProtocol="http",
|
||||||
|
OrchestratorHost="localhost", OrchestratorPort=80, OrchestratorAuthToken=None
|
||||||
|
):
|
||||||
|
from threading import Thread
|
||||||
|
import uuid
|
||||||
|
global mGlobalDict
|
||||||
|
class ThreadAsync(Thread):
|
||||||
|
def DataSendSync(self):
|
||||||
|
RobotValue = RobotStorage[RobotStorageKey]
|
||||||
|
lCookies = {}
|
||||||
|
# Set auth token if authorization is needed
|
||||||
|
if OrchestratorAuthToken:
|
||||||
|
lCookies["AuthToken"] = OrchestratorAuthToken
|
||||||
|
lURL = f'{OrchestratorProtocol}://{OrchestratorHost}:{OrchestratorPort}/Utils/Processor'
|
||||||
|
lDataJSON = [{"Type": "GlobalDictKeyListValueSet", "KeyList": OrchestratorKeyList, "Value": RobotValue}]
|
||||||
|
try:
|
||||||
|
lResult = requests.post(lURL, json=lDataJSON, cookies=lCookies)
|
||||||
|
lResultJSON = json.loads(lResult.text)
|
||||||
|
return (True, lResultJSON[0]["Result"]) # (Flag response is ok, Data)
|
||||||
|
except Exception:
|
||||||
|
mLogger.warning(
|
||||||
|
f"Orchestrator not responding. Def: DataSendAsync, RobotValue: {str(RobotValue)}, OrchestratorKeyList: {str(OrchestratorKeyList)}, OrchestratorProtocol: {str(OrchestratorProtocol)}, OrchestratorHost: {str(OrchestratorHost)}, OrchestratorPort: {str(OrchestratorPort)}")
|
||||||
|
return (False, None) # (Flag response is not ok, Data None)
|
||||||
|
# Thread init
|
||||||
|
def __init__(self, name):
|
||||||
|
Thread.__init__(self)
|
||||||
|
self.name = name
|
||||||
|
#Thread start
|
||||||
|
def run(self):
|
||||||
|
self.DataSendSync()
|
||||||
|
ThreadObject = ThreadAsync(f"ThreadAsync{str(uuid.uuid1())}")
|
||||||
|
ThreadObject.start()
|
||||||
|
return True
|
||||||
|
################################################################################
|
||||||
|
#IntervalDataSendAsync - Periodic send data from robot to orchestrator
|
||||||
|
def IntervalDataSendAsync(*args,**kwargs):
|
||||||
|
lInterval=3
|
||||||
|
#Delete index 0 from args
|
||||||
|
lArgs=copy.copy(args)
|
||||||
|
if len(lArgs)>0:
|
||||||
|
lInterval = lArgs[0]
|
||||||
|
lArgs = lArgs[1:]
|
||||||
|
#Delete Interval from kwargs
|
||||||
|
lKwargs = copy.copy(kwargs)
|
||||||
|
if "Interval" in lKwargs:
|
||||||
|
lInterval = lKwargs["Interval"]
|
||||||
|
del lKwargs["Interval"]
|
||||||
|
lTimer = TimerRepeat.TimerRepeat(lInterval, DataSendAsync, lArgs, lKwargs)
|
||||||
|
lTimer.start()
|
||||||
|
#Add timer to general list to stop this when needed
|
||||||
|
mTimerList.append(lTimer)
|
||||||
|
return lTimer
|
||||||
|
################################################################################
|
||||||
|
###################################
|
||||||
|
################################
|
||||||
|
###################################
|
||||||
|
################################################################################
|
||||||
|
# Check if RobotStorage[Key] Value has been changed > then send data + reset to orchestrator (asynchronyous) timeout 2 seconds
|
||||||
|
# Example:
|
||||||
|
# t=IntegrationOrchestrator.DataSendResetAsync(
|
||||||
|
# RobotStorage=mGlobal["Storage"],
|
||||||
|
# RobotStorageKey="R01_OrchestratorToRobot",
|
||||||
|
# RobotResetValue="Test",
|
||||||
|
# OrchestratorKeyList=["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
# OrchestratorProtocol="http",
|
||||||
|
# OrchestratorHost="localhost",
|
||||||
|
# OrchestratorPort=8081,
|
||||||
|
# OrchestratorAuthToken="1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
# )
|
||||||
|
def DataSendResetAsync(
|
||||||
|
RobotStorage, RobotStorageKey, RobotResetValue, OrchestratorKeyList, OrchestratorProtocol="http",
|
||||||
|
OrchestratorHost="localhost", OrchestratorPort=80, OrchestratorAuthToken=None
|
||||||
|
):
|
||||||
|
#Do operations if data not equal to ResetValue
|
||||||
|
if RobotStorage[RobotStorageKey] != RobotResetValue:
|
||||||
|
#Get value
|
||||||
|
lRobotValue = copy.deepcopy(RobotStorage[RobotStorageKey])
|
||||||
|
#Reset value
|
||||||
|
RobotStorage[RobotStorageKey] = copy.deepcopy(RobotResetValue)
|
||||||
|
#Send data (retry while data will be transferred completele)
|
||||||
|
from threading import Thread
|
||||||
|
import uuid
|
||||||
|
import time
|
||||||
|
global mGlobalDict
|
||||||
|
class ThreadAsync(Thread):
|
||||||
|
def DataSendSync(self):
|
||||||
|
RobotValue = lRobotValue
|
||||||
|
lCookies = {}
|
||||||
|
# Set auth token if authorization is needed
|
||||||
|
if OrchestratorAuthToken:
|
||||||
|
lCookies["AuthToken"] = OrchestratorAuthToken
|
||||||
|
lURL = f'{OrchestratorProtocol}://{OrchestratorHost}:{OrchestratorPort}/Utils/Processor'
|
||||||
|
lDataJSON = [{"Type": "GlobalDictKeyListValueSet", "KeyList": OrchestratorKeyList, "Value": RobotValue}]
|
||||||
|
lFlagDataTransmit = False
|
||||||
|
while not lFlagDataTransmit:
|
||||||
|
try:
|
||||||
|
lResult = requests.post(lURL, json=lDataJSON, cookies=lCookies)
|
||||||
|
lResultJSON = json.loads(lResult.text)
|
||||||
|
lFlagDataTransmit = True
|
||||||
|
except Exception:
|
||||||
|
mLogger.warning(
|
||||||
|
f"Orchestrator not responding - will retry to send update. Timeout 2 seconds. Def: DataSendResetAsync, RobotValue: {str(RobotValue)}, OrchestratorKeyList: {str(OrchestratorKeyList)}, OrchestratorProtocol: {str(OrchestratorProtocol)}, OrchestratorHost: {str(OrchestratorHost)}, OrchestratorPort: {str(OrchestratorPort)}")
|
||||||
|
time.sleep(2) #Timout for next loop
|
||||||
|
return (True,True) # Only True can be returned
|
||||||
|
# Thread init
|
||||||
|
def __init__(self, name):
|
||||||
|
Thread.__init__(self)
|
||||||
|
self.name = name
|
||||||
|
# Thread start
|
||||||
|
def run(self):
|
||||||
|
self.DataSendSync()
|
||||||
|
ThreadObject = ThreadAsync(f"ThreadAsync{str(uuid.uuid1())}")
|
||||||
|
ThreadObject.start()
|
||||||
|
return True
|
||||||
|
return True
|
||||||
|
################################################################################
|
||||||
|
################################################################################
|
||||||
|
#IntervalDataSendResetAsync - Periodic check changed and send + reset data from robot to orchestrator
|
||||||
|
def IntervalDataSendResetAsync(*args,**kwargs):
|
||||||
|
lInterval=3
|
||||||
|
#Delete index 0 from args
|
||||||
|
lArgs=copy.copy(args)
|
||||||
|
if len(lArgs)>0:
|
||||||
|
lInterval = lArgs[0]
|
||||||
|
lArgs = lArgs[1:]
|
||||||
|
#Delete Interval from kwargs
|
||||||
|
lKwargs = copy.copy(kwargs)
|
||||||
|
if "Interval" in lKwargs:
|
||||||
|
lInterval = lKwargs["Interval"]
|
||||||
|
del lKwargs["Interval"]
|
||||||
|
lTimer = TimerRepeat.TimerRepeat(lInterval, DataSendResetAsync, lArgs, lKwargs)
|
||||||
|
lTimer.start()
|
||||||
|
#Add timer to general list to stop this when needed
|
||||||
|
mTimerList.append(lTimer)
|
||||||
|
return lTimer
|
||||||
|
################################################################################
|
||||||
|
# Check changes in orchestrator - then replace in RobotStorage if not equeal. Has no timeout because You can use function IntervalDataReceiveResetAsync (asynchronyous)
|
||||||
|
#Next iteration do not rewrite value until new change has come from orchestrator
|
||||||
|
# Example:
|
||||||
|
# t=IntegrationOrchestrator.DataRecieveAsync(
|
||||||
|
# RobotStorage=mGlobal["Storage"],
|
||||||
|
# RobotStorageKey="R01_OrchestratorToRobot",
|
||||||
|
# RobotResetValue={"Test":"Test"},
|
||||||
|
# OrchestratorKeyList=["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
# OrchestratorProtocol="http",
|
||||||
|
# OrchestratorHost="localhost",
|
||||||
|
# OrchestratorPort=8081,
|
||||||
|
# OrchestratorAuthToken="1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
# )
|
||||||
|
def DataReceiveResetAsync(
|
||||||
|
RobotStorage, RobotStorageKey, RobotResetValue, OrchestratorKeyList, OrchestratorProtocol="http",
|
||||||
|
OrchestratorHost="localhost", OrchestratorPort=80, OrchestratorAuthToken=None
|
||||||
|
):
|
||||||
|
from threading import Thread
|
||||||
|
import uuid
|
||||||
|
global mGlobalDict
|
||||||
|
class ThreadAsync(Thread):
|
||||||
|
def DataRecieveSync(self):
|
||||||
|
lCookies = {}
|
||||||
|
#Set auth token if authorization is needed
|
||||||
|
if OrchestratorAuthToken:
|
||||||
|
lCookies["AuthToken"] = OrchestratorAuthToken
|
||||||
|
lURL = f'{OrchestratorProtocol}://{OrchestratorHost}:{OrchestratorPort}/Utils/Processor'
|
||||||
|
lDataJSON = [
|
||||||
|
{"Type": "GlobalDictKeyListValueGet", "KeyList": OrchestratorKeyList},
|
||||||
|
{"Type": "GlobalDictKeyListValueSet", "KeyList": OrchestratorKeyList, "Value": RobotResetValue}
|
||||||
|
]
|
||||||
|
try:
|
||||||
|
lResult = requests.post(lURL, json=lDataJSON, cookies = lCookies)
|
||||||
|
lResultJSON = json.loads(lResult.text)
|
||||||
|
#Change data if it changes with ResetValue
|
||||||
|
if lResultJSON[0]["Result"] != RobotResetValue:
|
||||||
|
return (True,lResultJSON[0]["Result"]) #(Flag data changes is ok, Data)
|
||||||
|
else:
|
||||||
|
return (False, lResultJSON[0]["Result"]) # (Flag data changes is false - dont rewrite in RobotStorage, Data)
|
||||||
|
except Exception:
|
||||||
|
mLogger.warning(
|
||||||
|
f"Orchestrator not responding. Def DataReceiveResetAsync, RobotResetValue: {str(RobotResetValue)}, OrchestratorKeyList: {str(OrchestratorKeyList)}, OrchestratorProtocol: {str(OrchestratorProtocol)}, OrchestratorHost: {str(OrchestratorHost)}, OrchestratorPort: {str(OrchestratorPort)}")
|
||||||
|
return (False,None) #(Flag response is not ok, Data None)
|
||||||
|
# Thread init
|
||||||
|
def __init__(self, name):
|
||||||
|
Thread.__init__(self)
|
||||||
|
self.name = name
|
||||||
|
#Thread start
|
||||||
|
def run(self):
|
||||||
|
(lFlagResponseOK,lResponseData) = self.DataRecieveSync()
|
||||||
|
if lFlagResponseOK:
|
||||||
|
RobotStorage[RobotStorageKey] = lResponseData
|
||||||
|
ThreadObject = ThreadAsync(f"ThreadAsync{str(uuid.uuid1())}")
|
||||||
|
ThreadObject.start()
|
||||||
|
return True
|
||||||
|
################################################################################
|
||||||
|
################################################################################
|
||||||
|
#IntervalDataReceiveResetAsync - Periodic receive + every time reset and check changed and reset data on robot storage
|
||||||
|
def IntervalDataReceiveResetAsync(*args,**kwargs):
|
||||||
|
lInterval=3
|
||||||
|
#Delete index 0 from args
|
||||||
|
lArgs=copy.copy(args)
|
||||||
|
if len(lArgs)>0:
|
||||||
|
lInterval = lArgs[0]
|
||||||
|
lArgs = lArgs[1:]
|
||||||
|
#Delete Interval from kwargs
|
||||||
|
lKwargs = copy.copy(kwargs)
|
||||||
|
if "Interval" in lKwargs:
|
||||||
|
lInterval = lKwargs["Interval"]
|
||||||
|
del lKwargs["Interval"]
|
||||||
|
lTimer = TimerRepeat.TimerRepeat(lInterval, DataReceiveResetAsync, lArgs, lKwargs)
|
||||||
|
lTimer.start()
|
||||||
|
#Add timer to general list to stop this when needed
|
||||||
|
mTimerList.append(lTimer)
|
||||||
|
return lTimer
|
||||||
|
#################################################################################
|
||||||
|
#################################################################################
|
||||||
|
################################################################################
|
||||||
|
#ConfigurationInit - Get dict configuration and init interval functions
|
||||||
|
def ConfigurationInit(inConfigurationDict):
|
||||||
|
for lItem in inConfigurationDict.keys():
|
||||||
|
lFunction = globals()[lItem]
|
||||||
|
#Iterate throught the nested list
|
||||||
|
for lFunctionConfigurationDict in inConfigurationDict[lItem]:
|
||||||
|
lFunction(**lFunctionConfigurationDict)
|
||||||
|
return True
|
@ -0,0 +1,34 @@
|
|||||||
|
import logging
|
||||||
|
import datetime
|
||||||
|
#Robot settings
|
||||||
|
def Settings():
|
||||||
|
import os
|
||||||
|
mDict = {
|
||||||
|
"Logger": logging.getLogger("Robot"),
|
||||||
|
"Storage": {
|
||||||
|
"Robot_R01_help": "Robot data storage in orchestrator env",
|
||||||
|
"Robot_R01": {}
|
||||||
|
},
|
||||||
|
"ProcessBitness": {
|
||||||
|
"Python32FullPath": None, #Set from user: "..\\Resources\\WPy32-3720\\python-3.7.2\\OpenRPARobotGUIx32.exe"
|
||||||
|
"Python64FullPath": None, #Set from user
|
||||||
|
"Python32ProcessName": "OpenRPAUIDesktopX32.exe", #Config set once
|
||||||
|
"Python64ProcessName": "OpenRPAUIDesktopX64.exe" #Config set once
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#Создать файл логирования
|
||||||
|
# add filemode="w" to overwrite
|
||||||
|
if not os.path.exists("Reports"):
|
||||||
|
os.makedirs("Reports")
|
||||||
|
##########################
|
||||||
|
#Подготовка логгера Robot
|
||||||
|
#########################
|
||||||
|
mRobotLogger=mDict["Logger"]
|
||||||
|
mRobotLogger.setLevel(logging.INFO)
|
||||||
|
# create the logging file handler
|
||||||
|
mRobotLoggerFH = logging.FileHandler("Reports\ReportRobot_"+datetime.datetime.now().strftime("%Y_%m_%d")+".log")
|
||||||
|
mRobotLoggerFormatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||||
|
mRobotLoggerFH.setFormatter(mRobotLoggerFormatter)
|
||||||
|
# add handler to logger object
|
||||||
|
mRobotLogger.addHandler(mRobotLoggerFH)
|
||||||
|
############################################
|
@ -0,0 +1,65 @@
|
|||||||
|
import unittest
|
||||||
|
from threading import Timer
|
||||||
|
import sys
|
||||||
|
lFolderPath = "/".join(__file__.split("\\")[:-3])
|
||||||
|
sys.path.insert(0, lFolderPath)
|
||||||
|
from pyOpenRPA.Robot import OrchestratorConnector
|
||||||
|
from pyOpenRPA.Robot import Utils
|
||||||
|
class MyTestCase(unittest.TestCase):
|
||||||
|
def test_something(self):
|
||||||
|
#self.assertEqual(True, False)
|
||||||
|
mGlobal={"Storage":{"R01_OrchestratorToRobot":{"Test":"Test2"}}}
|
||||||
|
# t=OrchestratorConnector.IntervalDataSendAsync(
|
||||||
|
# Interval=1,
|
||||||
|
# RobotStorage=mGlobal["Storage"],
|
||||||
|
# RobotStorageKey="R01_OrchestratorToRobot",
|
||||||
|
# OrchestratorKeyList=["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
# OrchestratorProtocol="http",
|
||||||
|
# OrchestratorHost="localhost",
|
||||||
|
# OrchestratorPort=8081,
|
||||||
|
# OrchestratorAuthToken="1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
# )
|
||||||
|
# t=OrchestratorConnector.DataSendSync(
|
||||||
|
# RobotValue="Test",
|
||||||
|
# OrchestratorKeyList=["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
# OrchestratorProtocol="http",
|
||||||
|
# OrchestratorHost="localhost",
|
||||||
|
# OrchestratorPort=8081,
|
||||||
|
# OrchestratorAuthToken="1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
# )
|
||||||
|
import time
|
||||||
|
#def Func(lT,inl):
|
||||||
|
# print(lT)
|
||||||
|
# return True
|
||||||
|
#lTimer= Utils.TimerRepeat.TimerRepeat(1, Func, ["dddd"],{"inl":9})
|
||||||
|
#lTimer.start()
|
||||||
|
OrchestratorConnector.ConfigurationInit({
|
||||||
|
"IntervalDataSendResetAsync": [
|
||||||
|
{
|
||||||
|
"Interval": 2,
|
||||||
|
"RobotStorage": mGlobal["Storage"],
|
||||||
|
"RobotStorageKey": "R01_OrchestratorToRobot",
|
||||||
|
"RobotResetValue": {"Test": "Test"},
|
||||||
|
"OrchestratorKeyList": ["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
"OrchestratorProtocol": "http",
|
||||||
|
"OrchestratorHost": "localhost",
|
||||||
|
"OrchestratorPort": 8081,
|
||||||
|
"OrchestratorAuthToken": "1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
while True:
|
||||||
|
print(mGlobal["Storage"]["R01_OrchestratorToRobot"])
|
||||||
|
# t = OrchestratorConnector.DataSendResetAsync(
|
||||||
|
# RobotStorage=mGlobal["Storage"],
|
||||||
|
# RobotStorageKey="R01_OrchestratorToRobot",
|
||||||
|
# RobotResetValue={"Test": "Test"},
|
||||||
|
# OrchestratorKeyList=["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
# OrchestratorProtocol="http",
|
||||||
|
# OrchestratorHost="localhost",
|
||||||
|
# OrchestratorPort=8081,
|
||||||
|
# OrchestratorAuthToken="1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
# )
|
||||||
|
time.sleep(0.5)
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
@ -0,0 +1,28 @@
|
|||||||
|
from threading import Timer
|
||||||
|
import datetime
|
||||||
|
# lTimer = RepeatedTimer(3, def, [], {}) # it auto-starts, no need of rt.start()
|
||||||
|
# if def return None = timer stops
|
||||||
|
# lTimer.start()
|
||||||
|
class TimerRepeat(object):
|
||||||
|
def __init__(self, interval, function, args, kwargs):
|
||||||
|
self._timer = None
|
||||||
|
self.interval = interval
|
||||||
|
self.function = function
|
||||||
|
self.args = args
|
||||||
|
self.kwargs = kwargs
|
||||||
|
self.is_running = False
|
||||||
|
self.start()
|
||||||
|
def _run(self):
|
||||||
|
self.is_running = False
|
||||||
|
lResult = self.function(*self.args, **self.kwargs)
|
||||||
|
if lResult is not None:
|
||||||
|
if lResult:
|
||||||
|
self.start()
|
||||||
|
def start(self):
|
||||||
|
if not self.is_running:
|
||||||
|
self._timer = Timer(self.interval, self._run)
|
||||||
|
self._timer.start()
|
||||||
|
self.is_running = True
|
||||||
|
def stop(self):
|
||||||
|
self._timer.cancel()
|
||||||
|
self.is_running = False
|
@ -0,0 +1,108 @@
|
|||||||
|
import pdb
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import zlib
|
||||||
|
import os
|
||||||
|
from . import ProcessCommunicator
|
||||||
|
import importlib
|
||||||
|
import traceback
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
import datetime
|
||||||
|
import struct
|
||||||
|
import shutil
|
||||||
|
from pyOpenRPA.Robot import UIDesktop
|
||||||
|
global mGlobalDict
|
||||||
|
####################################
|
||||||
|
#Info: Main module of the Robot app (OpenRPA - Robot)
|
||||||
|
####################################
|
||||||
|
|
||||||
|
#Usage:
|
||||||
|
#Here you can run some activity or list of activities
|
||||||
|
|
||||||
|
#After import this module you can use the folowing functions:
|
||||||
|
#ActivityRun(inActivitySpecificationDict): outActivityResultDict - function - run activity (function or procedure)
|
||||||
|
#ActivityRunJSON(inActivitySpecificationDictJSON): outActivityResultDictJSON
|
||||||
|
#ActivityListRun(inActivitySpecificationDictList): outActivityResultDictList - function - run list of activities (function or procedure)
|
||||||
|
#ActivityListRunJSON(inActivitySpecificationDictListJSON): outActivityResultDictListJSON
|
||||||
|
|
||||||
|
#Naming:
|
||||||
|
#Activity - some action/list of actions
|
||||||
|
#Module - Any *.py file, which consist of area specific functions
|
||||||
|
#Argument
|
||||||
|
|
||||||
|
#inActivitySpecificationDict:
|
||||||
|
#{
|
||||||
|
# ModuleName: <"GUI"|..., str>,
|
||||||
|
# ActivityName: <Function or procedure name in module, str>,
|
||||||
|
# ArgumentList: [<Argument 1, any type>, ...] - optional,
|
||||||
|
# ArgumentDict: {<Argument 1 name, str>:<Argument 1 value, any type>, ...} - optional
|
||||||
|
#}
|
||||||
|
|
||||||
|
#outActivityResultDict:
|
||||||
|
#{
|
||||||
|
# ActivitySpecificationDict: {
|
||||||
|
# ModuleName: <"GUI"|..., str>,
|
||||||
|
# ActivityName: <Function or procedure name in module, str>,
|
||||||
|
# ArgumentList: [<Argument 1, any type>, ...] - optional,
|
||||||
|
# ArgumentDict: {<Argument 1 name, str>: <Argument 1 value, any type>, ...} - optional
|
||||||
|
# },
|
||||||
|
# ErrorFlag: <Boolean flag - Activity result has error (true) or not (false), boolean>,
|
||||||
|
# ErrorMessage: <Error message, str> - required if ErrorFlag is true,
|
||||||
|
# ErrorTraceback: <Error traceback log, str> - required if ErrorFlag is true,
|
||||||
|
# Result: <Result, returned from the Activity, int, str, boolean, list, dict> - required if ErrorFlag is false
|
||||||
|
#}
|
||||||
|
|
||||||
|
####################
|
||||||
|
#Section: Activity
|
||||||
|
####################
|
||||||
|
def ActivityRun(inActivitySpecificationDict):
|
||||||
|
lResponseObject = {}
|
||||||
|
#Выполнить отправку в модуль UIDesktop, если ModuleName == "UIDesktop"
|
||||||
|
if inActivitySpecificationDict["ModuleName"] == "UIDesktop":
|
||||||
|
if "ArgumentList" not in inActivitySpecificationDict:
|
||||||
|
inActivitySpecificationDict["ArgumentList"]=[]
|
||||||
|
if "ArgumentDict" not in inActivitySpecificationDict:
|
||||||
|
inActivitySpecificationDict["ArgumentDict"]={}
|
||||||
|
#Run the activity
|
||||||
|
try:
|
||||||
|
#Найти функцию
|
||||||
|
lFunction=getattr(UIDesktop,inActivitySpecificationDict["ActivityName"])
|
||||||
|
#Выполнить вызов и записать результат
|
||||||
|
lResponseObject["Result"]=lFunction(*inActivitySpecificationDict["ArgumentList"],**inActivitySpecificationDict["ArgumentDict"])
|
||||||
|
except Exception as e:
|
||||||
|
#Установить флаг ошибки и передать тело ошибки
|
||||||
|
lResponseObject["ErrorFlag"]=True
|
||||||
|
lResponseObject["ErrorMessage"]=str(e)
|
||||||
|
lResponseObject["ErrorTraceback"]=traceback.format_exc()
|
||||||
|
#Остальные модули подключать и выполнять здесь
|
||||||
|
else:
|
||||||
|
lArgumentList=[]
|
||||||
|
if "ArgumentList" in inActivitySpecificationDict:
|
||||||
|
lArgumentList=inActivitySpecificationDict["ArgumentList"]
|
||||||
|
lArgumentDict={}
|
||||||
|
if "ArgumentDict" in inActivitySpecificationDict:
|
||||||
|
lArgumentDict=inActivitySpecificationDict["ArgumentDict"]
|
||||||
|
#Подготовить результирующую структуру
|
||||||
|
lResponseObject={"ActivitySpecificationDict":inActivitySpecificationDict,"ErrorFlag":False}
|
||||||
|
try:
|
||||||
|
#Подключить модуль для вызова
|
||||||
|
lModule=importlib.import_module(inActivitySpecificationDict["ModuleName"])
|
||||||
|
#Найти функцию
|
||||||
|
lFunction=getattr(lModule,inActivitySpecificationDict["ActivityName"])
|
||||||
|
#Выполнить вызов и записать результат
|
||||||
|
lResponseObject["Result"]=lFunction(*lArgumentList,**lArgumentDict)
|
||||||
|
except Exception as e:
|
||||||
|
#Установить флаг ошибки и передать тело ошибки
|
||||||
|
lResponseObject["ErrorFlag"]=True
|
||||||
|
lResponseObject["ErrorMessage"]=str(e)
|
||||||
|
lResponseObject["ErrorTraceback"]=traceback.format_exc()
|
||||||
|
return lResponseObject
|
||||||
|
#########################################################
|
||||||
|
#Run list of activities
|
||||||
|
#########################################################
|
||||||
|
def ActivityListRun(inActivitySpecificationDictList):
|
||||||
|
lResult=[]
|
||||||
|
for lItem in inActivitySpecificationDictList:
|
||||||
|
lResult.append(ActivityRun(lItem))
|
||||||
|
return lResult
|
@ -1,17 +1,34 @@
|
|||||||
from pyOpenRPA.Robot import UIDesktop
|
from pyOpenRPA.Robot import UIDesktop
|
||||||
from . import Connector
|
from . import Connector
|
||||||
|
import os
|
||||||
import pdb
|
import pdb
|
||||||
#Check for session is closed. Reopen if detected. Always keep session is active
|
#Check for session is closed. Reopen if detected. Always keep session is active
|
||||||
def Monitor(inGlobalDict, inListUpdateTimeout):
|
def Monitor(inGlobalDict, inListUpdateTimeout):
|
||||||
while True:
|
lFlagWhile = True
|
||||||
|
while lFlagWhile:
|
||||||
# UIOSelector list init
|
# UIOSelector list init
|
||||||
lUIOSelectorList = []
|
lUIOSelectorList = []
|
||||||
for lItem in inGlobalDict["RDPList"]:
|
for lItem in inGlobalDict["RDPList"]:
|
||||||
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']} — .*", "backend": "win32"}])
|
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']} — .*", "backend": "win32"}])
|
||||||
#Run wait command
|
#Run wait command
|
||||||
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
|
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
|
||||||
|
#Analyze if flag safeturn off is activated
|
||||||
|
if inGlobalDict.get("OrchestratorToRobotResetStorage",{}).get("SafeTurnOff",False):
|
||||||
|
lFlagWhile=False
|
||||||
|
#Set status disconnected for all RDP List
|
||||||
|
for lItem in inGlobalDict["RDPList"]:
|
||||||
|
lItem["FlagSessionIsActive"]=False
|
||||||
|
#Kill all RDP sessions
|
||||||
|
os.system('taskkill /F /im mstsc.exe')
|
||||||
|
#Return from function
|
||||||
|
return
|
||||||
for lItem in lRDPDissappearList:
|
for lItem in lRDPDissappearList:
|
||||||
|
inGlobalDict["RDPList"][lItem]["FlagSessionIsActive"] = False # Set flag that session is disconnected
|
||||||
#pdb.set_trace()
|
#pdb.set_trace()
|
||||||
#Session start
|
#Session start
|
||||||
Connector.Session(inGlobalDict["RDPList"][lItem])
|
try:
|
||||||
return None
|
Connector.Session(inGlobalDict["RDPList"][lItem])
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
#TODO Def garbage window cleaner (if connection was lost)
|
@ -1,22 +0,0 @@
|
|||||||
#Robot RDPActive settings
|
|
||||||
def Settings():
|
|
||||||
mDict = {
|
|
||||||
"RDPList":
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"Host": "77.77.22.22", # Host address
|
|
||||||
"Port": "7777", # RDP Port
|
|
||||||
"Login": "test", # Login
|
|
||||||
"Password": "test", # Password
|
|
||||||
"Screen": {
|
|
||||||
"Width": 1680, #Width of the remote desktop in pixels
|
|
||||||
"Height": 1050, #Height of the remote desktop in pixels
|
|
||||||
# "640x480" or "1680x1050" or "FullScreen". If Resolution not exists set full screen
|
|
||||||
"FlagUseAllMonitors": False, # True or False
|
|
||||||
"DepthBit": "32" # "32" or "24" or "16" or "15"
|
|
||||||
},
|
|
||||||
"SessionHex":"" # Hex is created when robot runs
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
return mDict
|
|
@ -1,6 +1,6 @@
|
|||||||
Metadata-Version: 2.1
|
Metadata-Version: 2.1
|
||||||
Name: pyOpenRPA
|
Name: pyOpenRPA
|
||||||
Version: 1.0.32
|
Version: 1.0.34
|
||||||
Summary: First open source RPA platform for business
|
Summary: First open source RPA platform for business
|
||||||
Home-page: https://gitlab.com/UnicodeLabs/OpenRPA
|
Home-page: https://gitlab.com/UnicodeLabs/OpenRPA
|
||||||
Author: Ivan Maslov
|
Author: Ivan Maslov
|
@ -1,46 +0,0 @@
|
|||||||
import requests
|
|
||||||
import grequests
|
|
||||||
#from requests import async
|
|
||||||
import json
|
|
||||||
###################################
|
|
||||||
##Orchestrator integration module (safe use when orchestrator is turned off)
|
|
||||||
###################################
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
#Send data to orchestrator (asynchronyous)
|
|
||||||
#Example: t=IntegrationOrchestrator.DataSend(["Storage","Robot_R01"],{"RunDateTimeString":"Test1","StepCurrentName":"Test2","StepCurrentDuration":"Test333","SafeStopSignal":True},"localhost",8081)
|
|
||||||
def DataSend(inKeyList,inValue,inOrchestratorHost="localhost",inOrchestratorPort=80):
|
|
||||||
lURL = f'http://{inOrchestratorHost}:{inOrchestratorPort}/ProcessingRun'
|
|
||||||
lDataJSON = {"actionList":[{"type":"AdministrationGlobalDictSetKeyListValue","key_list":inKeyList,"value":inValue}]}
|
|
||||||
#lAsyncList = []
|
|
||||||
lResultItem = [grequests.post(lURL, json=lDataJSON)]
|
|
||||||
return grequests.map(lResultItem)
|
|
||||||
#lAsyncList.append(lResultItem)
|
|
||||||
#return async.map(lAsyncList)
|
|
||||||
################################################################################
|
|
||||||
#recieve Data from orchestrator
|
|
||||||
#t=IntegrationOrchestrator.DataRecieve(["Storage","Robot_R01"],"localhost",8081)
|
|
||||||
def DataRecieve(inKeyList,inOrchestratorHost="localhost",inOrchestratorPort=80):
|
|
||||||
lURL = f'http://{inOrchestratorHost}:{inOrchestratorPort}/ProcessingRun'
|
|
||||||
lDataJSON = {"actionList":[{"type":"AdministrationGlobalDictGetKeyListValue","key_list":inKeyList}]}
|
|
||||||
try:
|
|
||||||
lResult = requests.post(lURL, json=lDataJSON)
|
|
||||||
lResultJSON = json.loads(lResult.text)
|
|
||||||
return lResultJSON["actionListResult"][0]["value"]
|
|
||||||
except Exception:
|
|
||||||
return None
|
|
||||||
################################################################################
|
|
||||||
#Check if orchestrator has safe stop signal
|
|
||||||
#Example: IntegrationOrchestrator.SafeStopSignalIs(["Storage","Robot_R01","SafeStopSignal"],"localhost",8081)
|
|
||||||
def SafeStopSignalIs(inKeyList,inOrchestratorHost="localhost",inOrchestratorPort=80):
|
|
||||||
lResult=False
|
|
||||||
lResponse=DataRecieve(inKeyList,inOrchestratorHost,inOrchestratorPort)
|
|
||||||
if lResponse is not None:
|
|
||||||
lResult = lResponse
|
|
||||||
return lResult
|
|
||||||
################################################################################
|
|
||||||
#Reset SafeStop signal in orchestrator
|
|
||||||
#Example: t=IntegrationOrchestrator.SafeStopSignalReset(["Storage","Robot_R01","SafeStopSignal"],"localhost",8081)
|
|
||||||
def SafeStopSignalReset(inKeyList,inOrchestratorHost="localhost",inOrchestratorPort=80):
|
|
||||||
lResponse=DataSend(inKeyList,False,inOrchestratorHost,inOrchestratorPort)
|
|
||||||
return lResponse
|
|
@ -0,0 +1,401 @@
|
|||||||
|
import requests
|
||||||
|
#Logging
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import datetime
|
||||||
|
import copy
|
||||||
|
from .Utils import TimerRepeat # Timer which can repeating
|
||||||
|
mLogger=logging.getLogger("OrchestratorConnector")
|
||||||
|
#########################
|
||||||
|
mTimerList=[]
|
||||||
|
def IntervalTerminateAll():
|
||||||
|
for lItem in mTimerList:
|
||||||
|
lItem.stop()
|
||||||
|
#########################
|
||||||
|
# Создать файл логирования
|
||||||
|
# add filemode="w" to overwrite
|
||||||
|
if not os.path.exists("Reports"):
|
||||||
|
os.makedirs("Reports")
|
||||||
|
##########################
|
||||||
|
# Подготовка логгера Robot
|
||||||
|
#########################
|
||||||
|
mLogger.setLevel(logging.INFO)
|
||||||
|
# create the logging file handler
|
||||||
|
mLoggerFH = logging.FileHandler("Reports\ReportOrchestratorConnector_" + datetime.datetime.now().strftime("%Y_%m_%d") + ".log")
|
||||||
|
mLoggerFormatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||||
|
mLoggerFH.setFormatter(mLoggerFormatter)
|
||||||
|
# add handler to logger object
|
||||||
|
mLogger.addHandler(mLoggerFH)
|
||||||
|
############################################
|
||||||
|
#Turn loggin level ERROR
|
||||||
|
def LoggerSetLevelError():
|
||||||
|
mLogger.setLevel(logging.ERROR)
|
||||||
|
#from requests import async
|
||||||
|
import json
|
||||||
|
###################################
|
||||||
|
##Orchestrator integration module (safe use when orchestrator is turned off)
|
||||||
|
###################################
|
||||||
|
################################################################################
|
||||||
|
# Recieve data from orchestrator (synchronyous)
|
||||||
|
# Example:
|
||||||
|
# t=IntegrationOrchestrator.DataRecieveAsync(
|
||||||
|
# RobotStorage=mGlobal["Storage"],
|
||||||
|
# RobotStorageKey="R01_OrchestratorToRobot",
|
||||||
|
# OrchestratorKeyList=["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
# OrchestratorProtocol="http",
|
||||||
|
# OrchestratorHost="localhost",
|
||||||
|
# OrchestratorPort=8081,
|
||||||
|
# OrchestratorAuthToken="1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
# )
|
||||||
|
def DataReceiveSync(
|
||||||
|
OrchestratorKeyList, OrchestratorProtocol="http",
|
||||||
|
OrchestratorHost="localhost", OrchestratorPort=80, OrchestratorAuthToken=None
|
||||||
|
):
|
||||||
|
lCookies = {}
|
||||||
|
# Set auth token if authorization is needed
|
||||||
|
if OrchestratorAuthToken:
|
||||||
|
lCookies["AuthToken"] = OrchestratorAuthToken
|
||||||
|
lURL = f'{OrchestratorProtocol}://{OrchestratorHost}:{OrchestratorPort}/Utils/Processor'
|
||||||
|
lDataJSON = [{"Type": "GlobalDictKeyListValueGet", "KeyList": OrchestratorKeyList}]
|
||||||
|
try:
|
||||||
|
lResult = requests.post(lURL, json=lDataJSON, cookies=lCookies)
|
||||||
|
lResultJSON = json.loads(lResult.text)
|
||||||
|
return (True, lResultJSON[0]["Result"]) # (Flag response is ok, Data)
|
||||||
|
except Exception:
|
||||||
|
mLogger.warning(
|
||||||
|
f"Orchestrator not responding. Def DataRecieveSync, OrchestratorKeyList: {str(OrchestratorKeyList)}, OrchestratorProtocol: {str(OrchestratorProtocol)}, OrchestratorHost: {str(OrchestratorHost)}, OrchestratorPort: {str(OrchestratorPort)}")
|
||||||
|
return (False, None) # (Flag response is not ok, Data None)
|
||||||
|
################################################################################
|
||||||
|
# Recieve data from orchestrator (asynchronyous)
|
||||||
|
# Example:
|
||||||
|
# t=IntegrationOrchestrator.DataRecieveAsync(
|
||||||
|
# RobotStorage=mGlobal["Storage"],
|
||||||
|
# RobotStorageKey="R01_OrchestratorToRobot",
|
||||||
|
# OrchestratorKeyList=["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
# OrchestratorProtocol="http",
|
||||||
|
# OrchestratorHost="localhost",
|
||||||
|
# OrchestratorPort=8081,
|
||||||
|
# OrchestratorAuthToken="1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
# )
|
||||||
|
def DataReceiveAsync(
|
||||||
|
RobotStorage, RobotStorageKey, OrchestratorKeyList, OrchestratorProtocol="http",
|
||||||
|
OrchestratorHost="localhost", OrchestratorPort=80, OrchestratorAuthToken=None
|
||||||
|
):
|
||||||
|
from threading import Thread
|
||||||
|
import uuid
|
||||||
|
global mGlobalDict
|
||||||
|
class ThreadAsync(Thread):
|
||||||
|
def DataRecieveSync(self):
|
||||||
|
lCookies = {}
|
||||||
|
#Set auth token if authorization is needed
|
||||||
|
if OrchestratorAuthToken:
|
||||||
|
lCookies["AuthToken"] = OrchestratorAuthToken
|
||||||
|
lURL = f'{OrchestratorProtocol}://{OrchestratorHost}:{OrchestratorPort}/Utils/Processor'
|
||||||
|
lDataJSON = [{"Type": "GlobalDictKeyListValueGet", "KeyList": OrchestratorKeyList}]
|
||||||
|
try:
|
||||||
|
lResult = requests.post(lURL, json=lDataJSON, cookies = lCookies)
|
||||||
|
lResultJSON = json.loads(lResult.text)
|
||||||
|
return (True,lResultJSON[0]["Result"]) #(Flag response is ok, Data)
|
||||||
|
except Exception:
|
||||||
|
mLogger.warning(
|
||||||
|
f"Orchestrator not responding. Def DataRecieveAsync, OrchestratorKeyList: {str(OrchestratorKeyList)}, OrchestratorProtocol: {str(OrchestratorProtocol)}, OrchestratorHost: {str(OrchestratorHost)}, OrchestratorPort: {str(OrchestratorPort)}")
|
||||||
|
return (False,None) #(Flag response is not ok, Data None)
|
||||||
|
# Thread init
|
||||||
|
def __init__(self, name):
|
||||||
|
Thread.__init__(self)
|
||||||
|
self.name = name
|
||||||
|
#Thread start
|
||||||
|
def run(self):
|
||||||
|
(lFlagResponseOK,lResponseData) = self.DataRecieveSync()
|
||||||
|
if lFlagResponseOK:
|
||||||
|
RobotStorage[RobotStorageKey] = lResponseData
|
||||||
|
ThreadObject = ThreadAsync(f"ThreadAsync{str(uuid.uuid1())}")
|
||||||
|
ThreadObject.start()
|
||||||
|
return True
|
||||||
|
################################################################################
|
||||||
|
#IntervalDataRecieveAsync - Periodic recieve data from orchestrator and update storage
|
||||||
|
def IntervalDataReceiveAsync(*args, **kwargs):
|
||||||
|
lInterval=3
|
||||||
|
#Delete index 0 from args
|
||||||
|
lArgs=copy.copy(args)
|
||||||
|
if len(lArgs)>0:
|
||||||
|
lInterval = lArgs[0]
|
||||||
|
lArgs = lArgs[1:]
|
||||||
|
#Delete Interval from kwargs
|
||||||
|
lKwargs = copy.copy(kwargs)
|
||||||
|
if "Interval" in lKwargs:
|
||||||
|
lInterval = lKwargs["Interval"]
|
||||||
|
del lKwargs["Interval"]
|
||||||
|
lTimer = TimerRepeat.TimerRepeat(lInterval, DataReceiveAsync, lArgs, lKwargs)
|
||||||
|
lTimer.start()
|
||||||
|
#Add timer to general list to stop this when needed
|
||||||
|
mTimerList.append(lTimer)
|
||||||
|
return lTimer
|
||||||
|
################################################################################
|
||||||
|
###################################
|
||||||
|
################################
|
||||||
|
###################################
|
||||||
|
################################################################################
|
||||||
|
# Send data from orchestrator (synchronyous)
|
||||||
|
# Example:
|
||||||
|
# t=IntegrationOrchestrator.DataSendSync(
|
||||||
|
# RobotValue="Value",
|
||||||
|
# OrchestratorKeyList=["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
# OrchestratorProtocol="http",
|
||||||
|
# OrchestratorHost="localhost",
|
||||||
|
# OrchestratorPort=8081,
|
||||||
|
# OrchestratorAuthToken="1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
# )
|
||||||
|
def DataSendSync(
|
||||||
|
RobotValue, OrchestratorKeyList, OrchestratorProtocol="http",
|
||||||
|
OrchestratorHost="localhost", OrchestratorPort=80, OrchestratorAuthToken=None
|
||||||
|
):
|
||||||
|
lCookies = {}
|
||||||
|
# Set auth token if authorization is needed
|
||||||
|
if OrchestratorAuthToken:
|
||||||
|
lCookies["AuthToken"] = OrchestratorAuthToken
|
||||||
|
lURL = f'{OrchestratorProtocol}://{OrchestratorHost}:{OrchestratorPort}/Utils/Processor'
|
||||||
|
lDataJSON = [{"Type": "GlobalDictKeyListValueSet", "KeyList": OrchestratorKeyList, "Value": RobotValue}]
|
||||||
|
try:
|
||||||
|
lResult = requests.post(lURL, json=lDataJSON, cookies=lCookies)
|
||||||
|
lResultJSON = json.loads(lResult.text)
|
||||||
|
return (True, lResultJSON[0]["Result"]) # (Flag response is ok, Data)
|
||||||
|
except Exception:
|
||||||
|
mLogger.warning(
|
||||||
|
f"Orchestrator not responding. Def: DataSendSync, RobotValue: {str(RobotValue)}, OrchestratorKeyList: {str(OrchestratorKeyList)}, OrchestratorProtocol: {str(OrchestratorProtocol)}, OrchestratorHost: {str(OrchestratorHost)}, OrchestratorPort: {str(OrchestratorPort)}")
|
||||||
|
return (False, None) # (Flag response is not ok, Data None)
|
||||||
|
################################################################################
|
||||||
|
# Send data from orchestrator (asynchronyous)
|
||||||
|
# Example:
|
||||||
|
# t=IntegrationOrchestrator.DataSendAsync(
|
||||||
|
# RobotStorage=mGlobal["Storage"],
|
||||||
|
# RobotStorageKey="R01_OrchestratorToRobot",
|
||||||
|
# OrchestratorKeyList=["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
# OrchestratorProtocol="http",
|
||||||
|
# OrchestratorHost="localhost",
|
||||||
|
# OrchestratorPort=8081,
|
||||||
|
# OrchestratorAuthToken="1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
# )
|
||||||
|
def DataSendAsync(
|
||||||
|
RobotStorage, RobotStorageKey, OrchestratorKeyList, OrchestratorProtocol="http",
|
||||||
|
OrchestratorHost="localhost", OrchestratorPort=80, OrchestratorAuthToken=None
|
||||||
|
):
|
||||||
|
from threading import Thread
|
||||||
|
import uuid
|
||||||
|
global mGlobalDict
|
||||||
|
class ThreadAsync(Thread):
|
||||||
|
def DataSendSync(self):
|
||||||
|
RobotValue = RobotStorage[RobotStorageKey]
|
||||||
|
lCookies = {}
|
||||||
|
# Set auth token if authorization is needed
|
||||||
|
if OrchestratorAuthToken:
|
||||||
|
lCookies["AuthToken"] = OrchestratorAuthToken
|
||||||
|
lURL = f'{OrchestratorProtocol}://{OrchestratorHost}:{OrchestratorPort}/Utils/Processor'
|
||||||
|
lDataJSON = [{"Type": "GlobalDictKeyListValueSet", "KeyList": OrchestratorKeyList, "Value": RobotValue}]
|
||||||
|
try:
|
||||||
|
lResult = requests.post(lURL, json=lDataJSON, cookies=lCookies)
|
||||||
|
lResultJSON = json.loads(lResult.text)
|
||||||
|
return (True, lResultJSON[0]["Result"]) # (Flag response is ok, Data)
|
||||||
|
except Exception:
|
||||||
|
mLogger.warning(
|
||||||
|
f"Orchestrator not responding. Def: DataSendAsync, RobotValue: {str(RobotValue)}, OrchestratorKeyList: {str(OrchestratorKeyList)}, OrchestratorProtocol: {str(OrchestratorProtocol)}, OrchestratorHost: {str(OrchestratorHost)}, OrchestratorPort: {str(OrchestratorPort)}")
|
||||||
|
return (False, None) # (Flag response is not ok, Data None)
|
||||||
|
# Thread init
|
||||||
|
def __init__(self, name):
|
||||||
|
Thread.__init__(self)
|
||||||
|
self.name = name
|
||||||
|
#Thread start
|
||||||
|
def run(self):
|
||||||
|
self.DataSendSync()
|
||||||
|
ThreadObject = ThreadAsync(f"ThreadAsync{str(uuid.uuid1())}")
|
||||||
|
ThreadObject.start()
|
||||||
|
return True
|
||||||
|
################################################################################
|
||||||
|
#IntervalDataSendAsync - Periodic send data from robot to orchestrator
|
||||||
|
def IntervalDataSendAsync(*args,**kwargs):
|
||||||
|
lInterval=3
|
||||||
|
#Delete index 0 from args
|
||||||
|
lArgs=copy.copy(args)
|
||||||
|
if len(lArgs)>0:
|
||||||
|
lInterval = lArgs[0]
|
||||||
|
lArgs = lArgs[1:]
|
||||||
|
#Delete Interval from kwargs
|
||||||
|
lKwargs = copy.copy(kwargs)
|
||||||
|
if "Interval" in lKwargs:
|
||||||
|
lInterval = lKwargs["Interval"]
|
||||||
|
del lKwargs["Interval"]
|
||||||
|
lTimer = TimerRepeat.TimerRepeat(lInterval, DataSendAsync, lArgs, lKwargs)
|
||||||
|
lTimer.start()
|
||||||
|
#Add timer to general list to stop this when needed
|
||||||
|
mTimerList.append(lTimer)
|
||||||
|
return lTimer
|
||||||
|
################################################################################
|
||||||
|
###################################
|
||||||
|
################################
|
||||||
|
###################################
|
||||||
|
################################################################################
|
||||||
|
# Check if RobotStorage[Key] Value has been changed > then send data + reset to orchestrator (asynchronyous) timeout 2 seconds
|
||||||
|
# Example:
|
||||||
|
# t=IntegrationOrchestrator.DataSendResetAsync(
|
||||||
|
# RobotStorage=mGlobal["Storage"],
|
||||||
|
# RobotStorageKey="R01_OrchestratorToRobot",
|
||||||
|
# RobotResetValue="Test",
|
||||||
|
# OrchestratorKeyList=["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
# OrchestratorProtocol="http",
|
||||||
|
# OrchestratorHost="localhost",
|
||||||
|
# OrchestratorPort=8081,
|
||||||
|
# OrchestratorAuthToken="1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
# )
|
||||||
|
def DataSendResetAsync(
|
||||||
|
RobotStorage, RobotStorageKey, RobotResetValue, OrchestratorKeyList, OrchestratorProtocol="http",
|
||||||
|
OrchestratorHost="localhost", OrchestratorPort=80, OrchestratorAuthToken=None
|
||||||
|
):
|
||||||
|
#Do operations if data not equal to ResetValue
|
||||||
|
if RobotStorage[RobotStorageKey] != RobotResetValue:
|
||||||
|
#Get value
|
||||||
|
lRobotValue = copy.deepcopy(RobotStorage[RobotStorageKey])
|
||||||
|
#Reset value
|
||||||
|
RobotStorage[RobotStorageKey] = copy.deepcopy(RobotResetValue)
|
||||||
|
#Send data (retry while data will be transferred completele)
|
||||||
|
from threading import Thread
|
||||||
|
import uuid
|
||||||
|
import time
|
||||||
|
global mGlobalDict
|
||||||
|
class ThreadAsync(Thread):
|
||||||
|
def DataSendSync(self):
|
||||||
|
RobotValue = lRobotValue
|
||||||
|
lCookies = {}
|
||||||
|
# Set auth token if authorization is needed
|
||||||
|
if OrchestratorAuthToken:
|
||||||
|
lCookies["AuthToken"] = OrchestratorAuthToken
|
||||||
|
lURL = f'{OrchestratorProtocol}://{OrchestratorHost}:{OrchestratorPort}/Utils/Processor'
|
||||||
|
lDataJSON = [{"Type": "GlobalDictKeyListValueSet", "KeyList": OrchestratorKeyList, "Value": RobotValue}]
|
||||||
|
lFlagDataTransmit = False
|
||||||
|
while not lFlagDataTransmit:
|
||||||
|
try:
|
||||||
|
lResult = requests.post(lURL, json=lDataJSON, cookies=lCookies)
|
||||||
|
lResultJSON = json.loads(lResult.text)
|
||||||
|
lFlagDataTransmit = True
|
||||||
|
except Exception:
|
||||||
|
mLogger.warning(
|
||||||
|
f"Orchestrator not responding - will retry to send update. Timeout 2 seconds. Def: DataSendResetAsync, RobotValue: {str(RobotValue)}, OrchestratorKeyList: {str(OrchestratorKeyList)}, OrchestratorProtocol: {str(OrchestratorProtocol)}, OrchestratorHost: {str(OrchestratorHost)}, OrchestratorPort: {str(OrchestratorPort)}")
|
||||||
|
time.sleep(2) #Timout for next loop
|
||||||
|
return (True,True) # Only True can be returned
|
||||||
|
# Thread init
|
||||||
|
def __init__(self, name):
|
||||||
|
Thread.__init__(self)
|
||||||
|
self.name = name
|
||||||
|
# Thread start
|
||||||
|
def run(self):
|
||||||
|
self.DataSendSync()
|
||||||
|
ThreadObject = ThreadAsync(f"ThreadAsync{str(uuid.uuid1())}")
|
||||||
|
ThreadObject.start()
|
||||||
|
return True
|
||||||
|
return True
|
||||||
|
################################################################################
|
||||||
|
################################################################################
|
||||||
|
#IntervalDataSendResetAsync - Periodic check changed and send + reset data from robot to orchestrator
|
||||||
|
def IntervalDataSendResetAsync(*args,**kwargs):
|
||||||
|
lInterval=3
|
||||||
|
#Delete index 0 from args
|
||||||
|
lArgs=copy.copy(args)
|
||||||
|
if len(lArgs)>0:
|
||||||
|
lInterval = lArgs[0]
|
||||||
|
lArgs = lArgs[1:]
|
||||||
|
#Delete Interval from kwargs
|
||||||
|
lKwargs = copy.copy(kwargs)
|
||||||
|
if "Interval" in lKwargs:
|
||||||
|
lInterval = lKwargs["Interval"]
|
||||||
|
del lKwargs["Interval"]
|
||||||
|
lTimer = TimerRepeat.TimerRepeat(lInterval, DataSendResetAsync, lArgs, lKwargs)
|
||||||
|
lTimer.start()
|
||||||
|
#Add timer to general list to stop this when needed
|
||||||
|
mTimerList.append(lTimer)
|
||||||
|
return lTimer
|
||||||
|
################################################################################
|
||||||
|
# Check changes in orchestrator - then replace in RobotStorage if not equeal. Has no timeout because You can use function IntervalDataReceiveResetAsync (asynchronyous)
|
||||||
|
#Next iteration do not rewrite value until new change has come from orchestrator
|
||||||
|
# Example:
|
||||||
|
# t=IntegrationOrchestrator.DataRecieveAsync(
|
||||||
|
# RobotStorage=mGlobal["Storage"],
|
||||||
|
# RobotStorageKey="R01_OrchestratorToRobot",
|
||||||
|
# RobotResetValue={"Test":"Test"},
|
||||||
|
# OrchestratorKeyList=["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
# OrchestratorProtocol="http",
|
||||||
|
# OrchestratorHost="localhost",
|
||||||
|
# OrchestratorPort=8081,
|
||||||
|
# OrchestratorAuthToken="1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
# )
|
||||||
|
def DataReceiveResetAsync(
|
||||||
|
RobotStorage, RobotStorageKey, RobotResetValue, OrchestratorKeyList, OrchestratorProtocol="http",
|
||||||
|
OrchestratorHost="localhost", OrchestratorPort=80, OrchestratorAuthToken=None
|
||||||
|
):
|
||||||
|
from threading import Thread
|
||||||
|
import uuid
|
||||||
|
global mGlobalDict
|
||||||
|
class ThreadAsync(Thread):
|
||||||
|
def DataRecieveSync(self):
|
||||||
|
lCookies = {}
|
||||||
|
#Set auth token if authorization is needed
|
||||||
|
if OrchestratorAuthToken:
|
||||||
|
lCookies["AuthToken"] = OrchestratorAuthToken
|
||||||
|
lURL = f'{OrchestratorProtocol}://{OrchestratorHost}:{OrchestratorPort}/Utils/Processor'
|
||||||
|
lDataJSON = [
|
||||||
|
{"Type": "GlobalDictKeyListValueGet", "KeyList": OrchestratorKeyList},
|
||||||
|
{"Type": "GlobalDictKeyListValueSet", "KeyList": OrchestratorKeyList, "Value": RobotResetValue}
|
||||||
|
]
|
||||||
|
try:
|
||||||
|
lResult = requests.post(lURL, json=lDataJSON, cookies = lCookies)
|
||||||
|
lResultJSON = json.loads(lResult.text)
|
||||||
|
#Change data if it changes with ResetValue
|
||||||
|
if lResultJSON[0]["Result"] != RobotResetValue:
|
||||||
|
return (True,lResultJSON[0]["Result"]) #(Flag data changes is ok, Data)
|
||||||
|
else:
|
||||||
|
return (False, lResultJSON[0]["Result"]) # (Flag data changes is false - dont rewrite in RobotStorage, Data)
|
||||||
|
except Exception:
|
||||||
|
mLogger.warning(
|
||||||
|
f"Orchestrator not responding. Def DataReceiveResetAsync, RobotResetValue: {str(RobotResetValue)}, OrchestratorKeyList: {str(OrchestratorKeyList)}, OrchestratorProtocol: {str(OrchestratorProtocol)}, OrchestratorHost: {str(OrchestratorHost)}, OrchestratorPort: {str(OrchestratorPort)}")
|
||||||
|
return (False,None) #(Flag response is not ok, Data None)
|
||||||
|
# Thread init
|
||||||
|
def __init__(self, name):
|
||||||
|
Thread.__init__(self)
|
||||||
|
self.name = name
|
||||||
|
#Thread start
|
||||||
|
def run(self):
|
||||||
|
(lFlagResponseOK,lResponseData) = self.DataRecieveSync()
|
||||||
|
if lFlagResponseOK:
|
||||||
|
RobotStorage[RobotStorageKey] = lResponseData
|
||||||
|
ThreadObject = ThreadAsync(f"ThreadAsync{str(uuid.uuid1())}")
|
||||||
|
ThreadObject.start()
|
||||||
|
return True
|
||||||
|
################################################################################
|
||||||
|
################################################################################
|
||||||
|
#IntervalDataReceiveResetAsync - Periodic receive + every time reset and check changed and reset data on robot storage
|
||||||
|
def IntervalDataReceiveResetAsync(*args,**kwargs):
|
||||||
|
lInterval=3
|
||||||
|
#Delete index 0 from args
|
||||||
|
lArgs=copy.copy(args)
|
||||||
|
if len(lArgs)>0:
|
||||||
|
lInterval = lArgs[0]
|
||||||
|
lArgs = lArgs[1:]
|
||||||
|
#Delete Interval from kwargs
|
||||||
|
lKwargs = copy.copy(kwargs)
|
||||||
|
if "Interval" in lKwargs:
|
||||||
|
lInterval = lKwargs["Interval"]
|
||||||
|
del lKwargs["Interval"]
|
||||||
|
lTimer = TimerRepeat.TimerRepeat(lInterval, DataReceiveResetAsync, lArgs, lKwargs)
|
||||||
|
lTimer.start()
|
||||||
|
#Add timer to general list to stop this when needed
|
||||||
|
mTimerList.append(lTimer)
|
||||||
|
return lTimer
|
||||||
|
#################################################################################
|
||||||
|
#################################################################################
|
||||||
|
################################################################################
|
||||||
|
#ConfigurationInit - Get dict configuration and init interval functions
|
||||||
|
def ConfigurationInit(inConfigurationDict):
|
||||||
|
for lItem in inConfigurationDict.keys():
|
||||||
|
lFunction = globals()[lItem]
|
||||||
|
#Iterate throught the nested list
|
||||||
|
for lFunctionConfigurationDict in inConfigurationDict[lItem]:
|
||||||
|
lFunction(**lFunctionConfigurationDict)
|
||||||
|
return True
|
@ -0,0 +1,34 @@
|
|||||||
|
import logging
|
||||||
|
import datetime
|
||||||
|
#Robot settings
|
||||||
|
def Settings():
|
||||||
|
import os
|
||||||
|
mDict = {
|
||||||
|
"Logger": logging.getLogger("Robot"),
|
||||||
|
"Storage": {
|
||||||
|
"Robot_R01_help": "Robot data storage in orchestrator env",
|
||||||
|
"Robot_R01": {}
|
||||||
|
},
|
||||||
|
"ProcessBitness": {
|
||||||
|
"Python32FullPath": None, #Set from user: "..\\Resources\\WPy32-3720\\python-3.7.2\\OpenRPARobotGUIx32.exe"
|
||||||
|
"Python64FullPath": None, #Set from user
|
||||||
|
"Python32ProcessName": "OpenRPAUIDesktopX32.exe", #Config set once
|
||||||
|
"Python64ProcessName": "OpenRPAUIDesktopX64.exe" #Config set once
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#Создать файл логирования
|
||||||
|
# add filemode="w" to overwrite
|
||||||
|
if not os.path.exists("Reports"):
|
||||||
|
os.makedirs("Reports")
|
||||||
|
##########################
|
||||||
|
#Подготовка логгера Robot
|
||||||
|
#########################
|
||||||
|
mRobotLogger=mDict["Logger"]
|
||||||
|
mRobotLogger.setLevel(logging.INFO)
|
||||||
|
# create the logging file handler
|
||||||
|
mRobotLoggerFH = logging.FileHandler("Reports\ReportRobot_"+datetime.datetime.now().strftime("%Y_%m_%d")+".log")
|
||||||
|
mRobotLoggerFormatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||||
|
mRobotLoggerFH.setFormatter(mRobotLoggerFormatter)
|
||||||
|
# add handler to logger object
|
||||||
|
mRobotLogger.addHandler(mRobotLoggerFH)
|
||||||
|
############################################
|
@ -0,0 +1,65 @@
|
|||||||
|
import unittest
|
||||||
|
from threading import Timer
|
||||||
|
import sys
|
||||||
|
lFolderPath = "/".join(__file__.split("\\")[:-3])
|
||||||
|
sys.path.insert(0, lFolderPath)
|
||||||
|
from pyOpenRPA.Robot import OrchestratorConnector
|
||||||
|
from pyOpenRPA.Robot import Utils
|
||||||
|
class MyTestCase(unittest.TestCase):
|
||||||
|
def test_something(self):
|
||||||
|
#self.assertEqual(True, False)
|
||||||
|
mGlobal={"Storage":{"R01_OrchestratorToRobot":{"Test":"Test2"}}}
|
||||||
|
# t=OrchestratorConnector.IntervalDataSendAsync(
|
||||||
|
# Interval=1,
|
||||||
|
# RobotStorage=mGlobal["Storage"],
|
||||||
|
# RobotStorageKey="R01_OrchestratorToRobot",
|
||||||
|
# OrchestratorKeyList=["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
# OrchestratorProtocol="http",
|
||||||
|
# OrchestratorHost="localhost",
|
||||||
|
# OrchestratorPort=8081,
|
||||||
|
# OrchestratorAuthToken="1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
# )
|
||||||
|
# t=OrchestratorConnector.DataSendSync(
|
||||||
|
# RobotValue="Test",
|
||||||
|
# OrchestratorKeyList=["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
# OrchestratorProtocol="http",
|
||||||
|
# OrchestratorHost="localhost",
|
||||||
|
# OrchestratorPort=8081,
|
||||||
|
# OrchestratorAuthToken="1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
# )
|
||||||
|
import time
|
||||||
|
#def Func(lT,inl):
|
||||||
|
# print(lT)
|
||||||
|
# return True
|
||||||
|
#lTimer= Utils.TimerRepeat.TimerRepeat(1, Func, ["dddd"],{"inl":9})
|
||||||
|
#lTimer.start()
|
||||||
|
OrchestratorConnector.ConfigurationInit({
|
||||||
|
"IntervalDataSendResetAsync": [
|
||||||
|
{
|
||||||
|
"Interval": 2,
|
||||||
|
"RobotStorage": mGlobal["Storage"],
|
||||||
|
"RobotStorageKey": "R01_OrchestratorToRobot",
|
||||||
|
"RobotResetValue": {"Test": "Test"},
|
||||||
|
"OrchestratorKeyList": ["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
"OrchestratorProtocol": "http",
|
||||||
|
"OrchestratorHost": "localhost",
|
||||||
|
"OrchestratorPort": 8081,
|
||||||
|
"OrchestratorAuthToken": "1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
while True:
|
||||||
|
print(mGlobal["Storage"]["R01_OrchestratorToRobot"])
|
||||||
|
# t = OrchestratorConnector.DataSendResetAsync(
|
||||||
|
# RobotStorage=mGlobal["Storage"],
|
||||||
|
# RobotStorageKey="R01_OrchestratorToRobot",
|
||||||
|
# RobotResetValue={"Test": "Test"},
|
||||||
|
# OrchestratorKeyList=["Storage", "R01_OrchestratorToRobot"],
|
||||||
|
# OrchestratorProtocol="http",
|
||||||
|
# OrchestratorHost="localhost",
|
||||||
|
# OrchestratorPort=8081,
|
||||||
|
# OrchestratorAuthToken="1992-04-03-0643-ru-b4ff-openrpa52zzz"
|
||||||
|
# )
|
||||||
|
time.sleep(0.5)
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
@ -0,0 +1,28 @@
|
|||||||
|
from threading import Timer
|
||||||
|
import datetime
|
||||||
|
# lTimer = RepeatedTimer(3, def, [], {}) # it auto-starts, no need of rt.start()
|
||||||
|
# if def return None = timer stops
|
||||||
|
# lTimer.start()
|
||||||
|
class TimerRepeat(object):
|
||||||
|
def __init__(self, interval, function, args, kwargs):
|
||||||
|
self._timer = None
|
||||||
|
self.interval = interval
|
||||||
|
self.function = function
|
||||||
|
self.args = args
|
||||||
|
self.kwargs = kwargs
|
||||||
|
self.is_running = False
|
||||||
|
self.start()
|
||||||
|
def _run(self):
|
||||||
|
self.is_running = False
|
||||||
|
lResult = self.function(*self.args, **self.kwargs)
|
||||||
|
if lResult is not None:
|
||||||
|
if lResult:
|
||||||
|
self.start()
|
||||||
|
def start(self):
|
||||||
|
if not self.is_running:
|
||||||
|
self._timer = Timer(self.interval, self._run)
|
||||||
|
self._timer.start()
|
||||||
|
self.is_running = True
|
||||||
|
def stop(self):
|
||||||
|
self._timer.cancel()
|
||||||
|
self.is_running = False
|
@ -0,0 +1,108 @@
|
|||||||
|
import pdb
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import zlib
|
||||||
|
import os
|
||||||
|
from . import ProcessCommunicator
|
||||||
|
import importlib
|
||||||
|
import traceback
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
import datetime
|
||||||
|
import struct
|
||||||
|
import shutil
|
||||||
|
from pyOpenRPA.Robot import UIDesktop
|
||||||
|
global mGlobalDict
|
||||||
|
####################################
|
||||||
|
#Info: Main module of the Robot app (OpenRPA - Robot)
|
||||||
|
####################################
|
||||||
|
|
||||||
|
#Usage:
|
||||||
|
#Here you can run some activity or list of activities
|
||||||
|
|
||||||
|
#After import this module you can use the folowing functions:
|
||||||
|
#ActivityRun(inActivitySpecificationDict): outActivityResultDict - function - run activity (function or procedure)
|
||||||
|
#ActivityRunJSON(inActivitySpecificationDictJSON): outActivityResultDictJSON
|
||||||
|
#ActivityListRun(inActivitySpecificationDictList): outActivityResultDictList - function - run list of activities (function or procedure)
|
||||||
|
#ActivityListRunJSON(inActivitySpecificationDictListJSON): outActivityResultDictListJSON
|
||||||
|
|
||||||
|
#Naming:
|
||||||
|
#Activity - some action/list of actions
|
||||||
|
#Module - Any *.py file, which consist of area specific functions
|
||||||
|
#Argument
|
||||||
|
|
||||||
|
#inActivitySpecificationDict:
|
||||||
|
#{
|
||||||
|
# ModuleName: <"GUI"|..., str>,
|
||||||
|
# ActivityName: <Function or procedure name in module, str>,
|
||||||
|
# ArgumentList: [<Argument 1, any type>, ...] - optional,
|
||||||
|
# ArgumentDict: {<Argument 1 name, str>:<Argument 1 value, any type>, ...} - optional
|
||||||
|
#}
|
||||||
|
|
||||||
|
#outActivityResultDict:
|
||||||
|
#{
|
||||||
|
# ActivitySpecificationDict: {
|
||||||
|
# ModuleName: <"GUI"|..., str>,
|
||||||
|
# ActivityName: <Function or procedure name in module, str>,
|
||||||
|
# ArgumentList: [<Argument 1, any type>, ...] - optional,
|
||||||
|
# ArgumentDict: {<Argument 1 name, str>: <Argument 1 value, any type>, ...} - optional
|
||||||
|
# },
|
||||||
|
# ErrorFlag: <Boolean flag - Activity result has error (true) or not (false), boolean>,
|
||||||
|
# ErrorMessage: <Error message, str> - required if ErrorFlag is true,
|
||||||
|
# ErrorTraceback: <Error traceback log, str> - required if ErrorFlag is true,
|
||||||
|
# Result: <Result, returned from the Activity, int, str, boolean, list, dict> - required if ErrorFlag is false
|
||||||
|
#}
|
||||||
|
|
||||||
|
####################
|
||||||
|
#Section: Activity
|
||||||
|
####################
|
||||||
|
def ActivityRun(inActivitySpecificationDict):
|
||||||
|
lResponseObject = {}
|
||||||
|
#Выполнить отправку в модуль UIDesktop, если ModuleName == "UIDesktop"
|
||||||
|
if inActivitySpecificationDict["ModuleName"] == "UIDesktop":
|
||||||
|
if "ArgumentList" not in inActivitySpecificationDict:
|
||||||
|
inActivitySpecificationDict["ArgumentList"]=[]
|
||||||
|
if "ArgumentDict" not in inActivitySpecificationDict:
|
||||||
|
inActivitySpecificationDict["ArgumentDict"]={}
|
||||||
|
#Run the activity
|
||||||
|
try:
|
||||||
|
#Найти функцию
|
||||||
|
lFunction=getattr(UIDesktop,inActivitySpecificationDict["ActivityName"])
|
||||||
|
#Выполнить вызов и записать результат
|
||||||
|
lResponseObject["Result"]=lFunction(*inActivitySpecificationDict["ArgumentList"],**inActivitySpecificationDict["ArgumentDict"])
|
||||||
|
except Exception as e:
|
||||||
|
#Установить флаг ошибки и передать тело ошибки
|
||||||
|
lResponseObject["ErrorFlag"]=True
|
||||||
|
lResponseObject["ErrorMessage"]=str(e)
|
||||||
|
lResponseObject["ErrorTraceback"]=traceback.format_exc()
|
||||||
|
#Остальные модули подключать и выполнять здесь
|
||||||
|
else:
|
||||||
|
lArgumentList=[]
|
||||||
|
if "ArgumentList" in inActivitySpecificationDict:
|
||||||
|
lArgumentList=inActivitySpecificationDict["ArgumentList"]
|
||||||
|
lArgumentDict={}
|
||||||
|
if "ArgumentDict" in inActivitySpecificationDict:
|
||||||
|
lArgumentDict=inActivitySpecificationDict["ArgumentDict"]
|
||||||
|
#Подготовить результирующую структуру
|
||||||
|
lResponseObject={"ActivitySpecificationDict":inActivitySpecificationDict,"ErrorFlag":False}
|
||||||
|
try:
|
||||||
|
#Подключить модуль для вызова
|
||||||
|
lModule=importlib.import_module(inActivitySpecificationDict["ModuleName"])
|
||||||
|
#Найти функцию
|
||||||
|
lFunction=getattr(lModule,inActivitySpecificationDict["ActivityName"])
|
||||||
|
#Выполнить вызов и записать результат
|
||||||
|
lResponseObject["Result"]=lFunction(*lArgumentList,**lArgumentDict)
|
||||||
|
except Exception as e:
|
||||||
|
#Установить флаг ошибки и передать тело ошибки
|
||||||
|
lResponseObject["ErrorFlag"]=True
|
||||||
|
lResponseObject["ErrorMessage"]=str(e)
|
||||||
|
lResponseObject["ErrorTraceback"]=traceback.format_exc()
|
||||||
|
return lResponseObject
|
||||||
|
#########################################################
|
||||||
|
#Run list of activities
|
||||||
|
#########################################################
|
||||||
|
def ActivityListRun(inActivitySpecificationDictList):
|
||||||
|
lResult=[]
|
||||||
|
for lItem in inActivitySpecificationDictList:
|
||||||
|
lResult.append(ActivityRun(lItem))
|
||||||
|
return lResult
|
@ -1,17 +1,34 @@
|
|||||||
from pyOpenRPA.Robot import UIDesktop
|
from pyOpenRPA.Robot import UIDesktop
|
||||||
from . import Connector
|
from . import Connector
|
||||||
|
import os
|
||||||
import pdb
|
import pdb
|
||||||
#Check for session is closed. Reopen if detected. Always keep session is active
|
#Check for session is closed. Reopen if detected. Always keep session is active
|
||||||
def Monitor(inGlobalDict, inListUpdateTimeout):
|
def Monitor(inGlobalDict, inListUpdateTimeout):
|
||||||
while True:
|
lFlagWhile = True
|
||||||
|
while lFlagWhile:
|
||||||
# UIOSelector list init
|
# UIOSelector list init
|
||||||
lUIOSelectorList = []
|
lUIOSelectorList = []
|
||||||
for lItem in inGlobalDict["RDPList"]:
|
for lItem in inGlobalDict["RDPList"]:
|
||||||
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']} — .*", "backend": "win32"}])
|
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']} — .*", "backend": "win32"}])
|
||||||
#Run wait command
|
#Run wait command
|
||||||
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
|
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
|
||||||
|
#Analyze if flag safeturn off is activated
|
||||||
|
if inGlobalDict.get("OrchestratorToRobotResetStorage",{}).get("SafeTurnOff",False):
|
||||||
|
lFlagWhile=False
|
||||||
|
#Set status disconnected for all RDP List
|
||||||
|
for lItem in inGlobalDict["RDPList"]:
|
||||||
|
lItem["FlagSessionIsActive"]=False
|
||||||
|
#Kill all RDP sessions
|
||||||
|
os.system('taskkill /F /im mstsc.exe')
|
||||||
|
#Return from function
|
||||||
|
return
|
||||||
for lItem in lRDPDissappearList:
|
for lItem in lRDPDissappearList:
|
||||||
|
inGlobalDict["RDPList"][lItem]["FlagSessionIsActive"] = False # Set flag that session is disconnected
|
||||||
#pdb.set_trace()
|
#pdb.set_trace()
|
||||||
#Session start
|
#Session start
|
||||||
Connector.Session(inGlobalDict["RDPList"][lItem])
|
try:
|
||||||
return None
|
Connector.Session(inGlobalDict["RDPList"][lItem])
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
#TODO Def garbage window cleaner (if connection was lost)
|
@ -1,22 +0,0 @@
|
|||||||
#Robot RDPActive settings
|
|
||||||
def Settings():
|
|
||||||
mDict = {
|
|
||||||
"RDPList":
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"Host": "77.77.22.22", # Host address
|
|
||||||
"Port": "7777", # RDP Port
|
|
||||||
"Login": "test", # Login
|
|
||||||
"Password": "test", # Password
|
|
||||||
"Screen": {
|
|
||||||
"Width": 1680, #Width of the remote desktop in pixels
|
|
||||||
"Height": 1050, #Height of the remote desktop in pixels
|
|
||||||
# "640x480" or "1680x1050" or "FullScreen". If Resolution not exists set full screen
|
|
||||||
"FlagUseAllMonitors": False, # True or False
|
|
||||||
"DepthBit": "32" # "32" or "24" or "16" or "15"
|
|
||||||
},
|
|
||||||
"SessionHex":"" # Hex is created when robot runs
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
return mDict
|
|
@ -0,0 +1,5 @@
|
|||||||
|
recursive-include pyOpenRPA\Resources *
|
||||||
|
recursive-include pyOpenRPA\Orchestrator\Web *
|
||||||
|
recursive-include pyOpenRPA\Studio\Web *
|
||||||
|
include pyOpenRPA\Tools\RobotRDPActive\Template.rdp
|
||||||
|
include pyOpenRPA\Tools\RobotScreenActive\ConsoleStart.bat
|
@ -1,3 +1,6 @@
|
|||||||
cd %~dp0
|
cd %~dp0
|
||||||
|
RD /S /Q "__pycache__"
|
||||||
|
RD /S /Q "build"
|
||||||
|
RD /S /Q "dist"
|
||||||
.\..\Resources\WPy64-3720\python-3.7.2.amd64\python.exe setup.py sdist bdist_wheel
|
.\..\Resources\WPy64-3720\python-3.7.2.amd64\python.exe setup.py sdist bdist_wheel
|
||||||
pause >nul
|
pause >nul
|
@ -1,4 +1,4 @@
|
|||||||
cd %~dp0\..\Sources
|
cd %~dp0\..\Sources
|
||||||
copy /Y ..\Resources\WPy64-3720\python-3.7.2.amd64\python.exe ..\Resources\WPy64-3720\python-3.7.2.amd64\OpenRPA_Studio.exe
|
copy /Y ..\Resources\WPy64-3720\python-3.7.2.amd64\python.exe ..\Resources\WPy64-3720\python-3.7.2.amd64\OpenRPA_Studio.exe
|
||||||
.\..\Resources\WPy64-3720\python-3.7.2.amd64\OpenRPA_Studio.exe -m pyOpenRPA.Studio "..\Studio\Settings.py"
|
.\..\Resources\WPy64-3720\python-3.7.2.amd64\OpenRPA_Studio.exe -m pyOpenRPA.Studio "..\Studio\SettingsStudioExample.py"
|
||||||
pause >nul
|
pause >nul
|
@ -1,4 +1,4 @@
|
|||||||
cd %~dp0..\..\Sources
|
cd %~dp0..\..\Sources
|
||||||
copy /Y ..\Resources\WPy64-3720\python-3.7.2.amd64\python.exe ..\Resources\WPy64-3720\python-3.7.2.amd64\OpenRPA_RobotRDPActive.exe
|
copy /Y ..\Resources\WPy64-3720\python-3.7.2.amd64\python.exe ..\Resources\WPy64-3720\python-3.7.2.amd64\OpenRPA_RobotRDPActive.exe
|
||||||
..\Resources\WPy64-3720\python-3.7.2.amd64\OpenRPA_RobotRDPActive.exe -m pyOpenRPA.Tools.RobotRDPActive "C:\Abs\Archive\scopeSrcUL\OpenRPA_Creds\RobotRDPActive\SettingsVSK.py"
|
..\Resources\WPy64-3720\python-3.7.2.amd64\OpenRPA_RobotRDPActive.exe -m pyOpenRPA.Tools.RobotRDPActive "..\Utils\RobotRDPActive\SettingsRobotRDPActiveExample.py"
|
||||||
pause >nul
|
pause >nul
|
Loading…
Reference in new issue