mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-23 17:47:31 +00:00
mv qt update checker to its own file
This commit is contained in:
parent
6926b8b2d4
commit
67d080b34a
3 changed files with 145 additions and 131 deletions
|
@ -75,6 +75,7 @@ from .fee_slider import FeeSlider
|
||||||
from .util import *
|
from .util import *
|
||||||
from .installwizard import WIF_HELP_TEXT
|
from .installwizard import WIF_HELP_TEXT
|
||||||
from .history_list import HistoryList, HistoryModel
|
from .history_list import HistoryList, HistoryModel
|
||||||
|
from .update_checker import UpdateCheck, UpdateCheckThread
|
||||||
|
|
||||||
|
|
||||||
class StatusBarButton(QPushButton):
|
class StatusBarButton(QPushButton):
|
||||||
|
|
141
electrum/gui/qt/update_checker.py
Normal file
141
electrum/gui/qt/update_checker.py
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
# Copyright (C) 2019 The Electrum developers
|
||||||
|
# Distributed under the MIT software license, see the accompanying
|
||||||
|
# file LICENCE or http://www.opensource.org/licenses/mit-license.php
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import base64
|
||||||
|
from distutils.version import StrictVersion
|
||||||
|
|
||||||
|
from PyQt5.QtCore import Qt, QThread, pyqtSignal
|
||||||
|
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QLabel, QProgressBar,
|
||||||
|
QHBoxLayout, QPushButton)
|
||||||
|
|
||||||
|
from electrum import version
|
||||||
|
from electrum import constants
|
||||||
|
from electrum import ecc
|
||||||
|
from electrum.i18n import _
|
||||||
|
from electrum.util import PrintError, make_aiohttp_session
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateCheck(QWidget, PrintError):
|
||||||
|
url = "https://electrum.org/version"
|
||||||
|
download_url = "https://electrum.org/#download"
|
||||||
|
|
||||||
|
VERSION_ANNOUNCEMENT_SIGNING_KEYS = (
|
||||||
|
"13xjmVAB1EATPP8RshTE8S8sNwwSUM9p1P",
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, main_window, latest_version=None):
|
||||||
|
self.main_window = main_window
|
||||||
|
QWidget.__init__(self)
|
||||||
|
self.setWindowTitle('Electrum - ' + _('Update Check'))
|
||||||
|
self.content = QVBoxLayout()
|
||||||
|
self.content.setContentsMargins(*[10]*4)
|
||||||
|
|
||||||
|
self.heading_label = QLabel()
|
||||||
|
self.content.addWidget(self.heading_label)
|
||||||
|
|
||||||
|
self.detail_label = QLabel()
|
||||||
|
self.detail_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse)
|
||||||
|
self.detail_label.setOpenExternalLinks(True)
|
||||||
|
self.content.addWidget(self.detail_label)
|
||||||
|
|
||||||
|
self.pb = QProgressBar()
|
||||||
|
self.pb.setMaximum(0)
|
||||||
|
self.pb.setMinimum(0)
|
||||||
|
self.content.addWidget(self.pb)
|
||||||
|
|
||||||
|
versions = QHBoxLayout()
|
||||||
|
versions.addWidget(QLabel(_("Current version: {}".format(version.ELECTRUM_VERSION))))
|
||||||
|
self.latest_version_label = QLabel(_("Latest version: {}".format(" ")))
|
||||||
|
versions.addWidget(self.latest_version_label)
|
||||||
|
self.content.addLayout(versions)
|
||||||
|
|
||||||
|
self.update_view(latest_version)
|
||||||
|
|
||||||
|
self.update_check_thread = UpdateCheckThread(self.main_window)
|
||||||
|
self.update_check_thread.checked.connect(self.on_version_retrieved)
|
||||||
|
self.update_check_thread.failed.connect(self.on_retrieval_failed)
|
||||||
|
self.update_check_thread.start()
|
||||||
|
|
||||||
|
close_button = QPushButton(_("Close"))
|
||||||
|
close_button.clicked.connect(self.close)
|
||||||
|
self.content.addWidget(close_button)
|
||||||
|
self.setLayout(self.content)
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
def on_version_retrieved(self, version):
|
||||||
|
self.update_view(version)
|
||||||
|
|
||||||
|
def on_retrieval_failed(self):
|
||||||
|
self.heading_label.setText('<h2>' + _("Update check failed") + '</h2>')
|
||||||
|
self.detail_label.setText(_("Sorry, but we were unable to check for updates. Please try again later."))
|
||||||
|
self.pb.hide()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_newer(latest_version):
|
||||||
|
return latest_version > StrictVersion(version.ELECTRUM_VERSION)
|
||||||
|
|
||||||
|
def update_view(self, latest_version=None):
|
||||||
|
if latest_version:
|
||||||
|
self.pb.hide()
|
||||||
|
self.latest_version_label.setText(_("Latest version: {}".format(latest_version)))
|
||||||
|
if self.is_newer(latest_version):
|
||||||
|
self.heading_label.setText('<h2>' + _("There is a new update available") + '</h2>')
|
||||||
|
url = "<a href='{u}'>{u}</a>".format(u=UpdateCheck.download_url)
|
||||||
|
self.detail_label.setText(_("You can download the new version from {}.").format(url))
|
||||||
|
else:
|
||||||
|
self.heading_label.setText('<h2>' + _("Already up to date") + '</h2>')
|
||||||
|
self.detail_label.setText(_("You are already on the latest version of Electrum."))
|
||||||
|
else:
|
||||||
|
self.heading_label.setText('<h2>' + _("Checking for updates...") + '</h2>')
|
||||||
|
self.detail_label.setText(_("Please wait while Electrum checks for available updates."))
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateCheckThread(QThread, PrintError):
|
||||||
|
checked = pyqtSignal(object)
|
||||||
|
failed = pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self, main_window):
|
||||||
|
super().__init__()
|
||||||
|
self.main_window = main_window
|
||||||
|
|
||||||
|
async def get_update_info(self):
|
||||||
|
async with make_aiohttp_session(proxy=self.main_window.network.proxy) as session:
|
||||||
|
async with session.get(UpdateCheck.url) as result:
|
||||||
|
signed_version_dict = await result.json(content_type=None)
|
||||||
|
# example signed_version_dict:
|
||||||
|
# {
|
||||||
|
# "version": "3.9.9",
|
||||||
|
# "signatures": {
|
||||||
|
# "1Lqm1HphuhxKZQEawzPse8gJtgjm9kUKT4": "IA+2QG3xPRn4HAIFdpu9eeaCYC7S5wS/sDxn54LJx6BdUTBpse3ibtfq8C43M7M1VfpGkD5tsdwl5C6IfpZD/gQ="
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
version_num = signed_version_dict['version']
|
||||||
|
sigs = signed_version_dict['signatures']
|
||||||
|
for address, sig in sigs.items():
|
||||||
|
if address not in UpdateCheck.VERSION_ANNOUNCEMENT_SIGNING_KEYS:
|
||||||
|
continue
|
||||||
|
sig = base64.b64decode(sig)
|
||||||
|
msg = version_num.encode('utf-8')
|
||||||
|
if ecc.verify_message_with_address(address=address, sig65=sig, message=msg,
|
||||||
|
net=constants.BitcoinMainnet):
|
||||||
|
self.print_error(f"valid sig for version announcement '{version_num}' from address '{address}'")
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise Exception('no valid signature for version announcement')
|
||||||
|
return StrictVersion(version_num.strip())
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
network = self.main_window.network
|
||||||
|
if not network:
|
||||||
|
self.failed.emit()
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
update_info = asyncio.run_coroutine_threadsafe(self.get_update_info(), network.asyncio_loop).result()
|
||||||
|
except Exception as e:
|
||||||
|
#self.print_error(traceback.format_exc())
|
||||||
|
self.print_error(f"got exception: '{repr(e)}'")
|
||||||
|
self.failed.emit()
|
||||||
|
else:
|
||||||
|
self.checked.emit(update_info)
|
|
@ -5,21 +5,17 @@ import sys
|
||||||
import platform
|
import platform
|
||||||
import queue
|
import queue
|
||||||
import traceback
|
import traceback
|
||||||
from distutils.version import StrictVersion
|
|
||||||
from functools import partial, lru_cache
|
from functools import partial, lru_cache
|
||||||
from typing import NamedTuple, Callable, Optional, TYPE_CHECKING
|
from typing import NamedTuple, Callable, Optional, TYPE_CHECKING
|
||||||
import base64
|
|
||||||
|
|
||||||
from PyQt5.QtGui import *
|
from PyQt5.QtGui import *
|
||||||
from PyQt5.QtCore import *
|
from PyQt5.QtCore import *
|
||||||
from PyQt5.QtWidgets import *
|
from PyQt5.QtWidgets import *
|
||||||
|
|
||||||
from electrum import version
|
|
||||||
from electrum import ecc
|
|
||||||
from electrum import constants
|
|
||||||
from electrum.i18n import _, languages
|
from electrum.i18n import _, languages
|
||||||
from electrum.util import (FileImportFailed, FileExportFailed, make_aiohttp_session,
|
from electrum.util import (FileImportFailed, FileExportFailed,
|
||||||
PrintError, resource_path)
|
resource_path)
|
||||||
from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_EXPIRED
|
from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_EXPIRED
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
@ -826,130 +822,6 @@ class FromList(QTreeWidget):
|
||||||
self.header().setSectionResizeMode(1, sm)
|
self.header().setSectionResizeMode(1, sm)
|
||||||
|
|
||||||
|
|
||||||
class UpdateCheck(QWidget, PrintError):
|
|
||||||
url = "https://electrum.org/version"
|
|
||||||
download_url = "https://electrum.org/#download"
|
|
||||||
|
|
||||||
VERSION_ANNOUNCEMENT_SIGNING_KEYS = (
|
|
||||||
"13xjmVAB1EATPP8RshTE8S8sNwwSUM9p1P",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(self, main_window, latest_version=None):
|
|
||||||
self.main_window = main_window
|
|
||||||
QWidget.__init__(self)
|
|
||||||
self.setWindowTitle('Electrum - ' + _('Update Check'))
|
|
||||||
self.content = QVBoxLayout()
|
|
||||||
self.content.setContentsMargins(*[10]*4)
|
|
||||||
|
|
||||||
self.heading_label = QLabel()
|
|
||||||
self.content.addWidget(self.heading_label)
|
|
||||||
|
|
||||||
self.detail_label = QLabel()
|
|
||||||
self.detail_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse)
|
|
||||||
self.detail_label.setOpenExternalLinks(True)
|
|
||||||
self.content.addWidget(self.detail_label)
|
|
||||||
|
|
||||||
self.pb = QProgressBar()
|
|
||||||
self.pb.setMaximum(0)
|
|
||||||
self.pb.setMinimum(0)
|
|
||||||
self.content.addWidget(self.pb)
|
|
||||||
|
|
||||||
versions = QHBoxLayout()
|
|
||||||
versions.addWidget(QLabel(_("Current version: {}".format(version.ELECTRUM_VERSION))))
|
|
||||||
self.latest_version_label = QLabel(_("Latest version: {}".format(" ")))
|
|
||||||
versions.addWidget(self.latest_version_label)
|
|
||||||
self.content.addLayout(versions)
|
|
||||||
|
|
||||||
self.update_view(latest_version)
|
|
||||||
|
|
||||||
self.update_check_thread = UpdateCheckThread(self.main_window)
|
|
||||||
self.update_check_thread.checked.connect(self.on_version_retrieved)
|
|
||||||
self.update_check_thread.failed.connect(self.on_retrieval_failed)
|
|
||||||
self.update_check_thread.start()
|
|
||||||
|
|
||||||
close_button = QPushButton(_("Close"))
|
|
||||||
close_button.clicked.connect(self.close)
|
|
||||||
self.content.addWidget(close_button)
|
|
||||||
self.setLayout(self.content)
|
|
||||||
self.show()
|
|
||||||
|
|
||||||
def on_version_retrieved(self, version):
|
|
||||||
self.update_view(version)
|
|
||||||
|
|
||||||
def on_retrieval_failed(self):
|
|
||||||
self.heading_label.setText('<h2>' + _("Update check failed") + '</h2>')
|
|
||||||
self.detail_label.setText(_("Sorry, but we were unable to check for updates. Please try again later."))
|
|
||||||
self.pb.hide()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def is_newer(latest_version):
|
|
||||||
return latest_version > StrictVersion(version.ELECTRUM_VERSION)
|
|
||||||
|
|
||||||
def update_view(self, latest_version=None):
|
|
||||||
if latest_version:
|
|
||||||
self.pb.hide()
|
|
||||||
self.latest_version_label.setText(_("Latest version: {}".format(latest_version)))
|
|
||||||
if self.is_newer(latest_version):
|
|
||||||
self.heading_label.setText('<h2>' + _("There is a new update available") + '</h2>')
|
|
||||||
url = "<a href='{u}'>{u}</a>".format(u=UpdateCheck.download_url)
|
|
||||||
self.detail_label.setText(_("You can download the new version from {}.").format(url))
|
|
||||||
else:
|
|
||||||
self.heading_label.setText('<h2>' + _("Already up to date") + '</h2>')
|
|
||||||
self.detail_label.setText(_("You are already on the latest version of Electrum."))
|
|
||||||
else:
|
|
||||||
self.heading_label.setText('<h2>' + _("Checking for updates...") + '</h2>')
|
|
||||||
self.detail_label.setText(_("Please wait while Electrum checks for available updates."))
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateCheckThread(QThread, PrintError):
|
|
||||||
checked = pyqtSignal(object)
|
|
||||||
failed = pyqtSignal()
|
|
||||||
|
|
||||||
def __init__(self, main_window):
|
|
||||||
super().__init__()
|
|
||||||
self.main_window = main_window
|
|
||||||
|
|
||||||
async def get_update_info(self):
|
|
||||||
async with make_aiohttp_session(proxy=self.main_window.network.proxy) as session:
|
|
||||||
async with session.get(UpdateCheck.url) as result:
|
|
||||||
signed_version_dict = await result.json(content_type=None)
|
|
||||||
# example signed_version_dict:
|
|
||||||
# {
|
|
||||||
# "version": "3.9.9",
|
|
||||||
# "signatures": {
|
|
||||||
# "1Lqm1HphuhxKZQEawzPse8gJtgjm9kUKT4": "IA+2QG3xPRn4HAIFdpu9eeaCYC7S5wS/sDxn54LJx6BdUTBpse3ibtfq8C43M7M1VfpGkD5tsdwl5C6IfpZD/gQ="
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
version_num = signed_version_dict['version']
|
|
||||||
sigs = signed_version_dict['signatures']
|
|
||||||
for address, sig in sigs.items():
|
|
||||||
if address not in UpdateCheck.VERSION_ANNOUNCEMENT_SIGNING_KEYS:
|
|
||||||
continue
|
|
||||||
sig = base64.b64decode(sig)
|
|
||||||
msg = version_num.encode('utf-8')
|
|
||||||
if ecc.verify_message_with_address(address=address, sig65=sig, message=msg,
|
|
||||||
net=constants.BitcoinMainnet):
|
|
||||||
self.print_error(f"valid sig for version announcement '{version_num}' from address '{address}'")
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
raise Exception('no valid signature for version announcement')
|
|
||||||
return StrictVersion(version_num.strip())
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
network = self.main_window.network
|
|
||||||
if not network:
|
|
||||||
self.failed.emit()
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
update_info = asyncio.run_coroutine_threadsafe(self.get_update_info(), network.asyncio_loop).result()
|
|
||||||
except Exception as e:
|
|
||||||
#self.print_error(traceback.format_exc())
|
|
||||||
self.print_error(f"got exception: '{repr(e)}'")
|
|
||||||
self.failed.emit()
|
|
||||||
else:
|
|
||||||
self.checked.emit(update_info)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app = QApplication([])
|
app = QApplication([])
|
||||||
t = WaitingDialog(None, 'testing ...', lambda: [time.sleep(1)], lambda x: QMessageBox.information(None, 'done', "done"))
|
t = WaitingDialog(None, 'testing ...', lambda: [time.sleep(1)], lambda x: QMessageBox.information(None, 'done', "done"))
|
||||||
|
|
Loading…
Add table
Reference in a new issue