# Test + Add web button + add model in front + Backward compatibility from v1.1.13 + try..except when load CP

dev-linux
Ivan Maslov 4 years ago
parent 5333209528
commit e2c1d3e575

@ -79,12 +79,12 @@ def Settings():
lOrchestratorFolder = "\\".join(pyOpenRPA.Orchestrator.__file__.split("\\")[:-1])
mDict = {
"Autocleaner": { # Some gurbage is collecting in g settings. So you can configure autocleaner to periodically clear gSettings
"IntervalSecFloat": 10, # Sec float to periodically clear gsettings
"IntervalSecFloat": 600.0, # Sec float to periodically clear gsettings
},
"Client":{ # Settings about client web orchestrator
"Session":{ # Settings about web session. Session algorythms works only for special requests (URL in ServerSettings)
"LifetimeSecFloat": 10.0, # Client Session lifetime in seconds. after this time server will forget about this client session
"LifetimeRequestSecFloat": 15.0, # 1 client request lifetime in server in seconds
"LifetimeSecFloat": 600.0, # Client Session lifetime in seconds. after this time server will forget about this client session
"LifetimeRequestSecFloat": 120.0, # 1 client request lifetime in server in seconds
"ControlPanelRefreshIntervalSecFloat": 1.5, # Interval to refresh control panels for session,
"TechnicalSessionGUIDCache": { # TEchnical cache. Fills when web browser is requesting
#"SessionGUIDStr":{ # Session with some GUID str. On client session guid stored in cookie "SessionGUIDStr"
@ -103,6 +103,8 @@ def Settings():
}
},
"Server": {
"WorkingDirectoryPathStr": None , # Will be filled automatically
"RequestTimeoutSecFloat": 300, # Time to handle request in seconds
"ListenPort_": "Порт, по которому можно подключиться к демону",
"ListenPort": 80,
"ListenURLList": [
@ -363,6 +365,7 @@ def Settings():
lFileList = [f for f in os.listdir(lSettingsPath) if os.path.isfile(os.path.join(lSettingsPath, f)) and f.split(".")[-1] == "py" and os.path.join(lSettingsPath, f) != __file__]
import importlib.util
for lModuleFilePathItem in lFileList + gControlPanelPyFilePathList: # UPD 2020 04 27 Add gControlPanelPyFilePathList to import py files from Robots
try: # Try to init - go next if error and log in logger
lModuleName = lModuleFilePathItem[0:-3]
lFileFullPath = os.path.join(lSettingsPath, lModuleFilePathItem)
lTechSpecification = importlib.util.spec_from_file_location(lModuleName, lFileFullPath)
@ -371,4 +374,6 @@ def Settings():
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
#Run SettingUpdate function in submodule
getattr(lTechModuleFromSpec, lSubmoduleFunctionName)(mDict)
except Exception as e:
if mRobotLogger: mRobotLogger.exception(f"Error when init .py file in orchestrator '{lModuleFilePathItem}'. Exception is below:")
return mDict

@ -0,0 +1,41 @@
# Def to check inGSettings and update structure to the backward compatibility
# !!! ATTENTION: Backward compatibility has been started from v1.1.13 !!!
# So you can use config of the orchestrator 1.1.13 in new Orchestrator versions and all will be ok :) (hope it's true)
def Update(inGSettings):
lL = inGSettings["Logger"] # Alias for logger
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# v1.1.13 to v1.1.14
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
if "Autocleaner" not in inGSettings: # Add "Autocleaner" structure
inGSettings["Autocleaner"] = { # Some gurbage is collecting in g settings. So you can configure autocleaner to periodically clear gSettings
"IntervalSecFloat": 600.0, # Sec float to periodically clear gsettings
}
if lL: lL.warning(f"Backward compatibility (v1.1.13 to v1.1.14): Add default 'Autocleaner' structure") # Log about compatibility
if "Client" not in inGSettings: # Add "Client" structure
inGSettings["Client"] = { # Settings about client web orchestrator
"Session":{ # Settings about web session. Session algorythms works only for special requests (URL in ServerSettings)
"LifetimeSecFloat": 600.0, # Client Session lifetime in seconds. after this time server will forget about this client session
"LifetimeRequestSecFloat": 120.0, # 1 client request lifetime in server in seconds
"ControlPanelRefreshIntervalSecFloat": 1.5, # Interval to refresh control panels for session,
"TechnicalSessionGUIDCache": { # TEchnical cache. Fills when web browser is requesting
#"SessionGUIDStr":{ # Session with some GUID str. On client session guid stored in cookie "SessionGUIDStr"
# "InitDatetime": None, # Datetime when session GUID was created
# "DatasetLast": {
# "ControlPanel": {
# "Data": None, # Struct to check with new iterations. None if starts
# "ReturnBool": False # flag to return, close request and return data as json
# }
# },
# "ClientRequestHandler": None, # Last client request handler
# "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
#}
}
}
}
if lL: lL.warning(
f"Backward compatibility (v1.1.13 to v1.1.14): Add default 'Client' structure") # Log about compatibility
if "RequestTimeoutSecFloat" not in inGSettings["Server"]: # Add Server > "RequestTimeoutSecFloat" property
inGSettings["Server"]["RequestTimeoutSecFloat"] = 300 # Time to handle request in seconds
if lL: lL.warning(
f"Backward compatibility (v1.1.13 to v1.1.14): Add default 'Server' > 'RequestTimeoutSecFloat' property") # Log about compatibility

@ -10,6 +10,7 @@ import pdb
from . import Server
from . import Timer
from . import Processor
from . import BackwardCompatibility # Backward compatibility from v1.1.13
#from .Settings import Settings
import importlib
@ -79,6 +80,10 @@ if os.path.exists("_SessionLast_RDPList.json"):
lDaemonLoopSeconds=gSettingsDict["Scheduler"]["ActivityTimeCheckLoopSeconds"]
lDaemonActivityLogDict={} #Словарь отработанных активностей, ключ - кортеж (<activityType>, <datetime>, <processPath || processName>, <processArgs>)
lDaemonLastDateTime=datetime.datetime.now()
gSettingsDict["Server"]["WorkingDirectoryPathStr"] = os.getcwd() # Set working directory in g settings
# Turn on backward compatibility
BackwardCompatibility.Update(inGSettings= gSettingsDict)
#Инициализация сервера
lThreadServer = Server.RobotDaemonServer("ServerThread", gSettingsDict)

@ -23,6 +23,9 @@ import psutil
# "Type": "OrchestratorRestart"
# },
# {
# "Type": "OrchestratorSessionSave"
# },
# {
# "Type": "GlobalDictKeyListValueSet",
# "KeyList": ["key1","key2",...],
# "Value": <List, Dict, String, int>
@ -117,12 +120,23 @@ def Activity(inActivity):
lFile = open("_SessionLast_RDPList.json", "w", encoding="utf-8")
lFile.write(json.dumps(gSettingsDict["RobotRDPActive"]["RDPList"])) # dump json to file
lFile.close() # Close the file
if lL: lL.info(f"Orchestrator has dump the RDP list before the restart. The RDP List is {gSettingsDict['RobotRDPActive']['RDPList']}")
if lL: lL.info(f"Orchestrator has dump the RDP list before the restart. The RDP List is {gSettingsDict['RobotRDPActive']['RDPList']}. Do restart")
# Restart session
os.execl(sys.executable, os.path.abspath(__file__), *sys.argv)
lItem["Result"] = True
sys.exit(0)
###########################################################
# Обработка команды OrchestratorSessionSave
###########################################################
if lItem["Type"] == "OrchestratorSessionSave":
# Dump RDP List in file json
lFile = open("_SessionLast_RDPList.json", "w", encoding="utf-8")
lFile.write(json.dumps(gSettingsDict["RobotRDPActive"]["RDPList"])) # dump json to file
lFile.close() # Close the file
if lL: lL.info(
f"Orchestrator has dump the RDP list before the restart. The RDP List is {gSettingsDict['RobotRDPActive']['RDPList']}")
lItem["Result"] = True
###########################################################
#Обработка команды GlobalDictKeyListValueSet
###########################################################
if lItem["Type"]=="GlobalDictKeyListValueSet":

@ -467,7 +467,7 @@ class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
daemon_threads = True
"""Handle requests in a separate thread."""
def finish_request(self, request, client_address):
request.settimeout(30)
request.settimeout(gSettingsDict["Server"]["RequestTimeoutSecFloat"])
# "super" can not be used because BaseServer is not created from object
HTTPServer.finish_request(self, request, client_address)
#inGlobalDict

@ -50,8 +50,8 @@ def Monitor_ControlPanelDictGet_SessionCheckInit(inRequest,inGlobalDict):
lItemValue["DatasetLast"]["ControlPanel"]["ReturnBool"] = True # Set flag to return the data
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Technicaldef - Create new session struct
def TechnicalSessionNew():
lCookieSessionGUIDStr = str(uuid.uuid4()) # Generate the new GUID
def TechnicalSessionNew(inSessionGUIDStr):
lCookieSessionGUIDStr = inSessionGUIDStr # Generate the new GUID
lSessionNew = { # Session with some GUID str. On client session guid stored in cookie "SessionGUIDStr"
"InitDatetime": datetime.datetime.now(), # Datetime when session GUID was created
"DatasetLast": {
@ -71,13 +71,15 @@ def Monitor_ControlPanelDictGet_SessionCheckInit(inRequest,inGlobalDict):
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
lCreateNewSessionBool = False # Flag to create new session structure
# step 1 - get cookie SessionGUIDStr
lCookies = cookies.SimpleCookie(inRequest.headers.get("Cookie", ""))
if "SessionGUIDStr" in lCookies:
lCookieSessionGUIDStr = lCookies.get("SessionGUIDStr", None).value # Get the cookie
if lCookieSessionGUIDStr not in inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"]:
lCookieSessionGUIDStr= TechnicalSessionNew() # Create new session
lSessionGUIDStr = inRequest.headers.get("SessionGUIDStr", None)
if lSessionGUIDStr is not None: # Check if GUID session is ok
lCookieSessionGUIDStr = lSessionGUIDStr # Get the existing GUID
if lSessionGUIDStr not in inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"]:
lCookieSessionGUIDStr= TechnicalSessionNew(inSessionGUIDStr = lSessionGUIDStr) # Create new session
else: # Update the datetime of the request session
inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr]["InitDatetime"]=datetime.datetime.now()
else:
lCookieSessionGUIDStr = TechnicalSessionNew() # Create new session
lCookieSessionGUIDStr = TechnicalSessionNew(inSessionGUIDStr = lSessionGUIDStr) # Create new session
# Init the RobotRDPActive in another thread
#lThreadCheckCPInterval = threading.Thread(target=TechnicalIntervalCheck)
#lThreadCheckCPInterval.daemon = True # Run the thread in daemon mode.
@ -103,7 +105,7 @@ def Monitor_ControlPanelDictGet_SessionCheckInit(inRequest,inGlobalDict):
lItemValue["DatasetLast"]["ControlPanel"]["ReturnBool"] = False # Set flag that data was returned
lDoWhileBool = False # Stop the iterations
else:
lCookieSessionGUIDStr = TechnicalSessionNew() # Create new session
lCookieSessionGUIDStr = TechnicalSessionNew(inSessionGUIDStr = lCookieSessionGUIDStr) # Create new session
if lDoWhileBool: # Sleep if we wait hte next iteration
time.sleep(lControlPanelRefreshIntervalSecFloat) # Sleep to the next iteration

@ -1,5 +1,12 @@
var mGlobal={}
window.onload=function() {
//document.cookie = "SessionGUIDStr=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
//Render existing data
//mGlobal.Monitor.fControlPanelRefresh_TechnicalRender()
}
$(document).ready(function() {
document.cookie = "SessionGUIDStr=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
console.log("Cookie is deleted")
// fix main menu to page on passing
$('.main.menu').visibility({
type: 'fixed'
@ -55,7 +62,7 @@ $(document).ready(function() {
//For data storage key
mGlobal["DataStorage"] = {}
// Clear the session cookie
document.cookie = "SessionGUIDStr=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
String.prototype.replaceAll = function(search, replace){
return this.split(search).join(replace);
}
@ -93,6 +100,7 @@ $(document).ready(function() {
/////Controller JS module
//////////////////////////
mGlobal.Controller={};
mGlobal.Controller.CMDRunText=function(inCMDText) {
///Подготовить конфигурацию
lData = [
@ -159,6 +167,28 @@ $(document).ready(function() {
dataType: "text"
});
}
///Restart PC
mGlobal.Controller.PCRestart = function () {
mGlobal.Controller.CMDRunText("shutdown -r")
}
///Orchestrator save session
mGlobal.Controller.OrchestratorSessionSave=function() {
///Подготовить конфигурацию
lData = [
{"Type":"OrchestratorSessionSave"}
]
$.ajax({
type: "POST",
url: 'Utils/Processor',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
},
dataType: "text"
});
}
///Перезагрузить Orchestrator
mGlobal.Controller.OrchestratorRestart=function() {
///Подготовить конфигурацию
@ -177,6 +207,10 @@ $(document).ready(function() {
dataType: "text"
});
}
mGlobal.Controller.OrchestratorGITPullRestart = function() {
mGlobal.Controller.OrchestratorSessionSave() //Save current RDP list session
mGlobal.Controller.CMDRunText("timeout 3 & taskkill /f /im OpenRPA_Orchestrator.exe & timeout 2 & cd "+mGlobal.WorkingDirectoryPathStr+" & git reset --hard & git pull & pyOpenRPA.Orchestrator_x64_administrator_startup.cmd");
}
//////////////////////////
/////Monitor JS module
//////////////////////////
@ -230,20 +264,18 @@ $(document).ready(function() {
ms += new Date().getTime();
while (new Date() < ms){}
}
mGlobal.Monitor.fControlPanelRefresh=function() {
try {
///Загрузка данных
$.ajax({
type: "GET",
url: 'Monitor/ControlPanelDictGet',
data: '',
xhrFields: {
withCredentials: true
},
success: function(lData,l2,l3)
function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
mGlobal.SessionGUIDStr = uuidv4() // Generate uuid4 of the session
//console.log(uuidv4());
mGlobal.Monitor.fControlPanelRefresh_TechnicalRender = function()
{
try {
var lResponseJSON=JSON.parse(lData)
lResponseJSON = mGlobal.Monitor.mDatasetLast
if (lResponseJSON!= null) {
///Escape onclick
/// RenderRobotList
lResponseJSON["RenderRobotList"].forEach(
@ -296,7 +328,28 @@ $(document).ready(function() {
$(".openrpa-robotrdpactive-control-panel").html(lHTMLCode)
///Очистить дерево
//mGlobal.ElementTree.fClear();
}
}
mGlobal.Monitor.mDatasetLast = null
mGlobal.Monitor.fControlPanelRefresh=function() {
try {
//var XHR = new XMLHttpRequest();
//XHR.setRequestHeader("Cookies",document.cookie)
///Загрузка данных
//console.log("Request is sent")
//console.log(document.cookie)
$.ajax({
type: "GET",
headers: {"SessionGUIDStr":mGlobal.SessionGUIDStr},
url: 'Monitor/ControlPanelDictGet',
data: '',
//cache: false,
//xhr: XHR,
success: function(lData,l2,l3) {
try {
var lResponseJSON=JSON.parse(lData)
mGlobal.Monitor.mDatasetLast = lResponseJSON
mGlobal.Monitor.fControlPanelRefresh_TechnicalRender()
}
catch(error) {
}
@ -615,4 +668,28 @@ $(document).ready(function() {
});
}
mGlobal.UserRoleUpdate() // Cal the update User Roles function
// Orchestrator model
mGlobal.WorkingDirectoryPathStr = null
mGlobal.OrchestratorModelUpdate=function() {
lData = [
{
"Type": "GlobalDictKeyListValueGet",
"KeyList": ["Server","WorkingDirectoryPathStr"]
}
]
$.ajax({
type: "POST",
url: 'Utils/Processor',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lUACAsk = mGlobal.UserRoleAsk // Alias
var lResponseList=JSON.parse(lData)
mGlobal.WorkingDirectoryPathStr = lResponseList[0]["Result"]
},
dataType: "text"
});
}
mGlobal.OrchestratorModelUpdate() // Cal the update orchestrator model
});

@ -2,7 +2,7 @@
<html lang="en" >
<head>
<meta charset="utf-8">
<title>OpenRPA</title>
<title>pyOpenRPA Orchestrator</title>
<link rel="stylesheet" type="text/css" href="3rdParty/Semantic-UI-CSS-master/semantic.min.css">
<script
src="3rdParty/jQuery/jquery-3.1.1.min.js"
@ -135,14 +135,14 @@
<i class="right arrow icon"></i>
</div>
</div>
<div class="ui animated button openrpa-control-restartorchestrator" onclick="mGlobal.Controller.OrchestratorRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Git pull + restart Orchestrator (next release)</div>
<div class="ui animated button openrpa-control-restartorchestrator" onclick="mGlobal.Controller.OrchestratorGITPullRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Git pull + restart Orchestrator</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
</div>
<div class="ui animated button openrpa-control-restartorchestrator red" onclick="mGlobal.Controller.OrchestratorRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Restart PC (next release)</div>
<div class="ui animated button openrpa-control-restartorchestrator red" onclick="mGlobal.Controller.PCRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Restart PC</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
@ -299,14 +299,14 @@
<div class="three wide column">
<h4 class="ui inverted header">GitLab</h4>
<div class="ui inverted link list">
<a href="https://gitlab.com/UnicodeLabs/OpenRPA" class="item" target="_blank">OpenRPA repository</a>
<a href="https://gitlab.com/UnicodeLabs" class="item" target="_blank">UnicodeLabs</a>
<a href="https://gitlab.com/UnicodeLabs/OpenRPA" class="item" target="_blank">pyOpenRPA repository</a>
<a href="https://www.facebook.com/RU.IT4Business" class="item" target="_blank">Ivan Maslov</a>
<a href="#" class="item">Link -</a>
<a href="#" class="item">Link -</a>
</div>
</div>
<div class="seven wide column">
<h4 class="ui inverted header">OpenRPA</h4>
<h4 class="ui inverted header">pyOpenRPA</h4>
<p>Open source Robotic Process Automation software by the Unicode Labs (Created by Ivan Maslov). Under the MIT license.</p>
</div>
</div>

Loading…
Cancel
Save