From 2f40c81a723f2dbb1cc91620f3c6e84410b09480 Mon Sep 17 00:00:00 2001 From: Ivan Maslov Date: Sun, 6 Dec 2020 13:58:46 +0300 Subject: [PATCH] - Agent: Add Agent defs as Alias in ProcessorDict - Agent Add 2 defs: - - def OSFileBytesCreate(inFilePathStr, inFileBytes,inGSettings = None): # Send CMD to OS. Result return to log + Orchestrator by the A2O connection - - def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None): # Send CMD to OS. Result return to log + Orchestrator by the A2O connection - Orc: Add Agent Defs - - def AgentActivityItemAdd(inGSettings, inHostNameStr, inUserStr, inActivityItemDict): # Add activity in AgentDict - - def AgentOSCMD(inGSettings, inHostNameStr, inUserStr, inCMDStr): # Send to agent activity item to OSCMD - - def AgentOSFileBytesCreate(inGSettings, inHostNameStr, inUserStr, inFilePathStr, inFileBytes): # Send to agent activity item to OSCMD - Orc WEB: Create mGlobal.pyOpenRPA.ActivityListExecute({}) to test some activities from the front --- Sources/pyOpenRPA/Agent/Agent.py | 65 ++++++++++++++++++- .../pyOpenRPA/Orchestrator/Orchestrator.py | 44 +++++++++++++ .../pyOpenRPA/Orchestrator/ServerSettings.py | 6 +- .../Orchestrator/SettingsTemplate.py | 2 +- Sources/pyOpenRPA/Orchestrator/Web/Index.js | 29 +++++++++ changelog.md | 9 +++ 6 files changed, 150 insertions(+), 5 deletions(-) diff --git a/Sources/pyOpenRPA/Agent/Agent.py b/Sources/pyOpenRPA/Agent/Agent.py index 80b055f8..65674e67 100644 --- a/Sources/pyOpenRPA/Agent/Agent.py +++ b/Sources/pyOpenRPA/Agent/Agent.py @@ -1,9 +1,72 @@ -import threading, socket, getpass +import threading, socket, getpass, sys, uuid, subprocess from . import O2A, A2O # Data flow Orchestrator To Agent from . import Processor # Processor Queue + +# Send CMD to OS. Result return to log + Orchestrator by the A2O connection +def OSFileBytesCreate(inFilePathStr, inFileBytes,inGSettings = None): + lFile = open(inFilePathStr, "wb") + lFile.write(inFileBytes) + lL = inGSettings.get("Logger", None) if type(inGSettings) is dict else None + lMessageStr = f"File {inFilePathStr} has been created." + if lL: lL.info(lMessageStr) + A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr]) + +# Send CMD to OS. Result return to log + Orchestrator by the A2O connection +def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None): + lResultStr = "" + # Subdef to listen OS result + def _CMDRunAndListenLogs(inCMDStr, inGSettings = None): + lL = inGSettings.get("Logger",None) if type(inGSettings) is dict else None + lResultStr = "" + lOSCMDKeyStr = str(uuid.uuid4())[0:4].upper() + lCMDProcess = subprocess.Popen(f'cmd /c {inCMDStr}', stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + lListenBool = True + lMessageStr = f"{lOSCMDKeyStr}: # # # # CMD Process has been STARTED # # # # " + if lL: lL.info(lMessageStr) + A2O.LogListSend(inGSettings=inGSettings,inLogList=[lMessageStr]) + lMessageStr = f"{lOSCMDKeyStr}: {inCMDStr}" + if lL: lL.info(lMessageStr) + A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr]) + while lListenBool: + lOutputLineBytes = lCMDProcess.stdout.readline() + if lOutputLineBytes == b"": + lListenBool = False + lStr = lOutputLineBytes.decode('cp866') + if lStr.endswith("\n"): lStr = lStr[:-1] + lMessageStr = f"{lOSCMDKeyStr}: {lStr}" + if lL: lL.info(lMessageStr) + A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr]) + lResultStr+=lStr + lMessageStr = f"{lOSCMDKeyStr}: # # # # CMD Process has been FINISHED # # # # " + if lL: lL.info(lMessageStr) + A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr]) + return lResultStr + # New call + if inRunAsyncBool: + lThread = threading.Thread(target=_CMDRunAndListenLogs, kwargs={"inCMDStr":inCMDStr, "inGSettings":inGSettings}) + lThread.start() + lResultStr="ActivityList has been started in async mode - no output is available here." + else: + lResultStr = _CMDRunAndListenLogs(inCMDStr=inCMDStr, inGSettings=inGSettings) + #lCMDCode = "cmd /c " + inCMDStr + #subprocess.Popen(lCMDCode) + #lResultCMDRun = 1 # os.system(lCMDCode) + return lResultStr + + # Main def def Agent(inGSettings): lL = inGSettings["Logger"] + + # Append Orchestrator def to ProcessorDictAlias + lModule = sys.modules[__name__] + lModuleDefList = dir(lModule) + for lItemDefNameStr in lModuleDefList: + # Dont append alias for defs Agent + if lItemDefNameStr not in ["Agent"]: + lItemDef = getattr(lModule,lItemDefNameStr) + if callable(lItemDef): inGSettings["ProcessorDict"]["AliasDefDict"][lItemDefNameStr]=lItemDef + # Detect Machine host name and username inGSettings["AgentDict"]["HostNameUpperStr"] = socket.gethostname().upper() inGSettings["AgentDict"]["UserUpperStr"] = getpass.getuser().upper() diff --git a/Sources/pyOpenRPA/Orchestrator/Orchestrator.py b/Sources/pyOpenRPA/Orchestrator/Orchestrator.py index ba23cce1..7d779fc4 100644 --- a/Sources/pyOpenRPA/Orchestrator/Orchestrator.py +++ b/Sources/pyOpenRPA/Orchestrator/Orchestrator.py @@ -17,12 +17,56 @@ from importlib import util import threading # Multi-threading for RobotRDPActive from .RobotRDPActive import RobotRDPActive #Start robot rdp active from .RobotScreenActive import Monitor #Start robot screen active +from . import SettingsTemplate # Settings template import uuid # Generate uuid import datetime # datetime #Единый глобальный словарь (За основу взять из Settings.py) global gSettingsDict +# AGENT DEFS + +# Add activity in AgentDict +def AgentActivityItemAdd(inGSettings, inHostNameStr, inUserStr, inActivityItemDict): + # Check if item is created + lAgentDictItemKeyTurple = (inHostNameStr.upper(),inUserStr.upper()) + if lAgentDictItemKeyTurple not in inGSettings["AgentDict"]: + inGSettings["AgentDict"][lAgentDictItemKeyTurple] = SettingsTemplate.__AgentDictItemCreate__() + lThisAgentDict = inGSettings["AgentDict"][lAgentDictItemKeyTurple] + lThisAgentDict["ActivityList"]+=inActivityItemDict + +# Send to agent activity item to OSCMD +def AgentOSCMD(inGSettings, inHostNameStr, inUserStr, inCMDStr): + # pyOpenRPA.Agent: Send CMD to OS. Result return to log + Orchestrator by the A2O connection + # def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings=None): + # Create Activity Item for the agent + lActivityItemDict = { + "Def":"OSCMD", # def alias (look pyOpeRPA.Agent gSettings["ProcessorDict"]["AliasDefDict"]) + "ArgList":[], # Args list + "ArgDict":{"inCMDStr":inCMDStr,"inRunAsyncBool":False}, # Args dictionary + "ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList) + "ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList) + } + #Send item in AgentDict for the futher data transmition + AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict) + +# Send to agent activity item to OSCMD +def AgentOSFileBytesCreate(inGSettings, inHostNameStr, inUserStr, inFilePathStr, inFileBytes): + # pyOpenRPA.Agent: Send CMD to OS. Result return to log + Orchestrator by the A2O connection + # def OSFileBytesCreate(inFilePathStr, inFileBytes,inGSettings = None): + # Create Activity Item for the agent + lActivityItemDict = { + "Def":"OSFileBytesCreate", # def alias (look pyOpeRPA.Agent gSettings["ProcessorDict"]["AliasDefDict"]) + "ArgList":[], # Args list + "ArgDict":{"inFilePathStr":inFilePathStr,"inFileBytes":inFileBytes}, # Args dictionary + "ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList) + "ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList) + } + #Send item in AgentDict for the futher data transmition + AgentActivityItemAdd(inGSettings=inGSettings, inHostNameStr=inHostNameStr, inUserStr=inUserStr, inActivityItemDict=lActivityItemDict) + + +# OS DEFS # Defs to use in orchestrator def OSCredentialsVerify(inUserStr, inPasswordStr, inDomainStr=""): ## Verify credentials in windows try: diff --git a/Sources/pyOpenRPA/Orchestrator/ServerSettings.py b/Sources/pyOpenRPA/Orchestrator/ServerSettings.py index fb264431..8db82e6b 100644 --- a/Sources/pyOpenRPA/Orchestrator/ServerSettings.py +++ b/Sources/pyOpenRPA/Orchestrator/ServerSettings.py @@ -238,14 +238,14 @@ def pyOpenRPA_Agent_O2A(inRequest, inGSettings): lDoLoopBool = False else: # Lifetime is good - do alg lThisAgentDict["IsListenBool"] = True # Set is online - lQueueList = lThisAgentDict["QueueList"] + lQueueList = lThisAgentDict["ActivityList"] if len(lQueueList)>0:# Do some operations if has queue items if lThisAgentDict["ConnectionCountInt"] == lThisAgentDict["ConnectionFirstQueueItemCountInt"] - 1: # POP QUEUE ITEM CONDITION ConnectionCountInt == ConnectionFirstQueueItemCountInt - 1 - lQueueItem = lThisAgentDict["QueueList"].pop(0) + lQueueItem = lThisAgentDict["ActivityList"].pop(0) lThisAgentDict["ConnectionFirstQueueItemCountInt"] = 0 else: - lQueueItem = lThisAgentDict["QueueList"][0] + lQueueItem = lThisAgentDict["ActivityList"][0] lThisAgentDict["ConnectionFirstQueueItemCountInt"] += 1 # Send QUEUE ITEM inRequest.OpenRPAResponseDict["Body"] = bytes(json.dumps(lQueueItem), "utf8") diff --git a/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py b/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py index d04b7b4c..ea85db9b 100644 --- a/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py +++ b/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py @@ -296,7 +296,7 @@ def __Create__(): # Create full configuration for def __AgentDictItemCreate__(): - return {"IsListenBool":False, "ConnectionCountInt":0, "ConnectionFirstQueueItemCountInt":0, "QueueList":[]} + return {"IsListenBool":False, "ConnectionCountInt":0, "ConnectionFirstQueueItemCountInt":0, "ActivityList":[]} # Create full configuration for def __UACClientAdminCreate__(): lResultDict = { diff --git a/Sources/pyOpenRPA/Orchestrator/Web/Index.js b/Sources/pyOpenRPA/Orchestrator/Web/Index.js index 3a3f22fc..a74b359e 100644 --- a/Sources/pyOpenRPA/Orchestrator/Web/Index.js +++ b/Sources/pyOpenRPA/Orchestrator/Web/Index.js @@ -364,6 +364,35 @@ $(document).ready(function() { } } + ///v 1.2.0 pyOpenRPA + + /// Execute ActivityItem + mGlobal.pyOpenRPA.ActivityItemExecute=function(inActivityItem) { + ///EXAMPLE + // { + // "Def":"OSCMD", // def link or def alias (look gSettings["Processor"]["AliasDefDict"]) + // "ArgList":[], // Args list + // "ArgDict":{"inCMDStr":lCMDCode,"inRunAsyncBool":false}, // Args dictionary + // "ArgGSettings": null, // Name of GSettings attribute: str (ArgDict) or index (for ArgList) + // "ArgLogger": "inLogger" // Name of GSettings attribute: str (ArgDict) or index (for ArgList) + // } + ///Подготовить конфигурацию + lData = [inActivityItem] + $.ajax({ + type: "POST", + url: '/pyOpenRPA/ActivityListExecute', + data: JSON.stringify(lData), + success: + function(lData,l2,l3) + { + var lResponseJSON=JSON.parse(lData) + console.log(lResponseJSON) + }, + dataType: "text" + }); + } + + /// v1.2.0 pyOpenRPA ServerData mGlobal.pyOpenRPA.ServerDataDict = null mGlobal.pyOpenRPA.ServerDataHashStr = "" diff --git a/changelog.md b/changelog.md index b9933660..14554134 100644 --- a/changelog.md +++ b/changelog.md @@ -58,6 +58,15 @@ - Orch: Add handler to set connection when Agent listen orch (/pyOpenRPA/Agent/O2A) - Orch start processor Dict in own thread (Processor.ProcessorRunSync(inGSettings)) - Agent: Create Processor in Agent similarly to Orchestrator (pyOpenRPA.Agent.Processor == pyOpenRPA.Orchestrator.Processor) +- Agent: Add Agent defs as Alias in ProcessorDict +- Agent Add 2 defs: +- - def OSFileBytesCreate(inFilePathStr, inFileBytes,inGSettings = None): # Send CMD to OS. Result return to log + Orchestrator by the A2O connection +- - def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None): # Send CMD to OS. Result return to log + Orchestrator by the A2O connection +- Orc: Add Agent Defs +- - def AgentActivityItemAdd(inGSettings, inHostNameStr, inUserStr, inActivityItemDict): # Add activity in AgentDict +- - def AgentOSCMD(inGSettings, inHostNameStr, inUserStr, inCMDStr): # Send to agent activity item to OSCMD +- - def AgentOSFileBytesCreate(inGSettings, inHostNameStr, inUserStr, inFilePathStr, inFileBytes): # Send to agent activity item to OSCMD +- Orc WEB: Create mGlobal.pyOpenRPA.ActivityListExecute({}) to test some activities from the front [1.1.0] After 2 month test prefinal with new improovements (+RobotRDPActive in Orchestrator + Easy ControlPanelTemplate) Beta before 1.1.0 (new way of OpenRPA with improvements. Sorry, but no backward compatibility)/ Backward compatibility will start from 1.0.1