From bde44722e9c62efde71c7243bff9ecffe8455f14 Mon Sep 17 00:00:00 2001 From: Ivan Maslov Date: Tue, 1 Dec 2020 20:58:53 +0300 Subject: [PATCH] # Add new Handler for the log dump - need to refactoring...!!!! --- .../Orchestrator/BackwardCompatibility.py | 10 +++- Sources/pyOpenRPA/Orchestrator/HandlerList.py | 14 +++++ .../pyOpenRPA/Orchestrator/Orchestrator.py | 10 ++++ .../pyOpenRPA/Orchestrator/ServerSettings.py | 34 +++++++++++- .../Orchestrator/SettingsTemplate.py | 11 +++- Sources/pyOpenRPA/Orchestrator/Web/Index.js | 52 ++++++++++++++++++- .../pyOpenRPA/Orchestrator/Web/Index.xhtml | 2 +- changelog.md | 2 + 8 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 Sources/pyOpenRPA/Orchestrator/HandlerList.py diff --git a/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py b/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py index a648db73..53766d8a 100644 --- a/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py +++ b/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py @@ -348,4 +348,12 @@ def Update(inGSettings): if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Create new structure 'ProcessorDict'") # Log about compatibility if "VersionStr" not in inGSettings: # Create new ProcessorDict structure inGSettings["VersionStr"] = None - if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Create new attribute 'VersionStr'") # Log about compatibility \ No newline at end of file + if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Create new attribute 'VersionStr'") # Log about compatibility + if "DumpLogListRefreshIntervalSecFloat" not in inGSettings["Client"]: # Create new ProcessorDict structure + inGSettings["Client"].update({ + "DumpLogListRefreshIntervalSecFloat": 5.0, # Duration between updates for the Client + "DumpLogListCountInt": 100, # Set the max row for the dump + "DumpLogList": [], # Will be filled automatically + "DumpLogListHashStr": None, # Will be filled automatically + }) + if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Create new attribute 'Client > DumpLog... with default parameters'") # Log about compatibility \ No newline at end of file diff --git a/Sources/pyOpenRPA/Orchestrator/HandlerList.py b/Sources/pyOpenRPA/Orchestrator/HandlerList.py new file mode 100644 index 00000000..72d00b3b --- /dev/null +++ b/Sources/pyOpenRPA/Orchestrator/HandlerList.py @@ -0,0 +1,14 @@ +from logging import StreamHandler + +class HandlerDumpLog(StreamHandler): + def __init__(self, inDict, inKeyStr, inHashKeyStr, inRowCountInt): + StreamHandler.__init__(self) + self.Dict = inDict + self.KeyStr = inKeyStr + self.HashKeyStr = inHashKeyStr + self.RowCountInt = inRowCountInt + self.Dict[self.HashKeyStr]="0" + def emit(self, inRecord): + inMessageStr = self.format(inRecord) + self.Dict[self.KeyStr].append(inMessageStr) + self.Dict[self.HashKeyStr]=str(int(self.Dict[self.HashKeyStr])+1) \ No newline at end of file diff --git a/Sources/pyOpenRPA/Orchestrator/Orchestrator.py b/Sources/pyOpenRPA/Orchestrator/Orchestrator.py index 660aa001..eb55d67b 100644 --- a/Sources/pyOpenRPA/Orchestrator/Orchestrator.py +++ b/Sources/pyOpenRPA/Orchestrator/Orchestrator.py @@ -540,8 +540,18 @@ def GSettingsAutocleaner(inGSettings): # # # # # # # # # # # # # # # # # # # # # # # # # # from .. import __version__ # Get version from the package +import logging # Main def for orchestrator def Orchestrator(inGSettings): + + # TEst + from . import HandlerList + mHandlerDumpLogList = HandlerList.HandlerDumpLog( inDict=inGSettings["Client"],inKeyStr="DumpLogList", inHashKeyStr="DumpLogListHashStr",inRowCountInt=100) + mRobotLoggerFormatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') + mHandlerDumpLogList.setFormatter(mRobotLoggerFormatter) + lL = inGSettings["Logger"] + lL.addHandler(mHandlerDumpLogList) + #mGlobalDict = Settings.Settings(sys.argv[1]) gSettingsDict = inGSettings # Alias for old name in alg inGSettings["VersionStr"] = __version__ diff --git a/Sources/pyOpenRPA/Orchestrator/ServerSettings.py b/Sources/pyOpenRPA/Orchestrator/ServerSettings.py index 37929b88..bd367326 100644 --- a/Sources/pyOpenRPA/Orchestrator/ServerSettings.py +++ b/Sources/pyOpenRPA/Orchestrator/ServerSettings.py @@ -95,7 +95,7 @@ def pyOpenRPA_ServerData(inRequest,inGSettings): lServerDataDictJSONStr = json.dumps(lServerDataDict) # Generate hash lServerDataHashStr = str(hash(lServerDataDictJSONStr)) - if lValueStr!=lServerDataHashStr: # Case if Hash is not equal + if lValueStr!=lServerDataHashStr and lServerDataHashStr!= "" and lServerDataHashStr!= None: # Case if Hash is not equal lFlagDoGenerateBool = False else: # Case Hashes are equal time.sleep(inGSettings["Client"]["Session"]["ControlPanelRefreshIntervalSecFloat"]) @@ -108,7 +108,36 @@ def pyOpenRPA_ServerData(inRequest,inGSettings): inResponseDict["Body"] = bytes(message, "utf8") return lResult - +#v1.2.0 Send data container to the client from the server +# /pyOpenRPA/ServerLog return {"HashStr" , "ServerLogList": ["row 1", "row 2"]} +# Client: mGlobal.pyOpenRPA.ServerLogListHashStr +# Client: mGlobal.pyOpenRPA.ServerLogList +def pyOpenRPA_ServerLog(inRequest,inGSDict): + # Extract the hash value from request + lValueStr = None + if inRequest.headers.get('Content-Length') is not None: + lInputByteArrayLength = int(inRequest.headers.get('Content-Length')) + lInputByteArray = inRequest.rfile.read(lInputByteArrayLength) + # Превращение массива байт в объект + lValueStr = (lInputByteArray.decode('utf8')) + # Generate ServerDataDict + lFlagDoGenerateBool = True + while lFlagDoGenerateBool: + lServerLogList = inGSDict["Client"]["DumpLogList"] + # Get hash + lServerLogListHashStr = inGSDict["Client"]["DumpLogListHashStr"] + if lValueStr!=lServerLogListHashStr and lServerLogListHashStr!= "" and lServerLogListHashStr!= None: # Case if Hash is not equal Fix because None can be obtained without JSON decode + lFlagDoGenerateBool = False + else: # Case Hashes are equal + time.sleep(inGSDict["Client"]["DumpLogListRefreshIntervalSecFloat"]) + # Return the result if Hash is changed + lResult = {"HashStr": lServerLogListHashStr, "ServerLogList": lServerLogList} + inResponseDict = inRequest.OpenRPAResponseDict + # Send message back to client + message = json.dumps(lResult) + # Write content as utf-8 data + inResponseDict["Body"] = bytes(message, "utf8") + return lResult def pyOpenRPA_Screenshot(inRequest,inGlobalDict): @@ -159,6 +188,7 @@ def SettingsUpdate(inGlobalConfiguration): {"Method": "POST", "URL": "/Orchestrator/UserRoleHierarchyGet", "MatchType": "Equal","ResponseDefRequestGlobal": BackwardCompatibility.v1_2_0_UserRoleHierarchyGet, "ResponseContentType": "application/json"}, # New way of the v.1.2.0 functionallity (all defs by the URL from /pyOpenRPA/...) {"Method": "POST", "URL": "/pyOpenRPA/ServerData", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_ServerData, "ResponseContentType": "application/json"}, + {"Method": "POST", "URL": "/pyOpenRPA/ServerLog", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_ServerLog, "ResponseContentType": "application/json"}, {"Method": "GET", "URL": "/pyOpenRPA/Screenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": pyOpenRPA_Screenshot, "ResponseContentType": "image/png"}, ] inGlobalConfiguration["Server"]["URLList"]=inGlobalConfiguration["Server"]["URLList"]+lURLList diff --git a/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py b/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py index 85f501d7..d15fc481 100644 --- a/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py +++ b/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py @@ -28,8 +28,14 @@ def __Create__(): # "UserADStr": None, # User, who connect. None if user is not exists # "DomainADStr": None, # Domain of the user who connect. None if user is not exists # } - } - } + }, + }, + # # # # # # Client... # # # # # # # # + "DumpLogListRefreshIntervalSecFloat": 5.0, # Duration between updates for the Client + "DumpLogListCountInt": 100, # Set the max row for the dump + "DumpLogList": [], # Will be filled automatically + "DumpLogListHashStr": None, # Will be filled automatically + # # # # # # # # # # # # # # # # # # }, "Server": { "WorkingDirectoryPathStr": None, # Will be filled automatically @@ -287,6 +293,7 @@ def __Create__(): # inModeStr: # "BASIC" - create standart configuration + def Create(inModeStr="BASIC"): if inModeStr=="BASIC": lResult = __Create__() # Create settings diff --git a/Sources/pyOpenRPA/Orchestrator/Web/Index.js b/Sources/pyOpenRPA/Orchestrator/Web/Index.js index 1e81769a..838eca83 100644 --- a/Sources/pyOpenRPA/Orchestrator/Web/Index.js +++ b/Sources/pyOpenRPA/Orchestrator/Web/Index.js @@ -350,7 +350,6 @@ $(document).ready(function() { } /// v1.2.0 pyOpenRPA ServerData - mGlobal.pyOpenRPA.ServerDataDict = null mGlobal.pyOpenRPA.ServerDataHashStr = "" mGlobal.pyOpenRPA.ServerDataRefreshDef_TechnicalRender = function() @@ -401,8 +400,56 @@ $(document).ready(function() { mGlobal.pyOpenRPA.ServerDataRefreshDef() // recursive } } - ///////////////////////////////////////////////////////////// + /// v1.2.0 pyOpenRPA ServerLogs + mGlobal.pyOpenRPA.ServerLogList = null + mGlobal.pyOpenRPA.ServerLogListHashStr = "" + mGlobal.pyOpenRPA.ServerLogListScrollBottomDef = function() { + var lTA = $("textarea.mGlobal-pyOpenRPA-ServerLogList")[0]; + lTA.scrollTop = lTA.scrollHeight; + } + mGlobal.pyOpenRPA.ServerLogListRefreshDef_TechnicalRender = function() + { + lResponseJSON = mGlobal.pyOpenRPA.ServerLogList + if (lResponseJSON!= null) { + lText = lResponseJSON.join("\n") /// Code for the processing the text + $("textarea.mGlobal-pyOpenRPA-ServerLogList")[0].value= lText ///Прогрузить новую таблицу + mGlobal.pyOpenRPA.ServerLogListScrollBottomDef() //Scroll to the bottom + } + } + mGlobal.pyOpenRPA.ServerLogListRefreshDef=function() { + try { + $.ajax({ + type: "POST", + headers: {}, + url: 'pyOpenRPA/ServerLog', + data: mGlobal.pyOpenRPA.ServerLogListHashStr, + success: function(lData,l2,l3) { + try { + var lResponseJSON=JSON.parse(lData) + mGlobal.pyOpenRPA.ServerLogList = lResponseJSON["ServerLogList"] + mGlobal.pyOpenRPA.ServerLogListHashStr = lResponseJSON["HashStr"] + mGlobal.pyOpenRPA.ServerLogListRefreshDef_TechnicalRender() + } + catch(error) { + } + mGlobal.pyOpenRPA.ServerLogListRefreshDef() // recursive + }, + dataType: "text", + error: function(jqXHR, textStatus, errorThrown ) { + sleep(3000) + mGlobal.pyOpenRPA.ServerLogListRefreshDef() // recursive + } + }); + } + catch(error) { + sleep(3000) + mGlobal.pyOpenRPA.ServerLogListRefreshDef() // recursive + } + } + ///////////////////////////////////////////////////////////// + + mGlobal.Monitor.mDatasetLast = null mGlobal.fControlPanelRefresh=function() { @@ -786,5 +833,6 @@ $(document).ready(function() { /// v1.2.0 pyOpenRPA Init defs mGlobal.pyOpenRPA.ServerDataRefreshDef() // Init the refresh data def from server side + mGlobal.pyOpenRPA.ServerLogListRefreshDef() // Init the refresh data def from the log window }); \ No newline at end of file diff --git a/Sources/pyOpenRPA/Orchestrator/Web/Index.xhtml b/Sources/pyOpenRPA/Orchestrator/Web/Index.xhtml index 7d948b0d..e63e8c61 100644 --- a/Sources/pyOpenRPA/Orchestrator/Web/Index.xhtml +++ b/Sources/pyOpenRPA/Orchestrator/Web/Index.xhtml @@ -279,7 +279,7 @@ Logs -