diff --git a/picard/ui/options/network.py b/picard/ui/options/network.py index 2d24ceab5..9cbebca0f 100644 --- a/picard/ui/options/network.py +++ b/picard/ui/options/network.py @@ -85,7 +85,9 @@ class NetworkOptionsPage(OptionsPage): config.setting["proxy_username"] = self.ui.username.text() config.setting["proxy_password"] = self.ui.password.text() self.tagger.webservice.setup_proxy() - config.setting["network_transfer_timeout_seconds"] = self.ui.transfer_timeout.value() + transfer_timeout = self.ui.transfer_timeout.value() + config.setting["network_transfer_timeout_seconds"] = transfer_timeout + self.tagger.webservice.set_transfer_timeout(transfer_timeout) config.setting["browser_integration"] = self.ui.browser_integration.isChecked() config.setting["browser_integration_port"] = self.ui.browser_integration_port.value() config.setting["browser_integration_localhost_only"] = \ diff --git a/picard/webservice/__init__.py b/picard/webservice/__init__.py index c8a0d8f31..04b9bf690 100644 --- a/picard/webservice/__init__.py +++ b/picard/webservice/__init__.py @@ -271,6 +271,7 @@ class WebService(QtCore.QObject): self.oauth_manager = OAuthManager(self) self.set_cache() self.setup_proxy() + self.set_transfer_timeout(config.setting['network_transfer_timeout_seconds']) self.manager.finished.connect(self._process_reply) self._request_methods = { "GET": self.manager.get, @@ -331,6 +332,14 @@ class WebService(QtCore.QObject): proxy.setPassword(config.setting["proxy_password"]) self.manager.setProxy(proxy) + def set_transfer_timeout(self, timeout): + timeout_ms = timeout * 1000 + if hasattr(self.manager, 'setTransferTimeout'): # Available since Qt 5.15 + self.manager.setTransferTimeout(timeout_ms) + self._transfer_timeout = 0 + else: # Use fallback implementation + self._transfer_timeout = timeout_ms + def _send_request(self, request, access_token=None): hostkey = request.get_host_key() ratecontrol.increment_requests(hostkey) @@ -338,19 +347,12 @@ class WebService(QtCore.QObject): request.access_token = access_token send = self._request_methods[request.method] data = request.data - transfer_timeout = config.setting['network_transfer_timeout_seconds'] * 1000 - if hasattr(self.manager, 'setTransferTimeout'): # Available since Qt 5.15 - native_timeout = True - request.setTransferTimeout(transfer_timeout) - else: - native_timeout = False reply = send(request, data.encode('utf-8')) if data is not None else send(request) - if not native_timeout: - self._start_transfer_timeout(reply, transfer_timeout) + self._start_transfer_timeout(reply) self._active_requests[reply] = request - def _start_transfer_timeout(self, reply, timeout): - if not timeout: + def _start_transfer_timeout(self, reply): + if not self._transfer_timeout: return # Fallback implementation of a transfer timeout for Qt < 5.15. # Aborts a request if no data gets transferred for TRANSFER_TIMEOUT milliseconds. @@ -359,14 +361,13 @@ class WebService(QtCore.QObject): timer.setTimerType(QtCore.Qt.PreciseTimer) timer.timeout.connect(partial(self._timeout_request, reply)) reply.finished.connect(timer.stop) - reset_callback = partial(self._reset_transfer_timeout, timer, timeout) + reset_callback = partial(self._reset_transfer_timeout) reply.uploadProgress.connect(reset_callback) reply.downloadProgress.connect(reset_callback) - timer.start(timeout) + timer.start(self._transfer_timeout) - @staticmethod - def _reset_transfer_timeout(timer, timeout, bytesTransferred, bytesTotal): - timer.start(timeout) + def _reset_transfer_timeout(self, timer, bytesTransferred, bytesTotal): + timer.start(self._transfer_timeout) @staticmethod def _timeout_request(reply): diff --git a/test/test_webservice.py b/test/test_webservice.py index 1070412b8..69ef13bbe 100644 --- a/test/test_webservice.py +++ b/test/test_webservice.py @@ -47,6 +47,7 @@ PROXY_SETTINGS = { "proxy_server_port": 3128, "proxy_username": 'user', "proxy_password": 'password', + "network_transfer_timeout_seconds": 30, } @@ -54,7 +55,11 @@ class WebServiceTest(PicardTestCase): def setUp(self): super().setUp() - config.setting = {'use_proxy': False, 'server_host': ''} + config.setting = { + 'use_proxy': False, + 'server_host': '', + 'network_transfer_timeout_seconds': 30, + } self.ws = WebService() def tearDown(self): @@ -92,7 +97,10 @@ class WebServiceTaskTest(PicardTestCase): def setUp(self): super().setUp() - config.setting = {'use_proxy': False} + config.setting = { + 'use_proxy': False, + 'network_transfer_timeout_seconds': 30, + } self.ws = WebService() # Patching the QTimers since they can only be started in a QThread