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 00000000..4053ac88 Binary files /dev/null and b/Resources/WPy32-3720/python-3.7.2/OpenRPAUIDesktopX32.exe differ 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