v1.1.0 After 2 month test prefinal with new improovements (+RobotRDPActive in Orchestrator + Easy ControlPanelTemplate)

dev-linux
Ivan Maslov 5 years ago
parent b8e4cd82b5
commit 18b98d89d3

@ -1,207 +0,0 @@
import psutil, datetime, logging, os, json
# # # # # # # ORCHESTRATOR CONTROL PANEL <Robot name> # # # # # # #
# Init parameters
gProcessNameWOEXE = "OpenRPA_RobotRDPActive_<RobotKeyName>"
gRDPOrchestratorStorageKey = "<RobotKeyName>"
gRDPStartFilePath = os.path.abspath(os.path.join(os.getcwd(), gRDPOrchestratorStorageKey+r"\pyOpenRPA.Tools.RobotRDPActive_x64.cmd")) # cwd is orchestrator working directory
gOrchestratorToRobotKeyList = ["Storage",gRDPOrchestratorStorageKey,"OrchestratorToRobotStorage"]
gOrchestratorToRobotResetKeyList = ["Storage",gRDPOrchestratorStorageKey,"OrchestratorToRobotResetStorage"]
gRobotToOrchestratorKeyList = ["Storage",gRDPOrchestratorStorageKey,"RobotToOrchestratorStorage"]
gRobotRDPActiveDefsFolderPath = ""
gRobotProcessNameWOEXE = "<RobotProcessName>"
gRobotProcessFilePath = r"path\to\start\link"
# Function, which is generate Dict for front-endswith
def ControlPanelRenderDict(inGSettings):
"""result={
"HeaderLeftText":"<Robot name>",
"HeaderRightText":"<header>",
"DataStorageKey":"Robot_Name", #Use key for set current dict in mGlobal.DataStorage["DataStorageKey"] on client side
"SubheaderText": "State: <span style=\"color:green\">Turned on</span>",
"BodyKeyValueList":[
{"Key":"Session list","Value":""},
{"Key":"Session list","Value":""}
],
"FooterText":"Last update: 9:38:00 09.10.2019",
"FooterButtonX2List":[
{"Text":"Turn on", "Color":"green", "Link":"", "OnClick": lOnClickRunButton.replace("\\","\\\\")},
],
"FooterButtonX1List":[
{"Text":"Kill", "Color":"red", "Link":"", "OnClick": lOnClickForceCloseButton.replace("\\","\\\\")}
]
}"""
# START :: Create activities :: START #
## RDP Start
lActivityRDPStartEscaped = (f"mGlobal.Controller.CMDRunText('start cmd /K {gRDPStartFilePath}');").replace("\\","\\\\").replace("\"","\'") # Need escape because this is render on client side and after that it goes to server side :(
## RDP Safe turn off
lActivityRDPSafeOffEscaped = (f"mGlobal.Processor.ServerValueSet({json.dumps(gOrchestratorToRobotKeyList+['SafeTurnOff'])},true);").replace("\\","\\\\").replace("\"","\'")
## RDP Kill
lActivityRDPKillEscaped = (f"mGlobal.Controller.CMDRunText('taskkill /F /im {gProcessNameWOEXE}.exe');").replace("\\","\\\\").replace("\"","\'")
## Robot start
lActivityROBOTStartList = [
{
"ModulePath": f"{os.path.abspath(os.path.join(gRobotRDPActiveDefsFolderPath,'Defs_SessionIndex.py'))}", # "RobotRDPActive\\SessionDefs.py"
"DefName":"ProcessStartIfNotRunning", # Function name
"ArgList":[], # Args list
"ArgDict":{"inSessionIndex": 0, "inProcessName": f"{gRobotProcessNameWOEXE}.exe", "inFilePath": gRobotProcessFilePath} # Args dictionary
}
]
lActivityROBOTStartEscaped = f"mGlobal.Processor.ServerValueSet({json.dumps(gOrchestratorToRobotResetKeyList+['ActivityList'])},{json.dumps(lActivityROBOTStartList)});".replace("\"","\'")
## ROBOT r3 stop
lActivityROBOTStopList = [
{
"ModulePath": f"{os.path.abspath(os.path.join(gRobotRDPActiveDefsFolderPath,'Defs_SessionIndex.py'))}", # "Session\\SessionDefs.py"
"DefName":"ProcessStop", # Function name
"ArgList":[], # Args list
"ArgDict":{"inSessionIndex": 0, "inProcessName": f"{gRobotProcessNameWOEXE}.exe", "inFlagForceClose":True} # Args dictionary
}
]
lActivityROBOTStopEscaped = f"mGlobal.Processor.ServerValueSet({json.dumps(gOrchestratorToRobotResetKeyList+['ActivityList'])},{json.dumps(lActivityROBOTStopList)});".replace("\"","\'")
## ROBOT r3 restart
lActivityROBOTRestartList = lActivityROBOTStartList + lActivityROBOTStopList
lActivityROBOTRestartEscaped = f"mGlobal.Processor.ServerValueSet({json.dumps(gOrchestratorToRobotResetKeyList+['ActivityList'])},{json.dumps(lActivityROBOTRestartList)});".replace("\"","\'")
# END :: Create activities :: END #
# START :: Init result dict template :: START #
lBodyKeyValue_r3_start=f'<a onclick="{lActivityROBOTStartEscaped}" style=\"color:green\">Start</a>'
lBodyKeyValue_r3_stop=f'<a onclick="{lActivityROBOTStopEscaped}" style=\"color:red\">Stop</a>'
lBodyKeyValue_r3_restart=f'<a onclick="{lActivityROBOTRestartEscaped}" style=\"color:orange\">restart</a>'
lResultDict={
"HeaderLeftText":"ROBOT r4",
"HeaderRightText":"r4",
"DataStorageKey":gRDPOrchestratorStorageKey, #Use key for set current dict in mGlobal.DataStorage["DataStorageKey"] on client side
"SubheaderText":"<Subheader text>",
"BodyKeyValueList":[
{"Key":"ROBOT robots (r1-r5) list","Value":""},
{"Key":"r4","Value":f"{lBodyKeyValue_r3_start}, {lBodyKeyValue_r3_stop}, {lBodyKeyValue_r3_restart}"},
{"Key":"Session list","Value":""}
],
"FooterText":"Last update: 9:38:00 09.10.2019",
"FooterButtonX2List":[
{"Text":"Turn on", "Color":"green", "Link":"", "OnClick": lActivityRDPStartEscaped},
{"Text":"Safe turn off", "Color":"orange", "Link":"", "OnClick": lActivityRDPSafeOffEscaped}
],
"FooterButtonX1List":[
{"Text":"Kill", "Color":"red", "Link":"", "OnClick": lActivityRDPKillEscaped}
],
"GlobalStorage": inGSettings.get("Storage",{}) # UNCOMMENT FOR DEBUG PURPOSE TO WATCH inGSettings on client side
}
# END :: Init result dict template :: END #
# START :: Fill BodyKeyValueList :: START #
## Read RDPList
lRDPList = TechDictKeyList_ItemGet(inDict=inGSettings, inKeyList=gRobotToOrchestratorKeyList+["RDPList"], inDefault=[])
lFullScreenSessionIndex = TechDictKeyList_ItemGet(inDict=inGSettings, inKeyList=gRobotToOrchestratorKeyList+["FullScreenSessionIndex"], inDefault=None)
lRDPListIndex = 0
for lItem in lRDPList:
### Lable that session has fullscreen
lLabelSessionFullScreen = ""
lLabelIsIgnored = ""
### Link set full screen
lOnClickSetFullScreen = f"mGlobal.Processor.ServerValueSet(['Storage','{gRDPOrchestratorStorageKey}','OrchestratorToRobotStorage','FullScreenSessionIndex'],{lRDPListIndex});"
lSetFullScreenA = f'<a onclick="{lOnClickSetFullScreen}" style=\"color:blue\">Set fullscreen</a>'
if lRDPListIndex == lFullScreenSessionIndex:
lLabelSessionFullScreen = '<span style=\"color:blue\">[Fullscreen]</span>'
lOnClickSetFullScreen = f"mGlobal.Processor.ServerValueSet(['Storage','{gRDPOrchestratorStorageKey}','OrchestratorToRobotStorage','FullScreenSessionIndex'],null);"
lSetFullScreenA = f'<a onclick="{lOnClickSetFullScreen}" style=\"color:blue\">Set minimized</a>'
lIgnoreIndexListOnClick = "$.ajax({type: 'POST', url: '{gRDPOrchestratorStorageKey}/IgnoreIndexListAppend', data: '"+str(lRDPListIndex)+"', success: function(lData,l2,l3){}, dataType: 'text'});"
lIgnoreIndexListLink = f'<a onclick="{lIgnoreIndexListOnClick}" style=\"color:red\">Ignore</a>'
### Check if in ignore
if lRDPListIndex in inGSettings.get("Storage",{}).get(gRDPOrchestratorStorageKey,{}).get("OrchestratorToRobotStorage",{}).get("IgnoreIndexList",[]):
lLabelIsIgnored = '<span style=\"color:red\">[Ignored]</span>'
lIgnoreIndexListOnClick = "$.ajax({type: 'POST', url: '"+gRDPOrchestratorStorageKey+"/IgnoreIndexListRemove', data: '"+str(lRDPListIndex)+"', success: function(lData,l2,l3){}, dataType: 'text'});"
lIgnoreIndexListLink = f'<a onclick="{lIgnoreIndexListOnClick}" style=\"color:red\">Unignore</a>'
### Session state
lItemSessionState='<span style=\"color:red\">Disconnected</span>'
if lItem.get("SessionIsWindowResponsibleBool",False):
lItemSessionState='<span style=\"color:green\">Connected</span>'
lResultDict["BodyKeyValueList"].append({"Key":f"[{str(lRDPListIndex)}]{lLabelSessionFullScreen}{lLabelIsIgnored}{lItem.get('Host','localhost')}:{lItem.get('Port','--')}","Value":f"{lItem.get('Login','--')}, {lItem.get('SessionHex','--')}, State {lItemSessionState}, {lSetFullScreenA}, {lIgnoreIndexListLink}"})
lRDPListIndex = lRDPListIndex + 1
# END :: Fill BodyKeyValueList :: END #
# START :: Fill SubheaderText :: START #
## Variants
lSubheaderRunTrueText="State: <span style=\"color:green\">Turned on</span>"
lSubheaderRunFalseText="State: <span style=\"color:red\">Turned off</span>"
if CheckIfProcessRunning(gProcessNameWOEXE):
lResultDict["SubheaderText"]=lSubheaderRunTrueText
else:
lResultDict["SubheaderText"]=lSubheaderRunFalseText
# END :: Fill SubheaderText :: END #
# Fill FooterText
lResultDict["FooterText"]=f'Last update: {datetime.datetime.now().strftime("%H:%M:%S %d.%m.%Y")}'
return lResultDict
# Check in control panel, that process is runnning
def CheckIfProcessRunning(processName):
'''Check if there is any running process that contains the given name processName.'''
#Iterate over the all the running process
for proc in psutil.process_iter():
try:
# Check if process name contains the given name string.
if processName.lower() in proc.name().lower():
return True
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
pass
return False
#Add to ignore list - AJAX request from client side
def IgnoreIndexListAppend(inRequest,inConfiguration):
lIgnoreList = TechDictKeyList_ItemGet(inDict=inConfiguration, inKeyList=gOrchestratorToRobotKeyList+["IgnoreIndexList"], inDefault=[])
lIgnoreIndex={}
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray=inRequest.rfile.read(lInputByteArrayLength)
#Превращение массива байт в объект
lIgnoreIndex=int(lInputByteArray.decode('utf8'))
#check if index not in list
if lIgnoreIndex not in lIgnoreList:
#append to list
lIgnoreList.append(lIgnoreIndex)
#remove from Ignore list - AJAX request from client side
def IgnoreIndexListRemove(inRequest,inConfiguration):
lIgnoreList = TechDictKeyList_ItemGet(inDict=inConfiguration, inKeyList=gOrchestratorToRobotKeyList+["IgnoreIndexList"], inDefault=[])
lIgnoreIndex={}
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray=inRequest.rfile.read(lInputByteArrayLength)
#Превращение массива байт в объект
lIgnoreIndex=int(lInputByteArray.decode('utf8'))
#check if index not in list
if lIgnoreIndex in lIgnoreList:
#append to list
lIgnoreList.remove(lIgnoreIndex) #Remove delete the element lIgnoreIndex
# Technical def - Get item by the list of keys
def TechDictKeyList_ItemGet(inDict, inKeyList, inDefault={}):
lResult=inDict
for lItem in inKeyList:
if lResult:
lResult = lResult.get(lItem,None)
if lResult is None:
lResult=inDefault
return lResult
# # # # # # # # # # # # # # # # # # # # # # # #
#Orchestrator settings
def SettingsUpdate(inGSettings):
#Add RobotRDPActive in control panel
inGSettings["ControlPanelDict"]["RobotList"].append({"RenderFunction": ControlPanelRenderDict})
#Default structure
inGSettings["Storage"][gRDPOrchestratorStorageKey]={
"OrchestratorToRobotResetStorage":{"SafeTurnOff":False, "ActivityList":[]},
"OrchestratorToRobotStorage":{
"FullScreenSessionIndex":None,
"IgnoreIndexList": []
}
}
#Add methods
inGSettings["Server"]["URLList"].append(
{
"Method":"POST",
"URL": f"/{gRDPOrchestratorStorageKey}/IgnoreIndexListAppend", #URL of the request
"MatchType": "Equal", #"BeginWith|Contains|Equal|EqualCase",
"ResponseDefRequestGlobal": IgnoreIndexListAppend #Function with str result
}
)
inGSettings["Server"]["URLList"].append(
{
"Method":"POST",
"URL": f"/{gRDPOrchestratorStorageKey}/IgnoreIndexListRemove", #URL of the request
"MatchType": "Equal", #"BeginWith|Contains|Equal|EqualCase",
"ResponseDefRequestGlobal": IgnoreIndexListRemove #Function with str result
}
)
return inGSettings

@ -0,0 +1,124 @@
import psutil, datetime, logging, os, json
# # # # # # # ORCHESTRATOR CONTROL PANEL <Robot name> # # # # # # #
# Init parameters
gRobotStartFilePathStr = r"path\to\start\file" # path\to\start\file
gRobotProcessNameWOEXEStr = "process name" # RobotProcessName
gRobotADLoginStr = "Login" # Login of the robot session
gRobotADPasswordStr = "Password" # Password for session
gRobotKeyStr = "Robot_Template"
gRDPSessionKeyStr = "RDP_Template"
gRDPSessionHostStr = "localhost" # Rdp session host
gRDPSessionPortStr = "3389" # Default 3389
gControlPanelKeyStr = "ControlPanel_Template"
gControlPanelCheckRobotProcessFromOrchestratorUserBool = True # Check process activity from orchestrator GUI session (with help of task manager, when users on the same machine)
# !! ATTENTION !! SCHEDULE TIME START STOP FILL BELOW IN ACTIVITY SECTION
gRobotToOrchestratorKeyList = ["Storage",gRobotKeyStr,"RobotToOrchestrator"]
gOrchestratorToRobotResetKeyList = ["Storage",gRobotKeyStr,"OrchestratorToRobotReset"]
gOrchestratorToRobotResetSafeStopKeyList = gOrchestratorToRobotResetKeyList+["SafeTurnOffBool"]
# Function, which is generate Dict for front-endswith
def ControlPanelRenderDict(inGSettings):
"""result={
"HeaderLeftText":"<Robot name>",
"HeaderRightText":"<header>",
"DataStorageKey":"Robot_Name", #Use key for set current dict in mGlobal.DataStorage["DataStorageKey"] on client side
"SubheaderText": "State: <span style=\"color:green\">Turned on</span>",
"BodyKeyValueList":[
{"Key":"Session list","Value":""},
{"Key":"Session list","Value":""}
],
"FooterText":"Last update: 9:38:00 09.10.2019",
"FooterButtonX2List":[
{"Text":"Turn on", "Color":"green", "Link":"", "OnClick": lOnClickRunButton.replace("\\","\\\\")},
],
"FooterButtonX1List":[
{"Text":"Kill", "Color":"red", "Link":"", "OnClick": lOnClickForceCloseButton.replace("\\","\\\\")}
]
}"""
# START :: Create activities :: START #
## Robot START (create RDP session, send CMD to start process)
lActivityROBOTStartList = [
{ # Start RDP Session
"DefNameStr":"RDPSessionConnect", # Function name in RobotRDPActive.Processor
"ArgList":[], # Args list
"ArgDict":{"inRDPSessionKeyStr": gRDPSessionKeyStr, "inHostStr": gRDPSessionHostStr, "inPortStr": gRDPSessionPortStr, "inLoginStr": gRobotADLoginStr, "inPasswordStr": gRobotADPasswordStr} # Args dictionary
},
{ # Run robot file in RDP session
"DefNameStr":"RDPSessionProcessStartIfNotRunning", # Function name in RobotRDPActive.Processor
"ArgList":[], # Args list
"ArgDict":{"inRDPSessionKeyStr": gRDPSessionKeyStr, "inProcessNameWEXEStr": f"{gRobotProcessNameWOEXEStr}.exe", "inFilePathStr": gRobotStartFilePathStr, "inFlagGetAbsPathBool": False} # Args dictionary
}
]
lActivityROBOTStartEscaped = f"mGlobal.Processor.ServerValueSet({json.dumps(['RobotRDPActive','ActivityList'])},{json.dumps(lActivityROBOTStartList)});".replace("\"","\'")
## Robot SAFE STOP (SAFE STOP COMMAND (FROM ROBOT RULES), Logoff must do robot when safe turn off)
lActivityROBOTSafeStopEscaped = f"mGlobal.Processor.ServerValueSet({json.dumps(gOrchestratorToRobotResetSafeStopKeyList)},true);".replace("\"","\'")
## Robot FORCE STOP (create RDP session, send CMD to start process)
lActivityROBOTStopList = [
{ # Kill process
"DefNameStr":"RDPSessionProcessStop", # Function name in RobotRDPActive.Processor
"ArgList":[], # Args list
"ArgDict":{"inRDPSessionKeyStr": gRDPSessionKeyStr, "inProcessNameWEXEStr":f"{gRobotProcessNameWOEXEStr}.exe","inFlagForceCloseBool": True} # Args dictionary
},
{ # Logoff RDP Session
"DefNameStr":"RDPSessionLogoff", # Function name in RobotRDPActive.Processor
"ArgList":[], # Args list
"ArgDict":{"inRDPSessionKeyStr": gRDPSessionKeyStr} # Args dictionary
}
]
lActivityROBOTStopEscaped = f"mGlobal.Processor.ServerValueSet({json.dumps(['RobotRDPActive','ActivityList'])},{json.dumps(lActivityROBOTStopList)});".replace("\"","\'")
# END :: Create activities :: END #
# START :: Init result dict template :: START #
# lBodyKeyValue_r3_start=f'<a onclick="{lActivityROBOTStartEscaped}" style=\"color:green\">Start</a>'
lResultDict={
"HeaderLeftText":"ROBOT KEYWORD",
"HeaderRightText":"ROBOT NAME",
"DataStorageKey":gControlPanelKeyStr, # CLIENT SIDE:: Use key for set current dict in mGlobal.DataStorage["DataStorageKey"] on client side
"SubheaderText":"<Subheader text, state filled below>",
"BodyKeyValueList":[
{"Key":"Info","Value":"1"},
{"Key":"Info","Value":"2"},
{"Key":"Info","Value":"3"},
{"Key":"Statistic","Value":""}
],
"FooterText":"Last update: 9:38:00 09.10.2019",
"FooterButtonX2List":[
{"Text":"Turn on", "Color":"green", "Link":"", "OnClick": lActivityROBOTStartEscaped},
{"Text":"Safe turn off", "Color":"orange", "Link":"", "OnClick": lActivityROBOTSafeStopEscaped}
],
"FooterButtonX1List":[
{"Text":"Kill", "Color":"red", "Link":"", "OnClick": lActivityROBOTStopEscaped}
],
# "GlobalStorage": inGSettings.get("Storage",{}) # UNCOMMENT FOR DEBUG PURPOSE TO WATCH inGSettings on client side
}
# END :: Init result dict template :: END #
# START :: Fill BodyKeyValueList :: START #
# END :: Fill BodyKeyValueList :: END #
# START :: Fill SubheaderText :: START #
## FILL Robot state by the check the RDP session state
lSubheaderRunTrueText="State: <span style=\"color:green\">Turned on</span>"
lSubheaderRunFalseText="State: <span style=\"color:red\">Turned off</span>"
if gControlPanelCheckRobotProcessFromOrchestratorUserBool and gRDPSessionKeyStr in inGSettings["RobotRDPActive"]["RDPList"]:
lResultDict["SubheaderText"]=lSubheaderRunTrueText
else:
lResultDict["SubheaderText"]=lSubheaderRunFalseText
# END :: Fill SubheaderText :: END #
# Fill FooterText
lResultDict["FooterText"]=f'Last update: {datetime.datetime.now().strftime("%H:%M:%S %d.%m.%Y")}'
return lResultDict
# Technical def - Get item by the list of keys
def TechDictKeyList_ItemGet(inDict, inKeyList, inDefault={}):
lResult=inDict
for lItem in inKeyList:
if lResult:
lResult = lResult.get(lItem,None)
if lResult is None:
lResult=inDefault
return lResult
# # # # # # # # # # # # # # # # # # # # # # # #
#Orchestrator settings update
def SettingsUpdate(inGSettings):
#Add RobotRDPActive in control panel
inGSettings["ControlPanelDict"]["RobotList"].append({"RenderFunction": ControlPanelRenderDict, "KeyStr": gControlPanelKeyStr})
return inGSettings

@ -18,7 +18,8 @@ def SettingsUpdate(inDict):
#"FlagAccessDefRequestGlobalAuthenticate": TestDef
"FlagAccess": True
}
]
],
"ControlPanelKeyAllowedList": ["TestControlPanel", "RobotRDPActive","RobotScreenActive", "ControlPanel_Template"] # If empty - all is allowed
}
}
#Append to global list

@ -1,155 +0,0 @@
import psutil
import datetime
import logging
import os
import json
lProcessName = "OpenRPA_RobotRDPActive.exe"
lStartFilePath = os.path.join(os.getcwd(), "..\\Utils\\RobotRDPActive\\pyOpenRPA.Tools.RobotRDPActive_x64.cmd")
def RenderRobotRDPActive(inGlobalConfiguration):
#Subheader Variants
lSubheaderRunTrueText="State: <span style=\"color:green\">Turned on</span>"
lSubheaderRunFalseText="State: <span style=\"color:red\">Turned off</span>"
#Run button
#Такое большое количество слэшей связано с тем, что этот текст отправляется сначала в браузер, рендерится там, а потом отправляется на процессор оркестратора
lRobotRDPActivePath = f"start cmd /K {lStartFilePath}"
lOnClickRunButton=f"mGlobal.Controller.CMDRunText('{lRobotRDPActivePath}');"
#Safe turn off
lOnClickSafeTurnOff = "mGlobal.Processor.ServerValueSet(['Storage','RobotRDPActive','OrchestratorToRobotResetStorage','SafeTurnOff'],true);"
#Force close button
lOnClickForceCloseButton=f"mGlobal.Controller.CMDRunText('taskkill /F /im {lProcessName}');"
# # # # # Add recieve file activity
lTestRecieveActivityList = [
{
"ModulePath": f"{os.path.join(lRobotRDPActiveFolderPath,'Defs_SessionIndex.py')}", # "Session\\SessionDefs.py"
"DefName":"FileStoredRecieve", # Function name
"ArgList":[], # Args list
"ArgDict":{"inSessionIndex": 0, "inHostFilePath": "testRecieve.txt","inRDPFilePath": "C:\\Temp\\testRecieve.txt"} # Args dictionary
}
]
lOnClickTestSendBaumanStr = f"mGlobal.Processor.ServerValueSet(['Storage','RobotRDPActive','OrchestratorToRobotResetStorage','ActivityList'],{json.dumps(lTestRecieveActivityList)});"
#Result template
lResultDict={
"HeaderLeftText":"Keep active RDP sessions",
"HeaderRightText":"Tech",
"DataStorageKey":"RobotRDPActive", #Use key for set current dict in mGlobal.DataStorage["DataStorageKey"] on client side
"SubheaderText":lSubheaderRunFalseText,
"BodyKeyValueList":[
{"Key":"Session list","Value":""}
],
"FooterText":"Last update: 9:38:00 09.10.2019",
"FooterButtonX2List":[
{"Text":"Turn on", "Color":"green", "Link":"", "OnClick": lOnClickRunButton.replace("\\","\\\\")},
{"Text":"Safe turn off", "Color":"orange", "Link":"", "OnClick": lOnClickSafeTurnOff.replace("\\","\\\\")}
],
"FooterButtonX1List":[
{"Text":"Kill", "Color":"red", "Link":"", "OnClick": lOnClickForceCloseButton.replace("\\","\\\\")}
]#,
#"GlobalStorage": inGlobalConfiguration.get("Storage",{})
}
#Read RDPList
lRDPList = inGlobalConfiguration.get("Storage",{}).get("RobotRDPActive",{}).get("RobotToOrchestratorStorage",{}).get("RDPList",[])
lFullScreenSessionIndex = inGlobalConfiguration.get("Storage",{}).get("RobotRDPActive",{}).get("RobotToOrchestratorStorage",{}).get("FullScreenSessionIndex",None)
lRDPListIndex = 0
for lItem in lRDPList:
#Lable that session has fullscreen
lLabelSessionFullScreen = ""
lLabelIsIgnored = ""
#Link set full screen
##############################
lOnClickSetFullScreen = f"mGlobal.Processor.ServerValueSet(['Storage','RobotRDPActive','OrchestratorToRobotStorage','FullScreenSessionIndex'],{lRDPListIndex});"
lSetFullScreenA = f'<a onclick="{lOnClickSetFullScreen}" style=\"color:blue\">Set fullscreen</a>'
if lRDPListIndex == lFullScreenSessionIndex:
lLabelSessionFullScreen = '<span style=\"color:blue\">[Fullscreen]</span>'
lOnClickSetFullScreen = f"mGlobal.Processor.ServerValueSet(['Storage','RobotRDPActive','OrchestratorToRobotStorage','FullScreenSessionIndex'],null);"
lSetFullScreenA = f'<a onclick="{lOnClickSetFullScreen}" style=\"color:blue\">Set minimized</a>'
#################################
lIgnoreIndexListOnClick = "$.ajax({type: 'POST', url: 'RobotRDPActive/IgnoreIndexListAppend', data: '"+str(lRDPListIndex)+"', success: function(lData,l2,l3){}, dataType: 'text'});"
lIgnoreIndexListLink = f'<a onclick="{lIgnoreIndexListOnClick}" style=\"color:red\">Ignore</a>'
#Check if in ignore
if lRDPListIndex in inGlobalConfiguration.get("Storage",{}).get("RobotRDPActive",{}).get("OrchestratorToRobotStorage",{}).get("IgnoreIndexList",[]):
lLabelIsIgnored = '<span style=\"color:red\">[Ignored]</span>'
lIgnoreIndexListOnClick = "$.ajax({type: 'POST', url: 'RobotRDPActive/IgnoreIndexListRemove', data: '"+str(lRDPListIndex)+"', success: function(lData,l2,l3){}, dataType: 'text'});"
lIgnoreIndexListLink = f'<a onclick="{lIgnoreIndexListOnClick}" style=\"color:red\">Unignore</a>'
################################
#Session state
lItemSessionState='<span style=\"color:red\">Disconnected</span>'
if lItem.get("SessionIsWindowResponsibleBool",False):
lItemSessionState='<span style=\"color:green\">Connected</span>'
lResultDict["BodyKeyValueList"].append({"Key":f"[{str(lRDPListIndex)}]{lLabelSessionFullScreen}{lLabelIsIgnored}{lItem.get('Host','localhost')}:{lItem.get('Port','--')}","Value":f"{lItem.get('Login','--')}, {lItem.get('SessionHex','--')}, State {lItemSessionState}, {lSetFullScreenA}, {lIgnoreIndexListLink}"})
lRDPListIndex = lRDPListIndex + 1
#Check if process running
if CheckIfProcessRunning("OpenRPA_RobotRDPActive"):
lResultDict["SubheaderText"]=lSubheaderRunTrueText
#Process not running
lResultDict["FooterText"]=f'Last update: {datetime.datetime.now().strftime("%H:%M:%S %d.%m.%Y")}'
return lResultDict
#Add to ignore list
def IgnoreIndexListAppend(inRequest,inConfiguration):
lIgnoreList = inConfiguration["Storage"]["RobotRDPActive"]["OrchestratorToRobotStorage"]["IgnoreIndexList"]
lIgnoreIndex={}
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray=inRequest.rfile.read(lInputByteArrayLength)
#Превращение массива байт в объект
lIgnoreIndex=int(lInputByteArray.decode('utf8'))
#check if index not in list
if lIgnoreIndex not in lIgnoreList:
#append to list
lIgnoreList.append(lIgnoreIndex)
#remove from Ignore list
def IgnoreIndexListRemove(inRequest,inConfiguration):
lIgnoreList = inConfiguration["Storage"]["RobotRDPActive"]["OrchestratorToRobotStorage"]["IgnoreIndexList"]
lIgnoreIndex={}
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray=inRequest.rfile.read(lInputByteArrayLength)
#Превращение массива байт в объект
lIgnoreIndex=int(lInputByteArray.decode('utf8'))
#check if index not in list
if lIgnoreIndex in lIgnoreList:
#append to list
lIgnoreList.remove(lIgnoreIndex) #Remove delete the element lIgnoreIndex
def CheckIfProcessRunning(processName):
'''
Check if there is any running process that contains the given name processName.
'''
#Iterate over the all the running process
for proc in psutil.process_iter():
try:
# Check if process name contains the given name string.
if processName.lower() in proc.name().lower():
return True
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
pass
return False;
#Orchestrator settings
def SettingsUpdate(inDict):
#Add RobotRDPActive in control panel
inDict["ControlPanelDict"]["RobotList"].append({"RenderFunction": RenderRobotRDPActive})
#Default structure
inDict["Storage"]["RobotRDPActive"]={
"OrchestratorToRobotResetStorage":{"SafeTurnOff":False},
"OrchestratorToRobotStorage":{
"FullScreenSessionIndex":None,
"IgnoreIndexList": []
}
}
#Add methods
inDict["Server"]["URLList"].append(
{
"Method":"POST",
"URL": "/RobotRDPActive/IgnoreIndexListAppend", #URL of the request
"MatchType": "Equal", #"BeginWith|Contains|Equal|EqualCase",
"ResponseDefRequestGlobal": IgnoreIndexListAppend #Function with str result
}
)
inDict["Server"]["URLList"].append(
{
"Method":"POST",
"URL": "/RobotRDPActive/IgnoreIndexListRemove", #URL of the request
"MatchType": "Equal", #"BeginWith|Contains|Equal|EqualCase",
"ResponseDefRequestGlobal": IgnoreIndexListRemove #Function with str result
}
)
return inDict

@ -56,5 +56,5 @@ def CheckIfProcessRunning(processName):
#Orchestrator settings
def SettingsUpdate(inDict):
#Add RobotRDPActive in control panel
inDict["ControlPanelDict"]["RobotList"].append({"RenderFunction": RenderRobotScreenActive})
inDict["ControlPanelDict"]["RobotList"].append({"RenderFunction": RenderRobotScreenActive , "KeyStr": "RobotScreenActive"})
return inDict

