Browse Source

Rewrite labels plugin using requests and own signals

283
ThomasV 10 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,())
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):

162
plugins/labels.py

@ -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:
@ -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):
@ -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
@ -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
@ -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")
@ -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)
@ -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)
@ -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
@ -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()

Loading…
Cancel
Save