From 52b877ac3d978021ff77f2196c737d2b838a48d0 Mon Sep 17 00:00:00 2001 From: Janus Date: Fri, 7 Sep 2018 11:34:56 +0200 Subject: [PATCH] network: add singleton accessor classmethod, port trustedcoin to aiohttp --- electrum/exchange_rate.py | 11 +--- .../gui/kivy/uix/dialogs/crash_reporter.py | 9 +-- electrum/gui/qt/exception_window.py | 9 +-- electrum/network.py | 8 +++ electrum/plugins/trustedcoin/trustedcoin.py | 60 +++++++++++-------- 5 files changed, 51 insertions(+), 46 deletions(-) diff --git a/electrum/exchange_rate.py b/electrum/exchange_rate.py index 6a89a6e06..4503ce31d 100644 --- a/electrum/exchange_rate.py +++ b/electrum/exchange_rate.py @@ -17,7 +17,7 @@ from .bitcoin import COIN from .i18n import _ from .util import PrintError, ThreadJob, make_dir, aiosafe from .util import make_aiohttp_session - +from .network import Network # See https://en.wikipedia.org/wiki/ISO_4217 CCY_PRECISIONS = {'BHD': 3, 'BIF': 0, 'BYR': 0, 'CLF': 4, 'CLP': 0, @@ -27,8 +27,6 @@ CCY_PRECISIONS = {'BHD': 3, 'BIF': 0, 'BYR': 0, 'CLF': 4, 'CLP': 0, 'RWF': 0, 'TND': 3, 'UGX': 0, 'UYI': 0, 'VND': 0, 'VUV': 0, 'XAF': 0, 'XAU': 4, 'XOF': 0, 'XPF': 0} -PROXY = None - class ExchangeBase(PrintError): def __init__(self, on_quotes, on_history): @@ -40,14 +38,14 @@ class ExchangeBase(PrintError): async def get_raw(self, site, get_string): # APIs must have https url = ''.join(['https://', site, get_string]) - async with make_aiohttp_session(PROXY) as session: + async with make_aiohttp_session(Network.get_instance().proxy) as session: async with session.get(url) as response: return await response.text() async def get_json(self, site, get_string): # APIs must have https url = ''.join(['https://', site, get_string]) - async with make_aiohttp_session(PROXY) as session: + async with make_aiohttp_session(Network.get_instance().proxy) as session: async with session.get(url) as response: return await response.json() @@ -448,11 +446,8 @@ class FxThread(ThreadJob): self.trigger.set() self.set_exchange(self.config_exchange()) make_dir(self.cache_dir) - self.set_proxy('bogus', self.network.proxy) def set_proxy(self, trigger_name, *args): - global PROXY - PROXY = args[0] self.trigger.set() def get_currencies(self, h): diff --git a/electrum/gui/kivy/uix/dialogs/crash_reporter.py b/electrum/gui/kivy/uix/dialogs/crash_reporter.py index 00e96f2f0..f02222fd7 100644 --- a/electrum/gui/kivy/uix/dialogs/crash_reporter.py +++ b/electrum/gui/kivy/uix/dialogs/crash_reporter.py @@ -103,11 +103,6 @@ class CrashReporter(BaseCrashReporter, Factory.Popup): self.ids.crash_message.text = BaseCrashReporter.CRASH_MESSAGE self.ids.request_help_message.text = BaseCrashReporter.REQUEST_HELP_MESSAGE self.ids.describe_error_message.text = BaseCrashReporter.DESCRIBE_ERROR_MESSAGE - self.proxy = self.main_window.network.proxy - self.main_window.network.register_callback(self.set_proxy, ['proxy_set']) - - def set_proxy(self, evt, proxy): - self.proxy = proxy def show_contents(self): details = CrashReportDetails(self.get_report_string()) @@ -121,7 +116,9 @@ class CrashReporter(BaseCrashReporter, Factory.Popup): def send_report(self): try: - response = json.loads(BaseCrashReporter.send_report(self, self.main_window.network.asyncio_loop, self.proxy, "/crash.json")) + loop = self.main_window.network.asyncio_loop + proxy = self.main_window.network.proxy + response = json.loads(BaseCrashReporter.send_report(self, loop, proxy, "/crash.json")) except (ValueError, ClientError): self.show_popup(_('Unable to send report'), _("Please check your network connection.")) else: diff --git a/electrum/gui/qt/exception_window.py b/electrum/gui/qt/exception_window.py index c4e337f1a..1d30b3eea 100644 --- a/electrum/gui/qt/exception_window.py +++ b/electrum/gui/qt/exception_window.py @@ -42,9 +42,6 @@ class Exception_Window(BaseCrashReporter, QWidget, MessageBoxMixin): BaseCrashReporter.__init__(self, exctype, value, tb) self.main_window = main_window - self.proxy = self.main_window.network.proxy - self.main_window.network.register_callback(self.set_proxy, ['proxy_set']) - QWidget.__init__(self) self.setWindowTitle('Electrum - ' + _('An Error Occurred')) self.setMinimumSize(600, 300) @@ -92,12 +89,10 @@ class Exception_Window(BaseCrashReporter, QWidget, MessageBoxMixin): self.setLayout(main_box) self.show() - def set_proxy(self, evt, proxy): - self.proxy = proxy - def send_report(self): try: - response = BaseCrashReporter.send_report(self, self.main_window.network.asyncio_loop, self.proxy) + proxy = self.main_window.network.proxy + response = BaseCrashReporter.send_report(self, self.main_window.network.asyncio_loop, proxy) except BaseException as e: traceback.print_exc(file=sys.stderr) self.main_window.show_critical(_('There was a problem with the automatic reporting:') + '\n' + diff --git a/electrum/network.py b/electrum/network.py index d14d22953..7794738ef 100644 --- a/electrum/network.py +++ b/electrum/network.py @@ -158,6 +158,8 @@ def deserialize_server(server_str): def serialize_server(host, port, protocol): return str(':'.join([host, port, protocol])) +INSTANCE = None + class Network(PrintError): """The Network class manages a set of connections to remote electrum servers, each connected socket is handled by an Interface() object. @@ -173,6 +175,8 @@ class Network(PrintError): verbosity_filter = 'n' def __init__(self, config=None): + global INSTANCE + INSTANCE = self if config is None: config = {} # Do not use mutables as default values! self.config = SimpleConfig(config) if isinstance(config, dict) else config @@ -244,6 +248,10 @@ class Network(PrintError): # just to not trigger a warning from switch_to_interface the first time we change default_server self.server_info_job.set_result(1) + @staticmethod + def get_instance(): + return INSTANCE + def with_interface_lock(func): def func_wrapper(self, *args, **kwargs): with self.interface_lock: diff --git a/electrum/plugins/trustedcoin/trustedcoin.py b/electrum/plugins/trustedcoin/trustedcoin.py index ccd24e332..638cda279 100644 --- a/electrum/plugins/trustedcoin/trustedcoin.py +++ b/electrum/plugins/trustedcoin/trustedcoin.py @@ -22,10 +22,9 @@ # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. - +import asyncio import socket import os -import requests import json import base64 from urllib.parse import urljoin @@ -38,8 +37,9 @@ from electrum.mnemonic import Mnemonic from electrum.wallet import Multisig_Wallet, Deterministic_Wallet from electrum.i18n import _ from electrum.plugin import BasePlugin, hook -from electrum.util import NotEnoughFunds +from electrum.util import NotEnoughFunds, make_aiohttp_session from electrum.storage import STO_EV_USER_PW +from electrum.network import Network # signing_xpub is hardcoded so that the wallet can be restored from seed, without TrustedCoin's server def get_signing_xpub(): @@ -104,34 +104,44 @@ class TrustedCoinCosignerClient(object): self.user_agent = user_agent def send_request(self, method, relative_url, data=None): - kwargs = {'headers': {}} - if self.user_agent: - kwargs['headers']['user-agent'] = self.user_agent - if method == 'get' and data: - kwargs['params'] = data - elif method == 'post' and data: - kwargs['data'] = json.dumps(data) - kwargs['headers']['content-type'] = 'application/json' + print("send_req") + return asyncio.run_coroutine_threadsafe(self._send_request(method, relative_url, data), Network.get_instance().asyncio_loop).result() + + async def handle_response(self, resp): + if resp.status != 200: + try: + r = await resp.json() + message = r['message'] + except: + message = await resp.text() + raise TrustedCoinException(message, resp.status) + try: + return await resp.json() + except: + return await resp.text() + + async def _send_request(self, method, relative_url, data): url = urljoin(self.base_url, relative_url) if self.debug: print('%s %s %s' % (method, url, data)) + headers = {} + if self.user_agent: + headers['user-agent'] = self.user_agent try: - response = requests.request(method, url, **kwargs) + proxy = Network.get_instance().proxy + async with make_aiohttp_session(proxy) as session: + if method == 'get': + async with session.get(url, params=data, headers=headers) as resp: + return await self.handle_response(resp) + elif method == 'post': + async with session.post(url, json=data, headers=headers) as resp: + return await self.handle_response(resp) + else: + assert False + except TrustedCoinException: + raise except Exception as e: raise ErrorConnectingServer(e) - if self.debug: - print(response.text) - if response.status_code != 200: - message = str(response.text) - if response.headers.get('content-type') == 'application/json': - r = response.json() - if 'message' in r: - message = r['message'] - raise TrustedCoinException(message, response.status_code) - if response.headers.get('content-type') == 'application/json': - return response.json() - else: - return response.text def get_terms_of_service(self, billing_plan='electrum-per-tx-otp'): """