URI: 
       tRewrite labels plugin using requests and own signals - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit bfb42409488d8bba704e2dd0cd90877ad1874fe6
   DIR parent 1369c02011720706d47a0a0957f73c85a82693f0
  HTML Author: ThomasV <thomasv@gitorious>
       Date:   Tue, 24 Mar 2015 13:25:51 +0100
       
       Rewrite labels plugin using requests and own signals
       
       Diffstat:
         M gui/qt/util.py                      |      31 +++++++++++++++++++++++++++++++
         M plugins/labels.py                   |     162 +++++++++++++------------------
       
       2 files changed, 97 insertions(+), 96 deletions(-)
       ---
   DIR diff --git a/gui/qt/util.py b/gui/qt/util.py
       t@@ -72,7 +72,38 @@ class EnterButton(QPushButton):
                    apply(self.func,())
        
        
       +class ThreadedButton(QPushButton):
       +    def __init__(self, text, func, on_success=None):
       +        QPushButton.__init__(self, text)
       +        self.run_task = func
       +        self.on_success = on_success
       +        self.clicked.connect(self.do_exec)
       +        self.connect(self, SIGNAL('done'), self.done)
       +        self.connect(self, SIGNAL('error'), self.on_error)
       +
       +    def done(self):
       +        if self.on_success:
       +            self.on_success()
       +        self.setEnabled(True)
       +
       +    def on_error(self):
       +        QMessageBox.information(None, _("Error"), self.error)
       +        self.setEnabled(True)
       +
       +    def do_func(self):
       +        self.setEnabled(False)
       +        try:
       +            self.result = self.run_task()
       +        except BaseException as e:
       +            self.error = str(e.message)
       +            self.emit(SIGNAL('error'))
       +            return
       +        self.emit(SIGNAL('done'))
        
       +    def do_exec(self):
       +        t = threading.Thread(target=self.do_func)
       +        t.setDaemon(True)
       +        t.start()
        
        
        class HelpButton(QPushButton):
   DIR diff --git a/plugins/labels.py b/plugins/labels.py
       t@@ -1,11 +1,12 @@
        from electrum.util import print_error
        
       -import httplib, urllib
       +
        import socket
       +import requests
        import threading
        import hashlib
        import json
       -from urlparse import urlparse, parse_qs
       +
        try:
            import PyQt4
        except Exception:
       t@@ -23,6 +24,7 @@ from electrum.plugins import BasePlugin, hook
        from electrum.i18n import _
        
        from electrum_gui.qt import HelpButton, EnterButton
       +from electrum_gui.qt.util import ThreadedButton, Buttons, CancelButton, OkButton
        
        class Plugin(BasePlugin):
        
       t@@ -47,7 +49,6 @@ class Plugin(BasePlugin):
                decoded_message = electrum.bitcoin.aes_decrypt_with_iv(self.encode_password, self.iv, base64.b64decode(message)).decode('utf8')
                return decoded_message
        
       -
            @hook
            def init_qt(self, gui):
                self.window = gui.main_window
       t@@ -60,6 +61,8 @@ class Plugin(BasePlugin):
                        self.set_enabled(False)
                        return False
        
       +        self.window.connect(self.window, SIGNAL('labels:pulled'), self.on_pulled)
       +
            @hook
            def load_wallet(self, wallet):
                self.wallet = wallet
       t@@ -77,7 +80,14 @@ class Plugin(BasePlugin):
        
                if self.auth_token():
                    # If there is an auth token we can try to actually start syncing
       -            threading.Thread(target=self.do_full_pull).start()
       +            def do_pull_thread():
       +                try:
       +                    self.pull_thread()
       +                except:
       +                    print_error("could not retrieve labels")
       +            t = threading.Thread(target=do_pull_thread)
       +            t.setDaemon(True)
       +            t.start()
        
            def auth_token(self):
                return self.config.get("plugin_label_api_key")
       t@@ -93,20 +103,10 @@ class Plugin(BasePlugin):
                if self.encode_password is None:
                    return
                if not changed:
       -            return 
       -        try:
       -            bundle = {"label": {"external_id": self.encode(item), "text": self.encode(label)}}
       -            params = json.dumps(bundle)
       -            connection = httplib.HTTPConnection(self.target_host)
       -            connection.request("POST", ("/api/wallets/%s/labels.json?auth_token=%s" % (self.wallet_id, self.auth_token())), params, {'Content-Type': 'application/json'})
       -
       -            response = connection.getresponse()
       -            if response.reason == httplib.responses[httplib.NOT_FOUND]:
       -                return
       -            response = json.loads(response.read())
       -        except socket.gaierror as e:
       -            print_error('Error connecting to service: %s ' %  e)
       -            return False
       +            return
       +        bundle = {"label": {"external_id": self.encode(item), "text": self.encode(label)}}
       +        t = threading.Thread(target=self.do_request, args=["POST", False, bundle])
       +        t.start()
        
            def settings_widget(self, window):
                return EnterButton(_('Settings'), self.settings_dialog)
       t@@ -124,8 +124,11 @@ class Plugin(BasePlugin):
                      self.accept.setEnabled(False)
        
                d = QDialog()
       -        layout = QGridLayout(d)
       -        layout.addWidget(QLabel("API Key: "),0,0)
       +        vbox = QVBoxLayout(d)
       +        layout = QGridLayout()
       +        vbox.addLayout(layout)
       +
       +        layout.addWidget(QLabel("API Key: "), 0, 0)
        
                self.auth_token_edit = QLineEdit(self.auth_token())
                self.auth_token_edit.textChanged.connect(check_for_api_key)
       t@@ -139,99 +142,66 @@ class Plugin(BasePlugin):
                layout.addWidget(QLabel("Decryption key: "),1,0)
                layout.addWidget(HelpButton("This key can be used on the LabElectrum website to decrypt your data in case you want to review it online."),1,2)
        
       -        self.upload = QPushButton("Force upload")
       -        self.upload.clicked.connect(self.full_push)
       -        layout.addWidget(self.upload, 2,1)
       -
       -        self.download = QPushButton("Force download")
       -        self.download.clicked.connect(self.full_pull)
       -        layout.addWidget(self.download, 2,2)
       +        self.upload = ThreadedButton("Force upload", self.push_thread, self.done_processing)
       +        layout.addWidget(self.upload, 2, 1)
        
       -        c = QPushButton(_("Cancel"))
       -        c.clicked.connect(d.reject)
       +        self.download = ThreadedButton("Force download", self.pull_thread, self.done_processing)
       +        layout.addWidget(self.download, 2, 2)
        
       -        self.accept = QPushButton(_("Done"))
       -        self.accept.clicked.connect(d.accept)
       -
       -        layout.addWidget(c,3,1)
       -        layout.addWidget(self.accept,3,2)
       +        self.accept = OkButton(d, _("Done"))
       +        vbox.addLayout(Buttons(CancelButton(d), self.accept))
        
                check_for_api_key(self.auth_token())
        
       -        self.window.labelsChanged.connect(self.done_processing)
       -
                if d.exec_():
       -          return True
       +            return True
                else:
       -          return False
       +            return False
       +
       +    def on_pulled(self):
       +        wallet = self.wallet
       +        wallet.storage.put('labels', wallet.labels, True)
       +        self.window.labelsChanged.emit()
        
            def done_processing(self):
                QMessageBox.information(None, _("Labels synchronised"), _("Your labels have been synchronised."))
        
       -    def full_push(self):
       -        threading.Thread(target=self.do_full_push).start()
       -
       -    def full_pull(self):
       -        threading.Thread(target=self.do_full_pull, args=([True])).start()
       +    def do_request(self, method, is_batch=False, data=None):
       +        url = 'http://' + self.target_host + "/api/wallets/%s/%s?auth_token=%s" % (self.wallet_id, 'labels/batch.json' if is_batch else 'labels.json', self.auth_token())
       +        kwargs = {'headers': {}}
       +        if method == 'GET' and data:
       +            kwargs['params'] = data
       +        elif method == 'POST' and data:
       +            kwargs['data'] = json.dumps(data)
       +            kwargs['headers']['Content-Type'] = 'application/json'
       +        response = requests.request(method, url, **kwargs)
       +        if response.status_code != 200:
       +            raise BaseException(response.status_code, response.text)
       +        response = response.json()
       +        if "error" in response:
       +            raise BaseException(response["error"])
       +        return response
        
       -    def do_full_push(self):
       -        try:
       -            bundle = {"labels": {}}
       -            for key, value in self.wallet.labels.iteritems():
       -                try:
       -                    encoded_key = self.encode(key)
       -                except:
       -                    print_error('cannot encode', repr(key))
       -                    continue
       -                try:
       -                    encoded_value = self.encode(value)
       -                except:
       -                    print_error('cannot encode', repr(value))
       -                    continue
       -                bundle["labels"][encoded_key] = encoded_value
       -
       -            params = json.dumps(bundle)
       -            connection = httplib.HTTPConnection(self.target_host)
       -            connection.request("POST", ("/api/wallets/%s/labels/batch.json?auth_token=%s" % (self.wallet_id, self.auth_token())), params, {'Content-Type': 'application/json'})
       -
       -            response = connection.getresponse()
       -            if response.reason == httplib.responses[httplib.NOT_FOUND]:
       -                print_error('404 error' %  e)
       -                return
       +    def push_thread(self):
       +        bundle = {"labels": {}}
       +        for key, value in self.wallet.labels.iteritems():
                    try:
       -                response = json.loads(response.read())
       -            except ValueError as e:
       -                print_error('Error loading labelsync response: %s' %  e)
       -                return False
       -
       -            if "error" in response:
       -                print_error('Error loading labelsync response.')
       -                return False
       -
       -        except socket.gaierror as e:
       -            print_error('Error connecting to service: %s ' %  e)
       -            return False
       -
       -        self.window.labelsChanged.emit()
       +                encoded_key = self.encode(key)
       +                encoded_value = self.encode(value)
       +            except:
       +                print_error('cannot encode', repr(key), repr(value))
       +                continue
       +            bundle["labels"][encoded_key] = encoded_value
        
       -    def do_full_pull(self, force = False):
       -        connection = httplib.HTTPConnection(self.target_host)
       -        connection.request("GET", ("/api/wallets/%s/labels.json?auth_token=%s" % (self.wallet_id, self.auth_token())),"", {'Content-Type': 'application/json'})
       -        response = connection.getresponse()
       -        if response.status != 200:
       -            print_error("Cannot retrieve labels:", response.status, response.reason)
       -            return
       -        response = json.loads(response.read())
       -        if "error" in response:
       -            raise BaseException(_("Could not sync labels: %s" % response["error"]))
       +        response = self.do_request("POST", True, bundle)
       +        self.window.emit(SIGNAL('labels:pushed'))
        
       +    def pull_thread(self, force = False):
       +        response = self.do_request("GET")
                result = {}
                for label in response:
                    try:
                        key = self.decode(label["external_id"])
       -            except:
       -                continue
       -            try:
                        value = self.decode(label["text"])
                    except:
                        continue
       t@@ -249,6 +219,6 @@ class Plugin(BasePlugin):
                for key, value in result.items():
                    if force or not wallet.labels.get(key):
                        wallet.labels[key] = value
       -        wallet.storage.put('labels', wallet.labels)
       +
       +        self.window.emit(SIGNAL('labels:pulled'))
                print_error("received %d labels"%len(response))
       -        self.window.labelsChanged.emit()