@ -85,7 +85,7 @@ def Settings():
"AccessUsers": { #Default - all URL is blocked
"FlagCredentialsAsk": True, #Turn on Authentication
"RuleDomainUserDict": {
#("DOMAIN", "USER"): { !!!!!only in upper case!!!!
#("DOMAIN", "USER"): { !!!!! only in upper case !!!!
# "MethodMatchURLBeforeList": [
# {
# "Method":"GET|POST",
@ -94,7 +94,8 @@ def Settings():
# "FlagAccessDefRequestGlobalAuthenticate": None, #Return bool
# "FlagAccess": True
# }
# ]
# ],
# "ControlPanelKeyAllowedList":[] # If empty - all is allowed
#}
},
"RuleMethodMatchURLBeforeList": [ #General MethodMatchURL list (no domain/user)
@ -217,7 +218,8 @@ def Settings():
"RefreshSeconds": 5,
"RobotList": [
{
"RenderFunction": RenderRobotR01
"RenderFunction": RenderRobotR01,
"KeyStr":"TestControlPanelKey"
}
]
},

@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: pyOpenRPA
Version: 1.0.42
Version: 1.1.0
Summary: First open source RPA platform for business
Home-page: https://gitlab.com/UnicodeLabs/OpenRPA
Author: Ivan Maslov

@ -1,14 +1,38 @@
pyOpenRPA-1.0.42.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pyOpenRPA-1.0.42.dist-info/METADATA,sha256=Spesv5ub8aq5ymKhq_1kDDFQ2lrCrTwXfF8PakH7OO8,3542
pyOpenRPA-1.0.42.dist-info/RECORD,,
pyOpenRPA-1.0.42.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97
pyOpenRPA-1.0.42.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10
pyOpenRPA/Orchestrator/Orchestrator.py,sha256=UKp7eqvWDM91kYLwl2mo0UB8Pw-qu8eJCsR9NEXD1aU,6436
pyOpenRPA/Orchestrator/Processor.py,sha256=kmGNIqe6AZMSrzCt1QlonEy58ecFeLunjo8AeRMsufU,11091
pyOpenRPA/Orchestrator/Server.py,sha256=s1ujCuRX6YxRllqPn541Df4pJP7kOexiS3RIuoT4nyE,22053
pyOpenRPA/Orchestrator/ServerSettings.py,sha256=jOXJTLwg8cJx6D-rN8J4dn5RCb2nepAhCH4F9hYVUdM,4912
pyOpenRPA/Orchestrator/Timer.py,sha256=FQZ3y6G9d47Ybx7RewzePKQV77H4gCkx5SaeFVlsuhc,2095
pyOpenRPA/Orchestrator/Web/Index.xhtml,sha256=su4tsDD_ZMbQz6Tbmqj55SM0ZZxuQw9tfPcytaB8wzs,32953
pyOpenRPA-1.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pyOpenRPA-1.1.0.dist-info/METADATA,sha256=yrWtVmt4O4pYWpBBOCBXDwfe6CVB7Qpkfkb1TnBiBEs,3541
pyOpenRPA-1.1.0.dist-info/RECORD,,
pyOpenRPA-1.1.0.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97
pyOpenRPA-1.1.0.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10
pyOpenRPA/Orchestrator/Orchestrator.py,sha256=0Q4VYZPdXV2qmLuowMWD_vERj1GQurQx_VFwfsxuucQ,7076
pyOpenRPA/Orchestrator/Processor.py,sha256=wqhbAcR9-7OszRHSX2u7BSONPNIMkEbDexvW47h0xdM,11954
pyOpenRPA/Orchestrator/RobotRDPActive/CMDStr.py,sha256=6otw1WnR2_evvQ5LGyOVh0BLk_nTdilViGub7p56fXQ,1531
pyOpenRPA/Orchestrator/RobotRDPActive/Clipboard.py,sha256=YB5HJL-Qf4IlVrFHyRv_ZMJ0Vo4vjyYqWKjvrTnf1k4,1564
pyOpenRPA/Orchestrator/RobotRDPActive/Connector.py,sha256=2nm5S_FOfnLkDVdlm2MVag9vL3DlyJ98LnwYNMzFNho,15914
pyOpenRPA/Orchestrator/RobotRDPActive/ConnectorExceptions.py,sha256=WgGqWoPAnMeXpI_w3iuFX0KUBssvlSk9MuPBuIsNOuY,491
pyOpenRPA/Orchestrator/RobotRDPActive/GlobalDictSessionIndex_Defs.py,sha256=4BbAozLyOlXJxNw0NAlHt38-AyV-B6-Nl1M1AY8CTtk,4212
pyOpenRPA/Orchestrator/RobotRDPActive/Monitor.py,sha256=Y4mhNslK0EBS1LIDfK67j3lkjTZSU5xq-HUl9XNKW-U,10609
pyOpenRPA/Orchestrator/RobotRDPActive/Processor.py,sha256=DrvRm6ZLgrGNcD8EjyKbZ4HZPfiGjQftuWDfqLeM6hw,7627
pyOpenRPA/Orchestrator/RobotRDPActive/RobotRDPActive.py,sha256=vsISwvRTMbbEtL_u9PU-rP6W71VUhAUBLMblOSGp2BE,9893
pyOpenRPA/Orchestrator/RobotRDPActive/Scheduler.py,sha256=21N0ilFzWI1mj3X5S9tPMgwvG7BviuBxfTuqBY85Hy4,9144
pyOpenRPA/Orchestrator/RobotRDPActive/Timer.py,sha256=y8--fUvg10qEFomecl_cmdWpdGjarZBlFpMbs_GvzoQ,1077
pyOpenRPA/Orchestrator/RobotRDPActive/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Orchestrator/RobotRDPActive/__main__.py,sha256=z9PaUK4_nBiGd0YJdYVHV_rFx6VjZaxrrmKxSyoTFwY,2508
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/CMDStr.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Clipboard.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Connector.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/ConnectorExceptions.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/GlobalDictSessionIndex_Defs.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Monitor.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Processor.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/RobotRDPActive.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Scheduler.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Timer.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Server.py,sha256=gqJO6FRDKTBZytJVdJgPF1PvOf05qYUyKDBJJkEpLzk,22755
pyOpenRPA/Orchestrator/ServerSettings.py,sha256=mpPAxAe6PvmKaZlreaoQAy_5wV80edz_0qc-iFrEmBQ,7123
pyOpenRPA/Orchestrator/Timer.py,sha256=HvYtEeH2Q5WVVjgds9XaBpWRmvZgwgBXurJDdVVq_T0,2097
pyOpenRPA/Orchestrator/Web/Index.xhtml,sha256=t-s45l9APe-wUWazdFVRP2aIsKpsNtlwU_xuSuP2d0Q,36537
pyOpenRPA/Orchestrator/Web/favicon.ico,sha256=0vdsnwKGh6pgB0FDB5mOKO7RwbxQ9F13Zg16F1pkvXs,5430
pyOpenRPA/Orchestrator/__init__.py,sha256=qVH8fEPgXk54rmy-ol0PnT8GF5OlGE0a8mExwJ4tFqY,124
pyOpenRPA/Orchestrator/__main__.py,sha256=cOd8WU77VGgzTZUB0WmWpPmdYyMZY1zVyuU9yx26MKs,144
@ -192,7 +216,7 @@ pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/outli
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/images/flags.png,sha256=lNXH8WYTAcSm3Ekdct1VmgYgzZF6gm8N8bAju5bqnd0,28123
pyOpenRPA/Resources/Web/jQuery/jquery-3.1.1.min.js,sha256=HPMOWdIdSuVgr3FD9ZE-_MgiK8qk_MdQjrgCtfqp6U4,86713
pyOpenRPA/Robot/Clipboard.py,sha256=q76X8L21zJwcwdoJJNPeCEwAV30xS6ylHP1WwvtxoWI,722
pyOpenRPA/Robot/OrchestratorConnector.py,sha256=Fihxz-jH9M4VakXEE0SZ0Vo9tLEQk8Tcg_C4HoH45gI,20037
pyOpenRPA/Robot/OrchestratorConnector.py,sha256=JUtdiUXCruqUqBD19gJBl9jk_b-tpWWx_v3MfBoKzoQ,20445
pyOpenRPA/Robot/SettingsTemplate.py,sha256=Rp5XPeV2I4tCS2uf4Zkqm_ERJ6pZMg4-e5_lMqGJYLk,1453
pyOpenRPA/Robot/Test.py,sha256=qXr990nXiFZX5SNv6QN9GLb_U4HZRmJnbZR2qSnwilY,2878
pyOpenRPA/Robot/UIDesktop.py,sha256=3I2bllTDvR9d10O2ltkjoKmYw34wkkDAZfPlRpwbj30,77476
@ -221,8 +245,8 @@ pyOpenRPA/Robot/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Robot/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Studio/JSONNormalize.py,sha256=g0Z8G2wojCgTAdZtyRiCfe0_FHSeAi72Va7R7mk27gg,3347
pyOpenRPA/Studio/ProcessCommunicator.py,sha256=HD3XASJae31_HV3OznFe8E2MgZFXnwt7YveVN82M8nU,7912
pyOpenRPA/Studio/RobotConnector.py,sha256=tQVC8X0k1HMHAAwAtkhtmeNA0cLMY3wuO-RCbgshdMk,5036
pyOpenRPA/Studio/Studio.py,sha256=zpIGLMM2FBsUt2pC3x3BBm2zZ0n42MPfG7zgqtKxF6o,8338
pyOpenRPA/Studio/RobotConnector.py,sha256=CYO0dQoqfs44SYD_VZ_TJh3WFu_DXigHBLHj4GJ2Icc,5038
pyOpenRPA/Studio/Studio.py,sha256=UoMDqnZm-MCiZHR8ToLTHHPN0Yx0Oa6-VOTJdUtoMKE,8352
pyOpenRPA/Studio/ValueVerify.py,sha256=ObskxU4fOMoCGw74_nzYt6-a5jjrAckb3sdBLYyhYxY,777
pyOpenRPA/Studio/Web/Index.xhtml,sha256=RqFW3qC1pFRr-qWEEDlCEhL9l3PwANyRbll3KZJnLvo,47927
pyOpenRPA/Studio/Web/favicon.ico,sha256=0vdsnwKGh6pgB0FDB5mOKO7RwbxQ9F13Zg16F1pkvXs,5430
@ -236,8 +260,8 @@ pyOpenRPA/Studio/__pycache__/ValueVerify.cpython-37.pyc,,
pyOpenRPA/Studio/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Studio/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/ExcelCom.py,sha256=hp0dvXOEC7Au00ueh7pqxkdixV-PC-km7tCt-wRunYs,343
pyOpenRPA/Tools/RobotDB/RobotDB.py,sha256=DZSb17fiCAYLdNVTLFJ7nTbQhk29PjzxE9OL6ydCDcI,1645
pyOpenRPA/Tools/RobotDB/Server.py,sha256=MYIbO5vGH1FKgJVu3dQnscKRgN8or0FV8ZxAQbdC2Rc,19865
pyOpenRPA/Tools/RobotDB/RobotDB.py,sha256=qtGu8PS2atd0L8taCNpk-08Qpxp8Qz1lqwAcBkyLFLM,1655
pyOpenRPA/Tools/RobotDB/Server.py,sha256=rjW9Sg-j9P8pFQD66Uih-rke6-f6sCulinwi4_W-3mc,19933
pyOpenRPA/Tools/RobotDB/ServerSettings.py,sha256=5p9JwrpKHh68oVHIWazTajB6AOfzeapARbvGcJOFmNc,7406
pyOpenRPA/Tools/RobotDB/__init__.py,sha256=qVH8fEPgXk54rmy-ol0PnT8GF5OlGE0a8mExwJ4tFqY,124
pyOpenRPA/Tools/RobotDB/__main__.py,sha256=w9sXIF4r_PeWJjHJutTuH8DSYpXxpgcAN0KUOjiJ6PI,140
@ -247,15 +271,6 @@ pyOpenRPA/Tools/RobotDB/__pycache__/Server.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/__pycache__/ServerSettings.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotRDPActive/Connector.py,sha256=qU5SXwHgQU177MjqEHyOwJDLAcSVnIkKKw76iD09J1w,7275
pyOpenRPA/Tools/RobotRDPActive/Monitor.py,sha256=H7ciateTh-hml8z69EYZjYgqdTZGkDRtnFwuYnytrCw,3278
pyOpenRPA/Tools/RobotRDPActive/Template.rdp,sha256=qPCLkjzTdYKURK7nRApkPUjRuS4K20vDPj9DIUNSSkE,2392
pyOpenRPA/Tools/RobotRDPActive/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Tools/RobotRDPActive/__main__.py,sha256=mVk8zVqcBrzAwwn7tbZPXFWTQbWUkgU6w89nbY6GN-8,2340
pyOpenRPA/Tools/RobotRDPActive/__pycache__/Connector.cpython-37.pyc,,
pyOpenRPA/Tools/RobotRDPActive/__pycache__/Monitor.cpython-37.pyc,,
pyOpenRPA/Tools/RobotRDPActive/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotRDPActive/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotScreenActive/ConsoleStart.bat,sha256=_HNadUKHOYI5y6foG3srh8wjSzhX33xaKNylFtDjOJk,114
pyOpenRPA/Tools/RobotScreenActive/Monitor.py,sha256=TV-YisVqa_uGiyJLG9oK4u-5aDjGiFYZFh1dPjOgYc8,492
pyOpenRPA/Tools/RobotScreenActive/Screen.py,sha256=VnYcvCVymrD35l2J4ln_tlVn7CilZhxE4Ggw9P-OhIw,606
@ -267,15 +282,14 @@ pyOpenRPA/Tools/RobotScreenActive/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotScreenActive/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/Crypter.py,sha256=VRrE5-oQxQtvMEPHM1lMXp2CKnceNBmIWJnsJoJkaVE,3616
pyOpenRPA/Tools/SafeSource/DistrCreate.py,sha256=-_8BTle57LBKVknnB_3af-LghxrRmRGfRNu08CLNIvY,3232
pyOpenRPA/Tools/SafeSource/DistrRun.py,sha256=TH4uExbufnOubBrTiO8Ccw00E5K6zaJ59-vApSxQ0iY,6661
pyOpenRPA/Tools/SafeSource/DistrRun.py,sha256=zwUh6Jy-rDAZHV6fcTUMupkukojntFMroHJHMsNQgrE,9637
pyOpenRPA/Tools/SafeSource/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Tools/SafeSource/__main__.py,sha256=g5aYWnuUZoM2jDX2mSIl9tRAJg05tu5VxD2rGJWcACg,649
pyOpenRPA/Tools/SafeSource/__pycache__/Crypter.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/__pycache__/DistrCreate.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/__pycache__/DistrRun.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Tools/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/__init__.py,sha256=9w2hSRgGrWKyQb3T_j71u7VoYGZsrTZz189nKtqEmOQ,175
pyOpenRPA/__init__.py,sha256=77eUDvkFqIZMsTqBvMu8L_kbwNSHWSXsJmPZaAgGrVQ,174
pyOpenRPA/__pycache__/__init__.cpython-37.pyc,,

@ -15,9 +15,11 @@ import copy
#from .Settings import Settings
import importlib
from importlib import util
import threading # Multi-threading for RobotRDPActive
from .RobotRDPActive import RobotRDPActive #Start robot rdp active
#Единый глобальный словарь (За основу взять из Settings.py)
global mGlobalDict
global gSettingsDict
#Call Settings function from argv[1] file
################################################
lSubmoduleFunctionName = "Settings"
@ -26,34 +28,41 @@ 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
gSettingsDict = None
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
# Run SettingUpdate function in submodule
mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
gSettingsDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
#################################################
#mGlobalDict = Settings.Settings(sys.argv[1])
Processor.mGlobalDict = mGlobalDict
Timer.mGlobalDict = mGlobalDict
Timer.Processor.mGlobalDict = mGlobalDict
Server.mGlobalDict = mGlobalDict
Server.Processor.mGlobalDict = mGlobalDict
Processor.gSettingsDict = gSettingsDict
Timer.gSettingsDict = gSettingsDict
Timer.Processor.gSettingsDict = gSettingsDict
Server.gSettingsDict = gSettingsDict
Server.Processor.gSettingsDict = gSettingsDict
#Инициализация настроечных параметров
lDaemonLoopSeconds=mGlobalDict["Scheduler"]["ActivityTimeCheckLoopSeconds"]
lDaemonLoopSeconds=gSettingsDict["Scheduler"]["ActivityTimeCheckLoopSeconds"]
lDaemonActivityLogDict={} #Словарь отработанных активностей, ключ - кортеж (<activityType>, <datetime>, <processPath || processName>, <processArgs>)
lDaemonStartDateTime=datetime.datetime.now()
#Инициализация сервера
lThreadServer = Server.RobotDaemonServer("ServerThread", mGlobalDict)
lThreadServer = Server.RobotDaemonServer("ServerThread", gSettingsDict)
lThreadServer.start()
# Init the RobotRDPActive in another thread
lRobotRDPActiveThread = threading.Thread(target= RobotRDPActive.RobotRDPActive, kwargs={"inGSettings":gSettingsDict})
lRobotRDPActiveThread.daemon = True # Run the thread in daemon mode.
lRobotRDPActiveThread.start() # Start the thread execution.
#Logging
mGlobalDict["Logger"].info("Scheduler loop init")
gSettingsDict["Logger"].info("Scheduler loop init")
# Выполнить активности при старте
for lActivityItem in gSettingsDict["OrchestratorStart"]["ActivityList"]:
Processor.ActivityListOrDict(lActivityItem)
#Вечный цикл
while True:
lCurrentDateTime = datetime.datetime.now()
#Циклический обход правил
lFlagSearchActivityType=True
for lIndex, lItem in enumerate(mGlobalDict["Scheduler"]["ActivityTimeList"]):
for lIndex, lItem in enumerate(gSettingsDict["Scheduler"]["ActivityTimeList"]):
#Проверка дней недели, в рамках которых можно запускать активность
lItemWeekdayList=lItem.get("WeekdayList", [0, 1, 2, 3, 4, 5, 6])
if lCurrentDateTime.weekday() in lItemWeekdayList:
@ -61,7 +70,7 @@ while True:
#Лог
lItemCopy = copy.deepcopy(lItem)
lItemCopy["DateTimeUTCStringStart"]=datetime.datetime.strftime(datetime.datetime.now(),"%Y-%m-%dT%H:%M:%S.%f")
mGlobalDict["Scheduler"]["LogList"].append(lItemCopy)
gSettingsDict["Scheduler"]["LogList"].append(lItemCopy)
#######################################################################
#Branch 1 - if has TimeHH:MM
#######################################################################

@ -29,6 +29,11 @@ import psutil
# "Value": <List, Dict, String, int>
# },
# {
# "Type": "GlobalDictKeyListValueAppend",
# "KeyList": ["key1","key2",...],
# "Value": <List, Dict, String, int>
# },
# {
# "Type": "GlobalDictKeyListValueGet",
# "KeyList": ["key1","key2",...]
# },
@ -72,9 +77,10 @@ import psutil
# "DateTimeUTCStringStart"
# "DateTimeUTCStringStop"
# "Result"
gSettingsDict = None
def Activity(inActivity):
#Глобальная переменная - глобальный словарь унаследованный от Settings.py
global mGlobalDict
global gSettingsDict
#Fill DateTimeUTCStringStart
inActivity["DateTimeUTCStringStart"] = datetime.datetime.strftime(datetime.datetime.now(),"%Y-%m-%dT%H:%M:%S.%f")
#Alias (compatibility)
@ -113,7 +119,7 @@ def Activity(inActivity):
#Обработка команды GlobalDictKeyListValueSet
###########################################################
if lItem["Type"]=="GlobalDictKeyListValueSet":
lDict = mGlobalDict
lDict = gSettingsDict
for lItem2 in lItem["KeyList"][:-1]:
#Check if key - value exists
if lItem2 in lDict:
@ -125,10 +131,25 @@ def Activity(inActivity):
lDict[lItem["KeyList"][-1]]=lItem["Value"]
lItem["Result"] = True
###########################################################
# Обработка команды GlobalDictKeyListValueAppend
###########################################################
if lItem["Type"] == "GlobalDictKeyListValueAppend":
lDict = gSettingsDict
for lItem2 in lItem["KeyList"][:-1]:
# Check if key - value exists
if lItem2 in lDict:
pass
else:
lDict[lItem2] = {}
lDict = lDict[lItem2]
# Set value
lDict[lItem["KeyList"][-1]].append(lItem["Value"])
lItem["Result"] = True
###########################################################
#Обработка команды GlobalDictKeyListValueGet
###########################################################
if lItem["Type"]=="GlobalDictKeyListValueGet":
lDict = mGlobalDict
lDict = gSettingsDict
for lItem2 in lItem["KeyList"][:-1]:
#Check if key - value exists
if lItem2 in lDict:
@ -147,7 +168,7 @@ def Activity(inActivity):
#Вид активности - запуск процесса
#Запись в массив отработанных активностей
#Лог
mGlobalDict["Processor"]["LogList"].append({"activityType":lItem["Type"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["Path"], "activityStartDateTime":str(lCurrentDateTime)})
gSettingsDict["Processor"]["LogList"].append({"activityType":lItem["Type"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["Path"], "activityStartDateTime":str(lCurrentDateTime)})
#Запустить процесс
lItemArgs=[lItem["Path"]]
lItemArgs.extend(lItem["ArgList"])
@ -169,7 +190,7 @@ def Activity(inActivity):
#Вид активности - запуск процесса
#Запись в массив отработанных активностей
#Лог
mGlobalDict["Processor"]["LogList"].append({"activityType":lItem["Type"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["Path"], "activityStartDateTime":str(lCurrentDateTime)})
gSettingsDict["Processor"]["LogList"].append({"activityType":lItem["Type"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["Path"], "activityStartDateTime":str(lCurrentDateTime)})
#Запустить процесс
lItemArgs=[lItem["Path"]]
lItemArgs.extend(lItem["ArgList"])
@ -189,7 +210,7 @@ def Activity(inActivity):
if lItem.get('User',"")!="":
lActivityCloseCommand+=f' /fi "username eq {lItem["User"]}"'
#Лог
mGlobalDict["Processor"]["LogList"].append({"activityType":lItem["Type"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["Name"], "activityStartDateTime":str(lCurrentDateTime)})
gSettingsDict["Processor"]["LogList"].append({"activityType":lItem["Type"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["Name"], "activityStartDateTime":str(lCurrentDateTime)})
#Завершить процесс
os.system(lActivityCloseCommand)
#################################
@ -228,9 +249,9 @@ def Activity(inActivity):
#Trace activity
##################
#print(mGlobalDict)
if mGlobalDict["Processor"].get(f"LogType_{lItem['Type']}",True):
if gSettingsDict["Processor"].get(f"LogType_{lItem['Type']}", True):
#Add activity in TransactionList if it is applicable
mGlobalDict["Processor"]["LogList"].append(copy.deepcopy(lItem))
gSettingsDict["Processor"]["LogList"].append(copy.deepcopy(lItem))
#Вернуть результат
return lItem

@ -0,0 +1,26 @@
import os # Get abs path of the file
# Create CMD str to run file if process.exe is not running
def ProcessStartIfNotRunning(inProcessName, inFilePath, inFlagGetAbsPath=True):
lFileAbsPath = inFilePath
if inFlagGetAbsPath:
lFileAbsPath = os.path.abspath(inFilePath)
lResult = f'tasklist /nh /fi "imagename eq {inProcessName}" | find /i "{inProcessName}" > nul || (start {lFileAbsPath})'
return lResult
# Create CMD str to stop process
def ProcessStop(inProcessName, inFlagForceClose):
lResult = f'taskkill /im "{inProcessName}" /fi "username eq %USERNAME%"'
if inFlagForceClose:
lResult+= " /F"
return lResult
# Send file from Host to Session RDP using shared drive in RDP (force copy)
def FileStoredSend(inHostFilePath, inRDPFilePath):
lHostFileAbsPath = os.path.join("\\\\tsclient", os.path.abspath(inHostFilePath).replace(":","")) # \\tsclient\C\path\to\file
lHostRDPFileAbsPath = os.path.abspath(inRDPFilePath) # File location in RDP
lResult = f'copy /Y "{lHostFileAbsPath}" "{lHostRDPFileAbsPath}"'
return lResult
# Send file from Session RDP to Host using shared drive in RDP (force copy)
def FileStoredRecieve(inRDPFilePath, inHostFilePath):
lHostFileAbsPath = os.path.join("\\\\tsclient", os.path.abspath(inHostFilePath).replace(":","")) # \\tsclient\C\path\to\file
lHostRDPFileAbsPath = os.path.abspath(inRDPFilePath) # File location in RDP
lResult = f'copy /Y "{lHostRDPFileAbsPath}" "{lHostFileAbsPath}"'
return lResult

@ -0,0 +1,40 @@
import win32clipboard
import keyboard # keyboard functions
import time # Some operations need wait
import random # random number for test
gWaitTextInClipboardSec = 1 # Second for wait text will be set in clipboard (for get operations)
# set clipboard data
def TextSet(inTextStr):
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText(inTextStr)
win32clipboard.CloseClipboard()
# get clipboard data
def TextGet(inWaitTextInClipboardSec = gWaitTextInClipboardSec):
time.sleep(inWaitTextInClipboardSec) # Wait for clipboard will save
win32clipboard.OpenClipboard()
data = win32clipboard.GetClipboardData()
win32clipboard.CloseClipboard()
return data
# Test in has text cursor and ready to apply
def InputIsFocused():
keyboard.press_and_release("ctrl+a")
keyboard.press_and_release("backspace") # remove old text
lTextForTest = str(random.randrange(100,99999))
keyboard.write(lTextForTest)
keyboard.press_and_release("ctrl+a")
keyboard.press_and_release("ctrl+c")
time.sleep(2)
keyboard.press_and_release("backspace") # remove old text
lClipboardText = TextGet()
lResult = lClipboardText == lTextForTest
return lResult
# Check if cmd is opened
def CMDIsOpen():
lTextForTest = str(random.randrange(100,99999))
keyboard.write(lTextForTest+" |clip")
keyboard.press_and_release("enter")
time.sleep(2)
lClipboardText = TextGet()
lResult = lClipboardText == lTextForTest
return lResult

@ -0,0 +1,308 @@
#Import parent folder to import current / other packages
from pyOpenRPA.Robot import UIDesktop #Lib to access RDP window
from . import ConnectorExceptions # Exceptions classes
import os #os for process run
import uuid #temp id for Template.rdp
import tempfile #Temporary location
import subprocess
from . import Clipboard # Clipboard functions get/set
import keyboard # Keyboard functions
import time
import random # random integers
from win32api import GetSystemMetrics # Get Screen rect
#Connect to RDP session
"""
{
"Host": "", #Host address
"Port": "", #RDP Port
"Login": "", # Login
"Password": "", #Password
"Screen": {
"Resolution":"FullScreen", #"640x480" or "1680x1050" or "FullScreen". If Resolution not exists set full screen
"FlagUseAllMonitors": False, # True or False
"DepthBit":"" #"32" or "24" or "16" or "15"
}
}
"""
def Session(inRDPSessionConfiguration):
#RDPConnector.SessionConnect(mConfiguration)
#RDPConnector.LoginPassSet("111.222.222.111","ww","dd")
(lRDPFile, lSessionHex) = SessionConfigurationCreate(inRDPSessionConfiguration)
#Set session hex in globalDict
inRDPSessionConfiguration["SessionHex"] = lSessionHex
#Set login/password
SessionLoginPasswordSet(inRDPSessionConfiguration["Host"],inRDPSessionConfiguration["Login"],inRDPSessionConfiguration["Password"])
#Start session
SessionRDPStart(lRDPFile)
#Remove temp file
time.sleep(4) #Delete file after some delay - one way to delete and run the RDP before because RDP is not read file in one moment
os.remove(lRDPFile) # delete the temp rdp
# Set the result
return inRDPSessionConfiguration
#Add login/ password to the windows credentials to run RDP
def SessionLoginPasswordSet(inHost, inLogin, inPassword):
#Clear old login/password if it exists
#os.system(f"cmdkey /delete:TERMSRV/{inHost}") #Dont need to delete because new user password will clear the previous creds
#Set login password for host
os.system(f'cmdkey /generic:TERMSRV/{inHost} /user:{inLogin} /pass:"{inPassword}"')
return None
#Create current .rdp file with settings
#Return (full path to file, session hex)
def SessionConfigurationCreate(inConfiguration):
#RobotRDPActive folder path
lFileFullPath=__file__
lFileFullPath = lFileFullPath.replace("/","\\")
lRobotRDPActiveFolderPath = "\\".join(lFileFullPath.split("\\")[:-1])
#Full path to Template.rdp file
lRDPTemplateFileFullPath = os.path.join(lRobotRDPActiveFolderPath, "Template.rdp")
#Open template file (.rdp encoding is USC-2 LE BOM = UTF-16 LE) http://qaru.site/questions/7156020/python-writing-a-ucs-2-little-endian-utf-16-le-file-with-bom
lRDPTemplateFileContent = open(lRDPTemplateFileFullPath, "r", encoding="utf-16-le").read()
#Prepare host:port
lHostPort=inConfiguration['Host']
if 'Port' in inConfiguration:
if inConfiguration['Port']:
lHostPort=f"{lHostPort}:{inConfiguration['Port']}"
# Generate parameter for .rdp "drivestoredirect:s:C:\;"
lDriveStoreDirectStr = ""
for lItem in inConfiguration['SharedDriveList']:
lDriveStoreDirectStr+=f"{lItem.upper()}:\\;" # Attention - all drives must be only in upper case!!!
#Replace {Width}, {Height}, {BitDepth}, {HostPort}, {Login}
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{Width}", str(inConfiguration.get('Screen',{}).get("Width",1680)))
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{Height}", str(inConfiguration.get('Screen',{}).get("Height",1050)))
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{BitDepth}", inConfiguration.get('Screen',{}).get("DepthBit","32"))
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{HostPort}", lHostPort)
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{Login}", inConfiguration['Login'])
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{SharedDriveList}", lDriveStoreDirectStr)
#Save template to temp file
lRDPCurrentFileFullPath = os.path.join(tempfile.gettempdir(), f"{uuid.uuid4().hex}.rdp")
open(lRDPCurrentFileFullPath, "w", encoding="utf-16-le").write(lRDPTemplateFileContent)
#Return .rdp full path
return (lRDPCurrentFileFullPath, (lRDPCurrentFileFullPath.split("\\")[-1])[0:-4])
#RDPSessionStart
def SessionRDPStart(inRDPFilePath):
#Disable certificate warning
lCMDString = 'reg add "HKEY_CURRENT_USER\\Software\\Microsoft\\Terminal Server Client" /v "AuthenticationLevelOverride" /t "REG_DWORD" /d 0 /f'
os.system(lCMDString)
#run rdp session
lItemArgs = [inRDPFilePath]
subprocess.Popen(lItemArgs, shell=True)
#Wait for UAC unknown publisher exists
lRDPFileName = (inRDPFilePath.split("\\")[-1])[0:-4]
lWaitResult = UIDesktop.UIOSelectorsSecs_WaitAppear_List(
[
[{"title": "Подключение к удаленному рабочему столу", "class_name": "#32770", "backend": "win32"},
{"title": "Боль&ше не выводить запрос о подключениях к этому компьютеру", "friendly_class_name": "CheckBox"}],
[{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "D&on't ask me again for connections to this computer",
"friendly_class_name": "CheckBox"}],
[{"title_re": f"{lRDPFileName}.*",
"class_name": "TscShellContainerClass", "backend": "win32"},{"depth_start":3, "depth_end": 3, "class_name":"UIMainClass"}]
],
30
)
#Enable certificate warning
lCMDString = 'reg add "HKEY_CURRENT_USER\\Software\\Microsoft\\Terminal Server Client" /v "AuthenticationLevelOverride" /t "REG_DWORD" /d 2 /f'
os.system(lCMDString)
#Click if 0 is appear (RUS)
if 0 in lWaitResult:
#Check the box do not retry
UIDesktop.UIOSelector_Get_UIO([{"title": "Подключение к удаленному рабочему столу", "backend": "win32"},
{"title": "Боль&ше не выводить запрос о подключениях к этому компьютеру", "friendly_class_name": "CheckBox"}]).check()
#Go to connection
UIDesktop.UIOSelector_Get_UIO([{"title": "Подключение к удаленному рабочему столу", "backend": "win32"},
{"title":"Подкл&ючить", "class_name":"Button"}]).click()
lWaitResult = UIDesktop.UIOSelectorsSecs_WaitAppear_List(
[
[{"title_re": f"{lRDPFileName}.*",
"class_name": "TscShellContainerClass", "backend": "win32"}]
],
30
)
# Click if 1 is appear (ENG)
if 1 in lWaitResult:
# Check the box do not retry
UIDesktop.UIOSelector_Get_UIO([{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "D&on't ask me again for connections to this computer",
"friendly_class_name": "CheckBox"}]).check()
# Go to connection
UIDesktop.UIOSelector_Get_UIO([{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "Co&nnect", "class_name": "Button"}]).click()
lWaitResult = UIDesktop.UIOSelectorsSecs_WaitAppear_List(
[
[{"title_re": f"{lRDPFileName}.*",
"class_name": "TscShellContainerClass", "backend": "win32"}]
],
30
)
# Raise exception if RDP is not active
if len(lWaitResult) == 0:
raise ConnectorExceptions.SessionWindowNotExistError("Error when initialize the RDP session - No RDP windows has appreared!")
# Wait for init
time.sleep(3)
SessionScreenSize_X_Y_W_H(inSessionHex = lRDPFileName, inXInt = 10, inYInt = 10, inWInt = 550, inHInt = 350) #Prepare little window
return None
#Set fullscreen for app
def SessionScreenFull(inSessionHex):
#Prepare little window
try:
lRDPWindow = UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHex}.*", "backend": "win32"}])
except Exception as e:
return None
lRDPWindow.set_focus()
lRDPWindow.maximize()
#time.sleep(0.5)
if not SessionIsFullScreen(inSessionHex):
lRDPWindow.type_keys("^%{BREAK}")
time.sleep(0.5)
return None
# Set the screen size
def SessionScreenSize_X_Y_W_H(inSessionHex, inXInt, inYInt, inWInt, inHInt):
lDoBool = True
while lDoBool:
#Prepare little window
try:
lRDPWindow = UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHex}.*", "backend": "win32"}])
except Exception as e:
return None
try:
lRDPWindow.set_focus()
if SessionIsFullScreen(inSessionHex):
lRDPWindow.type_keys("^%{BREAK}")
time.sleep(0.5)
lRDPWindow.restore()
time.sleep(0.5)
lRDPWindow.move_window(inXInt,inYInt,inWInt,inHInt)
except Exception as e:
time.sleep(1)
else:
lDoBool = False
return None
# Set Little window of the session
def SessionScreen100x550(inSessionHex):
SessionScreenSize_X_Y_W_H(inSessionHex = inSessionHex, inXInt = 10, inYInt = 10, inWInt = 550, inHInt = 100)
return None
# Session - close window
def SessionClose(inSessionHexStr):
#Close window
try:
UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHexStr}.*", "backend": "win32"}]).close()
except Exception as e:
pass
#Type command in CMD
# inSessionHex - SessionHex to catch window
# inModeStr "LISTEN", "CROSSCHECK", "RUN"
# "LISTEN" - Get result of the cmd command in result TODO get home script
# "CROSSCHECK" - Check if the command was successufully sent TODO get home script
# "RUN" - Run without crosscheck and get clipboard
# return {
# "OutStr": <> # Result string
# "IsResponsibleBool": True|False # Flag is RDP is responsible - works only when inModeStr = CROSSCHECK
# }
# example Connector.SessionCMDRun("4d1e48f3ff6c45cc810ea25d8adbeb50","start notepad", "RUN")
def SessionCMDRun(inSessionHex,inCMDCommandStr = "echo 1", inModeStr="CROSSCHECK", inClipboardTimeoutSec = 5):
# Init the result dict
lResult = {"OutStr": None,"IsResponsibleBool":True}
# Enter full screen mode
SessionScreenFull(inSessionHex)
time.sleep(2)
# Run CMD operations
lResult = SystemCMDRun(inCMDCommandStr = inCMDCommandStr, inModeStr = inModeStr, inClipboardTimeoutSec = inClipboardTimeoutSec)
# Exit fullscreen mode
SessionScreenSize_X_Y_W_H(inSessionHex=inSessionHex, inXInt=10, inYInt=10, inWInt=550,
inHInt=350) # Prepare little window
# Check if session is in Full screen mode
# Return True - is in fullscreen
# example print(Connector.SessionIsFullScreen(""))
def SessionIsFullScreen(inSessionHexStr):
#Default resul
lResult = False
lWeight = GetSystemMetrics(0)
lHeight = GetSystemMetrics(1)
#Get window screen
try:
lRectangle = UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHexStr}.*", "backend": "win32"}]).rectangle()
except Exception as e:
return lResult
# Get Height/Weight
lSessionWeight = lRectangle.right - lRectangle.left
lSessionHeight = lRectangle.bottom - lRectangle.top
#Case fullscreen
if lSessionHeight == lHeight and lSessionWeight == lWeight:
lResult = True
return lResult
# Check if RDP session is responsible (check with random combination in cmd)
# Attention - function will be work fine if RDP will be in full screen mode!!! (see def SessionScreenFull)
# Return True - is responsible; False - is not responsible
#Type command in CMD
# inFlagDoCrossCheck: True - Do check that CMD is executed (the text response will not be available)
# inModeStr "LISTEN", "CROSSCHECK", "RUN"
# "LISTEN" - Get result of the cmd command in result TODO get home script
# "CROSSCHECK" - Check if the command was successufully sent TODO get home script
# "RUN" - Run without crosscheck and get clipboard
# inClipboardTimeoutSec # Second for wait when clipboard will changed
# return {
# "OutStr": <> # Result string
# "IsResponsibleBool": True|False # Flag is RDP is responsible - works only when inModeStr = CROSSCHECK
# }
# example Connector.SessionCMDRun("4d1e48f3ff6c45cc810ea25d8adbeb50","start notepad", "RUN")
def SystemCMDRun(inCMDCommandStr = "echo 1", inModeStr="CROSSCHECK", inClipboardTimeoutSec = 5):
# Set random text to clipboard (for check purposes that clipboard text has been changed)
lClipboardTextOld = str(random.randrange(999,9999999))
Clipboard.TextSet(lClipboardTextOld)
# Init the result dict
lResult = {"OutStr": None,"IsResponsibleBool":True}
lCrosscheckKeyStr = str(random.randrange(999,9999999))
lCMDPostFixStr = "" # Case default "RUN"
if inModeStr == "CROSSCHECK":
lCMDPostFixStr = f"| echo {lCrosscheckKeyStr} | clip"
elif inModeStr == "LISTEN":
lCMDPostFixStr = f"| clip"
keyboard.press_and_release('win+r')
time.sleep(1)
# Remove old text
keyboard.press_and_release("ctrl+a")
keyboard.press_and_release("backspace")
# Write new text
keyboard.write(f"cmd /c {inCMDCommandStr} {lCMDPostFixStr}")
time.sleep(1)
# TODo cross check from clipboard
keyboard.press_and_release('enter')
# Get OutStr (Case CROSSCHECK and LISTEN)
if inModeStr == "CROSSCHECK" or inModeStr == "LISTEN":
lClipboardWaitTimeStartSec = time.time()
lResult["OutStr"] = Clipboard.TextGet() # Get text from clipboard
while lResult["OutStr"] == lClipboardTextOld and (time.time() - lClipboardWaitTimeStartSec) <= inClipboardTimeoutSec:
lResult["OutStr"] = Clipboard.TextGet() # Get text from clipboard
time.sleep(0.5) # wait some time for the next operation
# Do crosscheck
if inModeStr == "CROSSCHECK":
if lResult["OutStr"] == f"{lCrosscheckKeyStr} \r\n\x00\x00\x00\x00\x00":
lResult["IsResponsibleBool"] = True
else:
lResult["IsResponsibleBool"] = False
# return the result
return lResult
# Check if current RDP is responsible
def SystemRDPIsResponsible():
return SystemCMDRun(inCMDCommandStr = "echo 1", inModeStr="CROSSCHECK")["IsResponsibleBool"]
# Click OK on error messages
def SystemRDPWarningClickOk():
# Try to click OK Error window in RUS version
while UIDesktop.UIOSelector_Exist_Bool([{"title": "Подключение к удаленному рабочему столу", "class_name": "#32770", "backend": "win32"},
{"title": "ОК", "class_name": "Button"}]):
try:
UIDesktop.UIOSelector_Get_UIO([{"title": "Подключение к удаленному рабочему столу", "class_name": "#32770", "backend": "win32"},
{"title": "ОК", "class_name": "Button"}]).click()
except Exception as e:
pass
# Try to click OK Error window in ENG version
while UIDesktop.UIOSelector_Exist_Bool([{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "OK", "class_name": "Button"}]):
try:
UIDesktop.UIOSelector_Get_UIO([{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "OK", "class_name": "Button"}]).click()
except Exception as e:
pass

@ -0,0 +1,10 @@
#####################################
# RobotRDPActive Exceptions class
#####################################
class SessionWindowNotExistError(Exception): pass #Error when Window not exists
class SessionWindowNotResponsibleError(Exception): pass # Error when Window not responding
class HostNoGUIError(Exception): pass # Orchestrator session has no GUI
#try:
# raise SessionWindowNotResponsibleError("Test")
#except SessionWindowNotResponsibleError as e:
# print("Catched")

@ -0,0 +1,66 @@
# ATTENTION! HERE IS NO Relative import because it will be imported dynamically
# All function check the flag SessionIsWindowResponsibleBool == True else no cammand is processed
# All functions can return None, Bool or Dict { "IsSuccessful": True }
from pyOpenRPA.Tools.RobotRDPActive import CMDStr # Create CMD Strings
from pyOpenRPA.Tools.RobotRDPActive import Connector # RDP API
def ProcessStartIfNotRunning(inGlobalDict, inSessionIndex, inProcessName, inFilePath, inFlagGetAbsPath=True):
lResult = True
lCMDStr = CMDStr.ProcessStartIfNotRunning(inProcessName,inFilePath, inFlagGetAbsPath= inFlagGetAbsPath)
# Calculate the session Hex
lSessionHex = inGlobalDict["RDPList"][inSessionIndex]["SessionHex"]
# Check is Session is responsible
if inGlobalDict["RDPList"][inSessionIndex]["SessionIsWindowResponsibleBool"]:
# Run CMD
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
else:
# Write in logger - warning
inGlobalDict["Logger"].warning(f"GlobalDictSessionIndex_Defs.ProcessStartIfNotRunning: SessionIndex: {str(inSessionIndex)}, ProcessName: {inProcessName}:: Session is not responsible!")
lResult = False # Set false result - function has not been done
return lResult
# Create CMD str to stop process
def ProcessStop(inGlobalDict, inSessionIndex, inProcessName, inFlagForceClose):
lResult = True
lCMDStr = f'taskkill /im "{inProcessName}" /fi "username eq %USERNAME%"'
if inFlagForceClose:
lCMDStr+= " /F"
# Calculate the session Hex
lSessionHex = inGlobalDict["RDPList"][inSessionIndex]["SessionHex"]
# Check is Session is responsible
if inGlobalDict["RDPList"][inSessionIndex]["SessionIsWindowResponsibleBool"]:
# Run CMD
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
else:
# TODO Write in logger - warning
inGlobalDict["Logger"].warning(f"GlobalDictSessionIndex_Defs.ProcessStop: SessionIndex: {str(inSessionIndex)}, ProcessName: {inProcessName}:: Session is not responsible!")
lResult = False # Set false result - function has not been done
return lResult
# Send file from Host to Session RDP using shared drive in RDP
def FileStoredSend(inGlobalDict, inSessionIndex, inHostFilePath, inRDPFilePath):
lResult = True
lCMDStr = CMDStr.FileStoredSend(inHostFilePath = inHostFilePath, inRDPFilePath = inRDPFilePath)
# Calculate the session Hex
lSessionHex = inGlobalDict["RDPList"][inSessionIndex]["SessionHex"]
# Check is Session is responsible
if inGlobalDict["RDPList"][inSessionIndex]["SessionIsWindowResponsibleBool"]:
# Run CMD
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120)
else:
# Write in logger - warning
inGlobalDict["Logger"].warning(f"GlobalDictSessionIndex_Defs.FileStoredSend: SessionIndex: {str(inSessionIndex)}, HostFilePath: {inHostFilePath}:: Session is not responsible!")
lResult = False # Set false result - function has not been done
return lResult
# Recieve file from Session RDP to Host using shared drive in RDP
def FileStoredRecieve(inGlobalDict, inSessionIndex, inRDPFilePath, inHostFilePath):
lResult = True
lCMDStr = CMDStr.FileStoredRecieve(inRDPFilePath = inRDPFilePath, inHostFilePath = inHostFilePath)
# Calculate the session Hex
lSessionHex = inGlobalDict["RDPList"][inSessionIndex]["SessionHex"]
# Check is Session is responsible
if inGlobalDict["RDPList"][inSessionIndex]["SessionIsWindowResponsibleBool"]:
# Run CMD
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120)
else:
# Write in logger - warning
inGlobalDict["Logger"].warning(f"GlobalDictSessionIndex_Defs.FileStoredRecieve: SessionIndex: {str(inSessionIndex)}, HostFilePath: {inHostFilePath}:: Session is not responsible!")
lResult = False # Set false result - function has not been done
return lResult

@ -0,0 +1,158 @@
from pyOpenRPA.Robot import UIDesktop
from . import Connector
import os
import time # Time wait operations
import importlib # from dynamic import module
from . import ConnectorExceptions # Exceptions classes
#Check for session is closed. Reopen if detected. Always keep session is active
def Monitor(inGlobalDict, inListUpdateTimeout):
lFlagWhile = True
lResponsibilityCheckLastSec = time.time() # Get current time for check interval
while lFlagWhile:
try:
# UIOSelector list init
lUIOSelectorList = []
#Prepare selectors list for check
for lIndex, lItem in enumerate(inGlobalDict["RDPList"]):
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']}.*", "backend": "win32"}])
#Run wait command
#import pdb
#pdb.set_trace()
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
#print(lRDPDissappearList)
###########################################
#Analyze if flag safeturn off is activated
if inGlobalDict.get("OrchestratorToRobotResetStorage",{}).get("SafeTurnOff",False):
lFlagWhile=False
#Set status disconnected for all RDP List
for lItem in inGlobalDict["RDPList"]:
lItem["SessionIsWindowExistBool"]=False
lItem["SessionIsWindowResponsibleBool"]=False
#Kill all RDP sessions
os.system('taskkill /F /im mstsc.exe')
#Return from function
return
###########################################
###########################################
for lItem in lRDPDissappearList:
inGlobalDict["RDPList"][lItem]["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
inGlobalDict["RDPList"][lItem]["SessionIsWindowResponsibleBool"]=False
#pdb.set_trace()
#Session start if it is not in ignore list
#add check for selector if it is not in ignoreIndexList
if lItem not in inGlobalDict["OrchestratorToRobotStorage"]["IgnoreIndexList"]:
try:
Connector.Session(inGlobalDict["RDPList"][lItem])
inGlobalDict["RDPList"][lItem]["SessionIsWindowExistBool"] = True # Flag that session is started
inGlobalDict["RDPList"][lItem]["SessionIsWindowResponsibleBool"]= True
# Write in logger - info
inGlobalDict["Logger"].info(f"SessionHex: {str(inGlobalDict['RDPList'][lItem]['SessionHex'])}:: Session has been initialized!")
# catch ConnectorExceptions.SessionWindowNotExistError
except ConnectorExceptions.SessionWindowNotExistError as e:
inGlobalDict["RDPList"][lItem]["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
inGlobalDict["RDPList"][lItem]["SessionIsWindowResponsibleBool"]=False
# Write in logger - warning
inGlobalDict["Logger"].warning(f"SessionHex: {str(inGlobalDict['RDPList'][lItem]['SessionHex'])}:: Session is not exist!")
# catch ConnectorExceptions.SessionWindowNotResponsibleError
except ConnectorExceptions.SessionWindowNotResponsibleError as e:
inGlobalDict["RDPList"][lItem]["SessionIsWindowExistBool"] = True # Set flag that session is disconnected
inGlobalDict["RDPList"][lItem]["SessionIsWindowResponsibleBool"]=False
# Write in logger - warning
inGlobalDict["Logger"].warning(f"SessionHex: {str(inGlobalDict['RDPList'][lItem]['SessionHex'])}:: Session is not responsible!")
# general exceptions
except Exception as e:
# Write in logger - warning
inGlobalDict["Logger"].exception(f"!!! ATTENTION !!! Unrecognized error")
#######################
# Click all warning messages
Connector.SystemRDPWarningClickOk()
#######################
###########################################
#Check if from Orchestrator full screen session is set
if inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"] != inGlobalDict["FullScreenSessionIndex"]:
#Do some switches
#If full screen mode we have now
if inGlobalDict["FullScreenSessionIndex"] is not None:
if inGlobalDict["RDPList"][inGlobalDict["FullScreenSessionIndex"]]["SessionIsWindowExistBool"]:
Connector.SessionScreen100x550(inGlobalDict["RDPList"][inGlobalDict["FullScreenSessionIndex"]]["SessionHex"])
#If new session is setted
if inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"] is not None:
if inGlobalDict["RDPList"][inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]]["SessionIsWindowExistBool"]:
Connector.SessionScreenFull(inGlobalDict["RDPList"][inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]]["SessionHex"])
#Set one to other equal
inGlobalDict["FullScreenSessionIndex"] = inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]
###########################################
####################################
##### Block check responsibility interval [ResponsibilityCheckIntervalSec]
if inGlobalDict['ResponsibilityCheckIntervalSec']: # Do check if ResponsibilityCheckIntervalSec is not None
if (time.time - lResponsibilityCheckLastSec()) > inGlobalDict['ResponsibilityCheckIntervalSec']:
# Set new time
lResponsibilityCheckLastSec = time.time()
# Do responsibility check
for lIndex, lItem in enumerate(inGlobalDict["RDPList"]):
# Check RDP responsibility
lDoCheckResponsibilityBool = True
lDoCheckResponsibilityCountMax = 20
lDoCheckResponsibilityCountCurrent = 0
while lDoCheckResponsibilityBool:
# Enter full screen mode
Connector.SessionScreenFull(lItem['SessionHex'])
time.sleep(2)
# Check responding
lDoCheckResponsibilityBool = not Connector.SystemRDPIsResponsible()
# Check if counter is exceed - raise exception
if lDoCheckResponsibilityCountCurrent >= lDoCheckResponsibilityCountMax:
lItem["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
lItem["SessionIsWindowResponsibleBool"]=False
# Session window is not responsible - restart RDP (close window here - next loop will reconnect)
Connector.SessionClose(lItem['SessionHex'])
# Turn off the loop
lDoCheckResponsibilityBool = False
else:
# Exit fullscreen mode
Connector.SessionScreen100x550(lItem['SessionHex'])
# Wait if is not responding
if lDoCheckResponsibilityBool:
time.sleep(3)
# increase the couter
lDoCheckResponsibilityCountCurrent+=1
####################################
# Check ActivityList from orchestrator
lActivityListNew = []
lActivityListOld = inGlobalDict["OrchestratorToRobotResetStorage"]["ActivityList"]+inGlobalDict["ActivityListStart"]
inGlobalDict["ActivityListStart"] = []
for lActivityItem in lActivityListOld:
#################
#Call function from Activity structure
################################################
lSubmoduleFunctionName = lActivityItem["DefName"]
lFileFullPath = lActivityItem["ModulePath"] # "path\\to\\module.py"
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)
# Set gSettings in module
lTechModuleFromSpec.gSettings = inGlobalDict
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
# Run SettingUpdate function in submodule
#mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
lActivityItemResult=getattr(lTechModuleFromSpec, lSubmoduleFunctionName)(*lActivityItem["ArgList"],**lActivityItem["ArgDict"])
lActivityItemResultType = type(lActivityItemResult)
# Check if Result is bool
if lActivityItemResultType is bool:
if not lActivityItemResult:
# Activity is not done - add to list (retry in future)
lActivityListNew.append(lActivityItem)
#################################################
inGlobalDict["OrchestratorToRobotResetStorage"]["ActivityList"] = lActivityListNew # Override the value
except RuntimeError as e:
# case noGUI error passed - do nothing
# Write in logger - warning
inGlobalDict["Logger"].warning(f"Host session has lost the GUI")
finally:
# Wait for the next iteration
time.sleep(0.7)
return None
#TODO Def garbage window cleaner (if connection was lost)

