From 98f22ddb5877dc445e761fa6f3fffe641be67559 Mon Sep 17 00:00:00 2001 From: Ivan Maslov Date: Fri, 29 Nov 2019 22:59:46 +0300 Subject: [PATCH] - Robot: Add RobotSettings.py to Robot - Robot: Logger to GlobalDict - Robot: Exclude Robot.py - Studio: Add Settings.py - All: Remove print garbage Signed-off-by: Ivan Maslov --- .../python-3.7.2/OpenRPAUIDesktopX32.exe | Bin 0 -> 97296 bytes Robot/RobotSettings.py | 34 ++++ Sources/pyOpenRPA/Orchestrator/Server.py | 5 +- .../pyOpenRPA/Orchestrator/ServerSettings.py | 1 - .../pyOpenRPA/Robot/ProcessCommunicator.py | 5 - Sources/pyOpenRPA/Robot/Robot.py | 159 ------------------ Sources/pyOpenRPA/Robot/SettingsTemplate.py | 34 ++++ Sources/pyOpenRPA/Robot/UIDesktop.py | 22 +-- Sources/pyOpenRPA/Robot/__main__.py | 14 +- .../pyOpenRPA/Studio/ProcessCommunicator.py | 5 - Sources/pyOpenRPA/Studio/RobotConnector.py | 108 ++++++++++++ Sources/pyOpenRPA/Studio/Studio.py | 49 ++++-- Studio/Settings.py | 48 ++++++ Studio/pyOpenRPA.Studio_x64.cmd | 2 +- 14 files changed, 272 insertions(+), 214 deletions(-) create mode 100644 Resources/WPy32-3720/python-3.7.2/OpenRPAUIDesktopX32.exe create mode 100644 Robot/RobotSettings.py delete mode 100644 Sources/pyOpenRPA/Robot/Robot.py create mode 100644 Sources/pyOpenRPA/Robot/SettingsTemplate.py create mode 100644 Sources/pyOpenRPA/Studio/RobotConnector.py create mode 100644 Studio/Settings.py diff --git a/Resources/WPy32-3720/python-3.7.2/OpenRPAUIDesktopX32.exe b/Resources/WPy32-3720/python-3.7.2/OpenRPAUIDesktopX32.exe new file mode 100644 index 0000000000000000000000000000000000000000..4053ac882b73170b1f3cd11a44dda54166dc5012 GIT binary patch literal 97296 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

