Rewrite labels plugin using requests and own signals
This commit is contained in:
@@ -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):
|
||||||
|
|||||||
@@ -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 = ThreadedButton("Force download", self.pull_thread, self.done_processing)
|
||||||
self.download.clicked.connect(self.full_pull)
|
layout.addWidget(self.download, 2, 2)
|
||||||
layout.addWidget(self.download, 2,2)
|
|
||||||
|
|
||||||
c = QPushButton(_("Cancel"))
|
self.accept = OkButton(d, _("Done"))
|
||||||
c.clicked.connect(d.reject)
|
vbox.addLayout(Buttons(CancelButton(d), self.accept))
|
||||||
|
|
||||||
self.accept = QPushButton(_("Done"))
|
|
||||||
self.accept.clicked.connect(d.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:
|
||||||
def do_full_push(self):
|
kwargs['data'] = json.dumps(data)
|
||||||
try:
|
kwargs['headers']['Content-Type'] = 'application/json'
|
||||||
bundle = {"labels": {}}
|
response = requests.request(method, url, **kwargs)
|
||||||
for key, value in self.wallet.labels.iteritems():
|
if response.status_code != 200:
|
||||||
try:
|
raise BaseException(response.status_code, response.text)
|
||||||
encoded_key = self.encode(key)
|
response = response.json()
|
||||||
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:
|
|
||||||
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()
|
|
||||||
|
|
||||||
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:
|
if "error" in response:
|
||||||
raise BaseException(_("Could not sync labels: %s" % response["error"]))
|
raise BaseException(response["error"])
|
||||||
|
return response
|
||||||
|
|
||||||
|
def push_thread(self):
|
||||||
|
bundle = {"labels": {}}
|
||||||
|
for key, value in self.wallet.labels.iteritems():
|
||||||
|
try:
|
||||||
|
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
|
||||||
|
|
||||||
|
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 = {}
|
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()
|
|
||||||
|
|||||||
Reference in New Issue
Block a user