@ -0,0 +1,147 @@
# ATTENTION! HERE IS NO Relative import because it will be imported dynamically
# All function check the flag SessionIsWindowResponsibleBool == True else no cammand is processed
# All functions can return None, Bool or Dict { "IsSuccessful": True }
from . import CMDStr # Create CMD Strings
from . import Connector # RDP API
from . import ConnectorExceptions # Exceptions
import time # sleep function
# ATTENTION
gSettings = None # Gsettings will be initialized after the import module
# Create new RDPSession in RobotRDPActive
def RDPSessionConnect(inRDPSessionKeyStr, inHostStr, inPortStr, inLoginStr, inPasswordStr):
lRDPConfigurationItem = { # Init the configuration item
"Host": inHostStr, # Host address, example "77.77.22.22"
"Port": inPortStr, # RDP Port, example "3389"
"Login": inLoginStr, # Login, example "test"
"Password": inPasswordStr, # Password, example "test"
"Screen": {
"Width": 1680, # Width of the remote desktop in pixels, example 1680
"Height": 1050, # Height of the remote desktop in pixels, example 1050
# "640x480" or "1680x1050" or "FullScreen". If Resolution not exists set full screen, example
"FlagUseAllMonitors": False, # True or False, example False
"DepthBit": "32" # "32" or "24" or "16" or "15", example "32"
},
"SharedDriveList": ["c"], # List of the Root sesion hard drives, example ["c"]
###### Will updated in program ############
"SessionHex": "77777sdfsdf77777dsfdfsf77777777", # Hex is created when robot runs, example ""
"SessionIsWindowExistBool": False, # Flag if the RDP window is exist, old name "FlagSessionIsActive". Check every n seconds , example False
"SessionIsWindowResponsibleBool": False, # Flag if RDP window is responsible (recieve commands). Check every nn seconds. If window is Responsible - window is Exist too , example False
"SessionIsIgnoredBool": False # Flag to ignore RDP window False - dont ignore, True - ignore, example False
}
# Add item in RDPList
gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr] = lRDPConfigurationItem
# Create the RDP session
Connector.Session(lRDPConfigurationItem)
return True
# Disconnect the RDP session
def RDPSessionDisconnect(inRDPSessionKeyStr):
global gSettings
lSessionHex = gSettings["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
if lSessionHex:
gSettings["RobotRDPActive"]["RDPList"].pop(inRDPSessionKeyStr,None)
Connector.SessionClose(inSessionHexStr=lSessionHex)
return True
# RDP Session reconnect
def RDPSessionReconnect(inRDPSessionKeyStr):
global gSettings
lRDPConfigurationItem = gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr]
RDPSessionDisconnect(inRDPSessionKeyStr=inRDPSessionKeyStr) # Disconnect the RDP
# Add item in RDPList
gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr] = lRDPConfigurationItem
# Create the RDP session
Connector.Session(lRDPConfigurationItem)
return True
# Logoff the RDP session
def RDPSessionLogoff(inRDPSessionKeyStr):
global gSettings
lResult = True
lCMDStr = "shutdown -L" # CMD logoff command
# Calculate the session Hex
lSessionHex = gSettings["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
if lSessionHex:
gSettings["RobotRDPActive"]["RDPList"].pop(inRDPSessionKeyStr,None)
# Run CMD
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
return lResult
# Check RDP Session responsibility TODO NEED DEV + TEST
def RDPSessionResponsibilityCheck(inRDPSessionKeyStr):
global gSettings
inGlobalDict = gSettings
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr]["SessionHex"]
# set the fullscreen
Connector.SessionScreenFull(inSessionHex=lSessionHex)
time.sleep(1)
# Check RDP responsibility
lDoCheckResponsibilityBool = True
lDoCheckResponsibilityCountMax = 20
lDoCheckResponsibilityCountCurrent = 0
while lDoCheckResponsibilityBool:
# Check if counter is exceed - raise exception
if lDoCheckResponsibilityCountCurrent >= lDoCheckResponsibilityCountMax:
pass
#raise ConnectorExceptions.SessionWindowNotResponsibleError("Error when initialize the RDP session - RDP window is not responding!")
# Check responding
lDoCheckResponsibilityBool = not Connector.SystemRDPIsResponsible()
# Wait if is not responding
if lDoCheckResponsibilityBool:
time.sleep(3)
# increase the couter
lDoCheckResponsibilityCountCurrent+=1
return True
# Start process if it is not running
def RDPSessionProcessStartIfNotRunning(inRDPSessionKeyStr, inProcessNameWEXEStr, inFilePathStr, inFlagGetAbsPathBool=True):
global gSettings
inGlobalDict = gSettings
lResult = True
lCMDStr = CMDStr.ProcessStartIfNotRunning(inProcessNameWEXEStr, inFilePathStr, inFlagGetAbsPath= inFlagGetAbsPathBool)
# Calculate the session Hex
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
# Run CMD
if lSessionHex:
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
return lResult
# Create CMD str to stop process
def RDPSessionProcessStop(inRDPSessionKeyStr, inProcessNameWEXEStr, inFlagForceCloseBool):
global gSettings
inGlobalDict = gSettings
lResult = True
lCMDStr = f'taskkill /im "{inProcessNameWEXEStr}" /fi "username eq %USERNAME%"'
if inFlagForceCloseBool:
lCMDStr+= " /F"
# Calculate the session Hex
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
# Run CMD
if lSessionHex:
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
return lResult
# Send file from Host to Session RDP using shared drive in RDP
def RDPSessionFileStoredSend(inRDPSessionKeyStr, inHostFilePathStr, inRDPFilePathStr):
global gSettings
inGlobalDict = gSettings
lResult = True
lCMDStr = CMDStr.FileStoredSend(inHostFilePath = inHostFilePathStr, inRDPFilePath = inRDPFilePathStr)
# Calculate the session Hex
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr, {}).get("SessionHex", None)
#lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr]["SessionHex"]
# Run CMD
if lSessionHex:
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120)
return lResult
# Recieve file from Session RDP to Host using shared drive in RDP
def RDPSessionFileStoredRecieve(inRDPSessionKeyStr, inRDPFilePathStr, inHostFilePathStr):
global gSettings
inGlobalDict = gSettings
lResult = True
lCMDStr = CMDStr.FileStoredRecieve(inRDPFilePath = inRDPFilePathStr, inHostFilePath = inHostFilePathStr)
# Calculate the session Hex
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
# Run CMD
if lSessionHex:
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120)
return lResult

@ -0,0 +1,142 @@
from pyOpenRPA.Robot import UIDesktop
import os
import time # Time wait operations
from . import ConnectorExceptions # Exceptions classes
from . import Connector
from . import Processor # Module for process some functions on thr RDP
# Main function
def RobotRDPActive(inGSettings):
# inGSettings = {
# ... "RobotRDPActive": {} ...
# }
#import pdb
#pdb.set_trace()
lLogger = inGSettings["Logger"] # Synonim
Processor.gSettings = inGSettings # Set gSettings in processor module
mGSettingsRDPActiveDict = inGSettings["RobotRDPActive"] # Get configuration from global dict settings
# Global error handler
try:
######## Init the RDP List
for lRDPSessionKeyStrItem in mGSettingsRDPActiveDict["RDPList"]:
lConfigurationItem = mGSettingsRDPActiveDict["RDPList"][lRDPSessionKeyStrItem]
lConfigurationItem["SessionIsWindowExistBool"] = False # Flag that session is not started
lConfigurationItem["SessionIsWindowResponsibleBool"] = False # Flag that session is not started
lConfigurationItem["SessionHex"] = " 77777sdfsdf77777dsfdfsf77777777" # Flag that session is not started
##########
# Run monitor - main loop
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
inGlobalDict = mGSettingsRDPActiveDict # Compatibility
inListUpdateTimeout = 1 # Compatibility
lFlagWhile = True
lResponsibilityCheckLastSec = time.time() # Get current time for check interval
while lFlagWhile:
try:
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check RDP window is OK - reconnect if connection was lost
lUIOSelectorList = []
lRDPConfigurationDictList = []
# Prepare selectors list for check
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
lRDPConfigurationDictList.append(lItem) # Add RDP Configuration in list
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']}.*", "backend": "win32"}])
# Run wait command
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
for lItem in lRDPDissappearList: # Reconnect if connection was lost
lRDPConfigurationDict = lRDPConfigurationDictList[lItem] # Get RDP Configuration list
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
# Check if RDP window is not ignored
if not lRDPConfigurationDict["SessionIsIgnoredBool"]:
try:
Connector.Session(lRDPConfigurationDict)
lRDPConfigurationDict["SessionIsWindowExistBool"] = True # Flag that session is started
# Write in logger - info
lLogger.info(
f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session has been initialized!")
# catch ConnectorExceptions.SessionWindowNotExistError
except ConnectorExceptions.SessionWindowNotExistError as e:
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
# Write in logger - warning
lLogger.warning(
f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session is not exist!")
# general exceptions
except Exception as e:
# Write in logger - warning
lLogger.exception(f"!!! ATTENTION !!! Unrecognized error")
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Safe turn off the - no need because of Orchestrator control
#if inGlobalDict.get("OrchestratorToRobotResetStorage", {}).get("SafeTurnOff", False):
# lFlagWhile = False
# # Set status disconnected for all RDP List
# for lItem in inGlobalDict["RDPList"]:
# lItem["SessionIsWindowExistBool"] = False
# lItem["SessionIsWindowResponsibleBool"] = False
# # Kill all RDP sessions
# os.system('taskkill /F /im mstsc.exe')
# # Return from function
# return
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Connector.SystemRDPWarningClickOk() # Click all warning messages
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check if RDP session is full screen (if is not ignored)
if inGlobalDict["FullScreenRDPSessionKeyStr"] is not None:
lRDPSessionKeyStr = inGlobalDict["FullScreenRDPSessionKeyStr"] # Get the RDPSessionKeyStr
if lRDPSessionKeyStr in inGlobalDict["RDPList"]: # Session Key is in dict
lRDPConfigurationDict = inGlobalDict["RDPList"][lRDPSessionKeyStr]
#if not lRDPConfigurationDict["SessionIsIgnoredBool"]: # Session is not ignored
# Check if full screen
lIsFullScreenBool = Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDict["SessionHex"])
if not lIsFullScreenBool: # If not the full screen
# Check all RDP window and minimize it
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
if Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]):
Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"], inXInt=10, inYInt=10,
inWInt=550,
inHInt=350) # Prepare little window
# Set full screen for new window
Connector.SessionScreenFull(inSessionHex=lRDPConfigurationDict["SessionHex"])
else:
# Check all RDP window and minimize it
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
if Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]):
Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"],
inXInt=10, inYInt=10,
inWInt=550,
inHInt=350) # Prepare little window
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Iterate the activity list in robot RDP active
lActivityListNew = []
lActivityListOld = inGlobalDict["ActivityList"]
inGlobalDict["ActivityList"] = []
for lActivityItem in lActivityListOld:
lSubmoduleFunctionName = lActivityItem["DefNameStr"]
if lSubmoduleFunctionName in dir(Processor):
# Run SettingUpdate function in submodule
# mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
lActivityItemResult = getattr(Processor, lSubmoduleFunctionName)(
*lActivityItem["ArgList"], **lActivityItem["ArgDict"])
lActivityItemResultType = type(lActivityItemResult)
# Check if Result is bool
if lActivityItemResultType is bool:
if not lActivityItemResult:
# Activity is not done - add to list (retry in future)
lActivityListNew.append(lActivityItem)
inGlobalDict["ActivityList"] = lActivityListNew # Override the value
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
except RuntimeError as e:
# case noGUI error passed - do nothing
# Write in logger - warning
lLogger.warning(f"Host session has lost the GUI")
finally:
# Wait for the next iteration
time.sleep(0.7)
# Scheduler.Scheduler(mGSettingsRDPActiveDict["Scheduler"]) # Init & Run Scheduler TODO remake in processor list
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#Monitor.Monitor(mGSettingsRDPActiveDict, 1)
except Exception as e:
# Write in logger - warning
lLogger.exception(f"!!! ATTENTION !!! Global error handler - look at code")

@ -0,0 +1,111 @@
from . import Timer # Async thread
import threading # Create in another thread
import datetime # Datetime class
import time # time functions
import importlib # import lib functions
# Scheduler class - init and work by the configuration
# OOP
class Scheduler:
# Class properties
mSchedulerDict = None
mGSettings = None
#########################
# Init class
def __init__(self,inSchedulerDict, inGSettings = None):
self.Init(inSchedulerDict = inSchedulerDict, inGSettings = inGSettings)
# Init the class instance
def Init(self,inSchedulerDict, inGSettings):
self.mGSettings = inGSettings
self.mSchedulerDict = inSchedulerDict
# Init the threads
lTimerMainThread = threading.Thread(target = self.TimerMainThreadRun)
lTimerMainThread.start() # Start the Timer main thread
#print (f"Class instance configuration: {self.mSchedulerDict}, Init has been completed")
########################
# Main timer thread - run when init class instance
def TimerMainThreadRun(self):
lDaemonStartDateTime=datetime.datetime.now()
lDaemonLoopSeconds=self.mSchedulerDict["ActivityTimeCheckLoopSeconds"]
lDaemonActivityLogDict={} #Словарь отработанных активностей, ключ - кортеж (<activityType>, <datetime>, <processPath || processName>, <processArgs>)
#Вечный цикл
while True:
lCurrentDateTime = datetime.datetime.now()
#Циклический обход правил
lFlagSearchActivityType=True
for lIndex, lItem in enumerate(self.mSchedulerDict["ActivityTimeList"]):
#Проверка дней недели, в рамках которых можно запускать активность
lItemWeekdayList=lItem.get("WeekdayList", [0, 1, 2, 3, 4, 5, 6])
if lCurrentDateTime.weekday() in lItemWeekdayList:
if lFlagSearchActivityType:
#######################################################################
#Branch 1 - if has TimeHH:MM
#######################################################################
if "TimeHH:MM" in lItem:
#Вид активности - запуск процесса
#Сформировать временной штамп, относительно которого надо будет проверять время
#часовой пояс пока не учитываем
lActivityDateTime=datetime.datetime.strptime(lItem["TimeHH:MM"],"%H:%M")
lActivityDateTime=lActivityDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day)
#Убедиться в том, что время наступило
if (
lActivityDateTime>=lDaemonStartDateTime and
lCurrentDateTime>=lActivityDateTime and
(lIndex,lActivityDateTime) not in lDaemonActivityLogDict):
#Выполнить операцию
#Запись в массив отработанных активностей
lDaemonActivityLogDict[(lIndex,lActivityDateTime)]={"ActivityStartDateTime":lCurrentDateTime}
#Запустить процесс - new code
#################
#Call function from Activity structure
################################################
lSubmoduleFunctionName = lItem["Activity"]["DefName"]
lFileFullPath = lItem["Activity"]["ModulePath"] # "path\\to\\module.py"
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)
# Set gSettings in module
lTechModuleFromSpec.gSettings = self.mGSettings
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
# Run SettingUpdate function in submodule
#mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
getattr(lTechModuleFromSpec, lSubmoduleFunctionName)(*lItem["Activity"]["ArgList"],**lItem["Activity"]["ArgDict"])
#################################################
#######################################################################
#Branch 2 - if TimeHH:MMStart, TimeHH:MMStop, ActivityIntervalSeconds
#######################################################################
if "TimeHH:MMStart" in lItem and "TimeHH:MMStop" in lItem and "ActivityIntervalSeconds" in lItem:
#Сформировать временной штамп, относительно которого надо будет проверять время
#часовой пояс пока не учитываем
lActivityDateTime=datetime.datetime.strptime(lItem["TimeHH:MMStart"],"%H:%M")
lActivityDateTime=lActivityDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day)
lActivityTimeEndDateTime=datetime.datetime.strptime(lItem["TimeHH:MMStop"],"%H:%M")
lActivityTimeEndDateTime=lActivityTimeEndDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day)
#Убедиться в том, что время наступило
if (
lCurrentDateTime<lActivityTimeEndDateTime and
lCurrentDateTime>=lActivityDateTime and
(lIndex,lActivityDateTime) not in lDaemonActivityLogDict):
#Запись в массив отработанных активностей
lDaemonActivityLogDict[(lIndex,lActivityDateTime)]={"ActivityStartDateTime":lCurrentDateTime}
#Call function from Activity structure
################################################
lSubmoduleFunctionName = lItem["Activity"]["DefName"]
lFileFullPath = lItem["Activity"]["ModulePath"] # "path\\to\\module.py"
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)
# Set gSettings in module
lTechModuleFromSpec.gSettings = self.mGSettings
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
# Run SettingUpdate function in submodule
#mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
lDef = getattr(lTechModuleFromSpec, lSubmoduleFunctionName) #(*lItem["Activity"]["ArgList"],**lItem["Activity"]["ArgDict"])
#################################################
#Запуск циклической процедуры
#Timer.activityLoopStart(lItem["ActivityIntervalSeconds"], lActivityTimeEndDateTime, lItem["Activity"])
lTimer = Timer.RepeatedTimer(lItem["ActivityIntervalSeconds"], lActivityTimeEndDateTime, lDef, *lItem["Activity"]["ArgList"], **lItem["Activity"]["ArgDict"]) # it auto-starts, no need of rt.start()
#Уснуть до следующего прогона
#print (f"Loop has been completed")
time.sleep(lDaemonLoopSeconds)

@ -0,0 +1,31 @@
from threading import Timer
import datetime
class RepeatedTimer(object):
def __init__(self, interval, inDateTimeEnd, function, *args, **kwargs):
self._timer = None
self.interval = interval
self.function = function
self.args = args
self.kwargs = kwargs
self.is_running = False
self.mDateTimeEnd = inDateTimeEnd # DateTime when stop
self.start()
def _run(self):
self.is_running = False
lResultGoLoop=True
lCurrentDateTime=datetime.datetime.now()
self.function(*self.args, **self.kwargs)
if lCurrentDateTime>=self.mDateTimeEnd:
lResultGoLoop=False
if lResultGoLoop is not None:
if lResultGoLoop:
self.start()
def start(self):
if not self.is_running:
self._timer = Timer(self.interval, self._run)
self._timer.start()
self.is_running = True
def stop(self):
self._timer.cancel()
self.is_running = False

@ -13,7 +13,7 @@ import importlib
lFolderPath = "/".join(__file__.split("/")[:-4])
sys.path.insert(0, lFolderPath)
#Единый глобальный словарь (За основу взять из Settings.py)
global mGlobalDict
global gSettingsDict
#Call Settings function from argv[1] file
################################################
lSubmoduleFunctionName = "Settings"
@ -22,28 +22,30 @@ 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
gSettingsDict = None
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
# Run SettingUpdate function in submodule
mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
gSettingsDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
#################################################
#########################################################
from pyOpenRPA.Tools.RobotRDPActive import Connector
from pyOpenRPA.Tools.RobotRDPActive import Monitor
#Disable certificate warning
lCMDString = 'reg add "HKEY_CURRENT_USER\\Software\\Microsoft\\Terminal Server Client" /v "AuthenticationLevelOverride" /t "REG_DWORD" /d 0 /f'
os.system(lCMDString)
#time.sleep()
for lConfigurationItem in mGlobalDict["RDPList"]:
try:
Connector.Session(lConfigurationItem)
lConfigurationItem["FlagSessionIsActive"]=True #Flag that session is started
except Exception:
pass
#Run monitor
Monitor.Monitor(mGlobalDict, 1)
#Enable certificate warning
lCMDString = 'reg add "HKEY_CURRENT_USER\\Software\\Microsoft\\Terminal Server Client" /v "AuthenticationLevelOverride" /t "REG_DWORD" /d 2 /f'
os.system(lCMDString)
#Close all thread from OrchestratorConnection
mGlobalDict["OrchestratorConnectorTerminateAll"]()
from pyOpenRPA.Tools.RobotRDPActive import Scheduler # Scheduler operations
#### Global error handler
try:
#time.sleep()
######## Init the RDP List
for lConfigurationItem in gSettingsDict["RDPList"]:
lConfigurationItem["SessionIsWindowExistBool"]=False #Flag that session is not started
lConfigurationItem["SessionIsWindowResponsibleBool"]=False #Flag that session is not started
lConfigurationItem["SessionHex"]=" 77777sdfsdf77777dsfdfsf77777777" #Flag that session is not started
##########
#Run monitor
Scheduler.Scheduler(gSettingsDict["Scheduler"]) # Init & Run Scheduler
Monitor.Monitor(gSettingsDict, 1)
except Exception as e:
# Write in logger - warning
gSettingsDict["Logger"].exception(f"!!! ATTENTION !!! Global error handler - look at code")
finally:
#Close all thread from OrchestratorConnection
gSettingsDict["OrchestratorConnectorTerminateAll"]()

