mirror of
https://github.com/naruxde/revpicommander.git
synced 2026-08-16 13:47:04 +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 re import search
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from xmlrpc.client import Binary, ServerProxy
|
from xmlrpc.client import Binary, ServerProxy, Transport
|
||||||
|
|
||||||
from PyQt5 import QtCore
|
from PyQt5 import QtCore
|
||||||
from paramiko.ssh_exception import AuthenticationException
|
from paramiko.ssh_exception import AuthenticationException
|
||||||
@@ -32,6 +32,21 @@ homedir = environ.get("HOME", "") or environ.get("APPDATA", "")
|
|||||||
"""Home dir of user."""
|
"""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):
|
class ConnectionFail(IntEnum):
|
||||||
NO_XML_RPC = 1
|
NO_XML_RPC = 1
|
||||||
SSH_CONNECT = 2
|
SSH_CONNECT = 2
|
||||||
@@ -91,6 +106,11 @@ class RevPiSettings:
|
|||||||
if load_index is not None:
|
if load_index is not None:
|
||||||
self.load_from_index(load_index)
|
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:
|
def load_from_index(self, settings_index: int) -> None:
|
||||||
"""Load settings from 'connections' index."""
|
"""Load settings from 'connections' index."""
|
||||||
self._settings.beginReadArray("connections")
|
self._settings.beginReadArray("connections")
|
||||||
@@ -129,8 +149,11 @@ class RevPiSettings:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# These values must exists
|
# These values must exists
|
||||||
if not (self.name and self.address and self.port):
|
if not (self.name and self.address):
|
||||||
raise ValueError("Could not geht all required values from saved settings")
|
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()
|
self._settings.endArray()
|
||||||
|
|
||||||
@@ -379,10 +402,10 @@ class ConnectionManager(QtCore.QThread):
|
|||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
sp = ServerProxy("http://127.0.0.1:{0}".format(ssh_tunnel_port))
|
sp = create_server_proxy(revpi_settings, ssh_tunnel_port)
|
||||||
|
|
||||||
else:
|
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
|
# Load values and test connection to Revolution Pi
|
||||||
try:
|
try:
|
||||||
@@ -435,10 +458,7 @@ class ConnectionManager(QtCore.QThread):
|
|||||||
with self._lck_cli:
|
with self._lck_cli:
|
||||||
self.ssh_tunnel_server = ssh_tunnel_server
|
self.ssh_tunnel_server = ssh_tunnel_server
|
||||||
self._cli = sp
|
self._cli = sp
|
||||||
self._cli_connect.put_nowait((
|
self._cli_connect.put_nowait((revpi_settings, ssh_tunnel_port))
|
||||||
"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.connection_established.emit()
|
self.connection_established.emit()
|
||||||
|
|
||||||
@@ -552,8 +572,8 @@ class ConnectionManager(QtCore.QThread):
|
|||||||
self.status_changed.emit(self.tr("Not connected"), "lightblue")
|
self.status_changed.emit(self.tr("Not connected"), "lightblue")
|
||||||
elif not self._cli_connect.empty():
|
elif not self._cli_connect.empty():
|
||||||
# Get new connection information to create object in this thread
|
# Get new connection information to create object in this thread
|
||||||
item = self._cli_connect.get()
|
revpi_settings, ssh_tunnel_port = self._cli_connect.get()
|
||||||
sp = ServerProxy("http://{0}:{1}".format(*item))
|
sp = create_server_proxy(revpi_settings, ssh_tunnel_port)
|
||||||
self._cli_connect.task_done()
|
self._cli_connect.task_done()
|
||||||
|
|
||||||
if sp:
|
if sp:
|
||||||
@@ -582,7 +602,7 @@ class ConnectionManager(QtCore.QThread):
|
|||||||
self.settings.ssh_user,
|
self.settings.ssh_user,
|
||||||
self.ssh_pass
|
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:
|
with self._lck_cli:
|
||||||
self.ssh_tunnel_server = ssh_tunnel_server
|
self.ssh_tunnel_server = ssh_tunnel_server
|
||||||
self._cli = sp
|
self._cli = sp
|
||||||
@@ -669,12 +689,8 @@ class ConnectionManager(QtCore.QThread):
|
|||||||
|
|
||||||
Use connection_recovered signal to figure out new parameters.
|
Use connection_recovered signal to figure out new parameters.
|
||||||
"""
|
"""
|
||||||
if not self.settings.ssh_use_tunnel and self.settings.address and self.settings.port:
|
ssh_tunnel_port = self.ssh_tunnel_server.local_tunnel_port if self.ssh_tunnel_server else None
|
||||||
return ServerProxy("http://{0}:{1}".format(self.settings.address, self.settings.port))
|
return create_server_proxy(self.settings, ssh_tunnel_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
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def connected(self) -> bool:
|
def connected(self) -> bool:
|
||||||
@@ -699,6 +715,27 @@ cm = ConnectionManager()
|
|||||||
"""Clobal connection manager instance."""
|
"""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]:
|
def all_revpi_settings() -> [RevPiSettings]:
|
||||||
"""Get all revpi settings objects."""
|
"""Get all revpi settings objects."""
|
||||||
# Get length of array and close it, the RevPiSettings-class need it
|
# 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.sbx_ssh_port.setEnabled(con_item)
|
||||||
self.txt_ssh_user.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):
|
def _get_folder_item(self, name: str):
|
||||||
"""Find the folder entry by name."""
|
"""Find the folder entry by name."""
|
||||||
for i in range(self.tre_connections.topLevelItemCount()):
|
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 = self.__current_item.data(0, WidgetData.revpi_settings) # type: RevPiSettings
|
||||||
settings.address = text
|
settings.address = text
|
||||||
self.changes = True
|
self.changes = True
|
||||||
|
self._edit_state()
|
||||||
|
|
||||||
@QtCore.pyqtSlot(int)
|
@QtCore.pyqtSlot(int)
|
||||||
def on_sbx_port_valueChanged(self, value: int):
|
def on_sbx_port_valueChanged(self, value: int):
|
||||||
|
|||||||
Reference in New Issue
Block a user