Browse Source

Rewrite labels plugin using requests and own signals

master
ThomasV 11 years ago
parent
commit
bfb4240948
  1. 31
      gui/qt/util.py
  2. 162
      plugins/labels.py

31
gui/qt/util.py

@ -72,7 +72,38 @@ class EnterButton(QPushButton):
apply(self.func,()) 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): class HelpButton(QPushButton):

162
plugins/labels.py

@ -1,11 +1,12 @@
from electrum.util import print_error from electrum.util import print_error
import httplib, urllib
import socket import socket
import requests
import threading import threading
import hashlib import hashlib
import json import json
from urlparse import urlparse, parse_qs
try: try:
import PyQt4 import PyQt4
except Exception: except Exception:
@ -23,6 +24,7 @@ from electrum.plugins import BasePlugin, hook
from electrum.i18n import _ from electrum.i18n import _
from electrum_gui.qt import HelpButton, EnterButton from electrum_gui.qt import HelpButton, EnterButton
from electrum_gui.qt.util import ThreadedButton, Buttons, CancelButton, OkButton
class Plugin(BasePlugin): class Plugin(BasePlugin):
@ -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') decoded_message = electrum.bitcoin.aes_decrypt_with_iv(self.encode_password, self.iv, base64.b64decode(message)).decode('utf8')
return decoded_message return decoded_message
@hook @hook
def init_qt(self, gui): def init_qt(self, gui):
self.window = gui.main_window self.window = gui.main_window
@ -60,6 +61,8 @@ class Plugin(BasePlugin):
self.set_enabled(False) self.set_enabled(False)
return False return False
self.window.connect(self.window, SIGNAL('labels:pulled'), self.on_pulled)
@hook @hook
def load_wallet(self, wallet): def load_wallet(self, wallet):
self.wallet = wallet self.wallet = wallet
@ -77,7 +80,14 @@ class Plugin(BasePlugin):
if self.auth_token(): if self.auth_token():
# If there is an auth token we can try to actually start syncing # 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): def auth_token(self):
return self.config.get("plugin_label_api_key") return self.config.get("plugin_label_api_key")
@ -93,20 +103,10 @@ class Plugin(BasePlugin):
if self.encode_password is None: if self.encode_password is None:
return return
if not changed: if not changed:
return return
try: bundle = {"label": {"external_id": self.encode(item), "text": self.encode(label)}}
bundle = {"label": {"external_id": self.encode(item), "text": self.encode(label)}} t = threading.Thread(target=self.do_request, args=["POST", False, bundle])
params = json.dumps(bundle) t.start()
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
def settings_widget(self, window): def settings_widget(self, window):
return EnterButton(_('Settings'), self.settings_dialog) return EnterButton(_('Settings'), self.settings_dialog)
@ -124,8 +124,11 @@ class Plugin(BasePlugin):
self.accept.setEnabled(False) self.accept.setEnabled(False)
d = QDialog() d = QDialog()
layout = QGridLayout(d) vbox = QVBoxLayout(d)
layout.addWidget(QLabel("API Key: "),0,0) layout = QGridLayout()
vbox.addLayout(layout)
layout.addWidget(QLabel("API Key: "), 0, 0)
self.auth_token_edit = QLineEdit(self.auth_token()) self.auth_token_edit = QLineEdit(self.auth_token())
self.auth_token_edit.textChanged.connect(check_for_api_key) self.auth_token_edit.textChanged.connect(check_for_api_key)
@ -139,99 +142,66 @@ class Plugin(BasePlugin):
layout.addWidget(QLabel("Decryption key: "),1,0) 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) 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 = ThreadedButton("Force upload", self.push_thread, self.done_processing)
self.upload.clicked.connect(self.full_push) layout.addWidget(self.upload, 2, 1)
layout.addWidget(self.upload, 2,1)
self.download = QPushButton("Force download")
self.download.clicked.connect(self.full_pull)
layout.addWidget(self.download, 2,2)
c = QPushButton(_("Cancel")) self.download = ThreadedButton("Force download", self.pull_thread, self.done_processing)
c.clicked.connect(d.reject) layout.addWidget(self.download, 2, 2)
self.accept = QPushButton(_("Done")) self.accept = OkButton(d, _("Done"))
self.accept.clicked.connect(d.accept) vbox.addLayout(Buttons(CancelButton(d), self.accept))
layout.addWidget(c,3,1)
layout.addWidget(self.accept,3,2)
check_for_api_key(self.auth_token()) check_for_api_key(self.auth_token())
self.window.labelsChanged.connect(self.done_processing)
if d.exec_(): if d.exec_():
return True return True
else: 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): def done_processing(self):
QMessageBox.information(None, _("Labels synchronised"), _("Your labels have been synchronised.")) QMessageBox.information(None, _("Labels synchronised"), _("Your labels have been synchronised."))
def full_push(self): def do_request(self, method, is_batch=False, data=None):
threading.Thread(target=self.do_full_push).start() 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': {}}
def full_pull(self): if method == 'GET' and data:
threading.Thread(target=self.do_full_pull, args=([True])).start() 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): def push_thread(self):
try: bundle = {"labels": {}}
bundle = {"labels": {}} for key, value in self.wallet.labels.iteritems():
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
try: try:
response = json.loads(response.read()) encoded_key = self.encode(key)
except ValueError as e: encoded_value = self.encode(value)
print_error('Error loading labelsync response: %s' % e) except:
return False print_error('cannot encode', repr(key), repr(value))
continue
if "error" in response: bundle["labels"][encoded_key] = encoded_value
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()
def do_full_pull(self, force = False): response = self.do_request("POST", True, bundle)
connection = httplib.HTTPConnection(self.target_host) self.window.emit(SIGNAL('labels:pushed'))
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"]))
def pull_thread(self, force = False):
response = self.do_request("GET")
result = {} result = {}
for label in response: for label in response:
try: try:
key = self.decode(label["external_id"]) key = self.decode(label["external_id"])
except:
continue
try:
value = self.decode(label["text"]) value = self.decode(label["text"])
except: except:
continue continue
@ -249,6 +219,6 @@ class Plugin(BasePlugin):
for key, value in result.items(): for key, value in result.items():
if force or not wallet.labels.get(key): if force or not wallet.labels.get(key):
wallet.labels[key] = value wallet.labels[key] = value
wallet.storage.put('labels', wallet.labels)
self.window.emit(SIGNAL('labels:pulled'))
print_error("received %d labels"%len(response)) print_error("received %d labels"%len(response))
self.window.labelsChanged.emit()

Loading…
Cancel
Save