@ -1,3 +1,11 @@
# inRequest.OpenRPA = {}
# inRequest.OpenRPA["AuthToken"] = None
# inRequest.OpenRPA["Domain"] = None
# inRequest.OpenRPA["User"] = None
# lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None}
# self.OpenRPAResponseDict = lResponseDict
from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn
import threading
@ -11,8 +19,9 @@ import uuid
import datetime
import os #for path operations
from http import cookies
global mGlobalDict
global gSettingsDict
from . import ServerSettings
import copy
#Authenticate function ()
# return dict
# {
@ -26,17 +35,21 @@ def AuthenticateVerify(inRequest):
lCookies = cookies.SimpleCookie(inRequest.headers.get("Cookie", ""))
inRequest.OpenRPA = {}
inRequest.OpenRPA["AuthToken"] = None
inRequest.OpenRPA["Domain"] = None
inRequest.OpenRPA["User"] = None
#pdb.set_trace()
if "AuthToken" in lCookies:
lCookieAuthToken = lCookies.get("AuthToken", "").value
if lCookieAuthToken:
#Find AuthToken in GlobalDict
if lCookieAuthToken in mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("AuthTokensDict", {}):
if lCookieAuthToken in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("AuthTokensDict", {}):
#Auth Token Has Been Founded
lResult["Domain"] = mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"]
lResult["User"] = mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"]
lResult["Domain"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"]
lResult["User"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"]
#Set auth token
inRequest.OpenRPA["AuthToken"] = lCookieAuthToken
inRequest.OpenRPA["Domain"] = lResult["Domain"]
inRequest.OpenRPA["User"] = lResult["User"]
#Exit earlier
return lResult
######################################
@ -66,13 +79,15 @@ def AuthenticateVerify(inRequest):
lResult["User"] = lLogonResult["User"]
#Create token
lAuthToken=str(uuid.uuid1())
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {}
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"]
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"]
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now()
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {}
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"]
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"]
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now()
#Set-cookie
inRequest.OpenRPA["AuthToken"] = lAuthToken
inRequest.OpenRPA["Domain"] = lResult["Domain"]
inRequest.OpenRPA["User"] = lResult["User"]
inRequest.OpenRPASetCookie = {}
#New engine of server
inRequest.OpenRPAResponseDict["SetCookies"]["AuthToken"] = lAuthToken
@ -109,13 +124,13 @@ def UserAccessCheckBefore(inMethod, inRequest):
#go next if user is identified
lUserDict = None
if lAuthToken:
lUserDict = mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]
lUserDict = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]
#pdb.set_trace()
########################################
########################################
#Check general before rule (without User domain)
#Check rules
for lAccessRuleItem in mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("RuleMethodMatchURLBeforeList", []):
for lAccessRuleItem in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleMethodMatchURLBeforeList", []):
#Go next execution if flag is false
if not lResult:
#Check if Method is identical
@ -125,21 +140,21 @@ def UserAccessCheckBefore(inMethod, inRequest):
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: Contains
elif lAccessRuleItem["MatchType"].upper() == "CONTAINS":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.contains(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: Equal
elif lAccessRuleItem["MatchType"].upper() == "EQUAL":
if lAccessRuleItem["URL"].upper() == inRequest.path.upper():
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: EqualCase
elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE":
if lAccessRuleItem["URL"] == inRequest.path:
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
#########################################
#########################################
#Do check if lResult is false
@ -147,7 +162,7 @@ def UserAccessCheckBefore(inMethod, inRequest):
#Check access by User Domain
#Check rules to find first appicable
#Check rules
for lAccessRuleItem in mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", []):
for lAccessRuleItem in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", []):
#Go next execution if flag is false
if not lResult:
#Check if Method is identical
@ -157,21 +172,21 @@ def UserAccessCheckBefore(inMethod, inRequest):
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
#check Match type variant: Contains
elif lAccessRuleItem["MatchType"].upper() == "CONTAINS":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.contains(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: Equal
elif lAccessRuleItem["MatchType"].upper() == "EQUAL":
if lAccessRuleItem["URL"].upper() == inRequest.path.upper():
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: EqualCase
elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE":
if lAccessRuleItem["URL"] == inRequest.path:
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
#####################################
#####################################
#Return lResult
@ -221,24 +236,24 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
lURLPath = self.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(inURLItem["URL"].upper()):
URLItemDo(inURLItem, self, mGlobalDict)
URLItemDo(inURLItem, self, gSettingsDict)
return True
# check Match type variant: Contains
elif inURLItem["MatchType"].upper() == "CONTAINS":
lURLPath = self.path
lURLPath = lURLPath.upper()
if lURLPath.contains(inURLItem["URL"].upper()):
URLItemDo(inURLItem, self, mGlobalDict)
URLItemDo(inURLItem, self, gSettingsDict)
return True
# check Match type variant: Equal
elif inURLItem["MatchType"].upper() == "EQUAL":
if inURLItem["URL"].upper() == self.path.upper():
URLItemDo(inURLItem, self, mGlobalDict)
URLItemDo(inURLItem, self, gSettingsDict)
return True
# check Match type variant: EqualCase
elif inURLItem["MatchType"].upper() == "EQUALCASE":
if inURLItem["URL"] == self.path:
URLItemDo(inURLItem, self, mGlobalDict)
URLItemDo(inURLItem, self, gSettingsDict)
return True
return False
#ResponseContentTypeFile
@ -281,12 +296,12 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
# Logging
mGlobalDict["Logger"].info(f"HTTP request /. Domain: {lAuthenticateDict['Domain']}, User: {lAuthenticateDict['User']}")
# gSettingsDict["Logger"].info(f"HTTP request /. Domain: {lAuthenticateDict['Domain']}, User: {lAuthenticateDict['User']}")
if lFlagAccessUserBlock:
AuthenticateBlock(self)
#####################################
@ -295,7 +310,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
####################################
lFlagUserAccess = True
#If need user authentication
if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("GET", self)
######################################
if lFlagUserAccess:
@ -303,7 +318,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in mGlobalDict["Server"]["URLList"]:
for lURLItem in gSettingsDict["Server"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "GET")
@ -318,15 +333,15 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
self.send_header('Content-type','application/json')
self.end_headers()
# Send message back to client
message = json.dumps(mGlobalDict)
message = json.dumps(gSettingsDict)
# Write content as utf-8 data
self.wfile.write(bytes(message, "utf8"))
#Filemanager function
if self.path.lower().startswith('/filemanager/'):
lFileURL=self.path[13:]
# check if file in FileURL - File Path Mapping Dict
if lFileURL.lower() in mGlobalDict["FileManager"]["FileURLFilePathDict"]:
self.SendResponseContentTypeFile('application/octet-stream',mGlobalDict["FileManager"]["FileURLFilePathDict"][lFileURL])
if lFileURL.lower() in gSettingsDict["FileManager"]["FileURLFilePathDict"]:
self.SendResponseContentTypeFile('application/octet-stream', gSettingsDict["FileManager"]["FileURLFilePathDict"][lFileURL])
else:
#Set access denied code
# Send response status code
@ -345,7 +360,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
@ -357,7 +372,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
####################################
lFlagUserAccess = True
#If need user authentication
if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("POST", self)
######################################
if lFlagUserAccess:
@ -365,7 +380,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in mGlobalDict["Server"]["URLList"]:
for lURLItem in gSettingsDict["Server"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "POST")
@ -416,16 +431,16 @@ class RobotDaemonServer(Thread):
Thread.__init__(self)
self.name = name
# Update the global dict
ServerSettings.SettingsUpdate(mGlobalDict)
ServerSettings.SettingsUpdate(inGlobalDict)
def run(self):
inServerAddress="";
inPort = mGlobalDict["Server"]["ListenPort"];
inPort = gSettingsDict["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}")
gSettingsDict["Logger"].info(f"Server init. Listen URL: {inServerAddress}, Listen port: {inPort}")
#httpd.serve_forever()
httpd = ThreadedHTTPServer(server_address, testHTTPServer_RequestHandler)
#print('Starting server, use <Ctrl-C> to stop')

@ -3,12 +3,41 @@ import json
from desktopmagic.screengrab_win32 import (
getDisplayRects, saveScreenToBmp, saveRectToBmp, getScreenAsImage,
getRectAsImage, getDisplaysAsImages)
# /Orchestrator/RobotRDPActive/ControlPanelDictGet
def RobotRDPActive_ControlPanelDictGet(inRequest,inGlobalDict):
inResponseDict = inRequest.OpenRPAResponseDict
lResultDict = {
"DataList":[
# {"SessionKeyStr":"", "SessionHexStr": "", "IsFullScreenBool": False, "IsIgnoredBool": False}
]
}
# Iterate throught the RDP List
for lRDPSessionKeyStrItem in inGlobalDict["RobotRDPActive"]["RDPList"]:
lRDPConfiguration = inGlobalDict["RobotRDPActive"]["RDPList"][lRDPSessionKeyStrItem] # Get the configuration dict
lDataItemDict = {"SessionKeyStr":"", "SessionHexStr": "", "IsFullScreenBool": False, "IsIgnoredBool": False} # Template
lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str
lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex
lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGlobalDict["RobotRDPActive"]["FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window
lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored
lResultDict["DataList"].append(lDataItemDict)
# Send message back to client
message = json.dumps(lResultDict)
# Write content as utf-8 data
inResponseDict["Body"] = bytes(message, "utf8")
def Monitor_ControlPanelDictGet(inRequest,inGlobalDict):
inResponseDict = inRequest.OpenRPAResponseDict
# Create result JSON
lResultJSON = {"RenderRobotList": []}
lRenderFunctionsRobotList = inGlobalDict["ControlPanelDict"]["RobotList"]
for lItem in lRenderFunctionsRobotList:
lUACBool = True # Check if render function is applicable User Access Rights (UAC)
if inGlobalDict["Server"]["AccessUsers"]["FlagCredentialsAsk"] is True:
lUserRights = inGlobalDict["Server"]["AccessUsers"]["RuleDomainUserDict"][(inRequest.OpenRPA["Domain"].upper(),inRequest.OpenRPA["User"].upper())]
if len(lUserRights["ControlPanelKeyAllowedList"]) > 0 and lItem["KeyStr"] not in lUserRights["ControlPanelKeyAllowedList"]:
lUACBool = False # UAC Check is not passed - False for user
if lUACBool: # Run function if UAC is TRUE
# Выполнить вызов и записать результат
lItemResultDict = lItem["RenderFunction"](inGlobalDict)
# RunFunction
@ -60,7 +89,8 @@ def SettingsUpdate(inGlobalConfiguration):
{"Method":"GET", "URL": "/favicon.ico", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "Web\\favicon.ico"), "ResponseContentType": "image/x-icon"},
{"Method":"GET", "URL": "/3rdParty/Handlebars/handlebars-v4.1.2.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Handlebars\\handlebars-v4.1.2.js"), "ResponseContentType": "application/javascript"},
{"Method": "GET", "URL": "/Monitor/ControlPanelDictGet", "MatchType": "Equal", "ResponseDefRequestGlobal": Monitor_ControlPanelDictGet, "ResponseContentType": "application/json"},
{"Method": "GET", "URL": "/GetScreenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": GetScreenshot, "ResponseContentType": "image/png"}
{"Method": "GET", "URL": "/GetScreenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": GetScreenshot, "ResponseContentType": "image/png"},
{"Method": "GET", "URL": "/Orchestrator/RobotRDPActive/ControlPanelDictGet", "MatchType": "Equal","ResponseDefRequestGlobal": RobotRDPActive_ControlPanelDictGet, "ResponseContentType": "application/json"}
]
inGlobalConfiguration["Server"]["URLList"]=inGlobalConfiguration["Server"]["URLList"]+lURLList
return inGlobalConfiguration

@ -5,7 +5,7 @@ import importlib
import logging
from . import Processor
global mGlobalDict
global gSettingsDict
class RepeatedTimer(object):
def __init__(self, interval, function, *args, **kwargs):

