ipc: Remove support for connecting to legacy servers
This commit is contained in:
parent
cfb169b5f0
commit
6a2163d36f
@ -20,7 +20,6 @@
|
|||||||
"""Utilities for IPC with existing instances."""
|
"""Utilities for IPC with existing instances."""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
import json
|
import json
|
||||||
import getpass
|
import getpass
|
||||||
@ -41,8 +40,8 @@ ATIME_INTERVAL = 60 * 60 * 3 * 1000 # 3 hours
|
|||||||
PROTOCOL_VERSION = 1
|
PROTOCOL_VERSION = 1
|
||||||
|
|
||||||
|
|
||||||
def _get_socketname_legacy(basedir):
|
def _get_socketname_windows(basedir):
|
||||||
"""Legacy implementation of _get_socketname."""
|
"""Get a socketname to use for Windows."""
|
||||||
parts = ['qutebrowser', getpass.getuser()]
|
parts = ['qutebrowser', getpass.getuser()]
|
||||||
if basedir is not None:
|
if basedir is not None:
|
||||||
md5 = hashlib.md5(basedir.encode('utf-8')).hexdigest()
|
md5 = hashlib.md5(basedir.encode('utf-8')).hexdigest()
|
||||||
@ -50,10 +49,10 @@ def _get_socketname_legacy(basedir):
|
|||||||
return '-'.join(parts)
|
return '-'.join(parts)
|
||||||
|
|
||||||
|
|
||||||
def _get_socketname(basedir, legacy=False):
|
def _get_socketname(basedir):
|
||||||
"""Get a socketname to use."""
|
"""Get a socketname to use."""
|
||||||
if legacy or os.name == 'nt':
|
if os.name == 'nt':
|
||||||
return _get_socketname_legacy(basedir)
|
return _get_socketname_windows(basedir)
|
||||||
|
|
||||||
parts_to_hash = [getpass.getuser()]
|
parts_to_hash = [getpass.getuser()]
|
||||||
if basedir is not None:
|
if basedir is not None:
|
||||||
@ -415,41 +414,7 @@ class IPCServer(QObject):
|
|||||||
self._remove_server()
|
self._remove_server()
|
||||||
|
|
||||||
|
|
||||||
def _has_legacy_server(name):
|
def send_to_running_instance(socketname, command, target_arg, *, socket=None):
|
||||||
"""Check if there is a legacy server.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
name: The name to try to connect to.
|
|
||||||
|
|
||||||
Return:
|
|
||||||
True if there is a server with the given name, False otherwise.
|
|
||||||
"""
|
|
||||||
socket = QLocalSocket()
|
|
||||||
log.ipc.debug("Trying to connect to {}".format(name))
|
|
||||||
socket.connectToServer(name)
|
|
||||||
|
|
||||||
err = socket.error()
|
|
||||||
|
|
||||||
if err != QLocalSocket.UnknownSocketError:
|
|
||||||
log.ipc.debug("Socket error: {} ({})".format(
|
|
||||||
socket.errorString(), err))
|
|
||||||
|
|
||||||
mac_fail = (sys.platform == 'darwin' and
|
|
||||||
socket.errorString() == 'QLocalSocket::connectToServer: '
|
|
||||||
'Unknown error 38')
|
|
||||||
|
|
||||||
if err not in [QLocalSocket.ServerNotFoundError,
|
|
||||||
QLocalSocket.ConnectionRefusedError] and not mac_fail:
|
|
||||||
return True
|
|
||||||
|
|
||||||
socket.disconnectFromServer()
|
|
||||||
if socket.state() != QLocalSocket.UnconnectedState:
|
|
||||||
socket.waitForDisconnected(CONNECT_TIMEOUT)
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def send_to_running_instance(socketname, command, target_arg, *,
|
|
||||||
legacy_name=None, socket=None):
|
|
||||||
"""Try to send a commandline to a running instance.
|
"""Try to send a commandline to a running instance.
|
||||||
|
|
||||||
Blocks for CONNECT_TIMEOUT ms.
|
Blocks for CONNECT_TIMEOUT ms.
|
||||||
@ -459,7 +424,6 @@ def send_to_running_instance(socketname, command, target_arg, *,
|
|||||||
command: The command to send to the running instance.
|
command: The command to send to the running instance.
|
||||||
target_arg: --target command line argument
|
target_arg: --target command line argument
|
||||||
socket: The socket to read data from, or None.
|
socket: The socket to read data from, or None.
|
||||||
legacy_name: The legacy name to first try to connect to.
|
|
||||||
|
|
||||||
Return:
|
Return:
|
||||||
True if connecting was successful, False if no connection was made.
|
True if connecting was successful, False if no connection was made.
|
||||||
@ -467,13 +431,8 @@ def send_to_running_instance(socketname, command, target_arg, *,
|
|||||||
if socket is None:
|
if socket is None:
|
||||||
socket = QLocalSocket()
|
socket = QLocalSocket()
|
||||||
|
|
||||||
if legacy_name is not None and _has_legacy_server(legacy_name):
|
log.ipc.debug("Connecting to {}".format(socketname))
|
||||||
name_to_use = legacy_name
|
socket.connectToServer(socketname)
|
||||||
else:
|
|
||||||
name_to_use = socketname
|
|
||||||
|
|
||||||
log.ipc.debug("Connecting to {}".format(name_to_use))
|
|
||||||
socket.connectToServer(name_to_use)
|
|
||||||
|
|
||||||
connected = socket.waitForConnected(CONNECT_TIMEOUT)
|
connected = socket.waitForConnected(CONNECT_TIMEOUT)
|
||||||
if connected:
|
if connected:
|
||||||
@ -527,12 +486,10 @@ def send_or_listen(args):
|
|||||||
None if an instance was running and received our request.
|
None if an instance was running and received our request.
|
||||||
"""
|
"""
|
||||||
socketname = _get_socketname(args.basedir)
|
socketname = _get_socketname(args.basedir)
|
||||||
legacy_socketname = _get_socketname(args.basedir, legacy=True)
|
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
sent = send_to_running_instance(socketname, args.command,
|
sent = send_to_running_instance(socketname, args.command,
|
||||||
args.target,
|
args.target)
|
||||||
legacy_name=legacy_socketname)
|
|
||||||
if sent:
|
if sent:
|
||||||
return None
|
return None
|
||||||
log.init.debug("Starting IPC server...")
|
log.init.debug("Starting IPC server...")
|
||||||
@ -545,8 +502,7 @@ def send_or_listen(args):
|
|||||||
log.init.debug("Got AddressInUseError, trying again.")
|
log.init.debug("Got AddressInUseError, trying again.")
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
sent = send_to_running_instance(socketname, args.command,
|
sent = send_to_running_instance(socketname, args.command,
|
||||||
args.target,
|
args.target)
|
||||||
legacy_name=legacy_socketname)
|
|
||||||
if sent:
|
if sent:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
|
@ -182,11 +182,6 @@ def md5(inp):
|
|||||||
|
|
||||||
class TestSocketName:
|
class TestSocketName:
|
||||||
|
|
||||||
LEGACY_TESTS = [
|
|
||||||
(None, 'qutebrowser-testusername'),
|
|
||||||
('/x', 'qutebrowser-testusername-{}'.format(md5('/x'))),
|
|
||||||
]
|
|
||||||
|
|
||||||
POSIX_TESTS = [
|
POSIX_TESTS = [
|
||||||
(None, 'ipc-{}'.format(md5('testusername'))),
|
(None, 'ipc-{}'.format(md5('testusername'))),
|
||||||
('/x', 'ipc-{}'.format(md5('testusername-/x'))),
|
('/x', 'ipc-{}'.format(md5('testusername-/x'))),
|
||||||
@ -196,12 +191,10 @@ class TestSocketName:
|
|||||||
def patch_user(self, monkeypatch):
|
def patch_user(self, monkeypatch):
|
||||||
monkeypatch.setattr(ipc.getpass, 'getuser', lambda: 'testusername')
|
monkeypatch.setattr(ipc.getpass, 'getuser', lambda: 'testusername')
|
||||||
|
|
||||||
@pytest.mark.parametrize('basedir, expected', LEGACY_TESTS)
|
@pytest.mark.parametrize('basedir, expected', [
|
||||||
def test_legacy(self, basedir, expected):
|
(None, 'qutebrowser-testusername'),
|
||||||
socketname = ipc._get_socketname(basedir, legacy=True)
|
('/x', 'qutebrowser-testusername-{}'.format(md5('/x'))),
|
||||||
assert socketname == expected
|
])
|
||||||
|
|
||||||
@pytest.mark.parametrize('basedir, expected', LEGACY_TESTS)
|
|
||||||
@pytest.mark.windows
|
@pytest.mark.windows
|
||||||
def test_windows(self, basedir, expected):
|
def test_windows(self, basedir, expected):
|
||||||
socketname = ipc._get_socketname(basedir)
|
socketname = ipc._get_socketname(basedir)
|
||||||
@ -629,14 +622,6 @@ class TestSendOrListen:
|
|||||||
setattr(m, attr, getattr(QLocalSocket, attr))
|
setattr(m, attr, getattr(QLocalSocket, attr))
|
||||||
return m
|
return m
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def legacy_server(self, args):
|
|
||||||
legacy_name = ipc._get_socketname(args.basedir, legacy=True)
|
|
||||||
legacy_server = ipc.IPCServer(legacy_name)
|
|
||||||
legacy_server.listen()
|
|
||||||
yield legacy_server
|
|
||||||
legacy_server.shutdown()
|
|
||||||
|
|
||||||
@pytest.mark.linux(reason="Flaky on Windows and macOS")
|
@pytest.mark.linux(reason="Flaky on Windows and macOS")
|
||||||
def test_normal_connection(self, caplog, qtbot, args):
|
def test_normal_connection(self, caplog, qtbot, args):
|
||||||
ret_server = ipc.send_or_listen(args)
|
ret_server = ipc.send_or_listen(args)
|
||||||
@ -651,54 +636,6 @@ class TestSendOrListen:
|
|||||||
|
|
||||||
assert ret_client is None
|
assert ret_client is None
|
||||||
|
|
||||||
@pytest.mark.posix(reason="Unneeded on Windows")
|
|
||||||
def test_legacy_name(self, caplog, qtbot, args, legacy_server):
|
|
||||||
with qtbot.waitSignal(legacy_server.got_args):
|
|
||||||
ret = ipc.send_or_listen(args)
|
|
||||||
assert ret is None
|
|
||||||
msgs = [e.message for e in caplog.records]
|
|
||||||
assert "Connecting to {}".format(legacy_server._socketname) in msgs
|
|
||||||
|
|
||||||
@pytest.mark.posix(reason="Unneeded on Windows")
|
|
||||||
def test_stale_legacy_server(self, caplog, qtbot, args, legacy_server,
|
|
||||||
ipc_server, py_proc):
|
|
||||||
legacy_name = ipc._get_socketname(args.basedir, legacy=True)
|
|
||||||
logging.debug('== Setting up the legacy server ==')
|
|
||||||
cmdline = py_proc("""
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from PyQt5.QtCore import QCoreApplication
|
|
||||||
from PyQt5.QtNetwork import QLocalServer
|
|
||||||
|
|
||||||
app = QCoreApplication([])
|
|
||||||
|
|
||||||
QLocalServer.removeServer(sys.argv[1])
|
|
||||||
server = QLocalServer()
|
|
||||||
|
|
||||||
ok = server.listen(sys.argv[1])
|
|
||||||
assert ok
|
|
||||||
|
|
||||||
print(server.fullServerName())
|
|
||||||
""")
|
|
||||||
|
|
||||||
name = subprocess.check_output(
|
|
||||||
[cmdline[0]] + cmdline[1] + [legacy_name])
|
|
||||||
name = name.decode('utf-8').rstrip('\n')
|
|
||||||
|
|
||||||
# Closing the server should not remove the FIFO yet
|
|
||||||
assert os.path.exists(name)
|
|
||||||
|
|
||||||
## Setting up the new server
|
|
||||||
logging.debug('== Setting up new server ==')
|
|
||||||
ret_server = ipc.send_or_listen(args)
|
|
||||||
assert isinstance(ret_server, ipc.IPCServer)
|
|
||||||
|
|
||||||
logging.debug('== Connecting ==')
|
|
||||||
with qtbot.waitSignal(ret_server.got_args):
|
|
||||||
ret_client = ipc.send_or_listen(args)
|
|
||||||
|
|
||||||
assert ret_client is None
|
|
||||||
|
|
||||||
@pytest.mark.posix(reason="Unneeded on Windows")
|
@pytest.mark.posix(reason="Unneeded on Windows")
|
||||||
def test_correct_socket_name(self, args):
|
def test_correct_socket_name(self, args):
|
||||||
server = ipc.send_or_listen(args)
|
server = ipc.send_or_listen(args)
|
||||||
@ -723,9 +660,7 @@ class TestSendOrListen:
|
|||||||
|
|
||||||
qlocalsocket_mock().waitForConnected.side_effect = [False, True]
|
qlocalsocket_mock().waitForConnected.side_effect = [False, True]
|
||||||
qlocalsocket_mock().error.side_effect = [
|
qlocalsocket_mock().error.side_effect = [
|
||||||
QLocalSocket.ServerNotFoundError, # legacy name
|
|
||||||
QLocalSocket.ServerNotFoundError,
|
QLocalSocket.ServerNotFoundError,
|
||||||
QLocalSocket.ServerNotFoundError, # legacy name
|
|
||||||
QLocalSocket.UnknownSocketError,
|
QLocalSocket.UnknownSocketError,
|
||||||
QLocalSocket.UnknownSocketError, # error() gets called twice
|
QLocalSocket.UnknownSocketError, # error() gets called twice
|
||||||
]
|
]
|
||||||
@ -761,10 +696,8 @@ class TestSendOrListen:
|
|||||||
# If it fails, that's the "not sent" case above.
|
# If it fails, that's the "not sent" case above.
|
||||||
qlocalsocket_mock().waitForConnected.side_effect = [False, has_error]
|
qlocalsocket_mock().waitForConnected.side_effect = [False, has_error]
|
||||||
qlocalsocket_mock().error.side_effect = [
|
qlocalsocket_mock().error.side_effect = [
|
||||||
QLocalSocket.ServerNotFoundError, # legacy name
|
|
||||||
QLocalSocket.ServerNotFoundError,
|
QLocalSocket.ServerNotFoundError,
|
||||||
QLocalSocket.ServerNotFoundError,
|
QLocalSocket.ServerNotFoundError,
|
||||||
QLocalSocket.ServerNotFoundError, # legacy name
|
|
||||||
QLocalSocket.ConnectionRefusedError,
|
QLocalSocket.ConnectionRefusedError,
|
||||||
QLocalSocket.ConnectionRefusedError, # error() gets called twice
|
QLocalSocket.ConnectionRefusedError, # error() gets called twice
|
||||||
]
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user