Merge pull request #9769 from f321x/fix_plugins_dialog_bad_state
fix: PluginsDialog bugs causing exceptions
This commit is contained in:
@@ -4,12 +4,13 @@ import shutil
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from PyQt6.QtWidgets import QLabel, QVBoxLayout, QGridLayout, QPushButton, QWidget, QScrollArea, QFormLayout, QFileDialog, QMenu, QApplication
|
from PyQt6.QtWidgets import QLabel, QVBoxLayout, QGridLayout, QPushButton, QWidget, QScrollArea, QFormLayout, QFileDialog, QMenu, QApplication
|
||||||
from PyQt6.QtCore import Qt
|
from PyQt6.QtCore import QTimer
|
||||||
|
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
|
from electrum.logging import get_logger
|
||||||
|
|
||||||
from .util import WindowModalDialog, Buttons, CloseButton, WWLabel, insert_spaces, MessageBoxMixin, EnterButton
|
from .util import (WindowModalDialog, Buttons, CloseButton, WWLabel, insert_spaces, MessageBoxMixin,
|
||||||
from .util import read_QIcon_from_bytes, IconLabel
|
EnterButton, read_QIcon_from_bytes, IconLabel, RunCoroutineDialog)
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@@ -88,7 +89,7 @@ class PluginDialog(WindowModalDialog):
|
|||||||
_('Settings'),
|
_('Settings'),
|
||||||
partial(p.settings_dialog, self))
|
partial(p.settings_dialog, self))
|
||||||
buttons.insert(1, settings_button)
|
buttons.insert(1, settings_button)
|
||||||
# add buttonss
|
# add buttons
|
||||||
vbox.addLayout(Buttons(*buttons))
|
vbox.addLayout(Buttons(*buttons))
|
||||||
|
|
||||||
def do_toggle(self):
|
def do_toggle(self):
|
||||||
@@ -150,6 +151,7 @@ class PluginStatusButton(QPushButton):
|
|||||||
|
|
||||||
|
|
||||||
class PluginsDialog(WindowModalDialog, MessageBoxMixin):
|
class PluginsDialog(WindowModalDialog, MessageBoxMixin):
|
||||||
|
_logger = get_logger(__name__)
|
||||||
|
|
||||||
def __init__(self, config: 'SimpleConfig', plugins:'Plugins', *, gui_object: Optional['ElectrumGui'] = None):
|
def __init__(self, config: 'SimpleConfig', plugins:'Plugins', *, gui_object: Optional['ElectrumGui'] = None):
|
||||||
WindowModalDialog.__init__(self, None, _('Electrum Plugins'))
|
WindowModalDialog.__init__(self, None, _('Electrum Plugins'))
|
||||||
@@ -252,7 +254,8 @@ class PluginsDialog(WindowModalDialog, MessageBoxMixin):
|
|||||||
return
|
return
|
||||||
coro = self.plugins.download_external_plugin(url)
|
coro = self.plugins.download_external_plugin(url)
|
||||||
try:
|
try:
|
||||||
path = self.window.run_coroutine_dialog(coro, _("Downloading plugin..."))
|
d = RunCoroutineDialog(self, _("Downloading plugin..."), coro)
|
||||||
|
path = d.run()
|
||||||
except UserCancelled:
|
except UserCancelled:
|
||||||
return
|
return
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -264,7 +267,10 @@ class PluginsDialog(WindowModalDialog, MessageBoxMixin):
|
|||||||
self.show_error(f"{e}")
|
self.show_error(f"{e}")
|
||||||
success = False
|
success = False
|
||||||
if not success:
|
if not success:
|
||||||
os.unlink(path)
|
try:
|
||||||
|
os.unlink(path)
|
||||||
|
except FileNotFoundError:
|
||||||
|
self._logger.debug("", exc_info=True)
|
||||||
|
|
||||||
def add_plugin_dialog(self):
|
def add_plugin_dialog(self):
|
||||||
pubkey, salt = self.plugins.get_pubkey_bytes()
|
pubkey, salt = self.plugins.get_pubkey_bytes()
|
||||||
@@ -276,6 +282,9 @@ class PluginsDialog(WindowModalDialog, MessageBoxMixin):
|
|||||||
return
|
return
|
||||||
plugins_dir = self.plugins.get_external_plugin_dir()
|
plugins_dir = self.plugins.get_external_plugin_dir()
|
||||||
path = os.path.join(plugins_dir, os.path.basename(filename))
|
path = os.path.join(plugins_dir, os.path.basename(filename))
|
||||||
|
if os.path.exists(path):
|
||||||
|
self.show_warning(_('Plugin already installed.'))
|
||||||
|
return
|
||||||
shutil.copyfile(filename, path)
|
shutil.copyfile(filename, path)
|
||||||
try:
|
try:
|
||||||
success = self.add_external_plugin(path)
|
success = self.add_external_plugin(path)
|
||||||
@@ -283,7 +292,10 @@ class PluginsDialog(WindowModalDialog, MessageBoxMixin):
|
|||||||
self.show_error(f"{e}")
|
self.show_error(f"{e}")
|
||||||
success = False
|
success = False
|
||||||
if not success:
|
if not success:
|
||||||
os.unlink(path)
|
try:
|
||||||
|
os.unlink(path)
|
||||||
|
except FileNotFoundError:
|
||||||
|
self._logger.debug("", exc_info=True)
|
||||||
|
|
||||||
def add_external_plugin(self, path):
|
def add_external_plugin(self, path):
|
||||||
manifest = self.plugins.read_manifest(path)
|
manifest = self.plugins.read_manifest(path)
|
||||||
@@ -353,8 +365,7 @@ class PluginsDialog(WindowModalDialog, MessageBoxMixin):
|
|||||||
status_button.update()
|
status_button.update()
|
||||||
if self.gui_object:
|
if self.gui_object:
|
||||||
self.gui_object.reload_windows()
|
self.gui_object.reload_windows()
|
||||||
self.setFocus()
|
self.bring_to_front()
|
||||||
self.activateWindow()
|
|
||||||
|
|
||||||
def uninstall_plugin(self, name):
|
def uninstall_plugin(self, name):
|
||||||
if not self.question(_('Remove plugin \'{}\'?').format(name)):
|
if not self.question(_('Remove plugin \'{}\'?').format(name)):
|
||||||
@@ -363,3 +374,10 @@ class PluginsDialog(WindowModalDialog, MessageBoxMixin):
|
|||||||
if self.gui_object:
|
if self.gui_object:
|
||||||
self.gui_object.reload_windows()
|
self.gui_object.reload_windows()
|
||||||
self.show_list()
|
self.show_list()
|
||||||
|
self.bring_to_front()
|
||||||
|
|
||||||
|
def bring_to_front(self):
|
||||||
|
def _bring_self_to_front():
|
||||||
|
self.activateWindow()
|
||||||
|
self.setFocus()
|
||||||
|
QTimer.singleShot(100, _bring_self_to_front)
|
||||||
|
|||||||
@@ -246,10 +246,12 @@ class Plugins(DaemonThread):
|
|||||||
os.mkdir(pkg_path)
|
os.mkdir(pkg_path)
|
||||||
return pkg_path
|
return pkg_path
|
||||||
|
|
||||||
async def download_external_plugin(self, url):
|
async def download_external_plugin(self, url: str) -> str:
|
||||||
filename = os.path.basename(urlparse(url).path)
|
filename = os.path.basename(urlparse(url).path)
|
||||||
pkg_path = self.get_external_plugin_dir()
|
pkg_path = self.get_external_plugin_dir()
|
||||||
path = os.path.join(pkg_path, filename)
|
path = os.path.join(pkg_path, filename)
|
||||||
|
if os.path.exists(path):
|
||||||
|
raise FileExistsError(f"Plugin {filename} already exists at {path}")
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
async with session.get(url) as resp:
|
async with session.get(url) as resp:
|
||||||
if resp.status == 200:
|
if resp.status == 200:
|
||||||
|
|||||||
Reference in New Issue
Block a user