@ -292,7 +292,49 @@
}
mGlobal.Monitor.fControlPanelRefresh()
mGlobal.Monitor.fControlPanelAutoUpdateRun(3);
////////////////////////////////
/////// /Orchestrator/RobotRDPActive/ControlPanelDictGet
///////////////////////////////
mGlobal.RobotRDPActive = {}
///Refresh control panel
mGlobal.RobotRDPActive.fControlPanelRefresh=function() {
///Загрузка данных
$.ajax({
type: "GET",
url: 'Orchestrator/RobotRDPActive/ControlPanelDictGet',
data: '',
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
///Сформировать HTML код новой таблицы
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-robotrdpactive-control-panel",lResponseJSON)
//Присвоить ответ в mGlobal.RobotRDPActive.mResponseList
mGlobal.RobotRDPActive.mResponseList = lResponseJSON
///Прогрузить новую таблицу
$(".openrpa-robotrdpactive-control-panel").html(lHTMLCode)
},
dataType: "text"
});
}
///
mGlobal.RobotRDPActive.mControlPanelAutoUpdateSeconds=3;
mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent=3;
mGlobal.RobotRDPActive.fControlPanelAutoUpdateRun=function(inRefreshSeconds) {
mGlobal.RobotRDPActive.mControlPanelAutoUpdateSeconds=inRefreshSeconds;
//Функция обновления текста кнопки обновления
lControlPanelUpdate=function() {
mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent=mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent-1
if (mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent==-1) {
mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent=mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent=mGlobal.RobotRDPActive.mControlPanelAutoUpdateSeconds;
mGlobal.RobotRDPActive.fControlPanelRefresh()
}
$(".openrpa-robotrdpactive-control-panel-general .openrpa-refresh-button").html("Refresh "+mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent);
}
mGlobal.RobotRDPActive.mControlPanelAutoUpdateTimerId=setInterval(lControlPanelUpdate,1000)
}
mGlobal.RobotRDPActive.fControlPanelRefresh()
mGlobal.RobotRDPActive.fControlPanelAutoUpdateRun(3);
mGlobal.Test=function() {
///Обнулить таблицу
lData = [
@ -339,9 +381,9 @@
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
lResponseJSON["actionListResult"][0]["result"].forEach(function(lItem){lItem["processPathName"]=("processPath" in lItem ? lItem["processPath"] : lItem["processName"])})
lResponseJSON[0]["Result"].forEach(function(lItem){lItem["processPathName"]=("processPath" in lItem ? lItem["processPath"] : lItem["processName"])})
///Отправить запрос на формирование таблицы
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-info-table-planloglist",lResponseJSON["actionListResult"][0]);
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-info-table-planloglist",lResponseJSON[0]);
///Установить HTML код
$('.ui.modal.basic .content').html(lHTMLCode);
$('.ui.modal.basic').modal('show');
@ -349,12 +391,33 @@
dataType: "text"
});
}
///////////////////////////////
///Processor functions
///////////////////////////////
mGlobal.Processor = {}
mGlobal.Processor.ServerValueAppend = function(inKeyList,inValue) {
lData = [
{
"Type":"GlobalDictKeyListValueAppend",
"KeyList": inKeyList,
"Value": inValue
}
]
///Обнулить таблицу
$('.ui.modal.basic .content').html("");
$.ajax({
type: "POST",
url: 'Utils/Processor',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
///TODO Show error if exist error
},
dataType: "text"
});
}
mGlobal.Processor.ServerValueSet = function(inKeyList,inValue) {
lData = [
{
@ -532,58 +595,17 @@
///Установить HTML код
lElementParentElement.insertAdjacentHTML("beforeend",lHTMLCode);
}
///Test
lTestDataTable = {
"Title":"Test",
"Columns":["Дата/Время","Статус","Клиент","Файл"],
"Rows":[
["2019.10.31 13:21","Успешно", "ООО БалтКам", "test.xml"],
["2019.10.31 13:21","Успешно", "ООО Гренодер", "test.xml"],
["2019.10.31 13:21","Успешно", "ООО БалтКам", "test.xml"],
["2019.10.31 13:21","Успешно", "ООО Гренодер", "test.xml"],
["2019.10.31 13:21","Отказ", "ООО Сударь", "test.xml"],
["2019.10.31 13:21","Успешно", "ООО БалтКам", "test.xml"],
["2019.10.31 13:21","Отказ", "ООО Гренодер", "test.xml"],
["2019.10.31 13:21","Успешно", "ООО Гренодер", "test.xml"],
["2019.10.31 13:21","Успешно", "ООО Сударь", "test.xml"],
["2019.10.31 13:21","Успешно", "ООО БалтКам", "test.xml"],
["2019.10.31 13:21","Успешно", "ООО Гренодер", "test.xml"],
["2019.10.31 13:21","Отказ", "ООО Сударь", "test.xml"],
["2019.10.31 13:21","Успешно", "ООО БалтКам", "test.xml"],
["f","s"]
]
}
//mGlobal.Modal.TableFilter.Show(lTestData)
///Test
lTestData = {
"Title":"Test",
"List":[
{"Header":"Head 09","Description":"Test 21.02.2019"},
{"Header":"Head 09","Description":"Test 21.02.2019"},
{"Header":"Head 09","Description":"Test 21.02.2019"},
{"Header":"Head 09","Description":"TestNew 21.02.2019"},
{"Header":"Head 09","Description":"Test 21.02.2019"},
{"Header":"Head 09","Description":"TestNew 21.02.2019"},
{"Header":"Head 09","Description":"Test 21.02.2019"},
{"Header":"Head 09","Description":"Test 21.02.2019"}
]
}
// mGlobal.Modal.ListFilter.Show(lTestData)
})
;
</script>
<style type="text/css">
body {
background-color: #FFFFFF;
}
.main.container {
margin-top: 2em;
}
.overlay {
float: left;
margin: 0em 3em 1em 0em;
@ -593,7 +615,6 @@
left: 0;
transition: left 0.5s ease;
}
.main.menu.fixed {
background-color: #FFFFFF;
border: 1px solid #DDD;
@ -602,14 +623,12 @@
.overlay.fixed .menu {
left: 800px;
}
.text.container .left.floated.image {
margin: 2em 2em 2em -4em;
}
.text.container .right.floated.image {
margin: 2em -4em 2em 2em;
}
.ui.footer.segment {
margin: 5em 0em 0em;
padding: 5em 0em;
@ -626,7 +645,7 @@
<h1 class="ui header inverted">Orchestrator Web GUI</h1>
</div>
<div class="two wide column">
<h5>by UnicodeLabs</h5>
<h5>by Ivan Maslov</h5>
</div>
</div>
@ -689,17 +708,19 @@
</div>
</div>
<div class="row black">
<div class="three wide column">
</div>
<div class="three wide column">
<h2 class="ui header inverted">Monitor</h2>
<div class="five wide column">
<h2 class="ui header inverted">Controls</h2>
</div>
<div class="two wide column">
<h2 class="ui header inverted">...</h2>
</div>
<div class="nine wide column">
<h2 class="ui header inverted">Robot RDP active list</h2>
</div>
</div>
<div class="row">
<div class="five wide column">
<button class="ui labeled icon button" onclick="mGlobal.Monitor.ScreenshotModal.Show();">
<i class="desktop icon"></i>
Look machine screenshot
@ -722,14 +743,14 @@
</tr>
</thead>
<tbody>
{{#result}}
{{#Result}}
<tr>
<td>{{@index}}</td>
<td>{{activityType}}</td>
<td>{{time}}</td>
<td>{{processPathName}}</td>
<td>{{TimeHH:MM}}{{TimeHH:MMStart}}</td>
<td>{{TimeHH:MMStop}}</td>
<td>{{Activity}}</td>
</tr>
{{/result}}
{{/Result}}
</tbody>
</table>
</script>
@ -837,6 +858,52 @@
</div>
</div>
</script>
</div>
<div class="two wide column">
</div>
<div class="nine wide column openrpa-robotrdpactive-control-panel-general">
<div class="ui info message">
<button class="ui icon button labeled " onclick="mGlobal.RobotRDPActive.fControlPanelRefresh();">
<i class="sync alternate icon"></i>
<div class="openrpa-refresh-button">Refresh</div>
</button>
</div>
<div class="openrpa-robotrdpactive-control-panel"></div>
<script class="openrpa-hidden-robotrdpactive-control-panel" style="display:none" type="text/x-handlebars-template">
<div class="ui inverted segment">
<div class="ui inverted relaxed divided list">
{{#DataList}}
<div class="item">
<div class="right floated content">
<div class="ui button" onclick="mGlobal.Processor.ServerValueAppend(['RobotRDPActive','ActivityList'],{'DefNameStr': 'RDPSessionReconnect', 'ArgList': [], 'ArgDict': {'inRDPSessionKeyStr': '{{{SessionKeyStr}}}'} })" >Reconnect</div>
</div>
<div class="right floated content">
{{#if IsIgnoredBool}}
<div class="ui button red" onclick="mGlobal.Processor.ServerValueSet(['RobotRDPActive','RDPList','{{{SessionKeyStr}}}','SessionIsIgnoredBool'],false);">Ignore</div>
{{else}}
<div class="ui button" onclick="mGlobal.Processor.ServerValueSet(['RobotRDPActive','RDPList','{{{SessionKeyStr}}}','SessionIsIgnoredBool'],true);">Ignore</div>
{{/if}}
</div>
<div class="right floated content">
{{#if IsFullScreenBool}}
<div class="ui button green" onclick="mGlobal.Processor.ServerValueSet(['RobotRDPActive','FullScreenRDPSessionKeyStr'],null);">Full screen</div>
{{else}}
<div class="ui button" onclick="mGlobal.Processor.ServerValueSet(['RobotRDPActive','FullScreenRDPSessionKeyStr'],'{{{SessionKeyStr}}}');">Full screen</div>
{{/if}}
</div>
<div class="content">
<div class="header">Session key: {{{SessionKeyStr}}}</div>
{{{SessionHexStr}}}
</div>
</div>
{{/DataList}}
</div>
</div>
</script>
</div>
</div>
<div class="row openrpa-monitor">
</div>

@ -383,6 +383,13 @@ def IntervalDataReceiveResetAsync(*args,**kwargs):
if "Interval" in lKwargs:
lInterval = lKwargs["Interval"]
del lKwargs["Interval"]
# Reset the storage before start
DataSendSync(
RobotValue=lKwargs["RobotResetValue"],
OrchestratorKeyList=lKwargs["OrchestratorKeyList"], OrchestratorProtocol=lKwargs["OrchestratorProtocol"],
OrchestratorHost=lKwargs["OrchestratorHost"], OrchestratorPort=lKwargs["OrchestratorPort"],
OrchestratorAuthToken=lKwargs["OrchestratorAuthToken"]
)
lTimer = TimerRepeat.TimerRepeat(lInterval, DataReceiveResetAsync, lArgs, lKwargs)
lTimer.start()
#Add timer to general list to stop this when needed

@ -12,7 +12,7 @@ import datetime
import struct
import shutil
from pyOpenRPA.Robot import UIDesktop
global mGlobalDict
global gSettingsDict
####################################
#Info: Main module of the Robot app (OpenRPA - Robot)
####################################

@ -11,7 +11,7 @@ from . import RobotConnector
from . import JSONNormalize
import importlib
#Единый глобальный словарь (За основу взять из Settings.py)
global mGlobalDict
global gSettingsDict
#Call Settings function from argv[1] file
################################################
lSubmoduleFunctionName = "Settings"
@ -20,14 +20,14 @@ 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
gSettingsDict = None
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
# Run SettingUpdate function in submodule
mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
gSettingsDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
#################################################
RobotConnector.mGlobalDict = mGlobalDict
RobotConnector.mGlobalDict = gSettingsDict
#Init the robot
RobotConnector.UIDesktop.Utils.ProcessBitness.SettingsInit(mGlobalDict["ProcessBitness"])
RobotConnector.UIDesktop.Utils.ProcessBitness.SettingsInit(gSettingsDict["ProcessBitness"])
# HTTP Studio web server class
class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
@ -144,13 +144,13 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
def run():
inServerAddress = "";
inPort = mGlobalDict["Server"]["ListenPort"];
inPort = gSettingsDict["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}")
gSettingsDict["Logger"].info(f"Server init. Listen URL: {inServerAddress}, Listen port: {inPort}")
# Запуск адреса в браузере
os.system(f"explorer http://127.0.0.1:{str(inPort)}")
httpd.serve_forever()

@ -15,7 +15,7 @@ import importlib
from importlib import util
#Единый глобальный словарь (За основу взять из Settings.py)
global mGlobalDict
global gSettingsDict
#Call Settings function from argv[1] file
################################################
lSubmoduleFunctionName = "Settings"
@ -24,18 +24,18 @@ 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
gSettingsDict = None
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
# Run SettingUpdate function in submodule
mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
gSettingsDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
#################################################
#mGlobalDict = Settings.Settings(sys.argv[1])
Server.mGlobalDict = mGlobalDict
Server.mGlobalDict = gSettingsDict
#Инициализация настроечных параметров
lDaemonActivityLogDict={} #Словарь отработанных активностей, ключ - кортеж (<activityType>, <datetime>, <processPath || processName>, <processArgs>)
lDaemonStartDateTime=datetime.datetime.now()
#Инициализация сервера
lThreadServer = Server.RobotDaemonServer("ServerThread", mGlobalDict)
lThreadServer = Server.RobotDaemonServer("ServerThread", gSettingsDict)
lThreadServer.start()

@ -10,7 +10,7 @@ import uuid
import datetime
import os #for path operations
from http import cookies
global mGlobalDict
global gSettingsDict
from . import ServerSettings
#Authenticate function ()
# return dict
@ -30,10 +30,10 @@ def AuthenticateVerify(inRequest):
lCookieAuthToken = lCookies.get("AuthToken", "").value
if lCookieAuthToken:
#Find AuthToken in GlobalDict
if lCookieAuthToken in mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("AuthTokensDict", {}):
if lCookieAuthToken in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("AuthTokensDict", {}):
#Auth Token Has Been Founded
lResult["Domain"] = mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"]
lResult["User"] = mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"]
lResult["Domain"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"]
lResult["User"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"]
#Set auth token
inRequest.OpenRPA["AuthToken"] = lCookieAuthToken
#Exit earlier
@ -65,11 +65,11 @@ def AuthenticateVerify(inRequest):
lResult["User"] = lLogonResult["User"]
#Create token
lAuthToken=str(uuid.uuid1())
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {}
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"]
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"]
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now()
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {}
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"]
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"]
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now()
#Set-cookie
inRequest.OpenRPA["AuthToken"] = lAuthToken
inRequest.OpenRPASetCookie = {}
@ -108,13 +108,13 @@ def UserAccessCheckBefore(inMethod, inRequest):
#go next if user is identified
lUserDict = None
if lAuthToken:
lUserDict = mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]
lUserDict = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]
#pdb.set_trace()
########################################
########################################
#Check general before rule (without User domain)
#Check rules
for lAccessRuleItem in mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("RuleMethodMatchURLBeforeList", []):
for lAccessRuleItem in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleMethodMatchURLBeforeList", []):
#Go next execution if flag is false
if not lResult:
#Check if Method is identical
@ -124,21 +124,21 @@ def UserAccessCheckBefore(inMethod, inRequest):
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: Contains
elif lAccessRuleItem["MatchType"].upper() == "CONTAINS":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.contains(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: Equal
elif lAccessRuleItem["MatchType"].upper() == "EQUAL":
if lAccessRuleItem["URL"].upper() == inRequest.path.upper():
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: EqualCase
elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE":
if lAccessRuleItem["URL"] == inRequest.path:
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
#########################################
#########################################
#Do check if lResult is false
@ -146,7 +146,7 @@ def UserAccessCheckBefore(inMethod, inRequest):
#Check access by User Domain
#Check rules to find first appicable
#Check rules
for lAccessRuleItem in mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", []):
for lAccessRuleItem in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", []):
#Go next execution if flag is false
if not lResult:
#Check if Method is identical
@ -156,21 +156,21 @@ def UserAccessCheckBefore(inMethod, inRequest):
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
#check Match type variant: Contains
elif lAccessRuleItem["MatchType"].upper() == "CONTAINS":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.contains(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: Equal
elif lAccessRuleItem["MatchType"].upper() == "EQUAL":
if lAccessRuleItem["URL"].upper() == inRequest.path.upper():
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: EqualCase
elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE":
if lAccessRuleItem["URL"] == inRequest.path:
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
#####################################
#####################################
#Return lResult
@ -220,24 +220,24 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
lURLPath = self.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(inURLItem["URL"].upper()):
URLItemDo(inURLItem, self, mGlobalDict)
URLItemDo(inURLItem, self, gSettingsDict)
return True
# check Match type variant: Contains
elif inURLItem["MatchType"].upper() == "CONTAINS":
lURLPath = self.path
lURLPath = lURLPath.upper()
if lURLPath.contains(inURLItem["URL"].upper()):
URLItemDo(inURLItem, self, mGlobalDict)
URLItemDo(inURLItem, self, gSettingsDict)
return True
# check Match type variant: Equal
elif inURLItem["MatchType"].upper() == "EQUAL":
if inURLItem["URL"].upper() == self.path.upper():
URLItemDo(inURLItem, self, mGlobalDict)
URLItemDo(inURLItem, self, gSettingsDict)
return True
# check Match type variant: EqualCase
elif inURLItem["MatchType"].upper() == "EQUALCASE":
if inURLItem["URL"] == self.path:
URLItemDo(inURLItem, self, mGlobalDict)
URLItemDo(inURLItem, self, gSettingsDict)
return True
return False
#ResponseContentTypeFile
@ -280,12 +280,12 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
# Logging
mGlobalDict["Logger"].info(f"HTTP request /. Domain: {lAuthenticateDict['Domain']}, User: {lAuthenticateDict['User']}")
gSettingsDict["Logger"].info(f"HTTP request /. Domain: {lAuthenticateDict['Domain']}, User: {lAuthenticateDict['User']}")
if lFlagAccessUserBlock:
AuthenticateBlock(self)
#####################################
@ -294,7 +294,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
####################################
lFlagUserAccess = True
#If need user authentication
if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("GET", self)
######################################
if lFlagUserAccess:
@ -302,7 +302,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in mGlobalDict["Server"]["URLList"]:
for lURLItem in gSettingsDict["Server"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "GET")
@ -327,7 +327,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
@ -339,7 +339,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
####################################
lFlagUserAccess = True
#If need user authentication
if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("POST", self)
######################################
if lFlagUserAccess:
@ -347,7 +347,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in mGlobalDict["Server"]["URLList"]:
for lURLItem in gSettingsDict["Server"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "POST")
@ -380,16 +380,16 @@ class RobotDaemonServer(Thread):
Thread.__init__(self)
self.name = name
# Update the global dict
ServerSettings.SettingsUpdate(mGlobalDict)
ServerSettings.SettingsUpdate(gSettingsDict)
def run(self):
inServerAddress="";
inPort = mGlobalDict["Server"]["ListenPort"];
inPort = gSettingsDict["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}")
gSettingsDict["Logger"].info(f"Server init. Listen URL: {inServerAddress}, Listen port: {inPort}")
#httpd.serve_forever()
httpd = ThreadedHTTPServer(server_address, testHTTPServer_RequestHandler)
#print('Starting server, use <Ctrl-C> to stop')

@ -1,136 +0,0 @@
#Import parent folder to import current / other packages
from pyOpenRPA.Robot import UIDesktop #Lib to access RDP window
import os #os for process run
import uuid #temp id for Template.rdp
import tempfile #Temporary location
import time
import subprocess
#Connect to RDP session
"""
{
"Host": "", #Host address
"Port": "", #RDP Port
"Login": "", # Login
"Password": "", #Password
"Screen": {
"Resolution":"FullScreen", #"640x480" or "1680x1050" or "FullScreen". If Resolution not exists set full screen
"FlagUseAllMonitors": False, # True or False
"DepthBit":"" #"32" or "24" or "16" or "15"
}
}
"""
def Session(inRDPSessionConfiguration):
#RDPConnector.SessionConnect(mConfiguration)
#RDPConnector.LoginPassSet("111.222.222.111","ww","dd")
(lRDPFile, lSessionHex) = SessionConfigurationCreate(inRDPSessionConfiguration)
#Set session hex in globalDict
inRDPSessionConfiguration["SessionHex"] = lSessionHex
#Set login/password
SessionLoginPasswordSet(inRDPSessionConfiguration["Host"],inRDPSessionConfiguration["Login"],inRDPSessionConfiguration["Password"])
#Start session
SessionRDPStart(lRDPFile)
#Remove temp file
time.sleep(4) #Delete file after some delay - one way to delete and run the RDP before because RDP is not read file in one moment
os.remove(lRDPFile) # delete the temp rdp
return inRDPSessionConfiguration
#Add login/ password to the windows credentials to run RDP
def SessionLoginPasswordSet(inHost, inLogin, inPassword):
#Clear old login/password if it exists
#os.system(f"cmdkey /delete:TERMSRV/{inHost}") #Dont need to delete because new user password will clear the previous creds
#Set login password for host
os.system(f"cmdkey /generic:TERMSRV/{inHost} /user:{inLogin} /pass:{inPassword}")
return None
#Create current .rdp file with settings
#Return (full path to file, session hex)
def SessionConfigurationCreate(inConfiguration):
#RobotRDPActive folder path
lFileFullPath=__file__
lFileFullPath = lFileFullPath.replace("/","\\")
lRobotRDPActiveFolderPath = "\\".join(lFileFullPath.split("\\")[:-1])
#Full path to Template.rdp file
lRDPTemplateFileFullPath = os.path.join(lRobotRDPActiveFolderPath, "Template.rdp")
#Open template file (.rdp encoding is USC-2 LE BOM = UTF-16 LE) http://qaru.site/questions/7156020/python-writing-a-ucs-2-little-endian-utf-16-le-file-with-bom
lRDPTemplateFileContent = open(lRDPTemplateFileFullPath, "r", encoding="utf-16-le").read()
#Prepare host:port
lHostPort=inConfiguration['Host']
if 'Port' in inConfiguration:
if inConfiguration['Port']:
lHostPort=f"{lHostPort}:{inConfiguration['Port']}"
#Replace {Width}, {Height}, {BitDepth}, {HostPort}, {Login}
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{Width}", str(inConfiguration.get('Screen',{}).get("Width",1680)))
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{Height}", str(inConfiguration.get('Screen',{}).get("Height",1050)))
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{BitDepth}", inConfiguration.get('Screen',{}).get("DepthBit","32"))
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{HostPort}", lHostPort)
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{Login}", inConfiguration['Login'])
#Save template to temp file
lRDPCurrentFileFullPath = os.path.join(tempfile.gettempdir(), f"{uuid.uuid4().hex}.rdp")
open(lRDPCurrentFileFullPath, "w", encoding="utf-16-le").write(lRDPTemplateFileContent)
#Return .rdp full path
return (lRDPCurrentFileFullPath, (lRDPCurrentFileFullPath.split("\\")[-1])[0:-4])
#RDPSessionStart
def SessionRDPStart(inRDPFilePath):
#run rdp session
lItemArgs = [inRDPFilePath]
subprocess.Popen(lItemArgs, shell=True)
#Wait for UAC unknown publisher exists
lRDPFileName = (inRDPFilePath.split("\\")[-1])[0:-4]
lWaitResult = UIDesktop.UIOSelectorsSecs_WaitAppear_List(
[
[{"title": "Подключение к удаленному рабочему столу", "class_name": "#32770", "backend": "win32"},
{"title": "Боль&ше не выводить запрос о подключениях к этому компьютеру", "friendly_class_name": "CheckBox"}],
[{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "D&on't ask me again for connections to this computer",
"friendly_class_name": "CheckBox"}],
[{"title_re": f"{lRDPFileName}.*",
"class_name": "TscShellContainerClass", "backend": "win32"}]
],
30
)
#Click if 0 is appear (RUS)
if 0 in lWaitResult:
#Check the box do not retry
UIDesktop.UIOSelector_Get_UIO([{"title": "Подключение к удаленному рабочему столу", "backend": "win32"},
{"title": "Боль&ше не выводить запрос о подключениях к этому компьютеру", "friendly_class_name": "CheckBox"}]).check()
#Go to connection
UIDesktop.UIOSelector_Get_UIO([{"title": "Подключение к удаленному рабочему столу", "backend": "win32"},
{"title":"Подкл&ючить", "class_name":"Button"}]).click()
lWaitResult = UIDesktop.UIOSelectorsSecs_WaitAppear_List(
[
[{"title_re": f"{lRDPFileName}.*",
"class_name": "TscShellContainerClass", "backend": "win32"}]
],
30
)
# Click if 1 is appear (ENG)
if 1 in lWaitResult:
# Check the box do not retry
UIDesktop.UIOSelector_Get_UIO([{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "D&on't ask me again for connections to this computer",
"friendly_class_name": "CheckBox"}]).check()
# Go to connection
UIDesktop.UIOSelector_Get_UIO([{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "Co&nnect", "class_name": "Button"}]).click()
lWaitResult = UIDesktop.UIOSelectorsSecs_WaitAppear_List(
[
[{"title_re": f"{lRDPFileName}.*",
"class_name": "TscShellContainerClass", "backend": "win32"}]
],
30
)
#Prepare little window
SessionScreen100x550(lRDPFileName)
return None
#Set fullscreen for app
def SessionScreenFull(inSessionHex):
#Prepare little window
lRDPWindow = UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHex}.*", "backend": "win32"}])
lRDPWindow.maximize()
lRDPWindow.set_focus()
return None
#Set Little window of the session
def SessionScreen100x550(inSessionHex):
#Prepare little window
lRDPWindow = UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHex}.*", "backend": "win32"}])
lRDPWindow.restore()
lRDPWindow.move_window(10,10,550,100)
return None

@ -1,55 +0,0 @@
from pyOpenRPA.Robot import UIDesktop
from . import Connector
import os
import pdb
#Check for session is closed. Reopen if detected. Always keep session is active
def Monitor(inGlobalDict, inListUpdateTimeout):
lFlagWhile = True
while lFlagWhile:
# UIOSelector list init
lUIOSelectorList = []
#Prepare selectors list for check
for lIndex, lItem in enumerate(inGlobalDict["RDPList"]):
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']}.*", "backend": "win32"}])
#Run wait command
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
###########################################
#Analyze if flag safeturn off is activated
if inGlobalDict.get("OrchestratorToRobotResetStorage",{}).get("SafeTurnOff",False):
lFlagWhile=False
#Set status disconnected for all RDP List
for lItem in inGlobalDict["RDPList"]:
lItem["FlagSessionIsActive"]=False
#Kill all RDP sessions
os.system('taskkill /F /im mstsc.exe')
#Return from function
return
###########################################
###########################################
for lItem in lRDPDissappearList:
inGlobalDict["RDPList"][lItem]["FlagSessionIsActive"] = False # Set flag that session is disconnected
#pdb.set_trace()
#Session start if it is not in ignore list
#add check for selector if it is not in ignoreIndexList
if lItem not in inGlobalDict["OrchestratorToRobotStorage"]["IgnoreIndexList"]:
try:
Connector.Session(inGlobalDict["RDPList"][lItem])
inGlobalDict["RDPList"][lItem]["FlagSessionIsActive"] = True # Flag that session is started
except Exception:
pass
###########################################
#Check if from Orchestrator full screen session is set
if inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"] != inGlobalDict["FullScreenSessionIndex"]:
#Do some switches
#If full screen mode we have now
if inGlobalDict["FullScreenSessionIndex"] is not None:
if inGlobalDict["RDPList"][inGlobalDict["FullScreenSessionIndex"]]["FlagSessionIsActive"]:
Connector.SessionScreen100x550(inGlobalDict["RDPList"][inGlobalDict["FullScreenSessionIndex"]]["SessionHex"])
#If new session is setted
if inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"] is not None:
if inGlobalDict["RDPList"][inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]]["FlagSessionIsActive"]:
Connector.SessionScreenFull(inGlobalDict["RDPList"][inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]]["SessionHex"])
#Set one to other equal
inGlobalDict["FullScreenSessionIndex"] = inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]
return None
#TODO Def garbage window cleaner (if connection was lost)

@ -8,18 +8,35 @@ from . import Crypter # Crypto functions
import datetime #Datetime
import hashlib #Get hash of the word
import pyautogui
import os
import glob # list files
EXT = '.cry'
gExtensionName = "cry"
# How to run
# sys.meta_path.append(Base64Importer(root_pkg_path))
# Init cryptographer
def CryptographerInit(inFolderPath):
sys.meta_path.append(Base64Importer(inFolderPath))
def CryptographerInit(inFolderPathList, inKey):
#sys.meta_path.append(Base64Importer(inFolderPath))
# Flag add subfolder, which contains extension files
#path = 'c:\\projects\\hc2\\'
#folders = []
# Recursive walk throught the tree
# r=root, d=directories, f = files
#import pdb
#pdb.set_trace()
for lItem in inFolderPathList:
sys.meta_path.append(Base64Importer(os.path.abspath(lItem), inKey=inKey))
#for r, d, f in os.walk(lItem):
# for folder in d:
#folders.append(os.path.join(r, folder))
#sys.meta_path.append(Base64Importer(os.path.join(r, folder), inKey=inKey))
# pass
#for f in folders:
# print(f)
#===============================================================================
class Base64Importer(object):
"""Служит для поиска и импорта python-модулей, кодированных в base64
Класс реализует Import Protocol (PEP 302) для возможности импортирования
модулей, зашифрованных в base64 из указанного пакета.
"""
@ -27,25 +44,28 @@ class Base64Importer(object):
def __init__(self, root_package_path, inKey):
self.mKeyStr = inKey
self.__modules_info = self.__collect_modules_info(root_package_path)
# Create list of cry files when run
#for lItem in root_package_path_list:
# lCryptedFileList = [f for f in glob.glob(os.path.join(lItem,f"**/*.{EXT}"), recursive=True)]
#---------------------------------------------------------------------------
def find_module(self, fullname, path=None):
"""Метод будет вызван при импорте модулей
Если модуль с именем fullname является base64 и находится в заданной
папке, данный метод вернёт экземпляр импортёра (finder), либо None, если
модуль не является base64.
"""
#print(f"find_module:: Fullname: {fullname}, path: {path}")
#print(f"modules info: {self.__modules_info}")
if fullname in self.__modules_info:
return self
return None
#---------------------------------------------------------------------------
def load_module(self, fullname):
"""Метод загружает base64 модуль
Если модуль с именем fullname является base64, то метод попытается его
загрузить. Возбуждает исключение ImportError в случае любой ошибки.
"""
#print(f"load_module:: Fullname: {fullname}")
if not fullname in self.__modules_info:
raise ImportError(fullname)
# Для потокобезопасности
@ -53,6 +73,8 @@ class Base64Importer(object):
try:
mod = sys.modules.setdefault(fullname, imp.new_module(fullname))
mod.__file__ = "<{}>".format(self.__class__.__name__)
mod.__file__ = self.__modules_info[fullname]['filename'] #Hotfix
#print(f"MODFILE::{mod.__file__}")
mod.__loader__ = self
if self.is_package(fullname):
mod.__path__ = []
@ -61,7 +83,10 @@ class Base64Importer(object):
mod.__package__ = fullname.rpartition('.')[0]
src = self.get_source(fullname)
try:
exec(src) in mod.__dict__
#__name__ = "pyPackage"
#print(f"MODNAME:: {mod.__name__}")
#exec(src) in mod.__dict__
exec(src,mod.__dict__)
except:
del sys.modules[fullname]
raise ImportError(fullname)
@ -98,33 +123,55 @@ class Base64Importer(object):
"""Собирает информацию о модулях из указанного пакета
"""
modules = {}
"""
p = os.path.abspath(root_package_path)
dir_name = os.path.dirname(p) + os.sep
#dir_name = "" # Hotfix 2020 03 19
#print(f"__collect_modules_info:: root_package_path: {root_package_path}")
for root, _, files in os.walk(p):
# Информация о текущем пакете
filename = os.path.join(root, '__init__' + EXT)
p_fullname = root.rpartition(dir_name)[2].replace(os.sep, '.')
modules[p_fullname] = {
'filename': filename,
'ispackage': True
}
# Информация о модулях в текущем пакете
for f in files:
if not f.endswith(EXT):
continue
filename = os.path.join(root, f)
fullname = '.'.join([p_fullname, os.path.splitext(f)[0]])
fullname = os.path.splitext(f)[0]
modules[fullname] = {
'filename': filename,
'ispackage': False
}
"""
# # # # # # # # # # #
# New way of collection
lRootAbsPath = os.path.abspath(root_package_path)
#print(lRootAbsPath)
lNewPathIndex = len(lRootAbsPath)+len(os.sep) # Len of the root path + len sep
lCryptedFileList = [f for f in glob.glob(os.path.join(lRootAbsPath,f"**/*.{gExtensionName}"), recursive=True)]
#print(lCryptedFileList)
for lCryptedItemFullPath in lCryptedFileList:
# Get Module name
lModuleName = lCryptedItemFullPath[lNewPathIndex:-(1+len(gExtensionName))].replace(os.sep, '.')
# Check if file is not __init__.{EXT} - This is package
if f"__init__.{EXT}" in lCryptedItemFullPath:
# Add package
lModuleName = lModuleName.replace(f"{os.sep}__init__.{gExtensionName}","")
modules[lModuleName] = {
'filename': lCryptedItemFullPath,
'ispackage': True
}
else:
# Add item
modules[lModuleName] = {
'filename': lCryptedItemFullPath,
'ispackage': False
}
return modules
# Settings
gInUncryptedExtension = "py" # cry for filename.cry
@ -142,20 +189,25 @@ gSettings = {
}
}
# Create process run
def Run():
global gSettings
print(f"{str(datetime.datetime.now())}: Run decryptography")
############# Step 5 - Ask and confirm the secret word
lKeyHashStr_1 = hashlib.sha256(pyautogui.password('Please enter the key to protect source code').encode("utf-8")).digest()
lKeyHashStr_2 = hashlib.sha256(pyautogui.password('Please repeat the key to protect source code').encode("utf-8")).digest()
if lKeyHashStr_1 == lKeyHashStr_2:
sys.meta_path.append(Base64Importer("TestPackage",inKey = lKeyHashStr_1))
#CryptographerInit("", inKey = lKeyHashStr_1)
#Init the functions
import runpy
runpy.run_module(**gSettings["run_module"])
else:
raise Exception("User set different secret key 1 and key 2")
############ Step 6 - Final stage
# Settings
gInUncryptedExtension = "py" # cry for filename.cry
gOutCryptedExtension = "cry" # cry for filename.cry
gFileMaskToDelete = "pyc" #Remove all .pyc files
print(f"{str(datetime.datetime.now())}: Run decryptography")
############# Step 5 - Ask and confirm the secret word
lKeyHashStr_1 = hashlib.sha256(pyautogui.password('Please enter the key to protect source code').encode("utf-8")).digest()
lKeyHashStr_2 = hashlib.sha256(pyautogui.password('Please repeat the key to protect source code').encode("utf-8")).digest()
if lKeyHashStr_1 == lKeyHashStr_2:
#sys.meta_path.append(Base64Importer("TestPackage",inKey = lKeyHashStr_1))
CryptographerInit(sys.argv[1:], inKey = lKeyHashStr_1)
print(f"{str(datetime.datetime.now())}: Cryprography module has been successfully initialized")
if __name__ == "__main__":
#import runpy
#runpy.run_module(**gSettings["run_module"])
#runpy.run_path("pyPackage_Settings", init_globals=None, run_name=None)
# Here is the execution code...
#############
###########
#######
else:
raise Exception("User set different secret key 1 and key 2")

@ -3,7 +3,7 @@ r"""
The OpenRPA package (from UnicodeLabs)
"""
__version__ = 'v1.0.42'
__version__ = 'v1.1.0'
__all__ = []
__author__ = 'Ivan Maslov <ivan.maslov@unicodelabs.ru>'
#from .Core import Robot

@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: pyOpenRPA
Version: 1.0.42
Version: 1.1.0
Summary: First open source RPA platform for business
Home-page: https://gitlab.com/UnicodeLabs/OpenRPA
Author: Ivan Maslov

@ -1,14 +1,38 @@
pyOpenRPA-1.0.42.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pyOpenRPA-1.0.42.dist-info/METADATA,sha256=Spesv5ub8aq5ymKhq_1kDDFQ2lrCrTwXfF8PakH7OO8,3542
pyOpenRPA-1.0.42.dist-info/RECORD,,
pyOpenRPA-1.0.42.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97
pyOpenRPA-1.0.42.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10
pyOpenRPA/Orchestrator/Orchestrator.py,sha256=UKp7eqvWDM91kYLwl2mo0UB8Pw-qu8eJCsR9NEXD1aU,6436
pyOpenRPA/Orchestrator/Processor.py,sha256=kmGNIqe6AZMSrzCt1QlonEy58ecFeLunjo8AeRMsufU,11091
pyOpenRPA/Orchestrator/Server.py,sha256=s1ujCuRX6YxRllqPn541Df4pJP7kOexiS3RIuoT4nyE,22053
pyOpenRPA/Orchestrator/ServerSettings.py,sha256=jOXJTLwg8cJx6D-rN8J4dn5RCb2nepAhCH4F9hYVUdM,4912
pyOpenRPA/Orchestrator/Timer.py,sha256=FQZ3y6G9d47Ybx7RewzePKQV77H4gCkx5SaeFVlsuhc,2095
pyOpenRPA/Orchestrator/Web/Index.xhtml,sha256=su4tsDD_ZMbQz6Tbmqj55SM0ZZxuQw9tfPcytaB8wzs,32953
pyOpenRPA-1.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pyOpenRPA-1.1.0.dist-info/METADATA,sha256=yrWtVmt4O4pYWpBBOCBXDwfe6CVB7Qpkfkb1TnBiBEs,3541
pyOpenRPA-1.1.0.dist-info/RECORD,,
pyOpenRPA-1.1.0.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97
pyOpenRPA-1.1.0.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10
pyOpenRPA/Orchestrator/Orchestrator.py,sha256=0Q4VYZPdXV2qmLuowMWD_vERj1GQurQx_VFwfsxuucQ,7076
pyOpenRPA/Orchestrator/Processor.py,sha256=wqhbAcR9-7OszRHSX2u7BSONPNIMkEbDexvW47h0xdM,11954
pyOpenRPA/Orchestrator/RobotRDPActive/CMDStr.py,sha256=6otw1WnR2_evvQ5LGyOVh0BLk_nTdilViGub7p56fXQ,1531
pyOpenRPA/Orchestrator/RobotRDPActive/Clipboard.py,sha256=YB5HJL-Qf4IlVrFHyRv_ZMJ0Vo4vjyYqWKjvrTnf1k4,1564
pyOpenRPA/Orchestrator/RobotRDPActive/Connector.py,sha256=2nm5S_FOfnLkDVdlm2MVag9vL3DlyJ98LnwYNMzFNho,15914
pyOpenRPA/Orchestrator/RobotRDPActive/ConnectorExceptions.py,sha256=WgGqWoPAnMeXpI_w3iuFX0KUBssvlSk9MuPBuIsNOuY,491
pyOpenRPA/Orchestrator/RobotRDPActive/GlobalDictSessionIndex_Defs.py,sha256=4BbAozLyOlXJxNw0NAlHt38-AyV-B6-Nl1M1AY8CTtk,4212
pyOpenRPA/Orchestrator/RobotRDPActive/Monitor.py,sha256=Y4mhNslK0EBS1LIDfK67j3lkjTZSU5xq-HUl9XNKW-U,10609
pyOpenRPA/Orchestrator/RobotRDPActive/Processor.py,sha256=DrvRm6ZLgrGNcD8EjyKbZ4HZPfiGjQftuWDfqLeM6hw,7627
pyOpenRPA/Orchestrator/RobotRDPActive/RobotRDPActive.py,sha256=vsISwvRTMbbEtL_u9PU-rP6W71VUhAUBLMblOSGp2BE,9893
pyOpenRPA/Orchestrator/RobotRDPActive/Scheduler.py,sha256=21N0ilFzWI1mj3X5S9tPMgwvG7BviuBxfTuqBY85Hy4,9144
pyOpenRPA/Orchestrator/RobotRDPActive/Timer.py,sha256=y8--fUvg10qEFomecl_cmdWpdGjarZBlFpMbs_GvzoQ,1077
pyOpenRPA/Orchestrator/RobotRDPActive/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Orchestrator/RobotRDPActive/__main__.py,sha256=z9PaUK4_nBiGd0YJdYVHV_rFx6VjZaxrrmKxSyoTFwY,2508
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/CMDStr.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Clipboard.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Connector.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/ConnectorExceptions.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/GlobalDictSessionIndex_Defs.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Monitor.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Processor.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/RobotRDPActive.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Scheduler.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Timer.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Server.py,sha256=gqJO6FRDKTBZytJVdJgPF1PvOf05qYUyKDBJJkEpLzk,22755
pyOpenRPA/Orchestrator/ServerSettings.py,sha256=mpPAxAe6PvmKaZlreaoQAy_5wV80edz_0qc-iFrEmBQ,7123
pyOpenRPA/Orchestrator/Timer.py,sha256=HvYtEeH2Q5WVVjgds9XaBpWRmvZgwgBXurJDdVVq_T0,2097
pyOpenRPA/Orchestrator/Web/Index.xhtml,sha256=t-s45l9APe-wUWazdFVRP2aIsKpsNtlwU_xuSuP2d0Q,36537
pyOpenRPA/Orchestrator/Web/favicon.ico,sha256=0vdsnwKGh6pgB0FDB5mOKO7RwbxQ9F13Zg16F1pkvXs,5430
pyOpenRPA/Orchestrator/__init__.py,sha256=qVH8fEPgXk54rmy-ol0PnT8GF5OlGE0a8mExwJ4tFqY,124
pyOpenRPA/Orchestrator/__main__.py,sha256=cOd8WU77VGgzTZUB0WmWpPmdYyMZY1zVyuU9yx26MKs,144
@ -192,7 +216,7 @@ pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/outli
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/images/flags.png,sha256=lNXH8WYTAcSm3Ekdct1VmgYgzZF6gm8N8bAju5bqnd0,28123
pyOpenRPA/Resources/Web/jQuery/jquery-3.1.1.min.js,sha256=HPMOWdIdSuVgr3FD9ZE-_MgiK8qk_MdQjrgCtfqp6U4,86713
pyOpenRPA/Robot/Clipboard.py,sha256=q76X8L21zJwcwdoJJNPeCEwAV30xS6ylHP1WwvtxoWI,722
pyOpenRPA/Robot/OrchestratorConnector.py,sha256=Fihxz-jH9M4VakXEE0SZ0Vo9tLEQk8Tcg_C4HoH45gI,20037
pyOpenRPA/Robot/OrchestratorConnector.py,sha256=JUtdiUXCruqUqBD19gJBl9jk_b-tpWWx_v3MfBoKzoQ,20445
pyOpenRPA/Robot/SettingsTemplate.py,sha256=Rp5XPeV2I4tCS2uf4Zkqm_ERJ6pZMg4-e5_lMqGJYLk,1453
pyOpenRPA/Robot/Test.py,sha256=qXr990nXiFZX5SNv6QN9GLb_U4HZRmJnbZR2qSnwilY,2878
pyOpenRPA/Robot/UIDesktop.py,sha256=3I2bllTDvR9d10O2ltkjoKmYw34wkkDAZfPlRpwbj30,77476
@ -221,8 +245,8 @@ pyOpenRPA/Robot/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Robot/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Studio/JSONNormalize.py,sha256=g0Z8G2wojCgTAdZtyRiCfe0_FHSeAi72Va7R7mk27gg,3347
pyOpenRPA/Studio/ProcessCommunicator.py,sha256=HD3XASJae31_HV3OznFe8E2MgZFXnwt7YveVN82M8nU,7912
pyOpenRPA/Studio/RobotConnector.py,sha256=tQVC8X0k1HMHAAwAtkhtmeNA0cLMY3wuO-RCbgshdMk,5036
pyOpenRPA/Studio/Studio.py,sha256=zpIGLMM2FBsUt2pC3x3BBm2zZ0n42MPfG7zgqtKxF6o,8338
pyOpenRPA/Studio/RobotConnector.py,sha256=CYO0dQoqfs44SYD_VZ_TJh3WFu_DXigHBLHj4GJ2Icc,5038
pyOpenRPA/Studio/Studio.py,sha256=UoMDqnZm-MCiZHR8ToLTHHPN0Yx0Oa6-VOTJdUtoMKE,8352
pyOpenRPA/Studio/ValueVerify.py,sha256=ObskxU4fOMoCGw74_nzYt6-a5jjrAckb3sdBLYyhYxY,777
pyOpenRPA/Studio/Web/Index.xhtml,sha256=RqFW3qC1pFRr-qWEEDlCEhL9l3PwANyRbll3KZJnLvo,47927
pyOpenRPA/Studio/Web/favicon.ico,sha256=0vdsnwKGh6pgB0FDB5mOKO7RwbxQ9F13Zg16F1pkvXs,5430
@ -236,8 +260,8 @@ pyOpenRPA/Studio/__pycache__/ValueVerify.cpython-37.pyc,,
pyOpenRPA/Studio/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Studio/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/ExcelCom.py,sha256=hp0dvXOEC7Au00ueh7pqxkdixV-PC-km7tCt-wRunYs,343
pyOpenRPA/Tools/RobotDB/RobotDB.py,sha256=DZSb17fiCAYLdNVTLFJ7nTbQhk29PjzxE9OL6ydCDcI,1645
pyOpenRPA/Tools/RobotDB/Server.py,sha256=MYIbO5vGH1FKgJVu3dQnscKRgN8or0FV8ZxAQbdC2Rc,19865
pyOpenRPA/Tools/RobotDB/RobotDB.py,sha256=qtGu8PS2atd0L8taCNpk-08Qpxp8Qz1lqwAcBkyLFLM,1655
pyOpenRPA/Tools/RobotDB/Server.py,sha256=rjW9Sg-j9P8pFQD66Uih-rke6-f6sCulinwi4_W-3mc,19933
pyOpenRPA/Tools/RobotDB/ServerSettings.py,sha256=5p9JwrpKHh68oVHIWazTajB6AOfzeapARbvGcJOFmNc,7406
pyOpenRPA/Tools/RobotDB/__init__.py,sha256=qVH8fEPgXk54rmy-ol0PnT8GF5OlGE0a8mExwJ4tFqY,124
pyOpenRPA/Tools/RobotDB/__main__.py,sha256=w9sXIF4r_PeWJjHJutTuH8DSYpXxpgcAN0KUOjiJ6PI,140
@ -247,15 +271,6 @@ pyOpenRPA/Tools/RobotDB/__pycache__/Server.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/__pycache__/ServerSettings.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotRDPActive/Connector.py,sha256=qU5SXwHgQU177MjqEHyOwJDLAcSVnIkKKw76iD09J1w,7275
pyOpenRPA/Tools/RobotRDPActive/Monitor.py,sha256=H7ciateTh-hml8z69EYZjYgqdTZGkDRtnFwuYnytrCw,3278
pyOpenRPA/Tools/RobotRDPActive/Template.rdp,sha256=qPCLkjzTdYKURK7nRApkPUjRuS4K20vDPj9DIUNSSkE,2392
pyOpenRPA/Tools/RobotRDPActive/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Tools/RobotRDPActive/__main__.py,sha256=mVk8zVqcBrzAwwn7tbZPXFWTQbWUkgU6w89nbY6GN-8,2340
pyOpenRPA/Tools/RobotRDPActive/__pycache__/Connector.cpython-37.pyc,,
pyOpenRPA/Tools/RobotRDPActive/__pycache__/Monitor.cpython-37.pyc,,
pyOpenRPA/Tools/RobotRDPActive/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotRDPActive/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotScreenActive/ConsoleStart.bat,sha256=_HNadUKHOYI5y6foG3srh8wjSzhX33xaKNylFtDjOJk,114
pyOpenRPA/Tools/RobotScreenActive/Monitor.py,sha256=TV-YisVqa_uGiyJLG9oK4u-5aDjGiFYZFh1dPjOgYc8,492
pyOpenRPA/Tools/RobotScreenActive/Screen.py,sha256=VnYcvCVymrD35l2J4ln_tlVn7CilZhxE4Ggw9P-OhIw,606
@ -267,15 +282,14 @@ pyOpenRPA/Tools/RobotScreenActive/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotScreenActive/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/Crypter.py,sha256=VRrE5-oQxQtvMEPHM1lMXp2CKnceNBmIWJnsJoJkaVE,3616
pyOpenRPA/Tools/SafeSource/DistrCreate.py,sha256=-_8BTle57LBKVknnB_3af-LghxrRmRGfRNu08CLNIvY,3232
pyOpenRPA/Tools/SafeSource/DistrRun.py,sha256=TH4uExbufnOubBrTiO8Ccw00E5K6zaJ59-vApSxQ0iY,6661
pyOpenRPA/Tools/SafeSource/DistrRun.py,sha256=zwUh6Jy-rDAZHV6fcTUMupkukojntFMroHJHMsNQgrE,9637
pyOpenRPA/Tools/SafeSource/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Tools/SafeSource/__main__.py,sha256=g5aYWnuUZoM2jDX2mSIl9tRAJg05tu5VxD2rGJWcACg,649
pyOpenRPA/Tools/SafeSource/__pycache__/Crypter.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/__pycache__/DistrCreate.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/__pycache__/DistrRun.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Tools/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/__init__.py,sha256=9w2hSRgGrWKyQb3T_j71u7VoYGZsrTZz189nKtqEmOQ,175
pyOpenRPA/__init__.py,sha256=77eUDvkFqIZMsTqBvMu8L_kbwNSHWSXsJmPZaAgGrVQ,174
pyOpenRPA/__pycache__/__init__.cpython-37.pyc,,

@ -15,9 +15,11 @@ import copy
#from .Settings import Settings
import importlib
from importlib import util
import threading # Multi-threading for RobotRDPActive
from .RobotRDPActive import RobotRDPActive #Start robot rdp active
#Единый глобальный словарь (За основу взять из Settings.py)
global mGlobalDict
global gSettingsDict
#Call Settings function from argv[1] file
################################################
lSubmoduleFunctionName = "Settings"
@ -26,34 +28,41 @@ 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
gSettingsDict = None
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
# Run SettingUpdate function in submodule
mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
gSettingsDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
#################################################
#mGlobalDict = Settings.Settings(sys.argv[1])
Processor.mGlobalDict = mGlobalDict
Timer.mGlobalDict = mGlobalDict
Timer.Processor.mGlobalDict = mGlobalDict
Server.mGlobalDict = mGlobalDict
Server.Processor.mGlobalDict = mGlobalDict
Processor.gSettingsDict = gSettingsDict
Timer.gSettingsDict = gSettingsDict
Timer.Processor.gSettingsDict = gSettingsDict
Server.gSettingsDict = gSettingsDict
Server.Processor.gSettingsDict = gSettingsDict
#Инициализация настроечных параметров
lDaemonLoopSeconds=mGlobalDict["Scheduler"]["ActivityTimeCheckLoopSeconds"]
lDaemonLoopSeconds=gSettingsDict["Scheduler"]["ActivityTimeCheckLoopSeconds"]
lDaemonActivityLogDict={} #Словарь отработанных активностей, ключ - кортеж (<activityType>, <datetime>, <processPath || processName>, <processArgs>)
lDaemonStartDateTime=datetime.datetime.now()
#Инициализация сервера
lThreadServer = Server.RobotDaemonServer("ServerThread", mGlobalDict)
lThreadServer = Server.RobotDaemonServer("ServerThread", gSettingsDict)
lThreadServer.start()
# Init the RobotRDPActive in another thread
lRobotRDPActiveThread = threading.Thread(target= RobotRDPActive.RobotRDPActive, kwargs={"inGSettings":gSettingsDict})
lRobotRDPActiveThread.daemon = True # Run the thread in daemon mode.
lRobotRDPActiveThread.start() # Start the thread execution.
#Logging
mGlobalDict["Logger"].info("Scheduler loop init")
gSettingsDict["Logger"].info("Scheduler loop init")
# Выполнить активности при старте
for lActivityItem in gSettingsDict["OrchestratorStart"]["ActivityList"]:
Processor.ActivityListOrDict(lActivityItem)
#Вечный цикл
while True:
lCurrentDateTime = datetime.datetime.now()
#Циклический обход правил
lFlagSearchActivityType=True
for lIndex, lItem in enumerate(mGlobalDict["Scheduler"]["ActivityTimeList"]):
for lIndex, lItem in enumerate(gSettingsDict["Scheduler"]["ActivityTimeList"]):
#Проверка дней недели, в рамках которых можно запускать активность
lItemWeekdayList=lItem.get("WeekdayList", [0, 1, 2, 3, 4, 5, 6])
if lCurrentDateTime.weekday() in lItemWeekdayList:
@ -61,7 +70,7 @@ while True:
#Лог
lItemCopy = copy.deepcopy(lItem)
lItemCopy["DateTimeUTCStringStart"]=datetime.datetime.strftime(datetime.datetime.now(),"%Y-%m-%dT%H:%M:%S.%f")
mGlobalDict["Scheduler"]["LogList"].append(lItemCopy)
gSettingsDict["Scheduler"]["LogList"].append(lItemCopy)
#######################################################################
#Branch 1 - if has TimeHH:MM
#######################################################################

@ -29,6 +29,11 @@ import psutil
# "Value": <List, Dict, String, int>
# },
# {
# "Type": "GlobalDictKeyListValueAppend",
# "KeyList": ["key1","key2",...],
# "Value": <List, Dict, String, int>
# },
# {
# "Type": "GlobalDictKeyListValueGet",
# "KeyList": ["key1","key2",...]
# },
@ -72,9 +77,10 @@ import psutil
# "DateTimeUTCStringStart"
# "DateTimeUTCStringStop"
# "Result"
gSettingsDict = None
def Activity(inActivity):
#Глобальная переменная - глобальный словарь унаследованный от Settings.py
global mGlobalDict
global gSettingsDict
#Fill DateTimeUTCStringStart
inActivity["DateTimeUTCStringStart"] = datetime.datetime.strftime(datetime.datetime.now(),"%Y-%m-%dT%H:%M:%S.%f")
#Alias (compatibility)
@ -113,7 +119,7 @@ def Activity(inActivity):
#Обработка команды GlobalDictKeyListValueSet
###########################################################
if lItem["Type"]=="GlobalDictKeyListValueSet":
lDict = mGlobalDict
lDict = gSettingsDict
for lItem2 in lItem["KeyList"][:-1]:
#Check if key - value exists
if lItem2 in lDict:
@ -125,10 +131,25 @@ def Activity(inActivity):
lDict[lItem["KeyList"][-1]]=lItem["Value"]
lItem["Result"] = True
###########################################################
# Обработка команды GlobalDictKeyListValueAppend
###########################################################
if lItem["Type"] == "GlobalDictKeyListValueAppend":
lDict = gSettingsDict
for lItem2 in lItem["KeyList"][:-1]:
# Check if key - value exists
if lItem2 in lDict:
pass
else:
lDict[lItem2] = {}
lDict = lDict[lItem2]
# Set value
lDict[lItem["KeyList"][-1]].append(lItem["Value"])
lItem["Result"] = True
###########################################################
#Обработка команды GlobalDictKeyListValueGet
###########################################################
if lItem["Type"]=="GlobalDictKeyListValueGet":
lDict = mGlobalDict
lDict = gSettingsDict
for lItem2 in lItem["KeyList"][:-1]:
#Check if key - value exists
if lItem2 in lDict:
@ -147,7 +168,7 @@ def Activity(inActivity):
#Вид активности - запуск процесса
#Запись в массив отработанных активностей
#Лог
mGlobalDict["Processor"]["LogList"].append({"activityType":lItem["Type"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["Path"], "activityStartDateTime":str(lCurrentDateTime)})
gSettingsDict["Processor"]["LogList"].append({"activityType":lItem["Type"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["Path"], "activityStartDateTime":str(lCurrentDateTime)})
#Запустить процесс
lItemArgs=[lItem["Path"]]
lItemArgs.extend(lItem["ArgList"])
@ -169,7 +190,7 @@ def Activity(inActivity):
#Вид активности - запуск процесса
#Запись в массив отработанных активностей
#Лог
mGlobalDict["Processor"]["LogList"].append({"activityType":lItem["Type"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["Path"], "activityStartDateTime":str(lCurrentDateTime)})
gSettingsDict["Processor"]["LogList"].append({"activityType":lItem["Type"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["Path"], "activityStartDateTime":str(lCurrentDateTime)})
#Запустить процесс
lItemArgs=[lItem["Path"]]
lItemArgs.extend(lItem["ArgList"])
@ -189,7 +210,7 @@ def Activity(inActivity):
if lItem.get('User',"")!="":
lActivityCloseCommand+=f' /fi "username eq {lItem["User"]}"'
#Лог
mGlobalDict["Processor"]["LogList"].append({"activityType":lItem["Type"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["Name"], "activityStartDateTime":str(lCurrentDateTime)})
gSettingsDict["Processor"]["LogList"].append({"activityType":lItem["Type"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["Name"], "activityStartDateTime":str(lCurrentDateTime)})
#Завершить процесс
os.system(lActivityCloseCommand)
#################################
@ -228,9 +249,9 @@ def Activity(inActivity):
#Trace activity
##################
#print(mGlobalDict)
if mGlobalDict["Processor"].get(f"LogType_{lItem['Type']}",True):
if gSettingsDict["Processor"].get(f"LogType_{lItem['Type']}", True):
#Add activity in TransactionList if it is applicable
mGlobalDict["Processor"]["LogList"].append(copy.deepcopy(lItem))
gSettingsDict["Processor"]["LogList"].append(copy.deepcopy(lItem))
#Вернуть результат
return lItem

@ -0,0 +1,26 @@
import os # Get abs path of the file
# Create CMD str to run file if process.exe is not running
def ProcessStartIfNotRunning(inProcessName, inFilePath, inFlagGetAbsPath=True):
lFileAbsPath = inFilePath
if inFlagGetAbsPath:
lFileAbsPath = os.path.abspath(inFilePath)
lResult = f'tasklist /nh /fi "imagename eq {inProcessName}" | find /i "{inProcessName}" > nul || (start {lFileAbsPath})'
return lResult
# Create CMD str to stop process
def ProcessStop(inProcessName, inFlagForceClose):
lResult = f'taskkill /im "{inProcessName}" /fi "username eq %USERNAME%"'
if inFlagForceClose:
lResult+= " /F"
return lResult
# Send file from Host to Session RDP using shared drive in RDP (force copy)
def FileStoredSend(inHostFilePath, inRDPFilePath):
lHostFileAbsPath = os.path.join("\\\\tsclient", os.path.abspath(inHostFilePath).replace(":","")) # \\tsclient\C\path\to\file
lHostRDPFileAbsPath = os.path.abspath(inRDPFilePath) # File location in RDP
lResult = f'copy /Y "{lHostFileAbsPath}" "{lHostRDPFileAbsPath}"'
return lResult
# Send file from Session RDP to Host using shared drive in RDP (force copy)
def FileStoredRecieve(inRDPFilePath, inHostFilePath):
lHostFileAbsPath = os.path.join("\\\\tsclient", os.path.abspath(inHostFilePath).replace(":","")) # \\tsclient\C\path\to\file
lHostRDPFileAbsPath = os.path.abspath(inRDPFilePath) # File location in RDP
lResult = f'copy /Y "{lHostRDPFileAbsPath}" "{lHostFileAbsPath}"'
return lResult

@ -0,0 +1,40 @@
import win32clipboard
import keyboard # keyboard functions
import time # Some operations need wait
import random # random number for test
gWaitTextInClipboardSec = 1 # Second for wait text will be set in clipboard (for get operations)
# set clipboard data
def TextSet(inTextStr):
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText(inTextStr)
win32clipboard.CloseClipboard()
# get clipboard data
def TextGet(inWaitTextInClipboardSec = gWaitTextInClipboardSec):
time.sleep(inWaitTextInClipboardSec) # Wait for clipboard will save
win32clipboard.OpenClipboard()
data = win32clipboard.GetClipboardData()
win32clipboard.CloseClipboard()
return data
# Test in has text cursor and ready to apply
def InputIsFocused():
keyboard.press_and_release("ctrl+a")
keyboard.press_and_release("backspace") # remove old text
lTextForTest = str(random.randrange(100,99999))
keyboard.write(lTextForTest)
keyboard.press_and_release("ctrl+a")
keyboard.press_and_release("ctrl+c")
time.sleep(2)
keyboard.press_and_release("backspace") # remove old text
lClipboardText = TextGet()
lResult = lClipboardText == lTextForTest
return lResult
# Check if cmd is opened
def CMDIsOpen():
lTextForTest = str(random.randrange(100,99999))
keyboard.write(lTextForTest+" |clip")
keyboard.press_and_release("enter")
time.sleep(2)
lClipboardText = TextGet()
lResult = lClipboardText == lTextForTest
return lResult

@ -0,0 +1,308 @@
#Import parent folder to import current / other packages
from pyOpenRPA.Robot import UIDesktop #Lib to access RDP window
from . import ConnectorExceptions # Exceptions classes
import os #os for process run
import uuid #temp id for Template.rdp
import tempfile #Temporary location
import subprocess
from . import Clipboard # Clipboard functions get/set
import keyboard # Keyboard functions
import time
import random # random integers
from win32api import GetSystemMetrics # Get Screen rect
#Connect to RDP session
"""
{
"Host": "", #Host address
"Port": "", #RDP Port
"Login": "", # Login
"Password": "", #Password
"Screen": {
"Resolution":"FullScreen", #"640x480" or "1680x1050" or "FullScreen". If Resolution not exists set full screen
"FlagUseAllMonitors": False, # True or False
"DepthBit":"" #"32" or "24" or "16" or "15"
}
}
"""
def Session(inRDPSessionConfiguration):
#RDPConnector.SessionConnect(mConfiguration)
#RDPConnector.LoginPassSet("111.222.222.111","ww","dd")
(lRDPFile, lSessionHex) = SessionConfigurationCreate(inRDPSessionConfiguration)
#Set session hex in globalDict
inRDPSessionConfiguration["SessionHex"] = lSessionHex
#Set login/password
SessionLoginPasswordSet(inRDPSessionConfiguration["Host"],inRDPSessionConfiguration["Login"],inRDPSessionConfiguration["Password"])
#Start session
SessionRDPStart(lRDPFile)
#Remove temp file
time.sleep(4) #Delete file after some delay - one way to delete and run the RDP before because RDP is not read file in one moment
os.remove(lRDPFile) # delete the temp rdp
# Set the result
return inRDPSessionConfiguration
#Add login/ password to the windows credentials to run RDP
def SessionLoginPasswordSet(inHost, inLogin, inPassword):
#Clear old login/password if it exists
#os.system(f"cmdkey /delete:TERMSRV/{inHost}") #Dont need to delete because new user password will clear the previous creds
#Set login password for host
os.system(f'cmdkey /generic:TERMSRV/{inHost} /user:{inLogin} /pass:"{inPassword}"')
return None
#Create current .rdp file with settings
#Return (full path to file, session hex)
def SessionConfigurationCreate(inConfiguration):
#RobotRDPActive folder path
lFileFullPath=__file__
lFileFullPath = lFileFullPath.replace("/","\\")
lRobotRDPActiveFolderPath = "\\".join(lFileFullPath.split("\\")[:-1])
#Full path to Template.rdp file
lRDPTemplateFileFullPath = os.path.join(lRobotRDPActiveFolderPath, "Template.rdp")
#Open template file (.rdp encoding is USC-2 LE BOM = UTF-16 LE) http://qaru.site/questions/7156020/python-writing-a-ucs-2-little-endian-utf-16-le-file-with-bom
lRDPTemplateFileContent = open(lRDPTemplateFileFullPath, "r", encoding="utf-16-le").read()
#Prepare host:port
lHostPort=inConfiguration['Host']
if 'Port' in inConfiguration:
if inConfiguration['Port']:
lHostPort=f"{lHostPort}:{inConfiguration['Port']}"
# Generate parameter for .rdp "drivestoredirect:s:C:\;"
lDriveStoreDirectStr = ""
for lItem in inConfiguration['SharedDriveList']:
lDriveStoreDirectStr+=f"{lItem.upper()}:\\;" # Attention - all drives must be only in upper case!!!
#Replace {Width}, {Height}, {BitDepth}, {HostPort}, {Login}
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{Width}", str(inConfiguration.get('Screen',{}).get("Width",1680)))
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{Height}", str(inConfiguration.get('Screen',{}).get("Height",1050)))
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{BitDepth}", inConfiguration.get('Screen',{}).get("DepthBit","32"))
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{HostPort}", lHostPort)
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{Login}", inConfiguration['Login'])
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{SharedDriveList}", lDriveStoreDirectStr)
#Save template to temp file
lRDPCurrentFileFullPath = os.path.join(tempfile.gettempdir(), f"{uuid.uuid4().hex}.rdp")
open(lRDPCurrentFileFullPath, "w", encoding="utf-16-le").write(lRDPTemplateFileContent)
#Return .rdp full path
return (lRDPCurrentFileFullPath, (lRDPCurrentFileFullPath.split("\\")[-1])[0:-4])
#RDPSessionStart
def SessionRDPStart(inRDPFilePath):
#Disable certificate warning
lCMDString = 'reg add "HKEY_CURRENT_USER\\Software\\Microsoft\\Terminal Server Client" /v "AuthenticationLevelOverride" /t "REG_DWORD" /d 0 /f'
os.system(lCMDString)
#run rdp session
lItemArgs = [inRDPFilePath]
subprocess.Popen(lItemArgs, shell=True)
#Wait for UAC unknown publisher exists
lRDPFileName = (inRDPFilePath.split("\\")[-1])[0:-4]
lWaitResult = UIDesktop.UIOSelectorsSecs_WaitAppear_List(
[
[{"title": "Подключение к удаленному рабочему столу", "class_name": "#32770", "backend": "win32"},
{"title": "Боль&ше не выводить запрос о подключениях к этому компьютеру", "friendly_class_name": "CheckBox"}],
[{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "D&on't ask me again for connections to this computer",
"friendly_class_name": "CheckBox"}],
[{"title_re": f"{lRDPFileName}.*",
"class_name": "TscShellContainerClass", "backend": "win32"},{"depth_start":3, "depth_end": 3, "class_name":"UIMainClass"}]
],
30
)
#Enable certificate warning
lCMDString = 'reg add "HKEY_CURRENT_USER\\Software\\Microsoft\\Terminal Server Client" /v "AuthenticationLevelOverride" /t "REG_DWORD" /d 2 /f'
os.system(lCMDString)
#Click if 0 is appear (RUS)
if 0 in lWaitResult:
#Check the box do not retry
UIDesktop.UIOSelector_Get_UIO([{"title": "Подключение к удаленному рабочему столу", "backend": "win32"},
{"title": "Боль&ше не выводить запрос о подключениях к этому компьютеру", "friendly_class_name": "CheckBox"}]).check()
#Go to connection
UIDesktop.UIOSelector_Get_UIO([{"title": "Подключение к удаленному рабочему столу", "backend": "win32"},
{"title":"Подкл&ючить", "class_name":"Button"}]).click()
lWaitResult = UIDesktop.UIOSelectorsSecs_WaitAppear_List(
[
[{"title_re": f"{lRDPFileName}.*",
"class_name": "TscShellContainerClass", "backend": "win32"}]
],
30
)
# Click if 1 is appear (ENG)
if 1 in lWaitResult:
# Check the box do not retry
UIDesktop.UIOSelector_Get_UIO([{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "D&on't ask me again for connections to this computer",
"friendly_class_name": "CheckBox"}]).check()
# Go to connection
UIDesktop.UIOSelector_Get_UIO([{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "Co&nnect", "class_name": "Button"}]).click()
lWaitResult = UIDesktop.UIOSelectorsSecs_WaitAppear_List(
[
[{"title_re": f"{lRDPFileName}.*",
"class_name": "TscShellContainerClass", "backend": "win32"}]
],
30
)
# Raise exception if RDP is not active
if len(lWaitResult) == 0:
raise ConnectorExceptions.SessionWindowNotExistError("Error when initialize the RDP session - No RDP windows has appreared!")
# Wait for init
time.sleep(3)
SessionScreenSize_X_Y_W_H(inSessionHex = lRDPFileName, inXInt = 10, inYInt = 10, inWInt = 550, inHInt = 350) #Prepare little window
return None
#Set fullscreen for app
def SessionScreenFull(inSessionHex):
#Prepare little window
try:
lRDPWindow = UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHex}.*", "backend": "win32"}])
except Exception as e:
return None
lRDPWindow.set_focus()
lRDPWindow.maximize()
#time.sleep(0.5)
if not SessionIsFullScreen(inSessionHex):
lRDPWindow.type_keys("^%{BREAK}")
time.sleep(0.5)
return None
# Set the screen size
def SessionScreenSize_X_Y_W_H(inSessionHex, inXInt, inYInt, inWInt, inHInt):
lDoBool = True
while lDoBool:
#Prepare little window
try:
lRDPWindow = UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHex}.*", "backend": "win32"}])
except Exception as e:
return None
try:
lRDPWindow.set_focus()
if SessionIsFullScreen(inSessionHex):
lRDPWindow.type_keys("^%{BREAK}")
time.sleep(0.5)
lRDPWindow.restore()
time.sleep(0.5)
lRDPWindow.move_window(inXInt,inYInt,inWInt,inHInt)
except Exception as e:
time.sleep(1)
else:
lDoBool = False
return None
# Set Little window of the session
def SessionScreen100x550(inSessionHex):
SessionScreenSize_X_Y_W_H(inSessionHex = inSessionHex, inXInt = 10, inYInt = 10, inWInt = 550, inHInt = 100)
return None
# Session - close window
def SessionClose(inSessionHexStr):
#Close window
try:
UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHexStr}.*", "backend": "win32"}]).close()
except Exception as e:
pass
#Type command in CMD
# inSessionHex - SessionHex to catch window
# inModeStr "LISTEN", "CROSSCHECK", "RUN"
# "LISTEN" - Get result of the cmd command in result TODO get home script
# "CROSSCHECK" - Check if the command was successufully sent TODO get home script
# "RUN" - Run without crosscheck and get clipboard
# return {
# "OutStr": <> # Result string
# "IsResponsibleBool": True|False # Flag is RDP is responsible - works only when inModeStr = CROSSCHECK
# }
# example Connector.SessionCMDRun("4d1e48f3ff6c45cc810ea25d8adbeb50","start notepad", "RUN")
def SessionCMDRun(inSessionHex,inCMDCommandStr = "echo 1", inModeStr="CROSSCHECK", inClipboardTimeoutSec = 5):
# Init the result dict
lResult = {"OutStr": None,"IsResponsibleBool":True}
# Enter full screen mode
SessionScreenFull(inSessionHex)
time.sleep(2)
# Run CMD operations
lResult = SystemCMDRun(inCMDCommandStr = inCMDCommandStr, inModeStr = inModeStr, inClipboardTimeoutSec = inClipboardTimeoutSec)
# Exit fullscreen mode
SessionScreenSize_X_Y_W_H(inSessionHex=inSessionHex, inXInt=10, inYInt=10, inWInt=550,
inHInt=350) # Prepare little window
# Check if session is in Full screen mode
# Return True - is in fullscreen
# example print(Connector.SessionIsFullScreen(""))
def SessionIsFullScreen(inSessionHexStr):
#Default resul
lResult = False
lWeight = GetSystemMetrics(0)
lHeight = GetSystemMetrics(1)
#Get window screen
try:
lRectangle = UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHexStr}.*", "backend": "win32"}]).rectangle()
except Exception as e:
return lResult
# Get Height/Weight
lSessionWeight = lRectangle.right - lRectangle.left
lSessionHeight = lRectangle.bottom - lRectangle.top
#Case fullscreen
if lSessionHeight == lHeight and lSessionWeight == lWeight:
lResult = True
return lResult
# Check if RDP session is responsible (check with random combination in cmd)
# Attention - function will be work fine if RDP will be in full screen mode!!! (see def SessionScreenFull)
# Return True - is responsible; False - is not responsible
#Type command in CMD
# inFlagDoCrossCheck: True - Do check that CMD is executed (the text response will not be available)
# inModeStr "LISTEN", "CROSSCHECK", "RUN"
# "LISTEN" - Get result of the cmd command in result TODO get home script
# "CROSSCHECK" - Check if the command was successufully sent TODO get home script
# "RUN" - Run without crosscheck and get clipboard
# inClipboardTimeoutSec # Second for wait when clipboard will changed
# return {
# "OutStr": <> # Result string
# "IsResponsibleBool": True|False # Flag is RDP is responsible - works only when inModeStr = CROSSCHECK
# }
# example Connector.SessionCMDRun("4d1e48f3ff6c45cc810ea25d8adbeb50","start notepad", "RUN")
def SystemCMDRun(inCMDCommandStr = "echo 1", inModeStr="CROSSCHECK", inClipboardTimeoutSec = 5):
# Set random text to clipboard (for check purposes that clipboard text has been changed)
lClipboardTextOld = str(random.randrange(999,9999999))
Clipboard.TextSet(lClipboardTextOld)
# Init the result dict
lResult = {"OutStr": None,"IsResponsibleBool":True}
lCrosscheckKeyStr = str(random.randrange(999,9999999))
lCMDPostFixStr = "" # Case default "RUN"
if inModeStr == "CROSSCHECK":
lCMDPostFixStr = f"| echo {lCrosscheckKeyStr} | clip"
elif inModeStr == "LISTEN":
lCMDPostFixStr = f"| clip"
keyboard.press_and_release('win+r')
time.sleep(1)
# Remove old text
keyboard.press_and_release("ctrl+a")
keyboard.press_and_release("backspace")
# Write new text
keyboard.write(f"cmd /c {inCMDCommandStr} {lCMDPostFixStr}")
time.sleep(1)
# TODo cross check from clipboard
keyboard.press_and_release('enter')
# Get OutStr (Case CROSSCHECK and LISTEN)
if inModeStr == "CROSSCHECK" or inModeStr == "LISTEN":
lClipboardWaitTimeStartSec = time.time()
lResult["OutStr"] = Clipboard.TextGet() # Get text from clipboard
while lResult["OutStr"] == lClipboardTextOld and (time.time() - lClipboardWaitTimeStartSec) <= inClipboardTimeoutSec:
lResult["OutStr"] = Clipboard.TextGet() # Get text from clipboard
time.sleep(0.5) # wait some time for the next operation
# Do crosscheck
if inModeStr == "CROSSCHECK":
if lResult["OutStr"] == f"{lCrosscheckKeyStr} \r\n\x00\x00\x00\x00\x00":
lResult["IsResponsibleBool"] = True
else:
lResult["IsResponsibleBool"] = False
# return the result
return lResult
# Check if current RDP is responsible
def SystemRDPIsResponsible():
return SystemCMDRun(inCMDCommandStr = "echo 1", inModeStr="CROSSCHECK")["IsResponsibleBool"]
# Click OK on error messages
def SystemRDPWarningClickOk():
# Try to click OK Error window in RUS version
while UIDesktop.UIOSelector_Exist_Bool([{"title": "Подключение к удаленному рабочему столу", "class_name": "#32770", "backend": "win32"},
{"title": "ОК", "class_name": "Button"}]):
try:
UIDesktop.UIOSelector_Get_UIO([{"title": "Подключение к удаленному рабочему столу", "class_name": "#32770", "backend": "win32"},
{"title": "ОК", "class_name": "Button"}]).click()
except Exception as e:
pass
# Try to click OK Error window in ENG version
while UIDesktop.UIOSelector_Exist_Bool([{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "OK", "class_name": "Button"}]):
try:
UIDesktop.UIOSelector_Get_UIO([{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "OK", "class_name": "Button"}]).click()
except Exception as e:
pass

@ -0,0 +1,10 @@
#####################################
# RobotRDPActive Exceptions class
#####################################
class SessionWindowNotExistError(Exception): pass #Error when Window not exists
class SessionWindowNotResponsibleError(Exception): pass # Error when Window not responding
class HostNoGUIError(Exception): pass # Orchestrator session has no GUI
#try:
# raise SessionWindowNotResponsibleError("Test")
#except SessionWindowNotResponsibleError as e:
# print("Catched")

@ -0,0 +1,66 @@
# ATTENTION! HERE IS NO Relative import because it will be imported dynamically
# All function check the flag SessionIsWindowResponsibleBool == True else no cammand is processed
# All functions can return None, Bool or Dict { "IsSuccessful": True }
from pyOpenRPA.Tools.RobotRDPActive import CMDStr # Create CMD Strings
from pyOpenRPA.Tools.RobotRDPActive import Connector # RDP API
def ProcessStartIfNotRunning(inGlobalDict, inSessionIndex, inProcessName, inFilePath, inFlagGetAbsPath=True):
lResult = True
lCMDStr = CMDStr.ProcessStartIfNotRunning(inProcessName,inFilePath, inFlagGetAbsPath= inFlagGetAbsPath)
# Calculate the session Hex
lSessionHex = inGlobalDict["RDPList"][inSessionIndex]["SessionHex"]
# Check is Session is responsible
if inGlobalDict["RDPList"][inSessionIndex]["SessionIsWindowResponsibleBool"]:
# Run CMD
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
else:
# Write in logger - warning
inGlobalDict["Logger"].warning(f"GlobalDictSessionIndex_Defs.ProcessStartIfNotRunning: SessionIndex: {str(inSessionIndex)}, ProcessName: {inProcessName}:: Session is not responsible!")
lResult = False # Set false result - function has not been done
return lResult
# Create CMD str to stop process
def ProcessStop(inGlobalDict, inSessionIndex, inProcessName, inFlagForceClose):
lResult = True
lCMDStr = f'taskkill /im "{inProcessName}" /fi "username eq %USERNAME%"'
if inFlagForceClose:
lCMDStr+= " /F"
# Calculate the session Hex
lSessionHex = inGlobalDict["RDPList"][inSessionIndex]["SessionHex"]
# Check is Session is responsible
if inGlobalDict["RDPList"][inSessionIndex]["SessionIsWindowResponsibleBool"]:
# Run CMD
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
else:
# TODO Write in logger - warning
inGlobalDict["Logger"].warning(f"GlobalDictSessionIndex_Defs.ProcessStop: SessionIndex: {str(inSessionIndex)}, ProcessName: {inProcessName}:: Session is not responsible!")
lResult = False # Set false result - function has not been done
return lResult
# Send file from Host to Session RDP using shared drive in RDP
def FileStoredSend(inGlobalDict, inSessionIndex, inHostFilePath, inRDPFilePath):
lResult = True
lCMDStr = CMDStr.FileStoredSend(inHostFilePath = inHostFilePath, inRDPFilePath = inRDPFilePath)
# Calculate the session Hex
lSessionHex = inGlobalDict["RDPList"][inSessionIndex]["SessionHex"]
# Check is Session is responsible
if inGlobalDict["RDPList"][inSessionIndex]["SessionIsWindowResponsibleBool"]:
# Run CMD
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120)
else:
# Write in logger - warning
inGlobalDict["Logger"].warning(f"GlobalDictSessionIndex_Defs.FileStoredSend: SessionIndex: {str(inSessionIndex)}, HostFilePath: {inHostFilePath}:: Session is not responsible!")
lResult = False # Set false result - function has not been done
return lResult
# Recieve file from Session RDP to Host using shared drive in RDP
def FileStoredRecieve(inGlobalDict, inSessionIndex, inRDPFilePath, inHostFilePath):
lResult = True
lCMDStr = CMDStr.FileStoredRecieve(inRDPFilePath = inRDPFilePath, inHostFilePath = inHostFilePath)
# Calculate the session Hex
lSessionHex = inGlobalDict["RDPList"][inSessionIndex]["SessionHex"]
# Check is Session is responsible
if inGlobalDict["RDPList"][inSessionIndex]["SessionIsWindowResponsibleBool"]:
# Run CMD
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120)
else:
# Write in logger - warning
inGlobalDict["Logger"].warning(f"GlobalDictSessionIndex_Defs.FileStoredRecieve: SessionIndex: {str(inSessionIndex)}, HostFilePath: {inHostFilePath}:: Session is not responsible!")
lResult = False # Set false result - function has not been done
return lResult

@ -0,0 +1,158 @@
from pyOpenRPA.Robot import UIDesktop
from . import Connector
import os
import time # Time wait operations
import importlib # from dynamic import module
from . import ConnectorExceptions # Exceptions classes
#Check for session is closed. Reopen if detected. Always keep session is active
def Monitor(inGlobalDict, inListUpdateTimeout):
lFlagWhile = True
lResponsibilityCheckLastSec = time.time() # Get current time for check interval
while lFlagWhile:
try:
# UIOSelector list init
lUIOSelectorList = []
#Prepare selectors list for check
for lIndex, lItem in enumerate(inGlobalDict["RDPList"]):
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']}.*", "backend": "win32"}])
#Run wait command
#import pdb
#pdb.set_trace()
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
#print(lRDPDissappearList)
###########################################
#Analyze if flag safeturn off is activated
if inGlobalDict.get("OrchestratorToRobotResetStorage",{}).get("SafeTurnOff",False):
lFlagWhile=False
#Set status disconnected for all RDP List
for lItem in inGlobalDict["RDPList"]:
lItem["SessionIsWindowExistBool"]=False
lItem["SessionIsWindowResponsibleBool"]=False
#Kill all RDP sessions
os.system('taskkill /F /im mstsc.exe')
#Return from function
return
###########################################
###########################################
for lItem in lRDPDissappearList:
inGlobalDict["RDPList"][lItem]["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
inGlobalDict["RDPList"][lItem]["SessionIsWindowResponsibleBool"]=False
#pdb.set_trace()
#Session start if it is not in ignore list
#add check for selector if it is not in ignoreIndexList
if lItem not in inGlobalDict["OrchestratorToRobotStorage"]["IgnoreIndexList"]:
try:
Connector.Session(inGlobalDict["RDPList"][lItem])
inGlobalDict["RDPList"][lItem]["SessionIsWindowExistBool"] = True # Flag that session is started
inGlobalDict["RDPList"][lItem]["SessionIsWindowResponsibleBool"]= True
# Write in logger - info
inGlobalDict["Logger"].info(f"SessionHex: {str(inGlobalDict['RDPList'][lItem]['SessionHex'])}:: Session has been initialized!")
# catch ConnectorExceptions.SessionWindowNotExistError
except ConnectorExceptions.SessionWindowNotExistError as e:
inGlobalDict["RDPList"][lItem]["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
inGlobalDict["RDPList"][lItem]["SessionIsWindowResponsibleBool"]=False
# Write in logger - warning
inGlobalDict["Logger"].warning(f"SessionHex: {str(inGlobalDict['RDPList'][lItem]['SessionHex'])}:: Session is not exist!")
# catch ConnectorExceptions.SessionWindowNotResponsibleError
except ConnectorExceptions.SessionWindowNotResponsibleError as e:
inGlobalDict["RDPList"][lItem]["SessionIsWindowExistBool"] = True # Set flag that session is disconnected
inGlobalDict["RDPList"][lItem]["SessionIsWindowResponsibleBool"]=False
# Write in logger - warning
inGlobalDict["Logger"].warning(f"SessionHex: {str(inGlobalDict['RDPList'][lItem]['SessionHex'])}:: Session is not responsible!")
# general exceptions
except Exception as e:
# Write in logger - warning
inGlobalDict["Logger"].exception(f"!!! ATTENTION !!! Unrecognized error")
#######################
# Click all warning messages
Connector.SystemRDPWarningClickOk()
#######################
###########################################
#Check if from Orchestrator full screen session is set
if inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"] != inGlobalDict["FullScreenSessionIndex"]:
#Do some switches
#If full screen mode we have now
if inGlobalDict["FullScreenSessionIndex"] is not None:
if inGlobalDict["RDPList"][inGlobalDict["FullScreenSessionIndex"]]["SessionIsWindowExistBool"]:
Connector.SessionScreen100x550(inGlobalDict["RDPList"][inGlobalDict["FullScreenSessionIndex"]]["SessionHex"])
#If new session is setted
if inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"] is not None:
if inGlobalDict["RDPList"][inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]]["SessionIsWindowExistBool"]:
Connector.SessionScreenFull(inGlobalDict["RDPList"][inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]]["SessionHex"])
#Set one to other equal
inGlobalDict["FullScreenSessionIndex"] = inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]
###########################################
####################################
##### Block check responsibility interval [ResponsibilityCheckIntervalSec]
if inGlobalDict['ResponsibilityCheckIntervalSec']: # Do check if ResponsibilityCheckIntervalSec is not None
if (time.time - lResponsibilityCheckLastSec()) > inGlobalDict['ResponsibilityCheckIntervalSec']:
# Set new time
lResponsibilityCheckLastSec = time.time()
# Do responsibility check
for lIndex, lItem in enumerate(inGlobalDict["RDPList"]):
# Check RDP responsibility
lDoCheckResponsibilityBool = True
lDoCheckResponsibilityCountMax = 20
lDoCheckResponsibilityCountCurrent = 0
while lDoCheckResponsibilityBool:
# Enter full screen mode
Connector.SessionScreenFull(lItem['SessionHex'])
time.sleep(2)
# Check responding
lDoCheckResponsibilityBool = not Connector.SystemRDPIsResponsible()
# Check if counter is exceed - raise exception
if lDoCheckResponsibilityCountCurrent >= lDoCheckResponsibilityCountMax:
lItem["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
lItem["SessionIsWindowResponsibleBool"]=False
# Session window is not responsible - restart RDP (close window here - next loop will reconnect)
Connector.SessionClose(lItem['SessionHex'])
# Turn off the loop
lDoCheckResponsibilityBool = False
else:
# Exit fullscreen mode
Connector.SessionScreen100x550(lItem['SessionHex'])
# Wait if is not responding
if lDoCheckResponsibilityBool:
time.sleep(3)
# increase the couter
lDoCheckResponsibilityCountCurrent+=1
####################################
# Check ActivityList from orchestrator
lActivityListNew = []
lActivityListOld = inGlobalDict["OrchestratorToRobotResetStorage"]["ActivityList"]+inGlobalDict["ActivityListStart"]
inGlobalDict["ActivityListStart"] = []
for lActivityItem in lActivityListOld:
#################
#Call function from Activity structure
################################################
lSubmoduleFunctionName = lActivityItem["DefName"]
lFileFullPath = lActivityItem["ModulePath"] # "path\\to\\module.py"
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)
# Set gSettings in module
lTechModuleFromSpec.gSettings = inGlobalDict
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
# Run SettingUpdate function in submodule
#mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
lActivityItemResult=getattr(lTechModuleFromSpec, lSubmoduleFunctionName)(*lActivityItem["ArgList"],**lActivityItem["ArgDict"])
lActivityItemResultType = type(lActivityItemResult)
# Check if Result is bool
if lActivityItemResultType is bool:
if not lActivityItemResult:
# Activity is not done - add to list (retry in future)
lActivityListNew.append(lActivityItem)
#################################################
inGlobalDict["OrchestratorToRobotResetStorage"]["ActivityList"] = lActivityListNew # Override the value
except RuntimeError as e:
# case noGUI error passed - do nothing
# Write in logger - warning
inGlobalDict["Logger"].warning(f"Host session has lost the GUI")
finally:
# Wait for the next iteration
time.sleep(0.7)
return None
#TODO Def garbage window cleaner (if connection was lost)

@ -0,0 +1,147 @@
# ATTENTION! HERE IS NO Relative import because it will be imported dynamically
# All function check the flag SessionIsWindowResponsibleBool == True else no cammand is processed
# All functions can return None, Bool or Dict { "IsSuccessful": True }
from . import CMDStr # Create CMD Strings
from . import Connector # RDP API
from . import ConnectorExceptions # Exceptions
import time # sleep function
# ATTENTION
gSettings = None # Gsettings will be initialized after the import module
# Create new RDPSession in RobotRDPActive
def RDPSessionConnect(inRDPSessionKeyStr, inHostStr, inPortStr, inLoginStr, inPasswordStr):
lRDPConfigurationItem = { # Init the configuration item
"Host": inHostStr, # Host address, example "77.77.22.22"
"Port": inPortStr, # RDP Port, example "3389"
"Login": inLoginStr, # Login, example "test"
"Password": inPasswordStr, # Password, example "test"
"Screen": {
"Width": 1680, # Width of the remote desktop in pixels, example 1680
"Height": 1050, # Height of the remote desktop in pixels, example 1050
# "640x480" or "1680x1050" or "FullScreen". If Resolution not exists set full screen, example
"FlagUseAllMonitors": False, # True or False, example False
"DepthBit": "32" # "32" or "24" or "16" or "15", example "32"
},
"SharedDriveList": ["c"], # List of the Root sesion hard drives, example ["c"]
###### Will updated in program ############
"SessionHex": "77777sdfsdf77777dsfdfsf77777777", # Hex is created when robot runs, example ""
"SessionIsWindowExistBool": False, # Flag if the RDP window is exist, old name "FlagSessionIsActive". Check every n seconds , example False
"SessionIsWindowResponsibleBool": False, # Flag if RDP window is responsible (recieve commands). Check every nn seconds. If window is Responsible - window is Exist too , example False
"SessionIsIgnoredBool": False # Flag to ignore RDP window False - dont ignore, True - ignore, example False
}
# Add item in RDPList
gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr] = lRDPConfigurationItem
# Create the RDP session
Connector.Session(lRDPConfigurationItem)
return True
# Disconnect the RDP session
def RDPSessionDisconnect(inRDPSessionKeyStr):
global gSettings
lSessionHex = gSettings["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
if lSessionHex:
gSettings["RobotRDPActive"]["RDPList"].pop(inRDPSessionKeyStr,None)
Connector.SessionClose(inSessionHexStr=lSessionHex)
return True
# RDP Session reconnect
def RDPSessionReconnect(inRDPSessionKeyStr):
global gSettings
lRDPConfigurationItem = gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr]
RDPSessionDisconnect(inRDPSessionKeyStr=inRDPSessionKeyStr) # Disconnect the RDP
# Add item in RDPList
gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr] = lRDPConfigurationItem
# Create the RDP session
Connector.Session(lRDPConfigurationItem)
return True
# Logoff the RDP session
def RDPSessionLogoff(inRDPSessionKeyStr):
global gSettings
lResult = True
lCMDStr = "shutdown -L" # CMD logoff command
# Calculate the session Hex
lSessionHex = gSettings["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
if lSessionHex:
gSettings["RobotRDPActive"]["RDPList"].pop(inRDPSessionKeyStr,None)
# Run CMD
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
return lResult
# Check RDP Session responsibility TODO NEED DEV + TEST
def RDPSessionResponsibilityCheck(inRDPSessionKeyStr):
global gSettings
inGlobalDict = gSettings
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr]["SessionHex"]
# set the fullscreen
Connector.SessionScreenFull(inSessionHex=lSessionHex)
time.sleep(1)
# Check RDP responsibility
lDoCheckResponsibilityBool = True
lDoCheckResponsibilityCountMax = 20
lDoCheckResponsibilityCountCurrent = 0
while lDoCheckResponsibilityBool:
# Check if counter is exceed - raise exception
if lDoCheckResponsibilityCountCurrent >= lDoCheckResponsibilityCountMax:
pass
#raise ConnectorExceptions.SessionWindowNotResponsibleError("Error when initialize the RDP session - RDP window is not responding!")
# Check responding
lDoCheckResponsibilityBool = not Connector.SystemRDPIsResponsible()
# Wait if is not responding
if lDoCheckResponsibilityBool:
time.sleep(3)
# increase the couter
lDoCheckResponsibilityCountCurrent+=1
return True
# Start process if it is not running
def RDPSessionProcessStartIfNotRunning(inRDPSessionKeyStr, inProcessNameWEXEStr, inFilePathStr, inFlagGetAbsPathBool=True):
global gSettings
inGlobalDict = gSettings
lResult = True
lCMDStr = CMDStr.ProcessStartIfNotRunning(inProcessNameWEXEStr, inFilePathStr, inFlagGetAbsPath= inFlagGetAbsPathBool)
# Calculate the session Hex
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
# Run CMD
if lSessionHex:
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
return lResult
# Create CMD str to stop process
def RDPSessionProcessStop(inRDPSessionKeyStr, inProcessNameWEXEStr, inFlagForceCloseBool):
global gSettings
inGlobalDict = gSettings
lResult = True
lCMDStr = f'taskkill /im "{inProcessNameWEXEStr}" /fi "username eq %USERNAME%"'
if inFlagForceCloseBool:
lCMDStr+= " /F"
# Calculate the session Hex
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
# Run CMD
if lSessionHex:
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
return lResult
# Send file from Host to Session RDP using shared drive in RDP
def RDPSessionFileStoredSend(inRDPSessionKeyStr, inHostFilePathStr, inRDPFilePathStr):
global gSettings
inGlobalDict = gSettings
lResult = True
lCMDStr = CMDStr.FileStoredSend(inHostFilePath = inHostFilePathStr, inRDPFilePath = inRDPFilePathStr)
# Calculate the session Hex
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr, {}).get("SessionHex", None)
#lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr]["SessionHex"]
# Run CMD
if lSessionHex:
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120)
return lResult
# Recieve file from Session RDP to Host using shared drive in RDP
def RDPSessionFileStoredRecieve(inRDPSessionKeyStr, inRDPFilePathStr, inHostFilePathStr):
global gSettings
inGlobalDict = gSettings
lResult = True
lCMDStr = CMDStr.FileStoredRecieve(inRDPFilePath = inRDPFilePathStr, inHostFilePath = inHostFilePathStr)
# Calculate the session Hex
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
# Run CMD
if lSessionHex:
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120)
return lResult

@ -0,0 +1,142 @@
from pyOpenRPA.Robot import UIDesktop
import os
import time # Time wait operations
from . import ConnectorExceptions # Exceptions classes
from . import Connector
from . import Processor # Module for process some functions on thr RDP
# Main function
def RobotRDPActive(inGSettings):
# inGSettings = {
# ... "RobotRDPActive": {} ...
# }
#import pdb
#pdb.set_trace()
lLogger = inGSettings["Logger"] # Synonim
Processor.gSettings = inGSettings # Set gSettings in processor module
mGSettingsRDPActiveDict = inGSettings["RobotRDPActive"] # Get configuration from global dict settings
# Global error handler
try:
######## Init the RDP List
for lRDPSessionKeyStrItem in mGSettingsRDPActiveDict["RDPList"]:
lConfigurationItem = mGSettingsRDPActiveDict["RDPList"][lRDPSessionKeyStrItem]
lConfigurationItem["SessionIsWindowExistBool"] = False # Flag that session is not started
lConfigurationItem["SessionIsWindowResponsibleBool"] = False # Flag that session is not started
lConfigurationItem["SessionHex"] = " 77777sdfsdf77777dsfdfsf77777777" # Flag that session is not started
##########
# Run monitor - main loop
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
inGlobalDict = mGSettingsRDPActiveDict # Compatibility
inListUpdateTimeout = 1 # Compatibility
lFlagWhile = True
lResponsibilityCheckLastSec = time.time() # Get current time for check interval
while lFlagWhile:
try:
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check RDP window is OK - reconnect if connection was lost
lUIOSelectorList = []
lRDPConfigurationDictList = []
# Prepare selectors list for check
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
lRDPConfigurationDictList.append(lItem) # Add RDP Configuration in list
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']}.*", "backend": "win32"}])
# Run wait command
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
for lItem in lRDPDissappearList: # Reconnect if connection was lost
lRDPConfigurationDict = lRDPConfigurationDictList[lItem] # Get RDP Configuration list
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
# Check if RDP window is not ignored
if not lRDPConfigurationDict["SessionIsIgnoredBool"]:
try:
Connector.Session(lRDPConfigurationDict)
lRDPConfigurationDict["SessionIsWindowExistBool"] = True # Flag that session is started
# Write in logger - info
lLogger.info(
f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session has been initialized!")
# catch ConnectorExceptions.SessionWindowNotExistError
except ConnectorExceptions.SessionWindowNotExistError as e:
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
# Write in logger - warning
lLogger.warning(
f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session is not exist!")
# general exceptions
except Exception as e:
# Write in logger - warning
lLogger.exception(f"!!! ATTENTION !!! Unrecognized error")
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Safe turn off the - no need because of Orchestrator control
#if inGlobalDict.get("OrchestratorToRobotResetStorage", {}).get("SafeTurnOff", False):
# lFlagWhile = False
# # Set status disconnected for all RDP List
# for lItem in inGlobalDict["RDPList"]:
# lItem["SessionIsWindowExistBool"] = False
# lItem["SessionIsWindowResponsibleBool"] = False
# # Kill all RDP sessions
# os.system('taskkill /F /im mstsc.exe')
# # Return from function
# return
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Connector.SystemRDPWarningClickOk() # Click all warning messages
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check if RDP session is full screen (if is not ignored)
if inGlobalDict["FullScreenRDPSessionKeyStr"] is not None:
lRDPSessionKeyStr = inGlobalDict["FullScreenRDPSessionKeyStr"] # Get the RDPSessionKeyStr
if lRDPSessionKeyStr in inGlobalDict["RDPList"]: # Session Key is in dict
lRDPConfigurationDict = inGlobalDict["RDPList"][lRDPSessionKeyStr]
#if not lRDPConfigurationDict["SessionIsIgnoredBool"]: # Session is not ignored
# Check if full screen
lIsFullScreenBool = Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDict["SessionHex"])
if not lIsFullScreenBool: # If not the full screen
# Check all RDP window and minimize it
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
if Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]):
Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"], inXInt=10, inYInt=10,
inWInt=550,
inHInt=350) # Prepare little window
# Set full screen for new window
Connector.SessionScreenFull(inSessionHex=lRDPConfigurationDict["SessionHex"])
else:
# Check all RDP window and minimize it
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
if Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]):
Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"],
inXInt=10, inYInt=10,
inWInt=550,
inHInt=350) # Prepare little window
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Iterate the activity list in robot RDP active
lActivityListNew = []
lActivityListOld = inGlobalDict["ActivityList"]
inGlobalDict["ActivityList"] = []
for lActivityItem in lActivityListOld:
lSubmoduleFunctionName = lActivityItem["DefNameStr"]
if lSubmoduleFunctionName in dir(Processor):
# Run SettingUpdate function in submodule
# mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
lActivityItemResult = getattr(Processor, lSubmoduleFunctionName)(
*lActivityItem["ArgList"], **lActivityItem["ArgDict"])
lActivityItemResultType = type(lActivityItemResult)
# Check if Result is bool
if lActivityItemResultType is bool:
if not lActivityItemResult:
# Activity is not done - add to list (retry in future)
lActivityListNew.append(lActivityItem)
inGlobalDict["ActivityList"] = lActivityListNew # Override the value
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
except RuntimeError as e:
# case noGUI error passed - do nothing
# Write in logger - warning
lLogger.warning(f"Host session has lost the GUI")
finally:
# Wait for the next iteration
time.sleep(0.7)
# Scheduler.Scheduler(mGSettingsRDPActiveDict["Scheduler"]) # Init & Run Scheduler TODO remake in processor list
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#Monitor.Monitor(mGSettingsRDPActiveDict, 1)
except Exception as e:
# Write in logger - warning
lLogger.exception(f"!!! ATTENTION !!! Global error handler - look at code")

