feat: Add support for default local socket in connection settings

Introduces a checkbox to toggle the use of the default local Unix socket
for XML-RPC connections. Updates UI layout and enables dynamic state
handling for related fields, such as address and port, based on socket
usage. Ensures proper state synchronization and settings persistence.

Signed-off-by: Sven Sager <akira@narux.de>
This commit is contained in:
2026-08-06 10:00:14 +02:00
parent 0582925de6
commit 2f40a36420
4 changed files with 68 additions and 32 deletions
+3 -2
View File
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Helper functions for this application.""" """Helper functions for this application."""
__author__ = "Sven Sager" __author__ = "Sven Sager"
__copyright__ = "Copyright (C) 2023 Sven Sager" __copyright__ = "Copyright (C) 2023-2026 Sven Sager"
__license__ = "GPLv2" __license__ = "GPLv2"
import pickle import pickle
@@ -206,7 +206,8 @@ class RevPiSettings:
self._settings.setValue("port", self.port) self._settings.setValue("port", self.port)
self._settings.setValue("timeout", self.timeout) self._settings.setValue("timeout", self.timeout)
self._settings.setValue("ssh_use_tunnel", self.ssh_use_tunnel) # Disable SSH tunnel if unix socket is used. SSH will check the type on the remove system
self._settings.setValue("ssh_use_tunnel", self.ssh_use_tunnel and not self.is_unix_socket)
self._settings.setValue("ssh_port", self.ssh_port) self._settings.setValue("ssh_port", self.ssh_port)
self._settings.setValue("ssh_user", self.ssh_user) self._settings.setValue("ssh_user", self.ssh_user)
self._settings.setValue("ssh_saved_password", self.ssh_saved_password) self._settings.setValue("ssh_saved_password", self.ssh_saved_password)
+34 -16
View File
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Saved connections of Revolution Pi devices.""" """Saved connections of Revolution Pi devices."""
__author__ = "Sven Sager" __author__ = "Sven Sager"
__copyright__ = "Copyright (C) 2023 Sven Sager" __copyright__ = "Copyright (C) 2023-2026 Sven Sager"
__license__ = "GPLv2" __license__ = "GPLv2"
from enum import IntEnum from enum import IntEnum
@@ -16,6 +16,7 @@ from . import proginit as pi
from .helper import RevPiSettings, WidgetData from .helper import RevPiSettings, WidgetData
from .ui.revpiplclist_ui import Ui_diag_connections from .ui.revpiplclist_ui import Ui_diag_connections
DEFAULT_SOCKET_ADDRESS = "/run/revpipyload/xmlrpc.socket"
log = getLogger(__name__) log = getLogger(__name__)
@@ -40,6 +41,8 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
self.lbl_port.setText(self.lbl_port.text().format(self.__default_port)) self.lbl_port.setText(self.lbl_port.text().format(self.__default_port))
self.sbx_port.setValue(self.__default_port) self.sbx_port.setValue(self.__default_port)
self._mrk_address = ""
# Dirty workaround to remove default button to prevent action on ENTER key, while user edit texts # Dirty workaround to remove default button to prevent action on ENTER key, while user edit texts
self.__btn_dummy = QtWidgets.QPushButton(self) self.__btn_dummy = QtWidgets.QPushButton(self)
self.__btn_dummy.setVisible(False) self.__btn_dummy.setVisible(False)
@@ -189,12 +192,21 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
up_ok = index > 0 up_ok = index > 0
down_ok = index < self.tre_connections.topLevelItemCount() - 1 down_ok = index < self.tre_connections.topLevelItemCount() - 1
address = self.txt_address.text()
is_unix_socket = address.startswith("/") or address.startswith("./")
is_unix_default = address.lower() == DEFAULT_SOCKET_ADDRESS
# Value isn't saved in settings, resulting of address value
with QtCore.QSignalBlocker(self.cbx_local_socket):
self.cbx_local_socket.setChecked(is_unix_default)
self.btn_up.setEnabled(up_ok) self.btn_up.setEnabled(up_ok)
self.btn_down.setEnabled(down_ok) self.btn_down.setEnabled(down_ok)
self.btn_delete.setEnabled(con_item or dir_item) self.btn_delete.setEnabled(con_item or dir_item)
self.txt_name.setEnabled(con_item) self.txt_name.setEnabled(con_item)
self.txt_address.setEnabled(con_item) self.txt_address.setEnabled(con_item and not is_unix_default)
self.sbx_port.setEnabled(con_item) self.cbx_local_socket.setEnabled(con_item)
self.sbx_port.setEnabled(con_item and not is_unix_socket)
self.sbx_timeout.setEnabled(con_item) self.sbx_timeout.setEnabled(con_item)
self.cbb_folder.setEnabled(con_item or dir_item) self.cbb_folder.setEnabled(con_item or dir_item)
self.cbb_folder.setEditable(dir_item) self.cbb_folder.setEditable(dir_item)
@@ -202,19 +214,9 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
# Disable auto complete, this would override a new typed name with existing one # Disable auto complete, this would override a new typed name with existing one
self.cbb_folder.setCompleter(None) self.cbb_folder.setCompleter(None)
self.cbx_ssh_use_tunnel.setEnabled(con_item) self.cbx_ssh_use_tunnel.setEnabled(con_item and not is_unix_socket)
self.sbx_ssh_port.setEnabled(con_item) self.sbx_ssh_port.setEnabled(con_item and not is_unix_socket)
self.txt_ssh_user.setEnabled(con_item) self.txt_ssh_user.setEnabled(con_item and not is_unix_socket)
if con_item:
address = self.txt_address.text()
is_unix = address.startswith("/") or address.startswith("./")
if is_unix:
self.sbx_port.setEnabled(False)
self.cbx_ssh_use_tunnel.setChecked(False)
self.cbx_ssh_use_tunnel.setEnabled(False)
self.sbx_ssh_port.setEnabled(False)
self.txt_ssh_user.setEnabled(False)
def _get_folder_item(self, name: str): def _get_folder_item(self, name: str):
"""Find the folder entry by name.""" """Find the folder entry by name."""
@@ -280,6 +282,7 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
self.__current_item = QtWidgets.QTreeWidgetItem() self.__current_item = QtWidgets.QTreeWidgetItem()
self.cbb_folder.setCurrentText(current.text(0) if current else "") self.cbb_folder.setCurrentText(current.text(0) if current else "")
self._mrk_address = ""
self._edit_state() self._edit_state()
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
@@ -400,6 +403,21 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
settings.timeout = value settings.timeout = value
self.changes = True self.changes = True
@QtCore.pyqtSlot(int)
def on_cbx_local_socket_stateChanged(self, check_state: int):
if self.__current_item.type() != NodeType.CON:
return
if check_state == QtCore.Qt.CheckState.Checked:
# Backup fields to restore the text if unchecked
self._mrk_address = self.txt_address.text()
self.txt_address.setText(DEFAULT_SOCKET_ADDRESS)
self.on_txt_address_textEdited(self.txt_address.text())
else:
# Restore old address if it is not the default to unlock the address field
self.txt_address.setText("" if self._mrk_address == DEFAULT_SOCKET_ADDRESS else self._mrk_address)
self.on_txt_address_textEdited(self.txt_address.text())
@QtCore.pyqtSlot(int) @QtCore.pyqtSlot(int)
def on_cbx_ssh_use_tunnel_stateChanged(self, check_state: int): def on_cbx_ssh_use_tunnel_stateChanged(self, check_state: int):
if self.__current_item.type() != NodeType.CON: if self.__current_item.type() != NodeType.CON:
+14 -7
View File
@@ -37,7 +37,7 @@ class Ui_diag_connections(object):
self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.txt_address) self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.txt_address)
self.lbl_port = QtWidgets.QLabel(self.tab_connection) self.lbl_port = QtWidgets.QLabel(self.tab_connection)
self.lbl_port.setObjectName("lbl_port") self.lbl_port.setObjectName("lbl_port")
self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.lbl_port) self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.lbl_port)
self.sbx_port = QtWidgets.QSpinBox(self.tab_connection) self.sbx_port = QtWidgets.QSpinBox(self.tab_connection)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
@@ -48,10 +48,10 @@ class Ui_diag_connections(object):
self.sbx_port.setMaximum(65535) self.sbx_port.setMaximum(65535)
self.sbx_port.setProperty("value", 55123) self.sbx_port.setProperty("value", 55123)
self.sbx_port.setObjectName("sbx_port") self.sbx_port.setObjectName("sbx_port")
self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.sbx_port) self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.sbx_port)
self.lbl_timeout = QtWidgets.QLabel(self.tab_connection) self.lbl_timeout = QtWidgets.QLabel(self.tab_connection)
self.lbl_timeout.setObjectName("lbl_timeout") self.lbl_timeout.setObjectName("lbl_timeout")
self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.lbl_timeout) self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.lbl_timeout)
self.sbx_timeout = QtWidgets.QSpinBox(self.tab_connection) self.sbx_timeout = QtWidgets.QSpinBox(self.tab_connection)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
@@ -61,17 +61,23 @@ class Ui_diag_connections(object):
self.sbx_timeout.setMinimum(5) self.sbx_timeout.setMinimum(5)
self.sbx_timeout.setMaximum(30) self.sbx_timeout.setMaximum(30)
self.sbx_timeout.setObjectName("sbx_timeout") self.sbx_timeout.setObjectName("sbx_timeout")
self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.sbx_timeout) self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.sbx_timeout)
self.lbl_folder = QtWidgets.QLabel(self.tab_connection) self.lbl_folder = QtWidgets.QLabel(self.tab_connection)
self.lbl_folder.setObjectName("lbl_folder") self.lbl_folder.setObjectName("lbl_folder")
self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.lbl_folder) self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.lbl_folder)
self.cbb_folder = QtWidgets.QComboBox(self.tab_connection) self.cbb_folder = QtWidgets.QComboBox(self.tab_connection)
self.cbb_folder.setEditable(True) self.cbb_folder.setEditable(True)
self.cbb_folder.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents) self.cbb_folder.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents)
self.cbb_folder.setObjectName("cbb_folder") self.cbb_folder.setObjectName("cbb_folder")
self.cbb_folder.addItem("") self.cbb_folder.addItem("")
self.cbb_folder.setItemText(0, "") self.cbb_folder.setItemText(0, "")
self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.cbb_folder) self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.cbb_folder)
self.lbl_local_socket = QtWidgets.QLabel(self.tab_connection)
self.lbl_local_socket.setObjectName("lbl_local_socket")
self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.lbl_local_socket)
self.cbx_local_socket = QtWidgets.QCheckBox(self.tab_connection)
self.cbx_local_socket.setObjectName("cbx_local_socket")
self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.cbx_local_socket)
self.tab_properties.addTab(self.tab_connection, "") self.tab_properties.addTab(self.tab_connection, "")
self.tab_ssh = QtWidgets.QWidget() self.tab_ssh = QtWidgets.QWidget()
self.tab_ssh.setObjectName("tab_ssh") self.tab_ssh.setObjectName("tab_ssh")
@@ -157,11 +163,12 @@ class Ui_diag_connections(object):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
diag_connections.setWindowTitle(_translate("diag_connections", "RevPi Connections")) diag_connections.setWindowTitle(_translate("diag_connections", "RevPi Connections"))
self.lbl_name.setText(_translate("diag_connections", "Display name:")) self.lbl_name.setText(_translate("diag_connections", "Display name:"))
self.lbl_address.setText(_translate("diag_connections", "Address (DNS/IP):")) self.lbl_address.setText(_translate("diag_connections", "Address (DNS/IP/Socket):"))
self.lbl_port.setText(_translate("diag_connections", "Port (default {0}):")) self.lbl_port.setText(_translate("diag_connections", "Port (default {0}):"))
self.lbl_timeout.setText(_translate("diag_connections", "Connection timeout:")) self.lbl_timeout.setText(_translate("diag_connections", "Connection timeout:"))
self.sbx_timeout.setSuffix(_translate("diag_connections", " s")) self.sbx_timeout.setSuffix(_translate("diag_connections", " s"))
self.lbl_folder.setText(_translate("diag_connections", "Subfolder:")) self.lbl_folder.setText(_translate("diag_connections", "Subfolder:"))
self.lbl_local_socket.setText(_translate("diag_connections", "Use default local socket:"))
self.tab_properties.setTabText(self.tab_properties.indexOf(self.tab_connection), _translate("diag_connections", "Connection")) self.tab_properties.setTabText(self.tab_properties.indexOf(self.tab_connection), _translate("diag_connections", "Connection"))
self.lbl_ssh_use_tunnel.setText(_translate("diag_connections", "Connect over SSH tunnel:")) self.lbl_ssh_use_tunnel.setText(_translate("diag_connections", "Connect over SSH tunnel:"))
self.lbl_ssh_port.setText(_translate("diag_connections", "SSH port:")) self.lbl_ssh_port.setText(_translate("diag_connections", "SSH port:"))
+17 -7
View File
@@ -37,21 +37,21 @@
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="lbl_address"> <widget class="QLabel" name="lbl_address">
<property name="text"> <property name="text">
<string>Address (DNS/IP):</string> <string>Address (DNS/IP/Socket):</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QLineEdit" name="txt_address"/> <widget class="QLineEdit" name="txt_address"/>
</item> </item>
<item row="2" column="0"> <item row="3" column="0">
<widget class="QLabel" name="lbl_port"> <widget class="QLabel" name="lbl_port">
<property name="text"> <property name="text">
<string>Port (default {0}):</string> <string>Port (default {0}):</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="3" column="1">
<widget class="QSpinBox" name="sbx_port"> <widget class="QSpinBox" name="sbx_port">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed"> <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
@@ -70,14 +70,14 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="4" column="0">
<widget class="QLabel" name="lbl_timeout"> <widget class="QLabel" name="lbl_timeout">
<property name="text"> <property name="text">
<string>Connection timeout:</string> <string>Connection timeout:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="4" column="1">
<widget class="QSpinBox" name="sbx_timeout"> <widget class="QSpinBox" name="sbx_timeout">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed"> <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
@@ -96,14 +96,14 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="5" column="0">
<widget class="QLabel" name="lbl_folder"> <widget class="QLabel" name="lbl_folder">
<property name="text"> <property name="text">
<string>Subfolder:</string> <string>Subfolder:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="1"> <item row="5" column="1">
<widget class="QComboBox" name="cbb_folder"> <widget class="QComboBox" name="cbb_folder">
<property name="editable"> <property name="editable">
<bool>true</bool> <bool>true</bool>
@@ -118,6 +118,16 @@
</item> </item>
</widget> </widget>
</item> </item>
<item row="2" column="0">
<widget class="QLabel" name="lbl_local_socket">
<property name="text">
<string>Use default local socket:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="cbx_local_socket"/>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab_ssh"> <widget class="QWidget" name="tab_ssh">