mirror of
https://github.com/naruxde/revpicommander.git
synced 2026-08-16 05:45:53 +02:00
feat: Option to use unix sockets for xml-rpc
This commit is contained in:
@@ -15,7 +15,7 @@ from queue import Queue
|
||||
from re import search
|
||||
from threading import Lock
|
||||
from uuid import uuid4
|
||||
from xmlrpc.client import Binary, ServerProxy
|
||||
from xmlrpc.client import Binary, ServerProxy, Transport
|
||||
|
||||
from PyQt5 import QtCore
|
||||
from paramiko.ssh_exception import AuthenticationException
|
||||
@@ -32,6 +32,21 @@ homedir = environ.get("HOME", "") or environ.get("APPDATA", "")
|
||||
"""Home dir of user."""
|
||||
|
||||
|
||||
class UnixStreamTransport(Transport):
|
||||
"""Transport for xmlrpc to use unix domain sockets."""
|
||||
|
||||
def __init__(self, socket_path):
|
||||
super().__init__()
|
||||
self._socket_path = socket_path
|
||||
|
||||
def make_connection(self, host):
|
||||
import http.client
|
||||
conn = http.client.HTTPConnection("localhost")
|
||||
conn.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
conn.sock.connect(self._socket_path)
|
||||
return conn
|
||||
|
||||
|
||||
class ConnectionFail(IntEnum):
|
||||
NO_XML_RPC = 1
|
||||
SSH_CONNECT = 2
|
||||
@@ -91,6 +106,11 @@ class RevPiSettings:
|
||||
if load_index is not None:
|
||||
self.load_from_index(load_index)
|
||||
|
||||
@property
|
||||
def is_unix_socket(self) -> bool:
|
||||
"""Check if connection is a unix domain socket."""
|
||||
return self.address.startswith("/") or self.address.startswith("./")
|
||||
|
||||
def load_from_index(self, settings_index: int) -> None:
|
||||
"""Load settings from 'connections' index."""
|
||||
self._settings.beginReadArray("connections")
|
||||
@@ -129,8 +149,11 @@ class RevPiSettings:
|
||||
pass
|
||||
|
||||
# These values must exists
|
||||
if not (self.name and self.address and self.port):
|
||||
raise ValueError("Could not geht all required values from saved settings")
|
||||
if not (self.name and self.address):
|
||||
raise ValueError("Could not get all required values from saved settings")
|
||||
|
||||
if not self.is_unix_socket and not self.port:
|
||||
raise ValueError("Port is required for IP connections")
|
||||
|
||||
self._settings.endArray()
|
||||
|
||||
@@ -379,10 +402,10 @@ class ConnectionManager(QtCore.QThread):
|
||||
)
|
||||
return False
|
||||
|
||||
sp = ServerProxy("http://127.0.0.1:{0}".format(ssh_tunnel_port))
|
||||
sp = create_server_proxy(revpi_settings, ssh_tunnel_port)
|
||||
|
||||
else:
|
||||
sp = ServerProxy("http://{0}:{1}".format(revpi_settings.address, revpi_settings.port))
|
||||
sp = create_server_proxy(revpi_settings)
|
||||
|
||||
# Load values and test connection to Revolution Pi
|
||||
try:
|
||||
@@ -435,10 +458,7 @@ class ConnectionManager(QtCore.QThread):
|
||||
with self._lck_cli:
|
||||
self.ssh_tunnel_server = ssh_tunnel_server
|
||||
self._cli = sp
|
||||
self._cli_connect.put_nowait((
|
||||
"127.0.0.1" if revpi_settings.ssh_use_tunnel else revpi_settings.address,
|
||||
ssh_tunnel_port if revpi_settings.ssh_use_tunnel else revpi_settings.port
|
||||
))
|
||||
self._cli_connect.put_nowait((revpi_settings, ssh_tunnel_port))
|
||||
|
||||
self.connection_established.emit()
|
||||
|
||||
@@ -552,8 +572,8 @@ class ConnectionManager(QtCore.QThread):
|
||||
self.status_changed.emit(self.tr("Not connected"), "lightblue")
|
||||
elif not self._cli_connect.empty():
|
||||
# Get new connection information to create object in this thread
|
||||
item = self._cli_connect.get()
|
||||
sp = ServerProxy("http://{0}:{1}".format(*item))
|
||||
revpi_settings, ssh_tunnel_port = self._cli_connect.get()
|
||||
sp = create_server_proxy(revpi_settings, ssh_tunnel_port)
|
||||
self._cli_connect.task_done()
|
||||
|
||||
if sp:
|
||||
@@ -582,7 +602,7 @@ class ConnectionManager(QtCore.QThread):
|
||||
self.settings.ssh_user,
|
||||
self.ssh_pass
|
||||
)
|
||||
sp = ServerProxy("http://127.0.0.1:{0}".format(ssh_tunnel_port))
|
||||
sp = create_server_proxy(self.settings, ssh_tunnel_port)
|
||||
with self._lck_cli:
|
||||
self.ssh_tunnel_server = ssh_tunnel_server
|
||||
self._cli = sp
|
||||
@@ -669,12 +689,8 @@ class ConnectionManager(QtCore.QThread):
|
||||
|
||||
Use connection_recovered signal to figure out new parameters.
|
||||
"""
|
||||
if not self.settings.ssh_use_tunnel and self.settings.address and self.settings.port:
|
||||
return ServerProxy("http://{0}:{1}".format(self.settings.address, self.settings.port))
|
||||
if self.settings.ssh_use_tunnel and self.ssh_tunnel_server and self.ssh_tunnel_server.connected:
|
||||
return ServerProxy("http://127.0.0.1:{0}".format(self.ssh_tunnel_server.local_tunnel_port))
|
||||
|
||||
return None
|
||||
ssh_tunnel_port = self.ssh_tunnel_server.local_tunnel_port if self.ssh_tunnel_server else None
|
||||
return create_server_proxy(self.settings, ssh_tunnel_port)
|
||||
|
||||
@property
|
||||
def connected(self) -> bool:
|
||||
@@ -699,6 +715,27 @@ cm = ConnectionManager()
|
||||
"""Clobal connection manager instance."""
|
||||
|
||||
|
||||
def create_server_proxy(revpi_settings: RevPiSettings, ssh_tunnel_port: int = None) -> ServerProxy:
|
||||
"""
|
||||
Create a ServerProxy instance based on the given settings.
|
||||
|
||||
:param revpi_settings: Revolution Pi saved connection settings
|
||||
:param ssh_tunnel_port: Use this port if an SSH tunnel is already established
|
||||
:return: ServerProxy instance
|
||||
"""
|
||||
if revpi_settings.is_unix_socket:
|
||||
return ServerProxy("http://localhost", transport=UnixStreamTransport(revpi_settings.address))
|
||||
|
||||
if ssh_tunnel_port:
|
||||
return ServerProxy("http://127.0.0.1:{0}".format(ssh_tunnel_port))
|
||||
|
||||
if revpi_settings.ssh_use_tunnel:
|
||||
# This case is usually handled by passing ssh_tunnel_port after connecting the tunnel
|
||||
return ServerProxy("http://127.0.0.1:{0}".format(revpi_settings.port))
|
||||
|
||||
return ServerProxy("http://{0}:{1}".format(revpi_settings.address, revpi_settings.port))
|
||||
|
||||
|
||||
def all_revpi_settings() -> [RevPiSettings]:
|
||||
"""Get all revpi settings objects."""
|
||||
# Get length of array and close it, the RevPiSettings-class need it
|
||||
|
||||
@@ -206,6 +206,16 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
|
||||
self.sbx_ssh_port.setEnabled(con_item)
|
||||
self.txt_ssh_user.setEnabled(con_item)
|
||||
|
||||
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):
|
||||
"""Find the folder entry by name."""
|
||||
for i in range(self.tre_connections.topLevelItemCount()):
|
||||
@@ -369,6 +379,7 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
|
||||
settings = self.__current_item.data(0, WidgetData.revpi_settings) # type: RevPiSettings
|
||||
settings.address = text
|
||||
self.changes = True
|
||||
self._edit_state()
|
||||
|
||||
@QtCore.pyqtSlot(int)
|
||||
def on_sbx_port_valueChanged(self, value: int):
|
||||
|
||||
Reference in New Issue
Block a user