@ -0,0 +1,111 @@
from . import Timer # Async thread
import threading # Create in another thread
import datetime # Datetime class
import time # time functions
import importlib # import lib functions
# Scheduler class - init and work by the configuration
# OOP
class Scheduler:
# Class properties
mSchedulerDict = None
mGSettings = None
#########################
# Init class
def __init__(self,inSchedulerDict, inGSettings = None):
self.Init(inSchedulerDict = inSchedulerDict, inGSettings = inGSettings)
# Init the class instance
def Init(self,inSchedulerDict, inGSettings):
self.mGSettings = inGSettings
self.mSchedulerDict = inSchedulerDict
# Init the threads
lTimerMainThread = threading.Thread(target = self.TimerMainThreadRun)
lTimerMainThread.start() # Start the Timer main thread
#print (f"Class instance configuration: {self.mSchedulerDict}, Init has been completed")
########################
# Main timer thread - run when init class instance
def TimerMainThreadRun(self):
lDaemonStartDateTime=datetime.datetime.now()
lDaemonLoopSeconds=self.mSchedulerDict["ActivityTimeCheckLoopSeconds"]
lDaemonActivityLogDict={} #Словарь отработанных активностей, ключ - кортеж (<activityType>, <datetime>, <processPath || processName>, <processArgs>)
#Вечный цикл
while True:
lCurrentDateTime = datetime.datetime.now()
#Циклический обход правил
lFlagSearchActivityType=True
for lIndex, lItem in enumerate(self.mSchedulerDict["ActivityTimeList"]):
#Проверка дней недели, в рамках которых можно запускать активность
lItemWeekdayList=lItem.get("WeekdayList", [0, 1, 2, 3, 4, 5, 6])
if lCurrentDateTime.weekday() in lItemWeekdayList:
if lFlagSearchActivityType:
#######################################################################
#Branch 1 - if has TimeHH:MM
#######################################################################
if "TimeHH:MM" in lItem:
#Вид активности - запуск процесса
#Сформировать временной штамп, относительно которого надо будет проверять время
#часовой пояс пока не учитываем
lActivityDateTime=datetime.datetime.strptime(lItem["TimeHH:MM"],"%H:%M")
lActivityDateTime=lActivityDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day)
#Убедиться в том, что время наступило
if (
lActivityDateTime>=lDaemonStartDateTime and
lCurrentDateTime>=lActivityDateTime and
(lIndex,lActivityDateTime) not in lDaemonActivityLogDict):
#Выполнить операцию
#Запись в массив отработанных активностей
lDaemonActivityLogDict[(lIndex,lActivityDateTime)]={"ActivityStartDateTime":lCurrentDateTime}
#Запустить процесс - new code
#################
#Call function from Activity structure
################################################
lSubmoduleFunctionName = lItem["Activity"]["DefName"]
lFileFullPath = lItem["Activity"]["ModulePath"] # "path\\to\\module.py"
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)
# Set gSettings in module
lTechModuleFromSpec.gSettings = self.mGSettings
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
# Run SettingUpdate function in submodule
#mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
getattr(lTechModuleFromSpec, lSubmoduleFunctionName)(*lItem["Activity"]["ArgList"],**lItem["Activity"]["ArgDict"])
#################################################
#######################################################################
#Branch 2 - if TimeHH:MMStart, TimeHH:MMStop, ActivityIntervalSeconds
#######################################################################
if "TimeHH:MMStart" in lItem and "TimeHH:MMStop" in lItem and "ActivityIntervalSeconds" in lItem:
#Сформировать временной штамп, относительно которого надо будет проверять время
#часовой пояс пока не учитываем
lActivityDateTime=datetime.datetime.strptime(lItem["TimeHH:MMStart"],"%H:%M")
lActivityDateTime=lActivityDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day)
lActivityTimeEndDateTime=datetime.datetime.strptime(lItem["TimeHH:MMStop"],"%H:%M")
lActivityTimeEndDateTime=lActivityTimeEndDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day)
#Убедиться в том, что время наступило
if (
lCurrentDateTime<lActivityTimeEndDateTime and
lCurrentDateTime>=lActivityDateTime and
(lIndex,lActivityDateTime) not in lDaemonActivityLogDict):
#Запись в массив отработанных активностей
lDaemonActivityLogDict[(lIndex,lActivityDateTime)]={"ActivityStartDateTime":lCurrentDateTime}
#Call function from Activity structure
################################################
lSubmoduleFunctionName = lItem["Activity"]["DefName"]
lFileFullPath = lItem["Activity"]["ModulePath"] # "path\\to\\module.py"
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)
# Set gSettings in module
lTechModuleFromSpec.gSettings = self.mGSettings
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
# Run SettingUpdate function in submodule
#mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
lDef = getattr(lTechModuleFromSpec, lSubmoduleFunctionName) #(*lItem["Activity"]["ArgList"],**lItem["Activity"]["ArgDict"])
#################################################
#Запуск циклической процедуры
#Timer.activityLoopStart(lItem["ActivityIntervalSeconds"], lActivityTimeEndDateTime, lItem["Activity"])
lTimer = Timer.RepeatedTimer(lItem["ActivityIntervalSeconds"], lActivityTimeEndDateTime, lDef, *lItem["Activity"]["ArgList"], **lItem["Activity"]["ArgDict"]) # it auto-starts, no need of rt.start()
#Уснуть до следующего прогона
#print (f"Loop has been completed")
time.sleep(lDaemonLoopSeconds)

