Browse Source
This guards function calls by storing the function, args and kwargs into an added attribute '__auth_fcall' on the object using the decorator, then emits a signal that can be handled by the UI. The UI can signal auth-success or auth-failure back to the object by calling either the authProceed() slot or the authCancel slot. The object utilizing this decorator MUST inherit/mixin the AuthMixin class, which provides the above two slots, and handling of state. The decorator also accepts a 'reject' parameter, containing the name of a parameterless function on the object, which is called when authentication has failed/is cancelled.patch-4
Sander van Grieken
3 years ago
4 changed files with 87 additions and 4 deletions
@ -0,0 +1,58 @@ |
|||
from functools import wraps, partial |
|||
|
|||
from PyQt5.QtCore import pyqtSignal, pyqtSlot |
|||
|
|||
from electrum.logging import get_logger |
|||
|
|||
def auth_protect(func=None, reject=None): |
|||
if func is None: |
|||
return partial(auth_protect, reject=reject) |
|||
|
|||
@wraps(func) |
|||
def wrapper(self, *args, **kwargs): |
|||
self._logger.debug(str(self)) |
|||
if hasattr(self, '__auth_fcall'): |
|||
self._logger.debug('object already has a pending authed function call') |
|||
raise Exception('object already has a pending authed function call') |
|||
setattr(self, '__auth_fcall', (func,args,kwargs,reject)) |
|||
getattr(self, 'authRequired').emit() |
|||
|
|||
return wrapper |
|||
|
|||
class AuthMixin: |
|||
_auth_logger = get_logger(__name__) |
|||
|
|||
authRequired = pyqtSignal() |
|||
|
|||
@pyqtSlot() |
|||
def authProceed(self): |
|||
self._auth_logger.debug('Proceeding with authed fn()') |
|||
try: |
|||
self._auth_logger.debug(str(getattr(self, '__auth_fcall'))) |
|||
(func,args,kwargs,reject) = getattr(self, '__auth_fcall') |
|||
r = func(self, *args, **kwargs) |
|||
return r |
|||
except Exception as e: |
|||
self._auth_logger.error('Error executing wrapped fn(): %s' % repr(e)) |
|||
raise e |
|||
finally: |
|||
delattr(self,'__auth_fcall') |
|||
|
|||
@pyqtSlot() |
|||
def authCancel(self): |
|||
self._auth_logger.debug('Cancelling authed fn()') |
|||
if not hasattr(self, '__auth_fcall'): |
|||
return |
|||
|
|||
try: |
|||
(func,args,kwargs,reject) = getattr(self, '__auth_fcall') |
|||
if reject is not None: |
|||
if hasattr(self, reject): |
|||
getattr(self, reject)() |
|||
else: |
|||
self._auth_logger.error('Reject method \'%s\' not defined' % reject) |
|||
except Exception as e: |
|||
self._auth_logger.error('Error executing reject function \'%s\': %s' % (reject, repr(e))) |
|||
raise e |
|||
finally: |
|||
delattr(self, '__auth_fcall') |
Loading…
Reference in new issue