`G1w$=K$H1dL!MgW}S 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 literal 0 HcmV?d00001 diff --git a/Robot/RobotSettings.py b/Robot/RobotSettings.py new file mode 100644 index 00000000..b92b8d66 --- /dev/null +++ b/Robot/RobotSettings.py @@ -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) + ############################################ \ No newline at end of file diff --git a/Sources/pyOpenRPA/Orchestrator/Server.py b/Sources/pyOpenRPA/Orchestrator/Server.py index a7a44dc8..69365083 100644 --- a/Sources/pyOpenRPA/Orchestrator/Server.py +++ b/Sources/pyOpenRPA/Orchestrator/Server.py @@ -22,14 +22,14 @@ class RobotDaemonServer(Thread): def run(self): inServerAddress=""; inPort = mGlobalDict["Server"]["ListenPort"]; - #print('starting server..., port:'+str(inPort)+" inAddress:"+inServerAddress) # Server settings # Choose port 8080, for port 80, which is normally used for a http server, you need root access server_address = (inServerAddress, inPort) httpd = HTTPServer(server_address, testHTTPServer_RequestHandler) - #print('running server...') # Logging mGlobalDict["Logger"].info(f"Server init. Listen URL: {inServerAddress}, Listen port: {inPort}") + # Запуск адреса в браузере + os.system("explorer http://127.0.0.1:8081") httpd.serve_forever() #Authenticate function () @@ -325,7 +325,6 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): lFlagURLIsApplied=False lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "GET") if lFlagURLIsApplied: - #print("New engine") self.ResponseDictSend() return #Monitor diff --git a/Sources/pyOpenRPA/Orchestrator/ServerSettings.py b/Sources/pyOpenRPA/Orchestrator/ServerSettings.py index c8dc41ca..881a799c 100644 --- a/Sources/pyOpenRPA/Orchestrator/ServerSettings.py +++ b/Sources/pyOpenRPA/Orchestrator/ServerSettings.py @@ -16,7 +16,6 @@ def Monitor_ControlPanelDictGet(inRequest,inGlobalDict): # Send message back to client message = json.dumps(lResultJSON) # Write content as utf-8 data - #print(bytes(message, "utf8")) inResponseDict["Body"] = bytes(message, "utf8") def GetScreenshot(inRequest,inGlobalDict): diff --git a/Sources/pyOpenRPA/Robot/ProcessCommunicator.py b/Sources/pyOpenRPA/Robot/ProcessCommunicator.py index 87360f1c..1389ec52 100644 --- a/Sources/pyOpenRPA/Robot/ProcessCommunicator.py +++ b/Sources/pyOpenRPA/Robot/ProcessCommunicator.py @@ -41,7 +41,6 @@ def ProcessParentWriteString(lString): #Вернуть \f lByteString = lByteString.replace(b'\f',b'{{{f}}}') ############################ - #print(b"Result: "+lByteString) #lByteString= b'x\x9c\xdd\x95]O\xc20\x14\x86\xffJ\xb3[5\xa1Cqz\x07\xc4\xe8\x8d\x1fQ\x13.\x0cYJw\xb6U\xbav\xe9\xce"\x84\xf0\xdfm\'"\xb8\xa0L%Q\xb3\x9b\xf6=\xdfO\x9a\xb3\x99\x17\x97\x8a\xa3\xd0\xea\x8ae\xe0\x9d\x12\xaf[\xa2\xce\x98S\xee\x80\x19\x9e^\xea\xb2\x803\t\x19(\xbc\x10`\x9c6\xf5\xf6\x89\xc7LRt\x8daS\x1b\xf5\xf00\xf3\xd4"\xc1u\x0e\xea\xf6\xa6K\x0e\xc8\xb9\xd6\x89\x04\xd2O\x8d\xb6&\x1bb\x04OC\x84\t~\xe2\x97\x1b\xcd\xa1(B\x11YG\xdaj\xfb\xc1\x9b\xb8\xa2\xa4LE\xd2\xd5\xa4\xf6\xdenY\x85Kf\xc3^;yI\x18\x0eD\x94\x00\x0e\x84{{n}}\xa9K\xce\xb5B\xa3e\x88\xd3\xbc\xf2Z\xd5\xaa\x82\xaa\x94\xd25\x0b\x1c\x99J\xaa\x023OB\xec\xbavEP\xe7\x8b\x93\x11I\xeaTz\xe2\xbb\xebH\xa3eW5\xe8\xb7\xe6\xce^*\x14\xb6\x83e\xda\xf9phe]b^\xe2\xf5\xe8\xd1Vp\xf0\xfe.\xbb\x1b\xa6`\x87\xfc8\x1a\x9bSE0q\xa2\x15\xeer\xe0"\x16\xbcz\x9f\xfdT\xc8h\x9d\xdf\xc7\xd4\xbe\xcdj1\xd9:\xa9\x1f\xe1B7\x81\xa1\xef\xc0\xd0:\x98\xc3-\xc0\xd4X\xfc\xda\xf1i\xbb\xe9\xfc\xdb<\x8c\xff2\x7f\'\xa8\x8d\xdf\xdab\xfc\x9e\xd6\xe3\x8c\x99qQ\xe3\xb0f\xd9\x19\x90{\xade\x8f\x99/3\xa1AC(\xfe\x16P\x06F \x90\xb3\t\x07Iba\x17\x83P\xa4\xbf\xb7G\x9e\x04\xa6vE\x13\xb6\xfc\x13\xd6\xa85\x0b\xdd\x19\xd6^i\x11\xa8FT;G\xfe\x06\xac\xc1q\xb0N\x956\xd84\xae\xe4p\xbe\xfa=\x03\x01\xce\x95\x9a' #lByteString = b"x\x9c\xb5\x91\xcfO\xc3 \x14\xc7\xff\x95\xa6\xd7uI\xf9Q\x8a\xde\xd4\x93\x07\xbdx\xf00\x97\x05)[I(\x90\x8ef3\xcb\xfew\x81M\xbb\xd9M]\x8c!y\xd0\xf7}\xbc\xef\xe3\xd3\xc9&\xd5\xac\x11\xe9u\x92j\xb1J@2N\x1e\x8d\x13\x96U\xa3Q\x9a%i+y=sb\xed\xceV\xd8\xd6p\xb1\\\xced\xe5K{{n}}\x80`\x9f\xeb\x135\xd3\x95{{n}}.\x08RR\xe4>\xc3\x15\xf3\x97>\xbc\x8f:r\xa3]k\xd4\xcc\xbd\xd9(>K]\x99\xd5\xa1\x12\xbd\x00\xc6\xb0\xcc\xcb0\xa4\xe0\x8e\xe9E4\xd8\xa4J\xcc\xc3\xb44\x07^r\xc6\xfa3\x04(\xbeeQ\x07\x05P\x1a\xa4W\xe3\x9ci\xfc\xf7\x15(\xb6A\xee\xb4\x93\x8d\xd85\x9f`?\xf6n\xd8i0v\xadw\xd5\x95X\x87n>\xf1d\x05\x97s\xc9\x99\x93F\xdf\xd5R\xc5K=\xcc\x1bk\xd5^\x1d`\xfc\xa2]\x06PwJ\r\xf0\x9d\xa2\xf6 tw\xcb\xda\x01\xb6}\x83\xd3\xcc\x00\xec\x99\x15\xf4\x88Y\x99\x1f2\x83\xb4\xfc\x8e\x99\xdf\xb3d\x0c\x01.1E\x04\x93l\xff\x8e\xcf\x7f6\xa4Z\xfc\x82\xeaK\x97c BD\xf3\x101\x89g\xba\x8b\x03\xd0?\x97\xff#\xfb{'\x9a\x8b\xe0\x03H\xc89\xfa\x08\x15\x7f\xa2\x0f >\x80_\x0e\xe0\x93\xb3\xf0\xc3\xc4\xd3m\\\xef\xf8\x958\xa0" #lt=open("logSendByteStringWithoutN.log","wb") @@ -71,7 +70,6 @@ def ProcessChildSendString(lProcess,lString): lByteString = lByteString.replace(b'\n',b'{{n}}') #Отправить сообщение в дочерний процесс lProcess.stdin.write(lByteString+bytes('\n',"utf-8")) - #print(str(lByteString+bytes('\n',"utf-8"))) lProcess.stdin.flush() #Вернуть результат return @@ -82,7 +80,6 @@ def ProcessChildReadWaitString(lProcess): #pdb.set_trace() lResult = lProcess.stdout.readline() #Обработка спец символов - #print(b'NewLine: '+lResult) #Вернуть потенциальные \n lResult = lResult.replace(b'{{{n}}}',b'\n') #Вернуть \r @@ -99,8 +96,6 @@ def ProcessChildReadWaitString(lProcess): lResult = lResult.replace(b'{{{v}}}',b'\v') #Вернуть \f lResult = lResult.replace(b'{{{f}}}',b'\f') - #print("check") - #print(str(lResult)) try: lResult = zlib.decompress(lResult[0:-1]) lResult = lResult.decode("utf-8") diff --git a/Sources/pyOpenRPA/Robot/Robot.py b/Sources/pyOpenRPA/Robot/Robot.py deleted file mode 100644 index 77a26e07..00000000 --- a/Sources/pyOpenRPA/Robot/Robot.py +++ /dev/null @@ -1,159 +0,0 @@ -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 -#Создать файл логирования -# add filemode="w" to overwrite -if not os.path.exists("Reports"): - os.makedirs("Reports") -logging.basicConfig(filename="Reports\ReportRobotRun_"+datetime.datetime.now().strftime("%Y_%m_%d")+".log", level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s") - -#################################### -#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: , -# ArgumentList: [, ...] - optional, -# ArgumentDict: {:, ...} - optional -#} - -#outActivityResultDict: -#{ -# ActivitySpecificationDict: { -# ModuleName: <"GUI"|..., str>, -# ActivityName: , -# ArgumentList: [, ...] - optional, -# ArgumentDict: {: , ...} - optional -# }, -# ErrorFlag: , -# ErrorMessage: - required if ErrorFlag is true, -# ErrorTraceback: - required if ErrorFlag is true, -# Result: - required if ErrorFlag is false -#} - -#################### -#Section: Module initialization -#################### -#Start childprocess - GUI Module 32 bit -#pdb.set_trace() -if not os.path.isfile("..\\Resources\\WPy32-3720\\python-3.7.2\\OpenRPARobotGUIx32.exe"): - shutil.copyfile('..\\Resources\\WPy32-3720\\python-3.7.2\\python.exe',"..\\Resources\\WPy32-3720\\python-3.7.2\\OpenRPARobotGUIx32.exe") -mProcessGUI_x32 = subprocess.Popen(['..\\Resources\\WPy32-3720\\python-3.7.2\\OpenRPARobotGUIx32.exe',"-m",'pyOpenRPA.Robot'],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE) -#Start childprocess - GUI Module 64 bit - uncomment after WPy64 installation -ProcessCommunicator.ProcessChildSendObject(mProcessGUI_x32,{"ModuleName":"UIDesktop","ActivityName":"Get_OSBitnessInt","ArgumentList":[],"ArgumentDict":{}}) -lOSBitness = ProcessCommunicator.ProcessChildReadWaitObject(mProcessGUI_x32)["Result"] - -lProcessBitnessStr = str(struct.calcsize("P") * 8) -#start 64 if system support 64 -mProcessGUI_x64 = None -if lOSBitness == 64: - if not os.path.isfile("..\\Resources\\WPy64-3720\\python-3.7.2.amd64\\OpenRPARobotGUIx64.exe"): - shutil.copyfile('..\\Resources\\WPy64-3720\\python-3.7.2.amd64\\python.exe',"..\\Resources\\WPy64-3720\\python-3.7.2.amd64\\OpenRPARobotGUIx64.exe") - mProcessGUI_x64 = subprocess.Popen(['..\\Resources\\WPy64-3720\\python-3.7.2.amd64\\OpenRPARobotGUIx64.exe',"-m",'pyOpenRPA.Robot'],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE) - -#################### -#Section: Activity -#################### -def ActivityRun(inActivitySpecificationDict): - #Выполнить отправку в модуль UIDesktop, если ModuleName == "UIDesktop" - #pdb.set_trace() - if inActivitySpecificationDict["ModuleName"] == "UIDesktop": - if "ArgumentList" not in inActivitySpecificationDict: - inActivitySpecificationDict["ArgumentList"]=[] - if "ArgumentDict" not in inActivitySpecificationDict: - inActivitySpecificationDict["ArgumentDict"]={} - - #Если mProcessGUI_x64 не инициализирован - lFlagRun64=True - if mProcessGUI_x64 is None: - lFlagRun64=False - else: - if inActivitySpecificationDict["ActivityName"]=="UIOSelectorsSecs_WaitAppear_List": - #Функция ожидания появления элементов (тк элементы могут быть недоступны, неизвестно в каком фреймворке каждый из них может появиться) - lFlagRun64=True - elif inActivitySpecificationDict["ActivityName"].startswith("UIOSelector") or inActivitySpecificationDict["ActivityName"].startswith("PWASpecification"): - if len(inActivitySpecificationDict["ArgumentList"])>0: - if len(inActivitySpecificationDict["ArgumentList"][0])>0: - #Определение разрядности (32 и 64) для тех функций, где это необходимо - ###################################################### - #Выполнить проверку разрядности через UIOSelector_Get_BitnessInt - #Отправить запрос в дочерний процесс, который отвечает за работу с Windows окнами - #pdb.set_trace() - #Внимание! Проверка разрядности специально делается на процессе 64 бита, тк процесс 32 бита зависает на 35 итерации проверки - ProcessCommunicator.ProcessChildSendObject(mProcessGUI_x64,{"ModuleName":"UIDesktop","ActivityName":"UIOSelector_Get_BitnessInt","ArgumentList":[inActivitySpecificationDict["ArgumentList"][0]],"ArgumentDict":inActivitySpecificationDict["ArgumentDict"]}) - #Получить ответ от дочернего процесса - lResponseObject=ProcessCommunicator.ProcessChildReadWaitObject(mProcessGUI_x64) - #pdb.set_trace() - if lResponseObject["Result"]==32: - lFlagRun64=False - #Запуск 64 - #pdb.set_trace() - if lFlagRun64: - #Отправить запрос в дочерний процесс, который отвечает за работу с Windows окнами - ProcessCommunicator.ProcessChildSendObject(mProcessGUI_x64,inActivitySpecificationDict) - #Получить ответ от дочернего процесса - lResponseObject=ProcessCommunicator.ProcessChildReadWaitObject(mProcessGUI_x64) - else: - #Запуск 32 - #Отправить запрос в дочерний процесс, который отвечает за работу с Windows окнами - ProcessCommunicator.ProcessChildSendObject(mProcessGUI_x32,inActivitySpecificationDict) - #Получить ответ от дочернего процесса - lResponseObject=ProcessCommunicator.ProcessChildReadWaitObject(mProcessGUI_x32) - - #Остальные модули подключать и выполнять здесь - 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 \ No newline at end of file diff --git a/Sources/pyOpenRPA/Robot/SettingsTemplate.py b/Sources/pyOpenRPA/Robot/SettingsTemplate.py new file mode 100644 index 00000000..b92b8d66 --- /dev/null +++ b/Sources/pyOpenRPA/Robot/SettingsTemplate.py @@ -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) + ############################################ \ No newline at end of file diff --git a/Sources/pyOpenRPA/Robot/UIDesktop.py b/Sources/pyOpenRPA/Robot/UIDesktop.py index 74e7ae13..de74416f 100644 --- a/Sources/pyOpenRPA/Robot/UIDesktop.py +++ b/Sources/pyOpenRPA/Robot/UIDesktop.py @@ -21,25 +21,11 @@ import logging import re import copy -#Создать файл логирования -# add filemode="w" to overwrite -if not os.path.exists("Reports"): - os.makedirs("Reports") -########################## -#Подготовка логгера Robot -######################### -mRobotLogger=logging.getLogger("RobotLogger") -mRobotLogger.setLevel(logging.INFO) -# create the logging file handler -mRobotLoggerFH = logging.FileHandler("Reports\ReportRobotGUIRun_"+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) ############################################ -#When import UIDesktop init the other bitness python -#For this type UIDesktop.Utils.ProcessBitness.SettingsInit(inSettingsDict) -#inSettingsDict = { +# When import UIDesktop init the other bitness python +# For this type +# UIDesktop.Utils.ProcessBitness.SettingsInit(inSettingsDict) +# inSettingsDict = { # "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 diff --git a/Sources/pyOpenRPA/Robot/__main__.py b/Sources/pyOpenRPA/Robot/__main__.py index 6ccc71bd..338537e6 100644 --- a/Sources/pyOpenRPA/Robot/__main__.py +++ b/Sources/pyOpenRPA/Robot/__main__.py @@ -19,22 +19,22 @@ buffer = "" lJSONInputString = "" while True: #Reset the lProcessResponse - lProcessResponse={"ErrorFlag":False} + lProcessResponse = {"ErrorFlag": False} try: #Ожидаем синхронно поступление объекта lJSONInput = ProcessCommunicator.ProcessParentReadWaitObject() - lProcessResponse["ActivitySpecificationDict"]=lJSONInput + lProcessResponse["ActivitySpecificationDict"] = lJSONInput #Выполнить вызов функции - lFunction = getattr(UIDesktop,lJSONInput['ActivityName']) - lProcessResponse["Result"]=JSONNormalize.JSONNormalizeDictListStrIntBool(lFunction(*lJSONInput['ArgumentList'],**lJSONInput['ArgumentDict'])) + lFunction = getattr(UIDesktop, lJSONInput['ActivityName']) + lProcessResponse["Result"] = JSONNormalize.JSONNormalizeDictListStrIntBool(lFunction(*lJSONInput['ArgumentList'], **lJSONInput['ArgumentDict'])) except Exception as e: lProcessResponse["Result"] = None #Установить флаг ошибки - lProcessResponse["ErrorFlag"]=True + lProcessResponse["ErrorFlag"] = True #Зафиксировать traceback - lProcessResponse["ErrorTraceback"]=traceback.format_exc() + lProcessResponse["ErrorTraceback"] = traceback.format_exc() #Зафиксировать Error message - lProcessResponse["ErrorMessage"]=str(e) + lProcessResponse["ErrorMessage"] = str(e) #lProcessResponse["ErrorArgs"]=str(e.args) #Отправить ответ в родительский процесс ProcessCommunicator.ProcessParentWriteObject(lProcessResponse) \ No newline at end of file diff --git a/Sources/pyOpenRPA/Studio/ProcessCommunicator.py b/Sources/pyOpenRPA/Studio/ProcessCommunicator.py index 0ae75d72..8b21f252 100644 --- a/Sources/pyOpenRPA/Studio/ProcessCommunicator.py +++ b/Sources/pyOpenRPA/Studio/ProcessCommunicator.py @@ -40,7 +40,6 @@ def ProcessParentWriteString(lString): #Вернуть \f lByteString = lByteString.replace(b'\f',b'{{{f}}}') ############################ - #print(b"Result: "+lByteString) #lByteString= b'x\x9c\xdd\x95]O\xc20\x14\x86\xffJ\xb3[5\xa1Cqz\x07\xc4\xe8\x8d\x1fQ\x13.\x0cYJw\xb6U\xbav\xe9\xce"\x84\xf0\xdfm\'"\xb8\xa0L%Q\xb3\x9b\xf6=\xdfO\x9a\xb3\x99\x17\x97\x8a\xa3\xd0\xea\x8ae\xe0\x9d\x12\xaf[\xa2\xce\x98S\xee\x80\x19\x9e^\xea\xb2\x803\t\x19(\xbc\x10`\x9c6\xf5\xf6\x89\xc7LRt\x8daS\x1b\xf5\xf00\xf3\xd4"\xc1u\x0e\xea\xf6\xa6K\x0e\xc8\xb9\xd6\x89\x04\xd2O\x8d\xb6&\x1bb\x04OC\x84\t~\xe2\x97\x1b\xcd\xa1(B\x11YG\xdaj\xfb\xc1\x9b\xb8\xa2\xa4LE\xd2\xd5\xa4\xf6\xdenY\x85Kf\xc3^;yI\x18\x0eD\x94\x00\x0e\x84{{n}}\xa9K\xce\xb5B\xa3e\x88\xd3\xbc\xf2Z\xd5\xaa\x82\xaa\x94\xd25\x0b\x1c\x99J\xaa\x023OB\xec\xbavEP\xe7\x8b\x93\x11I\xeaTz\xe2\xbb\xebH\xa3eW5\xe8\xb7\xe6\xce^*\x14\xb6\x83e\xda\xf9phe]b^\xe2\xf5\xe8\xd1Vp\xf0\xfe.\xbb\x1b\xa6`\x87\xfc8\x1a\x9bSE0q\xa2\x15\xeer\xe0"\x16\xbcz\x9f\xfdT\xc8h\x9d\xdf\xc7\xd4\xbe\xcdj1\xd9:\xa9\x1f\xe1B7\x81\xa1\xef\xc0\xd0:\x98\xc3-\xc0\xd4X\xfc\xda\xf1i\xbb\xe9\xfc\xdb<\x8c\xff2\x7f\'\xa8\x8d\xdf\xdab\xfc\x9e\xd6\xe3\x8c\x99qQ\xe3\xb0f\xd9\x19\x90{\xade\x8f\x99/3\xa1AC(\xfe\x16P\x06F \x90\xb3\t\x07Iba\x17\x83P\xa4\xbf\xb7G\x9e\x04\xa6vE\x13\xb6\xfc\x13\xd6\xa85\x0b\xdd\x19\xd6^i\x11\xa8FT;G\xfe\x06\xac\xc1q\xb0N\x956\xd84\xae\xe4p\xbe\xfa=\x03\x01\xce\x95\x9a' #lByteString = b"x\x9c\xb5\x91\xcfO\xc3 \x14\xc7\xff\x95\xa6\xd7uI\xf9Q\x8a\xde\xd4\x93\x07\xbdx\xf00\x97\x05)[I(\x90\x8ef3\xcb\xfew\x81M\xbb\xd9M]\x8c!y\xd0\xf7}\xbc\xef\xe3\xd3\xc9&\xd5\xac\x11\xe9u\x92j\xb1J@2N\x1e\x8d\x13\x96U\xa3Q\x9a%i+y=sb\xed\xceV\xd8\xd6p\xb1\\\xced\xe5K{{n}}\x80`\x9f\xeb\x135\xd3\x95{{n}}.\x08RR\xe4>\xc3\x15\xf3\x97>\xbc\x8f:r\xa3]k\xd4\xcc\xbd\xd9(>K]\x99\xd5\xa1\x12\xbd\x00\xc6\xb0\xcc\xcb0\xa4\xe0\x8e\xe9E4\xd8\xa4J\xcc\xc3\xb44\x07^r\xc6\xfa3\x04(\xbeeQ\x07\x05P\x1a\xa4W\xe3\x9ci\xfc\xf7\x15(\xb6A\xee\xb4\x93\x8d\xd85\x9f`?\xf6n\xd8i0v\xadw\xd5\x95X\x87n>\xf1d\x05\x97s\xc9\x99\x93F\xdf\xd5R\xc5K=\xcc\x1bk\xd5^\x1d`\xfc\xa2]\x06PwJ\r\xf0\x9d\xa2\xf6 tw\xcb\xda\x01\xb6}\x83\xd3\xcc\x00\xec\x99\x15\xf4\x88Y\x99\x1f2\x83\xb4\xfc\x8e\x99\xdf\xb3d\x0c\x01.1E\x04\x93l\xff\x8e\xcf\x7f6\xa4Z\xfc\x82\xeaK\x97c BD\xf3\x101\x89g\xba\x8b\x03\xd0?\x97\xff#\xfb{'\x9a\x8b\xe0\x03H\xc89\xfa\x08\x15\x7f\xa2\x0f >\x80_\x0e\xe0\x93\xb3\xf0\xc3\xc4\xd3m\\\xef\xf8\x958\xa0" #lt=open("logSendByteStringWithoutN.log","wb") @@ -70,7 +69,6 @@ def ProcessChildSendString(lProcess,lString): lByteString = lByteString.replace(b'\n',b'{{n}}') #Отправить сообщение в дочерний процесс lProcess.stdin.write(lByteString+bytes('\n',"utf-8")) - #print(str(lByteString+bytes('\n',"utf-8"))) lProcess.stdin.flush() #Вернуть результат return @@ -80,7 +78,6 @@ def ProcessChildReadWaitString(lProcess): #Ожидаем ответ от процесса lResult = lProcess.stdout.readline() #Обработка спец символов - #print(b'NewLine: '+lResult) #Вернуть потенциальные \n lResult = lResult.replace(b'{{{n}}}',b'\n') #Вернуть \r @@ -97,8 +94,6 @@ def ProcessChildReadWaitString(lProcess): lResult = lResult.replace(b'{{{v}}}',b'\v') #Вернуть \f lResult = lResult.replace(b'{{{f}}}',b'\f') - #print("check") - #print(str(lResult)) lResult = zlib.decompress(lResult[0:-1]) lResult = lResult.decode("utf-8") #Вернуть результат diff --git a/Sources/pyOpenRPA/Studio/RobotConnector.py b/Sources/pyOpenRPA/Studio/RobotConnector.py new file mode 100644 index 00000000..f4cdf6c2 --- /dev/null +++ b/Sources/pyOpenRPA/Studio/RobotConnector.py @@ -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: , +# ArgumentList: [, ...] - optional, +# ArgumentDict: {:, ...} - optional +#} + +#outActivityResultDict: +#{ +# ActivitySpecificationDict: { +# ModuleName: <"GUI"|..., str>, +# ActivityName: , +# ArgumentList: [, ...] - optional, +# ArgumentDict: {: , ...} - optional +# }, +# ErrorFlag: , +# ErrorMessage: - required if ErrorFlag is true, +# ErrorTraceback: - required if ErrorFlag is true, +# Result: - 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 \ No newline at end of file diff --git a/Sources/pyOpenRPA/Studio/Studio.py b/Sources/pyOpenRPA/Studio/Studio.py index 57441e34..d6857031 100644 --- a/Sources/pyOpenRPA/Studio/Studio.py +++ b/Sources/pyOpenRPA/Studio/Studio.py @@ -5,12 +5,30 @@ import json import subprocess import zlib import os -from . import ProcessCommunicator import sys import traceback -from pyOpenRPA.Robot import Robot +from . import RobotConnector +import importlib +#Единый глобальный словарь (За основу взять из Settings.py) +global mGlobalDict +#Call Settings function from argv[1] file +################################################ +lSubmoduleFunctionName = "Settings" +lFileFullPath = sys.argv[1] +lModuleName = (lFileFullPath.split("\\")[-1])[0:-3] +lTechSpecification = importlib.util.spec_from_file_location(lModuleName, lFileFullPath) +lTechModuleFromSpec = importlib.util.module_from_spec(lTechSpecification) +lTechSpecificationModuleLoader = lTechSpecification.loader.exec_module(lTechModuleFromSpec) +mGlobalDict = None +if lSubmoduleFunctionName in dir(lTechModuleFromSpec): + # Run SettingUpdate function in submodule + mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)() +################################################# +RobotConnector.mGlobalDict = mGlobalDict +#Init the robot +RobotConnector.UIDesktop.Utils.ProcessBitness.SettingsInit(mGlobalDict["ProcessBitness"]) -# HTTPRequestHandler class +# HTTP Studio web server class class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): #ResponseContentTypeFile def SendResponseContentTypeFile(self,inContentType,inFilePath): @@ -82,7 +100,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): #pdb.set_trace() lRequestObject=lInputObject #Отправить команду роботу - lResponseObject=Robot.ActivityRun(lRequestObject) + lResponseObject=RobotConnector.ActivityRun(lRequestObject) message = json.dumps(lResponseObject) except Exception as e: #Установить флаг ошибки @@ -113,7 +131,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): lRequestObject=lInputObject lOutputObject=[] #pdb.set_trace() - lResponseObject=Robot.ActivityListRun(lRequestObject) + lResponseObject=RobotConnector.ActivityListRun(lRequestObject) #Сформировать текстовый ответ message = json.dumps(lResponseObject) # Write content as utf-8 data @@ -121,14 +139,15 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): return def run(): - print('starting server...') - # Server settings - # Choose port 8080, for port 80, which is normally used for a http server, you need root access - server_address = ('127.0.0.1', 8081) - httpd = HTTPServer(server_address, testHTTPServer_RequestHandler) - print('running server...') - #Запуск адреса в браузере - os.system("explorer http://127.0.0.1:8081") - httpd.serve_forever() -#print(ChildProcessReadWaitString(p)) + inServerAddress = ""; + inPort = mGlobalDict["Server"]["ListenPort"]; + # Server settings + # Choose port 8080, for port 80, which is normally used for a http server, you need root access + server_address = (inServerAddress, inPort) + httpd = HTTPServer(server_address, testHTTPServer_RequestHandler) + # Logging + mGlobalDict["Logger"].info(f"Server init. Listen URL: {inServerAddress}, Listen port: {inPort}") + # Запуск адреса в браузере + os.system("explorer http://127.0.0.1:8081") + httpd.serve_forever() run() diff --git a/Studio/Settings.py b/Studio/Settings.py new file mode 100644 index 00000000..e5fa6c06 --- /dev/null +++ b/Studio/Settings.py @@ -0,0 +1,48 @@ +import psutil +import datetime +import logging + +#Studio settings +def Settings(): + import os + mDict = { + "Server": { + "ListenPort_": "Порт, по которому можно подключиться к демону", + "ListenPort": 8081, + "ListenURLList": [ + { + "Description": "Local machine test", + "URL_": "Сетевое расположение сервера демона", + "URL": "http://127.0.0.1:8081" + } + ], + }, + "Logger": logging.getLogger("Studio"), + "Storage": { + "Robot_R01_help": "Robot data storage in orchestrator env", + "Robot_R01": {} + }, + "ProcessBitness": { #Section for robot init + "Python32FullPath": "..\\Resources\\WPy32-3720\\python-3.7.2\\python.exe", #Set from user: "..\\Resources\\WPy32-3720\\python-3.7.2\\OpenRPARobotGUIx32.exe" + "Python64FullPath": "..\\Resources\\WPy64-3720\\python-3.7.2.amd64\\python.exe", #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\ReportStudio_"+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) + ############################################ + return mDict \ No newline at end of file diff --git a/Studio/pyOpenRPA.Studio_x64.cmd b/Studio/pyOpenRPA.Studio_x64.cmd index 0f8b7c00..3216e1e7 100644 --- a/Studio/pyOpenRPA.Studio_x64.cmd +++ b/Studio/pyOpenRPA.Studio_x64.cmd @@ -1,4 +1,4 @@ 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 -.\..\Resources\WPy64-3720\python-3.7.2.amd64\OpenRPA_Studio.exe -m pyOpenRPA.Studio +.\..\Resources\WPy64-3720\python-3.7.2.amd64\OpenRPA_Studio.exe -m pyOpenRPA.Studio "..\Studio\Settings.py" pause >nul \ No newline at end of file