@ -0,0 +1,31 @@
from threading import Timer
import datetime
class RepeatedTimer(object):
def __init__(self, interval, inDateTimeEnd, function, *args, **kwargs):
self._timer = None
self.interval = interval
self.function = function
self.args = args
self.kwargs = kwargs
self.is_running = False
self.mDateTimeEnd = inDateTimeEnd # DateTime when stop
self.start()
def _run(self):
self.is_running = False
lResultGoLoop=True
lCurrentDateTime=datetime.datetime.now()
self.function(*self.args, **self.kwargs)
if lCurrentDateTime>=self.mDateTimeEnd:
lResultGoLoop=False
if lResultGoLoop is not None:
if lResultGoLoop:
self.start()
def start(self):
if not self.is_running:
self._timer = Timer(self.interval, self._run)
self._timer.start()
self.is_running = True
def stop(self):
self._timer.cancel()
self.is_running = False

@ -13,7 +13,7 @@ import importlib
lFolderPath = "/".join(__file__.split("/")[:-4])
sys.path.insert(0, lFolderPath)
#Единый глобальный словарь (За основу взять из Settings.py)
global mGlobalDict
global gSettingsDict
#Call Settings function from argv[1] file
################################################
lSubmoduleFunctionName = "Settings"
@ -22,28 +22,30 @@ 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
gSettingsDict = None
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
# Run SettingUpdate function in submodule
mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
gSettingsDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
#################################################
#########################################################
from pyOpenRPA.Tools.RobotRDPActive import Connector
from pyOpenRPA.Tools.RobotRDPActive import Monitor
#Disable certificate warning
lCMDString = 'reg add "HKEY_CURRENT_USER\\Software\\Microsoft\\Terminal Server Client" /v "AuthenticationLevelOverride" /t "REG_DWORD" /d 0 /f'
os.system(lCMDString)
#time.sleep()
for lConfigurationItem in mGlobalDict["RDPList"]:
try:
Connector.Session(lConfigurationItem)
lConfigurationItem["FlagSessionIsActive"]=True #Flag that session is started
except Exception:
pass
#Run monitor
Monitor.Monitor(mGlobalDict, 1)
#Enable certificate warning
lCMDString = 'reg add "HKEY_CURRENT_USER\\Software\\Microsoft\\Terminal Server Client" /v "AuthenticationLevelOverride" /t "REG_DWORD" /d 2 /f'
os.system(lCMDString)
#Close all thread from OrchestratorConnection
mGlobalDict["OrchestratorConnectorTerminateAll"]()
from pyOpenRPA.Tools.RobotRDPActive import Scheduler # Scheduler operations
#### Global error handler
try:
#time.sleep()
######## Init the RDP List
for lConfigurationItem in gSettingsDict["RDPList"]:
lConfigurationItem["SessionIsWindowExistBool"]=False #Flag that session is not started
lConfigurationItem["SessionIsWindowResponsibleBool"]=False #Flag that session is not started
lConfigurationItem["SessionHex"]=" 77777sdfsdf77777dsfdfsf77777777" #Flag that session is not started
##########
#Run monitor
Scheduler.Scheduler(gSettingsDict["Scheduler"]) # Init & Run Scheduler
Monitor.Monitor(gSettingsDict, 1)
except Exception as e:
# Write in logger - warning
gSettingsDict["Logger"].exception(f"!!! ATTENTION !!! Global error handler - look at code")
finally:
#Close all thread from OrchestratorConnection
gSettingsDict["OrchestratorConnectorTerminateAll"]()

@ -1,3 +1,11 @@
# inRequest.OpenRPA = {}
# inRequest.OpenRPA["AuthToken"] = None
# inRequest.OpenRPA["Domain"] = None
# inRequest.OpenRPA["User"] = None
# lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None}
# self.OpenRPAResponseDict = lResponseDict
from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn
import threading
@ -11,8 +19,9 @@ import uuid
import datetime
import os #for path operations
from http import cookies
global mGlobalDict
global gSettingsDict
from . import ServerSettings
import copy
#Authenticate function ()
# return dict
# {
@ -26,17 +35,21 @@ def AuthenticateVerify(inRequest):
lCookies = cookies.SimpleCookie(inRequest.headers.get("Cookie", ""))
inRequest.OpenRPA = {}
inRequest.OpenRPA["AuthToken"] = None
inRequest.OpenRPA["Domain"] = None
inRequest.OpenRPA["User"] = None
#pdb.set_trace()
if "AuthToken" in lCookies:
lCookieAuthToken = lCookies.get("AuthToken", "").value
if lCookieAuthToken:
#Find AuthToken in GlobalDict
if lCookieAuthToken in mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("AuthTokensDict", {}):
if lCookieAuthToken in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("AuthTokensDict", {}):
#Auth Token Has Been Founded
lResult["Domain"] = mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"]
lResult["User"] = mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"]
lResult["Domain"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"]
lResult["User"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"]
#Set auth token
inRequest.OpenRPA["AuthToken"] = lCookieAuthToken
inRequest.OpenRPA["Domain"] = lResult["Domain"]
inRequest.OpenRPA["User"] = lResult["User"]
#Exit earlier
return lResult
######################################
@ -66,13 +79,15 @@ def AuthenticateVerify(inRequest):
lResult["User"] = lLogonResult["User"]
#Create token
lAuthToken=str(uuid.uuid1())
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {}
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"]
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"]
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now()
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {}
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"]
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"]
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now()
#Set-cookie
inRequest.OpenRPA["AuthToken"] = lAuthToken
inRequest.OpenRPA["Domain"] = lResult["Domain"]
inRequest.OpenRPA["User"] = lResult["User"]
inRequest.OpenRPASetCookie = {}
#New engine of server
inRequest.OpenRPAResponseDict["SetCookies"]["AuthToken"] = lAuthToken
@ -109,13 +124,13 @@ def UserAccessCheckBefore(inMethod, inRequest):
#go next if user is identified
lUserDict = None
if lAuthToken:
lUserDict = mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]
lUserDict = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]
#pdb.set_trace()
########################################
########################################
#Check general before rule (without User domain)
#Check rules
for lAccessRuleItem in mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("RuleMethodMatchURLBeforeList", []):
for lAccessRuleItem in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleMethodMatchURLBeforeList", []):
#Go next execution if flag is false
if not lResult:
#Check if Method is identical
@ -125,21 +140,21 @@ def UserAccessCheckBefore(inMethod, inRequest):
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: Contains
elif lAccessRuleItem["MatchType"].upper() == "CONTAINS":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.contains(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: Equal
elif lAccessRuleItem["MatchType"].upper() == "EQUAL":
if lAccessRuleItem["URL"].upper() == inRequest.path.upper():
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: EqualCase
elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE":
if lAccessRuleItem["URL"] == inRequest.path:
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
#########################################
#########################################
#Do check if lResult is false
@ -147,7 +162,7 @@ def UserAccessCheckBefore(inMethod, inRequest):
#Check access by User Domain
#Check rules to find first appicable
#Check rules
for lAccessRuleItem in mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", []):
for lAccessRuleItem in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", []):
#Go next execution if flag is false
if not lResult:
#Check if Method is identical
@ -157,21 +172,21 @@ def UserAccessCheckBefore(inMethod, inRequest):
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
#check Match type variant: Contains
elif lAccessRuleItem["MatchType"].upper() == "CONTAINS":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.contains(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: Equal
elif lAccessRuleItem["MatchType"].upper() == "EQUAL":
if lAccessRuleItem["URL"].upper() == inRequest.path.upper():
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: EqualCase
elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE":
if lAccessRuleItem["URL"] == inRequest.path:
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
#####################################
#####################################
#Return lResult
@ -221,24 +236,24 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
lURLPath = self.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(inURLItem["URL"].upper()):
URLItemDo(inURLItem, self, mGlobalDict)
URLItemDo(inURLItem, self, gSettingsDict)
return True
# check Match type variant: Contains
elif inURLItem["MatchType"].upper() == "CONTAINS":
lURLPath = self.path
lURLPath = lURLPath.upper()
if lURLPath.contains(inURLItem["URL"].upper()):
URLItemDo(inURLItem, self, mGlobalDict)
URLItemDo(inURLItem, self, gSettingsDict)
return True
# check Match type variant: Equal
elif inURLItem["MatchType"].upper() == "EQUAL":
if inURLItem["URL"].upper() == self.path.upper():
URLItemDo(inURLItem, self, mGlobalDict)
URLItemDo(inURLItem, self, gSettingsDict)
return True
# check Match type variant: EqualCase
elif inURLItem["MatchType"].upper() == "EQUALCASE":
if inURLItem["URL"] == self.path:
URLItemDo(inURLItem, self, mGlobalDict)
URLItemDo(inURLItem, self, gSettingsDict)
return True
return False
#ResponseContentTypeFile
@ -281,12 +296,12 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
# Logging
mGlobalDict["Logger"].info(f"HTTP request /. Domain: {lAuthenticateDict['Domain']}, User: {lAuthenticateDict['User']}")
# gSettingsDict["Logger"].info(f"HTTP request /. Domain: {lAuthenticateDict['Domain']}, User: {lAuthenticateDict['User']}")
if lFlagAccessUserBlock:
AuthenticateBlock(self)
#####################################
@ -295,7 +310,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
####################################
lFlagUserAccess = True
#If need user authentication
if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("GET", self)
######################################
if lFlagUserAccess:
@ -303,7 +318,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in mGlobalDict["Server"]["URLList"]:
for lURLItem in gSettingsDict["Server"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "GET")
@ -318,15 +333,15 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
self.send_header('Content-type','application/json')
self.end_headers()
# Send message back to client
message = json.dumps(mGlobalDict)
message = json.dumps(gSettingsDict)
# Write content as utf-8 data
self.wfile.write(bytes(message, "utf8"))
#Filemanager function
if self.path.lower().startswith('/filemanager/'):
lFileURL=self.path[13:]
# check if file in FileURL - File Path Mapping Dict
if lFileURL.lower() in mGlobalDict["FileManager"]["FileURLFilePathDict"]:
self.SendResponseContentTypeFile('application/octet-stream',mGlobalDict["FileManager"]["FileURLFilePathDict"][lFileURL])
if lFileURL.lower() in gSettingsDict["FileManager"]["FileURLFilePathDict"]:
self.SendResponseContentTypeFile('application/octet-stream', gSettingsDict["FileManager"]["FileURLFilePathDict"][lFileURL])
else:
#Set access denied code
# Send response status code
@ -345,7 +360,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
@ -357,7 +372,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
####################################
lFlagUserAccess = True
#If need user authentication
if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("POST", self)
######################################
if lFlagUserAccess:
@ -365,7 +380,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in mGlobalDict["Server"]["URLList"]:
for lURLItem in gSettingsDict["Server"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "POST")
@ -416,16 +431,16 @@ class RobotDaemonServer(Thread):
Thread.__init__(self)
self.name = name
# Update the global dict
ServerSettings.SettingsUpdate(mGlobalDict)
ServerSettings.SettingsUpdate(inGlobalDict)
def run(self):
inServerAddress="";
inPort = mGlobalDict["Server"]["ListenPort"];
inPort = gSettingsDict["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}")
gSettingsDict["Logger"].info(f"Server init. Listen URL: {inServerAddress}, Listen port: {inPort}")
#httpd.serve_forever()
httpd = ThreadedHTTPServer(server_address, testHTTPServer_RequestHandler)
#print('Starting server, use <Ctrl-C> to stop')

@ -3,12 +3,41 @@ import json
from desktopmagic.screengrab_win32 import (
getDisplayRects, saveScreenToBmp, saveRectToBmp, getScreenAsImage,
getRectAsImage, getDisplaysAsImages)
# /Orchestrator/RobotRDPActive/ControlPanelDictGet
def RobotRDPActive_ControlPanelDictGet(inRequest,inGlobalDict):
inResponseDict = inRequest.OpenRPAResponseDict
lResultDict = {
"DataList":[
# {"SessionKeyStr":"", "SessionHexStr": "", "IsFullScreenBool": False, "IsIgnoredBool": False}
]
}
# Iterate throught the RDP List
for lRDPSessionKeyStrItem in inGlobalDict["RobotRDPActive"]["RDPList"]:
lRDPConfiguration = inGlobalDict["RobotRDPActive"]["RDPList"][lRDPSessionKeyStrItem] # Get the configuration dict
lDataItemDict = {"SessionKeyStr":"", "SessionHexStr": "", "IsFullScreenBool": False, "IsIgnoredBool": False} # Template
lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str
lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex
lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGlobalDict["RobotRDPActive"]["FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window
lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored
lResultDict["DataList"].append(lDataItemDict)
# Send message back to client
message = json.dumps(lResultDict)
# Write content as utf-8 data
inResponseDict["Body"] = bytes(message, "utf8")
def Monitor_ControlPanelDictGet(inRequest,inGlobalDict):
inResponseDict = inRequest.OpenRPAResponseDict
# Create result JSON
lResultJSON = {"RenderRobotList": []}
lRenderFunctionsRobotList = inGlobalDict["ControlPanelDict"]["RobotList"]
for lItem in lRenderFunctionsRobotList:
lUACBool = True # Check if render function is applicable User Access Rights (UAC)
if inGlobalDict["Server"]["AccessUsers"]["FlagCredentialsAsk"] is True:
lUserRights = inGlobalDict["Server"]["AccessUsers"]["RuleDomainUserDict"][(inRequest.OpenRPA["Domain"].upper(),inRequest.OpenRPA["User"].upper())]
if len(lUserRights["ControlPanelKeyAllowedList"]) > 0 and lItem["KeyStr"] not in lUserRights["ControlPanelKeyAllowedList"]:
lUACBool = False # UAC Check is not passed - False for user
if lUACBool: # Run function if UAC is TRUE
# Выполнить вызов и записать результат
lItemResultDict = lItem["RenderFunction"](inGlobalDict)
# RunFunction
@ -60,7 +89,8 @@ def SettingsUpdate(inGlobalConfiguration):
{"Method":"GET", "URL": "/favicon.ico", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "Web\\favicon.ico"), "ResponseContentType": "image/x-icon"},
{"Method":"GET", "URL": "/3rdParty/Handlebars/handlebars-v4.1.2.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Handlebars\\handlebars-v4.1.2.js"), "ResponseContentType": "application/javascript"},
{"Method": "GET", "URL": "/Monitor/ControlPanelDictGet", "MatchType": "Equal", "ResponseDefRequestGlobal": Monitor_ControlPanelDictGet, "ResponseContentType": "application/json"},
{"Method": "GET", "URL": "/GetScreenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": GetScreenshot, "ResponseContentType": "image/png"}
{"Method": "GET", "URL": "/GetScreenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": GetScreenshot, "ResponseContentType": "image/png"},
{"Method": "GET", "URL": "/Orchestrator/RobotRDPActive/ControlPanelDictGet", "MatchType": "Equal","ResponseDefRequestGlobal": RobotRDPActive_ControlPanelDictGet, "ResponseContentType": "application/json"}
]
inGlobalConfiguration["Server"]["URLList"]=inGlobalConfiguration["Server"]["URLList"]+lURLList
return inGlobalConfiguration

@ -5,7 +5,7 @@ import importlib
import logging
from . import Processor
global mGlobalDict
global gSettingsDict
class RepeatedTimer(object):
def __init__(self, interval, function, *args, **kwargs):

