def add_new_display(self): # cannot have more than 5 sessions if len(self.displays) >= 5: logger.warning("You have already 5 displays") return display_dlg = QDisplayDialog(list(self.displays.keys()), self.platform_config) display_dlg.setModal(True) if display_dlg.exec() != 1: return display_name = display_dlg.display_name display_id = '-'.join((display_name, str(uuid.uuid4()))) display_widget = QDisplaySessionWidget(self, display_id=display_id, display_name=display_name) self.rows_ver_layout.addWidget(display_widget) self.displays[display_id] = display_widget # start the worker worker = Worker(display_widget, self.remote_connection_manager, display_dlg.session_queue, display_dlg.session_vnc, display_dlg.display_size) worker.signals.status.connect(display_widget.on_status_change) self.window().thread_pool.start(worker) logger.info("Added new display")
def on_logged(self): if self.is_logged: # Show the session widget self.containerLoginWidget.hide() self.containerWaitingWidget.hide() self.containerSessionWidget.show() logger.info("Logged in " + self.session_name) # update sessions list if self.session_name in list(self.sessions_list): self.sessions_list.remove(self.session_name) if self.session_name: self.sessions_list.appendleft(self.session_name) self.sessions_changed.emit(self.sessions_list) # update config file self.update_config_file(self.session_name) # check if a new version is available self.update_executable() # Emit the logged_in signal. self.logged_in.emit(self.session_name, self.uuid) # update the session list to be shown self.reload() else: # Show the login widget again self.containerLoginWidget.show() self.containerSessionWidget.hide() self.containerWaitingWidget.hide()
def __init__(self): super().__init__() pack_info = rcm_utils.pack_info() title = "Remote Connection Manager - CINECA - v" + pack_info.rcmVersion self.setWindowTitle(title) width = 1000 height = 370 screen_width = QDesktopWidget().width() screen_height = QDesktopWidget().height() self.setGeometry((screen_width / 2) - (width / 2), (screen_height / 2) - (height / 2), width, height) self.setMinimumHeight(height) self.setMinimumWidth(width) self.build_menu() self.main_widget = MainWidget(self) self.setCentralWidget(self.main_widget) self.thread_pool = QThreadPool() logger.info("Welcome to RCM!") logger.debug("Multithreading with maximum %d threads" % self.thread_pool.maxThreadCount())
def login(self): self.user = str(self.user_line.text()) self.host = str(self.host_line.text()) password = str(self.pssw_line.text()) if not self.host: logger.warning("Host field is empty") return if not self.user: logger.warning("User field is empty") return self.session_name = self.user + "@" + self.host logger.info("Logging into " + self.session_name) # Show the waiting widget self.containerLoginWidget.hide() self.containerSessionWidget.hide() self.containerWaitingWidget.show() self.remote_connection_manager = manager.RemoteConnectionManager() self.remote_connection_manager.debug = False self.login_thread = LoginThread(self, self.host, self.user, password) self.login_thread.finished.connect(self.on_logged) self.login_thread.start()
def open_vnc_session(self): options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog filename, _ = QFileDialog.getOpenFileName( self, "Open...", "", "VNC Files (*.vnc);;All Files (*)", options=options) current_session_widget = self.main_widget.tabs.currentWidget() if filename: # check if session needs tunneling file = open(filename, 'r') if 'rcm_tunnel' in file.read(): file.seek(0) lines = file.readlines() for line in lines: if 'rcm_tunnel' in line: node = line.split('=')[1].rstrip() if not current_session_widget.is_logged: logger.error( "You are not logged in the current session. Please log in." ) return if node == current_session_widget.host: user = current_session_widget.user else: logger.error( "The host of the current session (" + current_session_widget.host + ") is different from the host of the vnc file (" + node + ")") return if 'host' in line: hostname = line.split('=')[1].rstrip() if 'port' in line: port = line.split('=')[1].rstrip() display = int(port) - 5900 if 'password' in line: password = line.split('=')[1].rstrip() session = rcm.rcm_session(node=hostname, tunnel='y', display=display, nodelogin=node, username=user, vncpassword=password) current_session_widget.remote_connection_manager.vncsession( session=session) logger.info("Connected to remote display " + str(display) + " on " + node + " as " + str(user) + " with tunnel") else: current_session_widget.remote_connection_manager.vncsession( configFile=filename)
def connect_display(self): try: logger.info("Connecting to remote display " + str(self.display_name)) self.parent.remote_connection_manager.submit( self.session, gui_cmd=self.enable_connect_button) except: logger.error("Failed to connect to remote display " + str(self.display_name))
def on_ok(self): """ :return: Return accept signal if the display name is unique """ session_line = self.findChild(QLineEdit, 'session_line') display_name = str(session_line.text()) # if the display_name is empty, it is set to test # if it is not empty we validate it using a regex if not re.match(r'^[\w\_\s]{0,16}$', display_name): logger.error("Invalid display name: only alphanumeric " "plus underscore plus space characters " "are allowed for a maximum of 16 characters") return if display_name == "": self.display_name = "test" else: self.display_name = display_name # if the display name already exists, it returns if self.display_name in self.display_names: logger.error("session " + str(self.display_name) + " already exists") return self.session_queue = str(self.session_queue_combo.currentText()) self.session_vnc = str(self.session_vnc_combo.currentText()) self.display_size = str(self.display_combo.currentText()) # add a new display size if it's fine for us in the combobox for the next time if self.display_size not in list(self.display_size_list): if re.match(r'^\d{1,5}x\d{1,5}$', self.display_size): self.display_size_list.appendleft(self.display_size) else: logger.error("Invalid display size") return # convert full screen in the format width x height if self.display_size == "full_screen": screen_width = QDesktopWidget().width() screen_height = QDesktopWidget().height() self.display_size = str(screen_width) + "x" + str(screen_height) logger.info("session queue: " + self.session_queue + "; " + "session vnc: " + self.session_vnc + "; " + "display size: " + self.display_size + ";") self.update_config_file() self.accept()
def login(self): if self.user != str(self.user_line.text()): self.user = str(self.user_line.text()) self.session_name = '' if self.host != str(self.host_line.text()): self.host = str(self.host_line.text()) self.session_name = '' if self.preload != str(self.preload_line.text()): self.preload = str(self.preload_line.text()) self.session_name = '' password = str(self.pssw_line.text()) if not self.host: logger.warning("Host field is empty") return if not self.user: logger.warning("User field is empty") return if not self.session_name: self.session_name = self.user + "@" + self.host if self.preload: # search this preload into existing sessions preload_name = '' for session_name, host, user, preload in self.sessions_list: if preload == self.preload: preload_name = ([''] + session_name.split('?')[1:])[-1] break if not preload_name: preload_name = hashlib.md5( self.preload.encode()).hexdigest()[:4] self.session_name += "?" + preload_name logger.info("Logging...") # Show the waiting widget self.containerLoginWidget.hide() self.containerSessionWidget.hide() self.containerWaitingWidget.show() self.remote_connection_manager = manager.RemoteConnectionManager() self.remote_connection_manager.debug = False self.login_thread = LoginThread(self, self.host, self.user, password, preload=self.preload) self.login_thread.finished.connect(self.on_logged) self.login_thread.start()
def remove_display(self, id): """ Remove the display widget from the tab :param id: display id name :return: """ # first we hide the display logger.debug("Hiding display " + str(id)) self.displays[id].hide() # then we remove it from the layout and from the dictionary self.rows_ver_layout.removeWidget(self.displays[id]) self.displays[id].setParent(None) del self.displays[id] logger.info("Removed display " + str(id))
def share_display(self): try: logger.info("Sharing display " + str(self.display_name)) filename_suggested = self.session.hash['session name'].replace( ' ', '_') + '.vnc' options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog filename, _ = QFileDialog.getSaveFileName( self, "Share display " + str(self.display_name), filename_suggested, " Vnc Files (*.vnc);;All Files (*)", options=options) if filename: with open(filename, 'w') as out_file: out_file.write("[Connection]\n") if self.session.hash['tunnel'] == 'y': # rcm_tunnel is a key word to know that I need to tunnel across that node out_file.write("rcm_tunnel={0}\n".format( self.session.hash['nodelogin'])) out_file.write("host={0}\n".format( self.session.hash['node'])) else: out_file.write("host={0}\n".format( self.session.hash['nodelogin'])) try: port = int(self.session.hash['port']) except Exception as e: logger.debug( str(e) + " - " + str(traceback.format_exc())) port = 5900 + int(self.session.hash['display']) out_file.write("port={0}\n".format(port)) out_file.write("password={0}\n".format( self.session.hash['vncpassword'])) except Exception as e: logger.debug(str(e) + " - " + str(traceback.format_exc())) logger.debug(str(self.session.hash)) logger.error("Failed to share display " + str(self.display_name))
def add_new_display(self): # cannot have more than 5 sessions if len(self.displays) >= 5: logger.warning("You have already 5 displays") return display_dialog_ui = None if self.platform_config: if 'jobscript_json_menu' in self.platform_config.config: display_dialog_ui = json.loads( self.platform_config.config.get('jobscript_json_menu', '{}'), object_pairs_hook=collections.OrderedDict) if display_dialog_ui: display_dlg = QDynamicDisplayDialog(display_dialog_ui) else: display_dlg = QDisplayDialog(list(self.displays.keys()), self.platform_config) display_dlg.setModal(True) if display_dlg.exec() != 1: return display_name = display_dlg.display_name display_id = '-'.join((display_name, str(uuid.uuid4()))) display_widget = QDisplaySessionWidget(self, display_id=display_id, display_name=display_name) self.rows_ver_layout.addWidget(display_widget) self.displays[display_id] = display_widget # start the worker worker = Worker(display_widget, self.remote_connection_manager, display_dlg) worker.signals.status.connect(display_widget.on_status_change) self.window().thread_pool.start(worker) logger.info("Added new display")
def on_logged(self): if self.is_logged: # Show the session widget self.containerLoginWidget.hide() self.containerWaitingWidget.hide() self.containerSessionWidget.show() logger.info("Logged as " + self.user + " to " + self.host) # update sessions list # warning, json load turns tuple into list # append new session only if content is different if self.session_name and list( self.session_tuple())[1:] not in list( self.sessions_list_content()): self.sessions_list.appendleft(self.session_tuple()) #self.sessions_changed.emit(self.sessions_list) self.sessions_changed.emit(self.sessions_list_names(), self.sessions_list) # update config file self.update_config_file(self.session_name) # check if a new version is available self.update_executable() # Emit the logged_in signal. self.logged_in.emit(self.session_name, self.uuid) # update the session list to be shown self.reload() else: # Show the login widget again self.containerLoginWidget.show() self.containerSessionWidget.hide() self.containerWaitingWidget.hide()
def update_executable(self): # update the executable only if we are running in a bundle if not pyinstaller_utils.is_bundled(): return logger.info("Checking if a new client version is available...") current_exe_checksum = rcm_utils.compute_checksum(sys.executable) logger.debug("Current client checksum: " + str(current_exe_checksum)) last_exe_checksum = self.platform_config.get_version()[0] last_exe_url = self.platform_config.get_version()[1] logger.debug("New client checksum: " + str(last_exe_checksum)) if current_exe_checksum != last_exe_checksum: question_title = "Release download" question_text = "A new version of the \"Remote Connection Manager\" is available at: " \ + last_exe_url + ". " \ "It is highly recommended to install the new version to keep working properly. " \ "Do you want to install it now?" buttonReply = QMessageBox.question( self, question_title, question_text, QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if buttonReply == QMessageBox.No: return logger.info('Downloading the new client version...') exe_dir = os.path.dirname(sys.executable) tmp_dir = tempfile.gettempdir() last_exe_path = os.path.join(tmp_dir, os.path.basename(sys.executable)) rcm_utils.download_file(last_exe_url, last_exe_path) downloaded_exe_checksum = rcm_utils.compute_checksum(last_exe_path) time.sleep(5) if downloaded_exe_checksum != last_exe_checksum: logger.warning('Downloaded file checksum mismatched. ' 'Expected: ' + str(last_exe_path) + '. Found: ' + str(downloaded_exe_checksum) + '. Update stopped.') os.remove(last_exe_path) else: if sys.platform == 'win32': batch_filename = os.path.join(tmp_dir, "RCM_update.bat") with open(batch_filename, 'w') as batch_file: batch_file.write("rem start update bat" + "\n") batch_file.write("cd /D " + exe_dir + "\n") batch_file.write("copy mybatch.bat mybatch.txt\n") batch_file.write('ping -n 3 localhost >nul 2>&1' + "\n") batch_file.write("del mybatch.txt\n") batch_file.write("ren " + os.path.basename(sys.executable) + " _" + os.path.basename(sys.executable) + "\n") batch_file.write("copy " + last_exe_path + "\n") batch_file.write("del " + " _" + os.path.basename(sys.executable) + "\n") batch_file.write("del " + last_exe_path + "\n") batch_file.write("start " + os.path.basename(sys.executable) + "\n") batch_file.write("del " + batch_filename + "\n") batch_file.write("exit\n") logger.info( "The application will be closed and the new one will start in a while." ) os.startfile(batch_filename) else: batch_filename = os.path.join(tmp_dir, "RCM_update.sh") with open(batch_filename, 'w') as batch_file: batch_file.write("#!/bin/bash\n") batch_file.write("#start update bat" + "\n") batch_file.write("cd " + exe_dir + "\n") batch_file.write("sleep 3 \n") batch_file.write("rm " + os.path.basename(sys.executable) + "\n") batch_file.write("cp " + last_exe_path + " .\n") batch_file.write("chmod a+x " + os.path.basename(sys.executable) + "\n") batch_file.write("sleep 2 \n") batch_file.write("./" + os.path.basename(sys.executable) + "\n") logger.info( "The application will be closed and the new one will start in a while!" ) subprocess.Popen(["sh", batch_filename]) else: logger.info('The client is up-to-date')