@ -292,7 +292,49 @@
}
mGlobal.Monitor.fControlPanelRefresh()
mGlobal.Monitor.fControlPanelAutoUpdateRun(3);
////////////////////////////////
/////// /Orchestrator/RobotRDPActive/ControlPanelDictGet
///////////////////////////////
mGlobal.RobotRDPActive = {}
///Refresh control panel
mGlobal.RobotRDPActive.fControlPanelRefresh=function() {
///Загрузка данных
$.ajax({
type: "GET",
url: 'Orchestrator/RobotRDPActive/ControlPanelDictGet',
data: '',
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
///Сформировать HTML код новой таблицы
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-robotrdpactive-control-panel",lResponseJSON)
//Присвоить ответ в mGlobal.RobotRDPActive.mResponseList
mGlobal.RobotRDPActive.mResponseList = lResponseJSON
///Прогрузить новую таблицу
$(".openrpa-robotrdpactive-control-panel").html(lHTMLCode)
},
dataType: "text"
});
}
///
mGlobal.RobotRDPActive.mControlPanelAutoUpdateSeconds=3;
mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent=3;
mGlobal.RobotRDPActive.fControlPanelAutoUpdateRun=function(inRefreshSeconds) {
mGlobal.RobotRDPActive.mControlPanelAutoUpdateSeconds=inRefreshSeconds;
//Функция обновления текста кнопки обновления
lControlPanelUpdate=function() {
mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent=mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent-1
if (mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent==-1) {
mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent=mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent=mGlobal.RobotRDPActive.mControlPanelAutoUpdateSeconds;
mGlobal.RobotRDPActive.fControlPanelRefresh()
}
$(".openrpa-robotrdpactive-control-panel-general .openrpa-refresh-button").html("Refresh "+mGlobal.RobotRDPActive.mControlPanelAutoUpdateSecondsCurrent);
}
mGlobal.RobotRDPActive.mControlPanelAutoUpdateTimerId=setInterval(lControlPanelUpdate,1000)
}
mGlobal.RobotRDPActive.fControlPanelRefresh()
mGlobal.RobotRDPActive.fControlPanelAutoUpdateRun(3);
mGlobal.Test=function() {
///Обнулить таблицу
lData = [
@ -339,9 +381,9 @@
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
lResponseJSON["actionListResult"][0]["result"].forEach(function(lItem){lItem["processPathName"]=("processPath" in lItem ? lItem["processPath"] : lItem["processName"])})
lResponseJSON[0]["Result"].forEach(function(lItem){lItem["processPathName"]=("processPath" in lItem ? lItem["processPath"] : lItem["processName"])})
///Отправить запрос на формирование таблицы
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-info-table-planloglist",lResponseJSON["actionListResult"][0]);
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-info-table-planloglist",lResponseJSON[0]);
///Установить HTML код
$('.ui.modal.basic .content').html(lHTMLCode);
$('.ui.modal.basic').modal('show');
@ -349,12 +391,33 @@
dataType: "text"
});
}
///////////////////////////////
///Processor functions
///////////////////////////////
mGlobal.Processor = {}
mGlobal.Processor.ServerValueAppend = function(inKeyList,inValue) {
lData = [
{
"Type":"GlobalDictKeyListValueAppend",
"KeyList": inKeyList,
"Value": inValue
}
]
///Обнулить таблицу
$('.ui.modal.basic .content').html("");
$.ajax({
type: "POST",
url: 'Utils/Processor',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
///TODO Show error if exist error
},
dataType: "text"
});
}
mGlobal.Processor.ServerValueSet = function(inKeyList,inValue) {
lData = [
{
@ -532,58 +595,17 @@
///Установить HTML код
lElementParentElement.insertAdjacentHTML("beforeend",lHTMLCode);
}
///Test
lTestDataTable = {
"Title":"Test",
"Columns":["Дата/Время","Статус","Клиент","Файл"],
"Rows":[
["2019.10.31 13:21","Успешно", "ООО БалтКам", "test.xml"],
["2019.10.31 13:21","Успешно", "ООО Гренодер", "test.xml"],
["2019.10.31 13:21","Успешно", "ООО БалтКам", "test.xml"],
["2019.10.31 13:21","Успешно", "ООО Гренодер", "test.xml"],
["2019.10.31 13:21","Отказ", "ООО Сударь", "test.xml"],
["2019.10.31 13:21","Успешно", "ООО БалтКам", "test.xml"],
["2019.10.31 13:21","Отказ", "ООО Гренодер", "test.xml"],
["2019.10.31 13:21","Успешно", "ООО Гренодер", "test.xml"],
["2019.10.31 13:21","Успешно", "ООО Сударь", "test.xml"],
["2019.10.31 13:21","Успешно", "ООО БалтКам", "test.xml"],
["2019.10.31 13:21","Успешно", "ООО Гренодер", "test.xml"],
["2019.10.31 13:21","Отказ", "ООО Сударь", "test.xml"],
["2019.10.31 13:21","Успешно", "ООО БалтКам", "test.xml"],
["f","s"]
]
}
//mGlobal.Modal.TableFilter.Show(lTestData)
///Test
lTestData = {
"Title":"Test",
"List":[
{"Header":"Head 09","Description":"Test 21.02.2019"},
{"Header":"Head 09","Description":"Test 21.02.2019"},
{"Header":"Head 09","Description":"Test 21.02.2019"},
{"Header":"Head 09","Description":"TestNew 21.02.2019"},
{"Header":"Head 09","Description":"Test 21.02.2019"},
{"Header":"Head 09","Description":"TestNew 21.02.2019"},
{"Header":"Head 09","Description":"Test 21.02.2019"},
{"Header":"Head 09","Description":"Test 21.02.2019"}
]
}
// mGlobal.Modal.ListFilter.Show(lTestData)
})
;
</script>
<style type="text/css">
body {
background-color: #FFFFFF;
}
.main.container {
margin-top: 2em;
}
.overlay {
float: left;
margin: 0em 3em 1em 0em;
@ -593,7 +615,6 @@
left: 0;
transition: left 0.5s ease;
}
.main.menu.fixed {
background-color: #FFFFFF;
border: 1px solid #DDD;
@ -602,14 +623,12 @@
.overlay.fixed .menu {
left: 800px;
}
.text.container .left.floated.image {
margin: 2em 2em 2em -4em;
}
.text.container .right.floated.image {
margin: 2em -4em 2em 2em;
}
.ui.footer.segment {
margin: 5em 0em 0em;
padding: 5em 0em;
@ -626,7 +645,7 @@
<h1 class="ui header inverted">Orchestrator Web GUI</h1>
</div>
<div class="two wide column">
<h5>by UnicodeLabs</h5>
<h5>by Ivan Maslov</h5>
</div>
</div>
@ -689,17 +708,19 @@
</div>
</div>
<div class="row black">
<div class="three wide column">
</div>
<div class="three wide column">
<h2 class="ui header inverted">Monitor</h2>
<div class="five wide column">
<h2 class="ui header inverted">Controls</h2>
</div>
<div class="two wide column">
<h2 class="ui header inverted">...</h2>
</div>
<div class="nine wide column">
<h2 class="ui header inverted">Robot RDP active list</h2>
</div>
</div>
<div class="row">
<div class="five wide column">
<button class="ui labeled icon button" onclick="mGlobal.Monitor.ScreenshotModal.Show();">
<i class="desktop icon"></i>
Look machine screenshot
@ -722,14 +743,14 @@
</tr>
</thead>
<tbody>
{{#result}}
{{#Result}}
<tr>
<td>{{@index}}</td>
<td>{{activityType}}</td>
<td>{{time}}</td>
<td>{{processPathName}}</td>
<td>{{TimeHH:MM}}{{TimeHH:MMStart}}</td>
<td>{{TimeHH:MMStop}}</td>
<td>{{Activity}}</td>
</tr>
{{/result}}
{{/Result}}
</tbody>
</table>
</script>
@ -837,6 +858,52 @@
</div>
</div>
</script>
</div>
<div class="two wide column">
</div>
<div class="nine wide column openrpa-robotrdpactive-control-panel-general">
<div class="ui info message">
<button class="ui icon button labeled " onclick="mGlobal.RobotRDPActive.fControlPanelRefresh();">
<i class="sync alternate icon"></i>
<div class="openrpa-refresh-button">Refresh</div>
</button>
</div>
<div class="openrpa-robotrdpactive-control-panel"></div>
<script class="openrpa-hidden-robotrdpactive-control-panel" style="display:none" type="text/x-handlebars-template">
<div class="ui inverted segment">
<div class="ui inverted relaxed divided list">
{{#DataList}}
<div class="item">
<div class="right floated content">
<div class="ui button" onclick="mGlobal.Processor.ServerValueAppend(['RobotRDPActive','ActivityList'],{'DefNameStr': 'RDPSessionReconnect', 'ArgList': [], 'ArgDict': {'inRDPSessionKeyStr': '{{{SessionKeyStr}}}'} })" >Reconnect</div>
</div>
<div class="right floated content">
{{#if IsIgnoredBool}}
<div class="ui button red" onclick="mGlobal.Processor.ServerValueSet(['RobotRDPActive','RDPList','{{{SessionKeyStr}}}','SessionIsIgnoredBool'],false);">Ignore</div>
{{else}}
<div class="ui button" onclick="mGlobal.Processor.ServerValueSet(['RobotRDPActive','RDPList','{{{SessionKeyStr}}}','SessionIsIgnoredBool'],true);">Ignore</div>
{{/if}}
</div>
<div class="right floated content">
{{#if IsFullScreenBool}}
<div class="ui button green" onclick="mGlobal.Processor.ServerValueSet(['RobotRDPActive','FullScreenRDPSessionKeyStr'],null);">Full screen</div>
{{else}}
<div class="ui button" onclick="mGlobal.Processor.ServerValueSet(['RobotRDPActive','FullScreenRDPSessionKeyStr'],'{{{SessionKeyStr}}}');">Full screen</div>
{{/if}}
</div>
<div class="content">
<div class="header">Session key: {{{SessionKeyStr}}}</div>
{{{SessionHexStr}}}
</div>
</div>
{{/DataList}}
</div>
</div>
</script>
</div>
</div>
<div class="row openrpa-monitor">
</div>

@ -383,6 +383,13 @@ def IntervalDataReceiveResetAsync(*args,**kwargs):
if "Interval" in lKwargs:
lInterval = lKwargs["Interval"]
del lKwargs["Interval"]
# Reset the storage before start
DataSendSync(
RobotValue=lKwargs["RobotResetValue"],
OrchestratorKeyList=lKwargs["OrchestratorKeyList"], OrchestratorProtocol=lKwargs["OrchestratorProtocol"],
OrchestratorHost=lKwargs["OrchestratorHost"], OrchestratorPort=lKwargs["OrchestratorPort"],
OrchestratorAuthToken=lKwargs["OrchestratorAuthToken"]
)
lTimer = TimerRepeat.TimerRepeat(lInterval, DataReceiveResetAsync, lArgs, lKwargs)
lTimer.start()
#Add timer to general list to stop this when needed

@ -12,7 +12,7 @@ import datetime
import struct
import shutil
from pyOpenRPA.Robot import UIDesktop
global mGlobalDict
global gSettingsDict
####################################
#Info: Main module of the Robot app (OpenRPA - Robot)
####################################

@ -11,7 +11,7 @@ from . import RobotConnector
from . import JSONNormalize
import importlib
#Единый глобальный словарь (За основу взять из Settings.py)
global mGlobalDict
global gSettingsDict
#Call Settings function from argv[1] file
################################################
lSubmoduleFunctionName = "Settings"
@ -20,14 +20,14 @@ 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
gSettingsDict = None
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
# Run SettingUpdate function in submodule
mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
gSettingsDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
#################################################
RobotConnector.mGlobalDict = mGlobalDict
RobotConnector.mGlobalDict = gSettingsDict
#Init the robot
RobotConnector.UIDesktop.Utils.ProcessBitness.SettingsInit(mGlobalDict["ProcessBitness"])
RobotConnector.UIDesktop.Utils.ProcessBitness.SettingsInit(gSettingsDict["ProcessBitness"])
# HTTP Studio web server class
class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
@ -144,13 +144,13 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
def run():
inServerAddress = "";
inPort = mGlobalDict["Server"]["ListenPort"];
inPort = gSettingsDict["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}")
gSettingsDict["Logger"].info(f"Server init. Listen URL: {inServerAddress}, Listen port: {inPort}")
# Запуск адреса в браузере
os.system(f"explorer http://127.0.0.1:{str(inPort)}")
httpd.serve_forever()

@ -15,7 +15,7 @@ import importlib
from importlib import util
#Единый глобальный словарь (За основу взять из Settings.py)
global mGlobalDict
global gSettingsDict
#Call Settings function from argv[1] file
################################################
lSubmoduleFunctionName = "Settings"
@ -24,18 +24,18 @@ 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
gSettingsDict = None
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
# Run SettingUpdate function in submodule
mGlobalDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
gSettingsDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
#################################################
#mGlobalDict = Settings.Settings(sys.argv[1])
Server.mGlobalDict = mGlobalDict
Server.mGlobalDict = gSettingsDict
#Инициализация настроечных параметров
lDaemonActivityLogDict={} #Словарь отработанных активностей, ключ - кортеж (<activityType>, <datetime>, <processPath || processName>, <processArgs>)
lDaemonStartDateTime=datetime.datetime.now()
#Инициализация сервера
lThreadServer = Server.RobotDaemonServer("ServerThread", mGlobalDict)
lThreadServer = Server.RobotDaemonServer("ServerThread", gSettingsDict)
lThreadServer.start()

@ -10,7 +10,7 @@ import uuid
import datetime
import os #for path operations
from http import cookies
global mGlobalDict
global gSettingsDict
from . import ServerSettings
#Authenticate function ()
# return dict
@ -30,10 +30,10 @@ def AuthenticateVerify(inRequest):
lCookieAuthToken = lCookies.get("AuthToken", "").value
if lCookieAuthToken:
#Find AuthToken in GlobalDict
if lCookieAuthToken in mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("AuthTokensDict", {}):
if lCookieAuthToken in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("AuthTokensDict", {}):
#Auth Token Has Been Founded
lResult["Domain"] = mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"]
lResult["User"] = mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"]
lResult["Domain"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"]
lResult["User"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"]
#Set auth token
inRequest.OpenRPA["AuthToken"] = lCookieAuthToken
#Exit earlier
@ -65,11 +65,11 @@ def AuthenticateVerify(inRequest):
lResult["User"] = lLogonResult["User"]
#Create token
lAuthToken=str(uuid.uuid1())
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {}
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"]
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"]
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False
mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now()
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {}
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"]
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"]
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now()
#Set-cookie
inRequest.OpenRPA["AuthToken"] = lAuthToken
inRequest.OpenRPASetCookie = {}
@ -108,13 +108,13 @@ def UserAccessCheckBefore(inMethod, inRequest):
#go next if user is identified
lUserDict = None
if lAuthToken:
lUserDict = mGlobalDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]
lUserDict = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]
#pdb.set_trace()
########################################
########################################
#Check general before rule (without User domain)
#Check rules
for lAccessRuleItem in mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("RuleMethodMatchURLBeforeList", []):
for lAccessRuleItem in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleMethodMatchURLBeforeList", []):
#Go next execution if flag is false
if not lResult:
#Check if Method is identical
@ -124,21 +124,21 @@ def UserAccessCheckBefore(inMethod, inRequest):
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: Contains
elif lAccessRuleItem["MatchType"].upper() == "CONTAINS":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.contains(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: Equal
elif lAccessRuleItem["MatchType"].upper() == "EQUAL":
if lAccessRuleItem["URL"].upper() == inRequest.path.upper():
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: EqualCase
elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE":
if lAccessRuleItem["URL"] == inRequest.path:
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
#########################################
#########################################
#Do check if lResult is false
@ -146,7 +146,7 @@ def UserAccessCheckBefore(inMethod, inRequest):
#Check access by User Domain
#Check rules to find first appicable
#Check rules
for lAccessRuleItem in mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", []):
for lAccessRuleItem in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", []):
#Go next execution if flag is false
if not lResult:
#Check if Method is identical
@ -156,21 +156,21 @@ def UserAccessCheckBefore(inMethod, inRequest):
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
#check Match type variant: Contains
elif lAccessRuleItem["MatchType"].upper() == "CONTAINS":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.contains(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: Equal
elif lAccessRuleItem["MatchType"].upper() == "EQUAL":
if lAccessRuleItem["URL"].upper() == inRequest.path.upper():
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: EqualCase
elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE":
if lAccessRuleItem["URL"] == inRequest.path:
lResult = HelpGetFlag(lAccessRuleItem, inRequest, mGlobalDict, lUserDict)
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
#####################################
#####################################
#Return lResult
@ -220,24 +220,24 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
lURLPath = self.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(inURLItem["URL"].upper()):
URLItemDo(inURLItem, self, mGlobalDict)
URLItemDo(inURLItem, self, gSettingsDict)
return True
# check Match type variant: Contains
elif inURLItem["MatchType"].upper() == "CONTAINS":
lURLPath = self.path
lURLPath = lURLPath.upper()
if lURLPath.contains(inURLItem["URL"].upper()):
URLItemDo(inURLItem, self, mGlobalDict)
URLItemDo(inURLItem, self, gSettingsDict)
return True
# check Match type variant: Equal
elif inURLItem["MatchType"].upper() == "EQUAL":
if inURLItem["URL"].upper() == self.path.upper():
URLItemDo(inURLItem, self, mGlobalDict)
URLItemDo(inURLItem, self, gSettingsDict)
return True
# check Match type variant: EqualCase
elif inURLItem["MatchType"].upper() == "EQUALCASE":
if inURLItem["URL"] == self.path:
URLItemDo(inURLItem, self, mGlobalDict)
URLItemDo(inURLItem, self, gSettingsDict)
return True
return False
#ResponseContentTypeFile
@ -280,12 +280,12 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
# Logging
mGlobalDict["Logger"].info(f"HTTP request /. Domain: {lAuthenticateDict['Domain']}, User: {lAuthenticateDict['User']}")
gSettingsDict["Logger"].info(f"HTTP request /. Domain: {lAuthenticateDict['Domain']}, User: {lAuthenticateDict['User']}")
if lFlagAccessUserBlock:
AuthenticateBlock(self)
#####################################
@ -294,7 +294,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
####################################
lFlagUserAccess = True
#If need user authentication
if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("GET", self)
######################################
if lFlagUserAccess:
@ -302,7 +302,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in mGlobalDict["Server"]["URLList"]:
for lURLItem in gSettingsDict["Server"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "GET")
@ -327,7 +327,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
@ -339,7 +339,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
####################################
lFlagUserAccess = True
#If need user authentication
if mGlobalDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("POST", self)
######################################
if lFlagUserAccess:
@ -347,7 +347,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in mGlobalDict["Server"]["URLList"]:
for lURLItem in gSettingsDict["Server"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "POST")
@ -380,16 +380,16 @@ class RobotDaemonServer(Thread):
Thread.__init__(self)
self.name = name
# Update the global dict
ServerSettings.SettingsUpdate(mGlobalDict)
ServerSettings.SettingsUpdate(gSettingsDict)
def run(self):
inServerAddress="";
inPort = mGlobalDict["Server"]["ListenPort"];
inPort = gSettingsDict["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}")
gSettingsDict["Logger"].info(f"Server init. Listen URL: {inServerAddress}, Listen port: {inPort}")
#httpd.serve_forever()
httpd = ThreadedHTTPServer(server_address, testHTTPServer_RequestHandler)
#print('Starting server, use <Ctrl-C> to stop')

@ -1,136 +0,0 @@
#Import parent folder to import current / other packages
from pyOpenRPA.Robot import UIDesktop #Lib to access RDP window
import os #os for process run
import uuid #temp id for Template.rdp
import tempfile #Temporary location
import time
import subprocess
#Connect to RDP session
"""
{
"Host": "", #Host address
"Port": "", #RDP Port
"Login": "", # Login
"Password": "", #Password
"Screen": {
"Resolution":"FullScreen", #"640x480" or "1680x1050" or "FullScreen". If Resolution not exists set full screen
"FlagUseAllMonitors": False, # True or False
"DepthBit":"" #"32" or "24" or "16" or "15"
}
}
"""
def Session(inRDPSessionConfiguration):
#RDPConnector.SessionConnect(mConfiguration)
#RDPConnector.LoginPassSet("111.222.222.111","ww","dd")
(lRDPFile, lSessionHex) = SessionConfigurationCreate(inRDPSessionConfiguration)
#Set session hex in globalDict
inRDPSessionConfiguration["SessionHex"] = lSessionHex
#Set login/password
SessionLoginPasswordSet(inRDPSessionConfiguration["Host"],inRDPSessionConfiguration["Login"],inRDPSessionConfiguration["Password"])
#Start session
SessionRDPStart(lRDPFile)
#Remove temp file
time.sleep(4) #Delete file after some delay - one way to delete and run the RDP before because RDP is not read file in one moment
os.remove(lRDPFile) # delete the temp rdp
return inRDPSessionConfiguration
#Add login/ password to the windows credentials to run RDP
def SessionLoginPasswordSet(inHost, inLogin, inPassword):
#Clear old login/password if it exists
#os.system(f"cmdkey /delete:TERMSRV/{inHost}") #Dont need to delete because new user password will clear the previous creds
#Set login password for host
os.system(f"cmdkey /generic:TERMSRV/{inHost} /user:{inLogin} /pass:{inPassword}")
return None
#Create current .rdp file with settings
#Return (full path to file, session hex)
def SessionConfigurationCreate(inConfiguration):
#RobotRDPActive folder path
lFileFullPath=__file__
lFileFullPath = lFileFullPath.replace("/","\\")
lRobotRDPActiveFolderPath = "\\".join(lFileFullPath.split("\\")[:-1])
#Full path to Template.rdp file
lRDPTemplateFileFullPath = os.path.join(lRobotRDPActiveFolderPath, "Template.rdp")
#Open template file (.rdp encoding is USC-2 LE BOM = UTF-16 LE) http://qaru.site/questions/7156020/python-writing-a-ucs-2-little-endian-utf-16-le-file-with-bom
lRDPTemplateFileContent = open(lRDPTemplateFileFullPath, "r", encoding="utf-16-le").read()
#Prepare host:port
lHostPort=inConfiguration['Host']
if 'Port' in inConfiguration:
if inConfiguration['Port']:
lHostPort=f"{lHostPort}:{inConfiguration['Port']}"
#Replace {Width}, {Height}, {BitDepth}, {HostPort}, {Login}
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{Width}", str(inConfiguration.get('Screen',{}).get("Width",1680)))
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{Height}", str(inConfiguration.get('Screen',{}).get("Height",1050)))
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{BitDepth}", inConfiguration.get('Screen',{}).get("DepthBit","32"))
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{HostPort}", lHostPort)
lRDPTemplateFileContent = lRDPTemplateFileContent.replace("{Login}", inConfiguration['Login'])
#Save template to temp file
lRDPCurrentFileFullPath = os.path.join(tempfile.gettempdir(), f"{uuid.uuid4().hex}.rdp")
open(lRDPCurrentFileFullPath, "w", encoding="utf-16-le").write(lRDPTemplateFileContent)
#Return .rdp full path
return (lRDPCurrentFileFullPath, (lRDPCurrentFileFullPath.split("\\")[-1])[0:-4])
#RDPSessionStart
def SessionRDPStart(inRDPFilePath):
#run rdp session
lItemArgs = [inRDPFilePath]
subprocess.Popen(lItemArgs, shell=True)
#Wait for UAC unknown publisher exists
lRDPFileName = (inRDPFilePath.split("\\")[-1])[0:-4]
lWaitResult = UIDesktop.UIOSelectorsSecs_WaitAppear_List(
[
[{"title": "Подключение к удаленному рабочему столу", "class_name": "#32770", "backend": "win32"},
{"title": "Боль&ше не выводить запрос о подключениях к этому компьютеру", "friendly_class_name": "CheckBox"}],
[{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "D&on't ask me again for connections to this computer",
"friendly_class_name": "CheckBox"}],
[{"title_re": f"{lRDPFileName}.*",
"class_name": "TscShellContainerClass", "backend": "win32"}]
],
30
)
#Click if 0 is appear (RUS)
if 0 in lWaitResult:
#Check the box do not retry
UIDesktop.UIOSelector_Get_UIO([{"title": "Подключение к удаленному рабочему столу", "backend": "win32"},
{"title": "Боль&ше не выводить запрос о подключениях к этому компьютеру", "friendly_class_name": "CheckBox"}]).check()
#Go to connection
UIDesktop.UIOSelector_Get_UIO([{"title": "Подключение к удаленному рабочему столу", "backend": "win32"},
{"title":"Подкл&ючить", "class_name":"Button"}]).click()
lWaitResult = UIDesktop.UIOSelectorsSecs_WaitAppear_List(
[
[{"title_re": f"{lRDPFileName}.*",
"class_name": "TscShellContainerClass", "backend": "win32"}]
],
30
)
# Click if 1 is appear (ENG)
if 1 in lWaitResult:
# Check the box do not retry
UIDesktop.UIOSelector_Get_UIO([{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "D&on't ask me again for connections to this computer",
"friendly_class_name": "CheckBox"}]).check()
# Go to connection
UIDesktop.UIOSelector_Get_UIO([{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "Co&nnect", "class_name": "Button"}]).click()
lWaitResult = UIDesktop.UIOSelectorsSecs_WaitAppear_List(
[
[{"title_re": f"{lRDPFileName}.*",
"class_name": "TscShellContainerClass", "backend": "win32"}]
],
30
)
#Prepare little window
SessionScreen100x550(lRDPFileName)
return None
#Set fullscreen for app
def SessionScreenFull(inSessionHex):
#Prepare little window
lRDPWindow = UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHex}.*", "backend": "win32"}])
lRDPWindow.maximize()
lRDPWindow.set_focus()
return None
#Set Little window of the session
def SessionScreen100x550(inSessionHex):
#Prepare little window
lRDPWindow = UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHex}.*", "backend": "win32"}])
lRDPWindow.restore()
lRDPWindow.move_window(10,10,550,100)
return None

@ -1,55 +0,0 @@
from pyOpenRPA.Robot import UIDesktop
from . import Connector
import os
import pdb
#Check for session is closed. Reopen if detected. Always keep session is active
def Monitor(inGlobalDict, inListUpdateTimeout):
lFlagWhile = True
while lFlagWhile:
# UIOSelector list init
lUIOSelectorList = []
#Prepare selectors list for check
for lIndex, lItem in enumerate(inGlobalDict["RDPList"]):
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']}.*", "backend": "win32"}])
#Run wait command
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
###########################################
#Analyze if flag safeturn off is activated
if inGlobalDict.get("OrchestratorToRobotResetStorage",{}).get("SafeTurnOff",False):
lFlagWhile=False
#Set status disconnected for all RDP List
for lItem in inGlobalDict["RDPList"]:
lItem["FlagSessionIsActive"]=False
#Kill all RDP sessions
os.system('taskkill /F /im mstsc.exe')
#Return from function
return
###########################################
###########################################
for lItem in lRDPDissappearList:
inGlobalDict["RDPList"][lItem]["FlagSessionIsActive"] = False # Set flag that session is disconnected
#pdb.set_trace()
#Session start if it is not in ignore list
#add check for selector if it is not in ignoreIndexList
if lItem not in inGlobalDict["OrchestratorToRobotStorage"]["IgnoreIndexList"]:
try:
Connector.Session(inGlobalDict["RDPList"][lItem])
inGlobalDict["RDPList"][lItem]["FlagSessionIsActive"] = True # Flag that session is started
except Exception:
pass
###########################################
#Check if from Orchestrator full screen session is set
if inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"] != inGlobalDict["FullScreenSessionIndex"]:
#Do some switches
#If full screen mode we have now
if inGlobalDict["FullScreenSessionIndex"] is not None:
if inGlobalDict["RDPList"][inGlobalDict["FullScreenSessionIndex"]]["FlagSessionIsActive"]:
Connector.SessionScreen100x550(inGlobalDict["RDPList"][inGlobalDict["FullScreenSessionIndex"]]["SessionHex"])
#If new session is setted
if inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"] is not None:
if inGlobalDict["RDPList"][inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]]["FlagSessionIsActive"]:
Connector.SessionScreenFull(inGlobalDict["RDPList"][inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]]["SessionHex"])
#Set one to other equal
inGlobalDict["FullScreenSessionIndex"] = inGlobalDict["OrchestratorToRobotStorage"]["FullScreenSessionIndex"]
return None
#TODO Def garbage window cleaner (if connection was lost)

@ -8,18 +8,35 @@ from . import Crypter # Crypto functions
import datetime #Datetime
import hashlib #Get hash of the word
import pyautogui
import os
import glob # list files
EXT = '.cry'
gExtensionName = "cry"
# How to run
# sys.meta_path.append(Base64Importer(root_pkg_path))
# Init cryptographer
def CryptographerInit(inFolderPath):
sys.meta_path.append(Base64Importer(inFolderPath))
def CryptographerInit(inFolderPathList, inKey):
#sys.meta_path.append(Base64Importer(inFolderPath))
# Flag add subfolder, which contains extension files
#path = 'c:\\projects\\hc2\\'
#folders = []
# Recursive walk throught the tree
# r=root, d=directories, f = files
#import pdb
#pdb.set_trace()
for lItem in inFolderPathList:
sys.meta_path.append(Base64Importer(os.path.abspath(lItem), inKey=inKey))
#for r, d, f in os.walk(lItem):
# for folder in d:
#folders.append(os.path.join(r, folder))
#sys.meta_path.append(Base64Importer(os.path.join(r, folder), inKey=inKey))
# pass
#for f in folders:
# print(f)
#===============================================================================
class Base64Importer(object):
"""Служит для поиска и импорта python-модулей, кодированных в base64
Класс реализует Import Protocol (PEP 302) для возможности импортирования
модулей, зашифрованных в base64 из указанного пакета.
"""
@ -27,25 +44,28 @@ class Base64Importer(object):
def __init__(self, root_package_path, inKey):
self.mKeyStr = inKey
self.__modules_info = self.__collect_modules_info(root_package_path)
# Create list of cry files when run
#for lItem in root_package_path_list:
# lCryptedFileList = [f for f in glob.glob(os.path.join(lItem,f"**/*.{EXT}"), recursive=True)]
#---------------------------------------------------------------------------
def find_module(self, fullname, path=None):
"""Метод будет вызван при импорте модулей
Если модуль с именем fullname является base64 и находится в заданной
папке, данный метод вернёт экземпляр импортёра (finder), либо None, если
модуль не является base64.
"""
#print(f"find_module:: Fullname: {fullname}, path: {path}")
#print(f"modules info: {self.__modules_info}")
if fullname in self.__modules_info:
return self
return None
#---------------------------------------------------------------------------
def load_module(self, fullname):
"""Метод загружает base64 модуль
Если модуль с именем fullname является base64, то метод попытается его
загрузить. Возбуждает исключение ImportError в случае любой ошибки.
"""
#print(f"load_module:: Fullname: {fullname}")
if not fullname in self.__modules_info:
raise ImportError(fullname)
# Для потокобезопасности
@ -53,6 +73,8 @@ class Base64Importer(object):
try:
mod = sys.modules.setdefault(fullname, imp.new_module(fullname))
mod.__file__ = "<{}>".format(self.__class__.__name__)
mod.__file__ = self.__modules_info[fullname]['filename'] #Hotfix
#print(f"MODFILE::{mod.__file__}")
mod.__loader__ = self
if self.is_package(fullname):
mod.__path__ = []
@ -61,7 +83,10 @@ class Base64Importer(object):
mod.__package__ = fullname.rpartition('.')[0]
src = self.get_source(fullname)
try:
exec(src) in mod.__dict__
#__name__ = "pyPackage"
#print(f"MODNAME:: {mod.__name__}")
#exec(src) in mod.__dict__
exec(src,mod.__dict__)
except:
del sys.modules[fullname]
raise ImportError(fullname)
@ -98,33 +123,55 @@ class Base64Importer(object):
"""Собирает информацию о модулях из указанного пакета
"""
modules = {}
"""
p = os.path.abspath(root_package_path)
dir_name = os.path.dirname(p) + os.sep
#dir_name = "" # Hotfix 2020 03 19
#print(f"__collect_modules_info:: root_package_path: {root_package_path}")
for root, _, files in os.walk(p):
# Информация о текущем пакете
filename = os.path.join(root, '__init__' + EXT)
p_fullname = root.rpartition(dir_name)[2].replace(os.sep, '.')
modules[p_fullname] = {
'filename': filename,
'ispackage': True
}
# Информация о модулях в текущем пакете
for f in files:
if not f.endswith(EXT):
continue
filename = os.path.join(root, f)
fullname = '.'.join([p_fullname, os.path.splitext(f)[0]])
fullname = os.path.splitext(f)[0]
modules[fullname] = {
'filename': filename,
'ispackage': False
}
"""
# # # # # # # # # # #
# New way of collection
lRootAbsPath = os.path.abspath(root_package_path)
#print(lRootAbsPath)
lNewPathIndex = len(lRootAbsPath)+len(os.sep) # Len of the root path + len sep
lCryptedFileList = [f for f in glob.glob(os.path.join(lRootAbsPath,f"**/*.{gExtensionName}"), recursive=True)]
#print(lCryptedFileList)
for lCryptedItemFullPath in lCryptedFileList:
# Get Module name
lModuleName = lCryptedItemFullPath[lNewPathIndex:-(1+len(gExtensionName))].replace(os.sep, '.')
# Check if file is not __init__.{EXT} - This is package
if f"__init__.{EXT}" in lCryptedItemFullPath:
# Add package
lModuleName = lModuleName.replace(f"{os.sep}__init__.{gExtensionName}","")
modules[lModuleName] = {
'filename': lCryptedItemFullPath,
'ispackage': True
}
else:
# Add item
modules[lModuleName] = {
'filename': lCryptedItemFullPath,
'ispackage': False
}
return modules
# Settings
gInUncryptedExtension = "py" # cry for filename.cry
@ -142,20 +189,25 @@ gSettings = {
}
}
# Create process run
def Run():
global gSettings
print(f"{str(datetime.datetime.now())}: Run decryptography")
############# Step 5 - Ask and confirm the secret word
lKeyHashStr_1 = hashlib.sha256(pyautogui.password('Please enter the key to protect source code').encode("utf-8")).digest()
lKeyHashStr_2 = hashlib.sha256(pyautogui.password('Please repeat the key to protect source code').encode("utf-8")).digest()
if lKeyHashStr_1 == lKeyHashStr_2:
sys.meta_path.append(Base64Importer("TestPackage",inKey = lKeyHashStr_1))
#CryptographerInit("", inKey = lKeyHashStr_1)
#Init the functions
import runpy
runpy.run_module(**gSettings["run_module"])
else:
raise Exception("User set different secret key 1 and key 2")
############ Step 6 - Final stage
# Settings
gInUncryptedExtension = "py" # cry for filename.cry
gOutCryptedExtension = "cry" # cry for filename.cry
gFileMaskToDelete = "pyc" #Remove all .pyc files
print(f"{str(datetime.datetime.now())}: Run decryptography")
############# Step 5 - Ask and confirm the secret word
lKeyHashStr_1 = hashlib.sha256(pyautogui.password('Please enter the key to protect source code').encode("utf-8")).digest()
lKeyHashStr_2 = hashlib.sha256(pyautogui.password('Please repeat the key to protect source code').encode("utf-8")).digest()
if lKeyHashStr_1 == lKeyHashStr_2:
#sys.meta_path.append(Base64Importer("TestPackage",inKey = lKeyHashStr_1))
CryptographerInit(sys.argv[1:], inKey = lKeyHashStr_1)
print(f"{str(datetime.datetime.now())}: Cryprography module has been successfully initialized")
if __name__ == "__main__":
#import runpy
#runpy.run_module(**gSettings["run_module"])
#runpy.run_path("pyPackage_Settings", init_globals=None, run_name=None)
# Here is the execution code...
#############
###########
#######
else:
raise Exception("User set different secret key 1 and key 2")

@ -3,7 +3,7 @@ r"""
The OpenRPA package (from UnicodeLabs)
"""
__version__ = 'v1.0.42'
__version__ = 'v1.1.0'
__all__ = []
__author__ = 'Ivan Maslov <ivan.maslov@unicodelabs.ru>'
#from .Core import Robot

@ -159,11 +159,14 @@ def SessionScreenFull(inSessionHex):
# Set the screen size
def SessionScreenSize_X_Y_W_H(inSessionHex, inXInt, inYInt, inWInt, inHInt):
lDoBool = True
while lDoBool:
#Prepare little window
try:
lRDPWindow = UIDesktop.UIOSelector_Get_UIO([{"title_re": f"{inSessionHex}.*", "backend": "win32"}])
except Exception as e:
return None
try:
lRDPWindow.set_focus()
if SessionIsFullScreen(inSessionHex):
lRDPWindow.type_keys("^%{BREAK}")
@ -171,6 +174,10 @@ def SessionScreenSize_X_Y_W_H(inSessionHex, inXInt, inYInt, inWInt, inHInt):
lRDPWindow.restore()
time.sleep(0.5)
lRDPWindow.move_window(inXInt,inYInt,inWInt,inHInt)
except Exception as e:
time.sleep(1)
else:
lDoBool = False
return None
# Set Little window of the session

@ -38,7 +38,8 @@ def RDPSessionConnect(inRDPSessionKeyStr, inHostStr, inPortStr, inLoginStr, inPa
# Disconnect the RDP session
def RDPSessionDisconnect(inRDPSessionKeyStr):
global gSettings
lSessionHex = gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr]["SessionHex"]
lSessionHex = gSettings["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
if lSessionHex:
gSettings["RobotRDPActive"]["RDPList"].pop(inRDPSessionKeyStr,None)
Connector.SessionClose(inSessionHexStr=lSessionHex)
return True
@ -54,6 +55,19 @@ def RDPSessionReconnect(inRDPSessionKeyStr):
Connector.Session(lRDPConfigurationItem)
return True
# Logoff the RDP session
def RDPSessionLogoff(inRDPSessionKeyStr):
global gSettings
lResult = True
lCMDStr = "shutdown -L" # CMD logoff command
# Calculate the session Hex
lSessionHex = gSettings["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
if lSessionHex:
gSettings["RobotRDPActive"]["RDPList"].pop(inRDPSessionKeyStr,None)
# Run CMD
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
return lResult
# Check RDP Session responsibility TODO NEED DEV + TEST
def RDPSessionResponsibilityCheck(inRDPSessionKeyStr):
global gSettings
@ -81,72 +95,53 @@ def RDPSessionResponsibilityCheck(inRDPSessionKeyStr):
return True
# Start process if it is not running
def RDPSessionProcessStartIfNotRunning(inRDPSessionKey, inProcessName, inFilePath, inFlagGetAbsPath=True):
def RDPSessionProcessStartIfNotRunning(inRDPSessionKeyStr, inProcessNameWEXEStr, inFilePathStr, inFlagGetAbsPathBool=True):
global gSettings
inGlobalDict = gSettings
lResult = True
lCMDStr = CMDStr.ProcessStartIfNotRunning(inProcessName,inFilePath, inFlagGetAbsPath= inFlagGetAbsPath)
lCMDStr = CMDStr.ProcessStartIfNotRunning(inProcessNameWEXEStr, inFilePathStr, inFlagGetAbsPath= inFlagGetAbsPathBool)
# Calculate the session Hex
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKey]["SessionHex"]
# Check is Session is responsible
if inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKey]["SessionIsWindowResponsibleBool"]:
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
# Run CMD
if lSessionHex:
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
else:
# Write in logger - warning
inGlobalDict["Logger"].warning(f"Defs_SessionIndex.ProcessStartIfNotRunning: SessionIndex: {str(inRDPSessionKey)}, ProcessName: {inProcessName}:: Session is not responsible!")
lResult = False # Set false result - function has not been done
return lResult
# Create CMD str to stop process
def RDPSessionProcessStop(inRDPSessionKey, inProcessName, inFlagForceClose):
def RDPSessionProcessStop(inRDPSessionKeyStr, inProcessNameWEXEStr, inFlagForceCloseBool):
global gSettings
inGlobalDict = gSettings
lResult = True
lCMDStr = f'taskkill /im "{inProcessName}" /fi "username eq %USERNAME%"'
if inFlagForceClose:
lCMDStr = f'taskkill /im "{inProcessNameWEXEStr}" /fi "username eq %USERNAME%"'
if inFlagForceCloseBool:
lCMDStr+= " /F"
# Calculate the session Hex
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKey]["SessionHex"]
# Check is Session is responsible
if inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKey]["SessionIsWindowResponsibleBool"]:
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
# Run CMD
if lSessionHex:
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN")
else:
# TODO Write in logger - warning
inGlobalDict["Logger"].warning(f"Defs_SessionIndex.ProcessStop: SessionIndex: {str(inRDPSessionKey)}, ProcessName: {inProcessName}:: Session is not responsible!")
lResult = False # Set false result - function has not been done
return lResult
# Send file from Host to Session RDP using shared drive in RDP
def RDPSessionFileStoredSend(inRDPSessionKey, inHostFilePath, inRDPFilePath):
def RDPSessionFileStoredSend(inRDPSessionKeyStr, inHostFilePathStr, inRDPFilePathStr):
global gSettings
inGlobalDict = gSettings
lResult = True
lCMDStr = CMDStr.FileStoredSend(inHostFilePath = inHostFilePath, inRDPFilePath = inRDPFilePath)
lCMDStr = CMDStr.FileStoredSend(inHostFilePath = inHostFilePathStr, inRDPFilePath = inRDPFilePathStr)
# Calculate the session Hex
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKey]["SessionHex"]
# Check is Session is responsible
if inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKey]["SessionIsWindowResponsibleBool"]:
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr, {}).get("SessionHex", None)
#lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr]["SessionHex"]
# Run CMD
if lSessionHex:
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120)
else:
# Write in logger - warning
inGlobalDict["Logger"].warning(f"Defs_SessionIndex.FileStoredSend: SessionIndex: {str(inRDPSessionKey)}, HostFilePath: {inHostFilePath}:: Session is not responsible!")
lResult = False # Set false result - function has not been done
return lResult
# Recieve file from Session RDP to Host using shared drive in RDP
def RDPSessionFileStoredRecieve(inRDPSessionKey, inRDPFilePath, inHostFilePath):
def RDPSessionFileStoredRecieve(inRDPSessionKeyStr, inRDPFilePathStr, inHostFilePathStr):
global gSettings
inGlobalDict = gSettings
lResult = True
lCMDStr = CMDStr.FileStoredRecieve(inRDPFilePath = inRDPFilePath, inHostFilePath = inHostFilePath)
lCMDStr = CMDStr.FileStoredRecieve(inRDPFilePath = inRDPFilePathStr, inHostFilePath = inHostFilePathStr)
# Calculate the session Hex
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKey]["SessionHex"]
# Check is Session is responsible
if inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKey]["SessionIsWindowResponsibleBool"]:
lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
# Run CMD
if lSessionHex:
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="LISTEN", inClipboardTimeoutSec = 120)
else:
# Write in logger - warning
inGlobalDict["Logger"].warning(f"Defs_SessionIndex.FileStoredRecieve: SessionIndex: {str(inRDPSessionKey)}, HostFilePath: {inHostFilePath}:: Session is not responsible!")
lResult = False # Set false result - function has not been done
return lResult

@ -1,3 +1,11 @@
# inRequest.OpenRPA = {}
# inRequest.OpenRPA["AuthToken"] = None
# inRequest.OpenRPA["Domain"] = None
# inRequest.OpenRPA["User"] = None
# lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None}
# self.OpenRPAResponseDict = lResponseDict
from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn
import threading
@ -78,6 +86,8 @@ def AuthenticateVerify(inRequest):
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now()
#Set-cookie
inRequest.OpenRPA["AuthToken"] = lAuthToken
inRequest.OpenRPA["Domain"] = lResult["Domain"]
inRequest.OpenRPA["User"] = lResult["User"]
inRequest.OpenRPASetCookie = {}
#New engine of server
inRequest.OpenRPAResponseDict["SetCookies"]["AuthToken"] = lAuthToken

@ -32,6 +32,12 @@ def Monitor_ControlPanelDictGet(inRequest,inGlobalDict):
lResultJSON = {"RenderRobotList": []}
lRenderFunctionsRobotList = inGlobalDict["ControlPanelDict"]["RobotList"]
for lItem in lRenderFunctionsRobotList:
lUACBool = True # Check if render function is applicable User Access Rights (UAC)
if inGlobalDict["Server"]["AccessUsers"]["FlagCredentialsAsk"] is True:
lUserRights = inGlobalDict["Server"]["AccessUsers"]["RuleDomainUserDict"][(inRequest.OpenRPA["Domain"].upper(),inRequest.OpenRPA["User"].upper())]
if len(lUserRights["ControlPanelKeyAllowedList"]) > 0 and lItem["KeyStr"] not in lUserRights["ControlPanelKeyAllowedList"]:
lUACBool = False # UAC Check is not passed - False for user
if lUACBool: # Run function if UAC is TRUE
# Выполнить вызов и записать результат
lItemResultDict = lItem["RenderFunction"](inGlobalDict)
# RunFunction

@ -3,7 +3,7 @@ r"""
The OpenRPA package (from UnicodeLabs)
"""
__version__ = 'v1.0.42'
__version__ = 'v1.1.0'
__all__ = []
__author__ = 'Ivan Maslov <ivan.maslov@unicodelabs.ru>'
#from .Core import Robot

@ -1,3 +1,5 @@
[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 improovments. Sorry, but no backward compatibility)/ Backward compatibility will start from 1.0.1
[1.0.37]
Minor fix in RobotRDPActive

Loading…
Cancel
Save