From 8a7971401fef52c14498b57105773dd800708068 Mon Sep 17 00:00:00 2001 From: Sandip Pandey Date: Wed, 10 Oct 2018 12:20:00 +0200 Subject: [PATCH 01/13] Added memory map pragma to sqlite --- Tribler/Core/CacheDB/sqlitecachedb.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Tribler/Core/CacheDB/sqlitecachedb.py b/Tribler/Core/CacheDB/sqlitecachedb.py index 9eee0fa3abb..75dfa97e9b9 100644 --- a/Tribler/Core/CacheDB/sqlitecachedb.py +++ b/Tribler/Core/CacheDB/sqlitecachedb.py @@ -131,6 +131,9 @@ def _open_connection(self): if os.path.exists(shm_file) or os.path.exists(wal_file): self.do_quick_integrity_check() + # Enable memory map in sqlite (256MB) + cursor.execute(u"PRAGMA mmap_size=268435456;") + # apply pragma page_size, = next(cursor.execute(u"PRAGMA page_size")) if page_size < 8192: From f486a925becfb08235547d77983e547fdaac13ea Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Tue, 16 Oct 2018 11:21:13 +0200 Subject: [PATCH 02/13] Not loading cm downloads if it's disabled --- Tribler/Core/APIImplementation/LaunchManyCore.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Tribler/Core/APIImplementation/LaunchManyCore.py b/Tribler/Core/APIImplementation/LaunchManyCore.py index cd8e11ffdb9..63c1c1b940a 100644 --- a/Tribler/Core/APIImplementation/LaunchManyCore.py +++ b/Tribler/Core/APIImplementation/LaunchManyCore.py @@ -831,11 +831,12 @@ def resume_download(self, filename, setupDelay=0): if tdef and dscfg: if dscfg.get_dest_dir() != '': # removed torrent ignoring try: - if not self.download_exists(tdef.get_infohash()): - self.add(tdef, dscfg, pstate, setupDelay=setupDelay) - else: + if self.download_exists(tdef.get_infohash()): self._logger.info("tlm: not resuming checkpoint because download has already been added") - + elif dscfg.get_credit_mining() and not self.session.config.get_credit_mining_enabled(): + self._logger.info("tlm: not resuming checkpoint since token mining is disabled") + else: + self.add(tdef, dscfg, pstate, setupDelay=setupDelay) except Exception as e: self._logger.exception("tlm: load check_point: exception while adding download %s", tdef) else: From 212bcddcbd85865c0695e1fb6c2705625fdf6d23 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Tue, 16 Oct 2018 11:37:27 +0200 Subject: [PATCH 03/13] Fixed exit_nodes file path --- Tribler/community/triblertunnel/community.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tribler/community/triblertunnel/community.py b/Tribler/community/triblertunnel/community.py index 1a4bb5c7e20..4a88480765a 100644 --- a/Tribler/community/triblertunnel/community.py +++ b/Tribler/community/triblertunnel/community.py @@ -38,8 +38,8 @@ def __init__(self, *args, **kwargs): num_random_slots = kwargs.pop('random_slots', 5) self.bandwidth_wallet = kwargs.pop('bandwidth_wallet', None) socks_listen_ports = kwargs.pop('socks_listen_ports', None) - self.exitnode_cache = kwargs.pop('exitnode_cache', (self.tribler_session.config.get_state_dir() - if self.tribler_session else '') + 'exitnode_cache.dat') + state_path = self.tribler_session.config.get_state_dir() if self.tribler_session else '' + self.exitnode_cache = kwargs.pop('exitnode_cache', os.path.join(state_path, 'exitnode_cache.dat')) super(TriblerTunnelCommunity, self).__init__(*args, **kwargs) self._use_main_thread = True From 39808697fc24e8c43e02625904393df895f92c44 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Tue, 16 Oct 2018 11:50:58 +0200 Subject: [PATCH 04/13] Ignoring socket error 10053 --- Tribler/Core/Session.py | 4 ++++ Tribler/Test/Core/test_session.py | 1 + 2 files changed, 5 insertions(+) diff --git a/Tribler/Core/Session.py b/Tribler/Core/Session.py index 4647aa4c58c..a37dbcf503e 100644 --- a/Tribler/Core/Session.py +++ b/Tribler/Core/Session.py @@ -188,6 +188,10 @@ def unhandled_error_observer(self, event): self._logger.error("Could not send data: socket is busy.") return + if 'socket.error' in text and '[Errno 10053]' in text: + self._logger.error("An established connection was aborted by the software in your host machine.") + return + if 'socket.error' in text and '[Errno 10054]' in text: self._logger.error("Connection forcibly closed by the remote host.") return diff --git a/Tribler/Test/Core/test_session.py b/Tribler/Test/Core/test_session.py index edce941d29b..3a4d8070714 100644 --- a/Tribler/Test/Core/test_session.py +++ b/Tribler/Test/Core/test_session.py @@ -135,6 +135,7 @@ def on_tribler_exception(_): self.session.unhandled_error_observer({'isError': True, 'log_failure': 'socket.error: [Errno 113]'}) self.session.unhandled_error_observer({'isError': True, 'log_failure': 'socket.error: [Errno 51]'}) self.session.unhandled_error_observer({'isError': True, 'log_failure': 'socket.error: [Errno 16]'}) + self.session.unhandled_error_observer({'isError': True, 'log_failure': 'socket.error: [Errno 10053]'}) self.session.unhandled_error_observer({'isError': True, 'log_failure': 'socket.error: [Errno 10054]'}) self.session.unhandled_error_observer({'isError': True, 'log_failure': 'socket.error: [Errno %s]' % SOCKET_BLOCK_ERRORCODE}) From 99cafad761dae2ba6414962ba34f631ef8f19a8e Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Tue, 16 Oct 2018 12:42:01 +0200 Subject: [PATCH 05/13] Improved market order creation in GUI --- .../Core/Modules/restapi/wallets_endpoint.py | 6 ++- TriblerGUI/dialogs/newmarketorderdialog.py | 41 +++++++++++++++++-- .../qt_resources/newmarketorderdialog.ui | 11 ++++- TriblerGUI/widgets/marketpage.py | 33 ++++++--------- 4 files changed, 64 insertions(+), 27 deletions(-) diff --git a/Tribler/Core/Modules/restapi/wallets_endpoint.py b/Tribler/Core/Modules/restapi/wallets_endpoint.py index ef205091576..ba8909ab4af 100644 --- a/Tribler/Core/Modules/restapi/wallets_endpoint.py +++ b/Tribler/Core/Modules/restapi/wallets_endpoint.py @@ -36,6 +36,9 @@ def render_GET(self, request): "wallets": [{ "created": True, "name": "Bitcoin", + "unlocked": True, + "precision": 8, + "min_unit": 100000, "address": "17AVS7n3zgBjPq1JT4uVmEXdcX3vgB2wAh", "balance": { "available": 0.000126, @@ -54,7 +57,8 @@ def render_GET(self, request): 'unlocked': wallet.unlocked, 'address': wallet.get_address(), 'name': wallet.get_name(), - 'precision': wallet.precision() + 'precision': wallet.precision(), + 'min_unit': wallet.min_unit() } balance_deferreds.append(wallet.get_balance().addCallback( lambda balance, wid=wallet_id: (wid, balance))) diff --git a/TriblerGUI/dialogs/newmarketorderdialog.py b/TriblerGUI/dialogs/newmarketorderdialog.py index 00e95711803..99ceb0d6851 100644 --- a/TriblerGUI/dialogs/newmarketorderdialog.py +++ b/TriblerGUI/dialogs/newmarketorderdialog.py @@ -10,7 +10,7 @@ class NewMarketOrderDialog(DialogContainer): button_clicked = pyqtSignal(int) - def __init__(self, parent, is_ask, asset1_type, asset2_type): + def __init__(self, parent, is_ask, asset1_type, asset2_type, wallets): DialogContainer.__init__(self, parent) self.is_ask = is_ask @@ -18,6 +18,11 @@ def __init__(self, parent, is_ask, asset1_type, asset2_type): self.price_type = asset2_type self.quantity = -1 self.quantity_type = asset1_type + self.wallets = wallets + + # These asset amount values are only set when the order has been verified on the GUI side + self.asset1_amount = 0 + self.asset2_amount = 0 uic.loadUi(get_ui_file_path('newmarketorderdialog.ui'), self.dialog_widget) @@ -40,19 +45,47 @@ def __init__(self, parent, is_ask, asset1_type, asset2_type): def on_create_clicked(self): # Validate user input try: - self.quantity = int(self.dialog_widget.order_quantity_input.text()) + self.quantity = float(self.dialog_widget.order_quantity_input.text()) except ValueError: - self.dialog_widget.error_text_label.setText("The volume must be a valid whole number.") + self.dialog_widget.error_text_label.setText("The quantity must be a valid number.") self.dialog_widget.error_text_label.show() return try: self.price = float(self.dialog_widget.order_price_input.text()) except ValueError: - self.dialog_widget.error_text_label.setText("The price must be a valid whole number.") + self.dialog_widget.error_text_label.setText("The price must be a valid number.") + self.dialog_widget.error_text_label.show() + return + + # Check whether we are trading at least the minimum amount of assets + asset1_amount = int(self.quantity * (10 ** self.wallets[self.quantity_type]["precision"])) + if asset1_amount < self.wallets[self.quantity_type]['min_unit']: + min_amount = float(self.wallets[self.quantity_type]["min_unit"]) / \ + float(10 ** self.wallets[self.quantity_type]["precision"]) + self.dialog_widget.error_text_label.setText("The quantity is less than the minimum amount (%g %s)." % + (min_amount, self.quantity_type)) + self.dialog_widget.error_text_label.show() + return + + price_num = self.price * (10 ** self.wallets[self.price_type]["precision"]) + price_denom = float(10 ** self.wallets[self.quantity_type]["precision"]) + price = price_num / price_denom + asset2_amount = int(asset1_amount * price) + + # Check whether the price will lead to a trade where at least the minimum amount of assets are exchanged + if asset2_amount < self.wallets[self.price_type]['min_unit']: + min_amount = float(self.wallets[self.price_type]["min_unit"]) / \ + float(10 ** self.wallets[self.price_type]["precision"]) + self.dialog_widget.error_text_label.setText("The price leads to a trade where less than the minimum amount " + "of assets are exchanged (%g %s)." % + (min_amount, self.price_type)) self.dialog_widget.error_text_label.show() return + # Everything is valid, proceed with order creation + self.asset1_amount = asset1_amount + self.asset2_amount = asset2_amount self.update_window() self.button_clicked.emit(1) diff --git a/TriblerGUI/qt_resources/newmarketorderdialog.ui b/TriblerGUI/qt_resources/newmarketorderdialog.ui index becc63441e4..476147ebc9d 100644 --- a/TriblerGUI/qt_resources/newmarketorderdialog.ui +++ b/TriblerGUI/qt_resources/newmarketorderdialog.ui @@ -7,7 +7,7 @@ 0 0 538 - 232 + 248 @@ -166,6 +166,9 @@ margin-top: 4px; + + Quantity + @@ -192,7 +195,11 @@ margin-top: 4px; - + + + Price + + diff --git a/TriblerGUI/widgets/marketpage.py b/TriblerGUI/widgets/marketpage.py index cda86d70323..339ebe1aa9b 100644 --- a/TriblerGUI/widgets/marketpage.py +++ b/TriblerGUI/widgets/marketpage.py @@ -1,5 +1,3 @@ -from urllib import urlencode - import datetime from PyQt5.QtCore import Qt from PyQt5.QtCore import pyqtSignal @@ -12,7 +10,6 @@ from TriblerGUI.defs import PAGE_MARKET_TRANSACTIONS, PAGE_MARKET_WALLETS, PAGE_MARKET_ORDERS from TriblerGUI.dialogs.confirmationdialog import ConfirmationDialog -from TriblerGUI.dialogs.iom_input_dialog import IomInputDialog from TriblerGUI.dialogs.newmarketorderdialog import NewMarketOrderDialog from TriblerGUI.tribler_action_menu import TriblerActionMenu from TriblerGUI.tribler_request_manager import TriblerRequestManager @@ -243,20 +240,12 @@ def on_transaction_complete(self, transaction): self.load_asks() self.load_bids() - def create_order(self, is_ask, price, price_type, quantity, quantity_type): + def create_order(self, is_ask, asset1_amount, asset1_type, asset2_amount, asset2_type): """ Create a new ask or bid order. """ - asset1_amount = long(quantity * (10 ** self.wallets[quantity_type]["precision"])) - - price_num = price * (10 ** self.wallets[price_type]["precision"]) - price_denom = float(10 ** self.wallets[quantity_type]["precision"]) - price = price_num / price_denom - - asset2_amount = long(asset1_amount * price) - post_data = str("first_asset_amount=%d&first_asset_type=%s&second_asset_amount=%d&second_asset_type=%s" % - (asset1_amount, quantity_type, asset2_amount, price_type)) + (asset1_amount, asset1_type, asset2_amount, asset2_type)) self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("market/%s" % ('asks' if is_ask else 'bids'), lambda response: self.on_order_created(response, is_ask), @@ -318,15 +307,18 @@ def on_create_bid_clicked(self): def on_asset_type_clicked(self): menu = TriblerActionMenu(self) + asset_pairs = [] for first_wallet_id in self.wallets.keys(): for second_wallet_id in self.wallets.keys(): if first_wallet_id >= second_wallet_id: continue + asset_pairs.append((first_wallet_id, second_wallet_id)) - wallet_action = QAction('%s / %s' % (first_wallet_id, second_wallet_id), self) - wallet_action.triggered.connect( - lambda _, id1=first_wallet_id, id2=second_wallet_id: self.on_asset_type_changed(id1, id2)) - menu.addAction(wallet_action) + for asset_pair in sorted(asset_pairs): + wallet_action = QAction('%s / %s' % asset_pair, self) + wallet_action.triggered.connect( + lambda _, id1=asset_pair[0], id2=asset_pair[1]: self.on_asset_type_changed(id1, id2)) + menu.addAction(wallet_action) menu.exec_(QCursor.pos()) def on_asset_type_changed(self, asset1, asset2): @@ -348,14 +340,15 @@ def show_new_order_dialog(self, is_ask): "%s wallet not available, please create it first." % self.chosen_wallets[1]) return - self.dialog = NewMarketOrderDialog(self.window().stackedWidget, is_ask, self.chosen_wallets[0], self.chosen_wallets[1]) + self.dialog = NewMarketOrderDialog(self.window().stackedWidget, is_ask, self.chosen_wallets[0], + self.chosen_wallets[1], self.wallets) self.dialog.button_clicked.connect(self.on_new_order_action) self.dialog.show() def on_new_order_action(self, action): if action == 1: - self.create_order(self.dialog.is_ask, self.dialog.price, self.dialog.price_type, - self.dialog.quantity, self.dialog.quantity_type) + self.create_order(self.dialog.is_ask, self.dialog.asset1_amount, self.dialog.quantity_type, + self.dialog.asset2_amount, self.dialog.price_type) self.dialog.close_dialog() self.dialog = None From 1e93cd2800ca561ccf5e4d1d87c5d9590a97ece2 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Wed, 17 Oct 2018 10:20:45 +0200 Subject: [PATCH 06/13] Properly handling DHT errors in market community --- Tribler/Test/Community/Market/test_community.py | 8 +++++++- Tribler/community/market/community.py | 13 ++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Tribler/Test/Community/Market/test_community.py b/Tribler/Test/Community/Market/test_community.py index 637e704f9d2..eb0c1af09a6 100644 --- a/Tribler/Test/Community/Market/test_community.py +++ b/Tribler/Test/Community/Market/test_community.py @@ -1,5 +1,8 @@ +from twisted.python.failure import Failure + from Tribler.Core.Modules.wallet.dummy_wallet import DummyWallet1, DummyWallet2 from Tribler.Core.Modules.wallet.tc_wallet import TrustchainWallet +from Tribler.Test.Core.base_test import MockObject from Tribler.community.market.block import MarketBlock from Tribler.community.market.community import MarketCommunity, PingRequestCache from Tribler.community.market.core.assetamount import AssetAmount @@ -271,7 +274,10 @@ def test_address_resolv_fail(self): """ yield self.introduce_nodes() - self.nodes[1].overlay.get_address_for_trader = lambda *_: succeed(None) + # Clean the mid register of node 1 and make sure DHT peer connection fails + self.nodes[1].overlay.mid_register = {} + self.nodes[1].overlay.dht = MockObject() + self.nodes[1].overlay.dht.connect_peer = lambda *_: fail(Failure(RuntimeError())) ask_order = yield self.nodes[0].overlay.create_ask( AssetPair(AssetAmount(1, 'DUM1'), AssetAmount(1, 'DUM2')), 3600) diff --git a/Tribler/community/market/community.py b/Tribler/community/market/community.py index 2dfb00806f9..a71fee4e5d5 100644 --- a/Tribler/community/market/community.py +++ b/Tribler/community/market/community.py @@ -218,7 +218,11 @@ def on_peers(peers): self.update_ip(trader_id, peers[0].address) deferred.callback(peers[0].address) - self.dht.connect_peer(str(trader_id).decode('hex')).addCallback(on_peers) + def on_dht_error(failure): + self._logger.warning("Unable to get address for trader %s", trader_id) + deferred.errback(failure) + + self.dht.connect_peer(str(trader_id).decode('hex')).addCallbacks(on_peers, on_dht_error) return deferred @@ -832,7 +836,8 @@ def on_peer_address(address): self.endpoint.send(address, packet) def get_address(): - self.get_address_for_trader(recipient_order_id.trader_id).addCallback(on_peer_address) + err_handler = lambda _: on_peer_address(None) + self.get_address_for_trader(recipient_order_id.trader_id).addCallbacks(on_peer_address, err_handler) reactor.callFromThread(get_address) @@ -902,7 +907,9 @@ def on_peer_address(address): # Fetch the address of the target peer (we are not guaranteed to know it at this point since we might have # received the order indirectly) def get_address(): - self.get_address_for_trader(propose_trade.recipient_order_id.trader_id).addCallback(on_peer_address) + err_handler = lambda _: on_peer_address(None) + self.get_address_for_trader(propose_trade.recipient_order_id.trader_id)\ + .addCallbacks(on_peer_address, err_handler) reactor.callFromThread(get_address) From 02c1d50444b7ccc66e1fb5e1f6cbe843b28f4217 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Wed, 17 Oct 2018 10:23:49 +0200 Subject: [PATCH 07/13] Properly handling DHT errors in direct payouts --- Tribler/Core/Modules/payout_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tribler/Core/Modules/payout_manager.py b/Tribler/Core/Modules/payout_manager.py index c9a3db8b8d5..09177390c17 100644 --- a/Tribler/Core/Modules/payout_manager.py +++ b/Tribler/Core/Modules/payout_manager.py @@ -35,7 +35,7 @@ def on_nodes(nodes): if total_bytes >= 1024 * 1024: # Do at least 1MB payouts self.logger.info("Doing direct payout to %s (%d bytes)", mid.encode('hex'), total_bytes) - self.dht.connect_peer(mid).addCallback(on_nodes) + self.dht.connect_peer(mid).addCallbacks(on_nodes, lambda _: on_nodes([])) # Remove the outstanding bytes; otherwise we will payout again self.tribler_peers.pop(mid, None) From 204cfdf6696de04f74daf4c6c84ee5db558a62c4 Mon Sep 17 00:00:00 2001 From: Sandip Pandey Date: Tue, 23 Oct 2018 09:15:59 +0200 Subject: [PATCH 08/13] Fixed NoneType error in home recommended items page --- TriblerGUI/widgets/home_recommended_item.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/TriblerGUI/widgets/home_recommended_item.py b/TriblerGUI/widgets/home_recommended_item.py index d30fbffb182..99ae78d9ea9 100644 --- a/TriblerGUI/widgets/home_recommended_item.py +++ b/TriblerGUI/widgets/home_recommended_item.py @@ -76,6 +76,8 @@ def on_download_button_clicked(self): self.window().start_download_from_uri(self.download_uri) def update_with_torrent(self, torrent): + if not torrent: + return self.show_torrent = True self.torrent_info = torrent self.thumbnail_widget.initialize(torrent["name"], HOME_ITEM_FONT_SIZE) @@ -87,6 +89,8 @@ def update_with_torrent(self, torrent): self.detail_label.setText("Size: " + format_size(torrent["size"])) def update_with_channel(self, channel): + if not channel: + return self.show_torrent = False self.channel_info = channel self.thumbnail_widget.initialize(channel["name"], HOME_ITEM_FONT_SIZE) From 6576ff261edf4a9676d9cd7626b45a4eb00c35ee Mon Sep 17 00:00:00 2001 From: Sandip Pandey Date: Tue, 23 Oct 2018 10:48:48 +0200 Subject: [PATCH 09/13] Trap SchemeNotSupported twisted error on creating discovered channel --- .../Modules/restapi/channels/channels_torrents_endpoint.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tribler/Core/Modules/restapi/channels/channels_torrents_endpoint.py b/Tribler/Core/Modules/restapi/channels/channels_torrents_endpoint.py index ba9130ff008..3e4e83a6f37 100644 --- a/Tribler/Core/Modules/restapi/channels/channels_torrents_endpoint.py +++ b/Tribler/Core/Modules/restapi/channels/channels_torrents_endpoint.py @@ -1,4 +1,5 @@ import base64 +from twisted.web.error import SchemeNotSupported from twisted.internet.defer import Deferred from twisted.web import http @@ -201,7 +202,7 @@ def _on_added(added): request.finish() def _on_add_failed(failure): - failure.trap(ValueError, DuplicateTorrentFileError) + failure.trap(ValueError, DuplicateTorrentFileError, SchemeNotSupported) self._logger.exception(failure.value) request.write(BaseChannelsEndpoint.return_500(self, request, failure.value)) request.finish() From 39e5e4246185ba7694b09430a25731b6af058aba Mon Sep 17 00:00:00 2001 From: Sandip Pandey Date: Tue, 23 Oct 2018 11:46:00 +0200 Subject: [PATCH 10/13] Fixed error with credit mining disk space --- TriblerGUI/widgets/settingspage.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/TriblerGUI/widgets/settingspage.py b/TriblerGUI/widgets/settingspage.py index c4c0f84e442..1d9fe2f235f 100644 --- a/TriblerGUI/widgets/settingspage.py +++ b/TriblerGUI/widgets/settingspage.py @@ -413,7 +413,13 @@ def save_settings(self): return settings_data['credit_mining']['enabled'] = self.window().credit_mining_enabled_checkbox.isChecked() - settings_data['credit_mining']['max_disk_space'] = int(self.window().max_disk_space_input.text()) + try: + settings_data['credit_mining']['max_disk_space'] = int(self.window().max_disk_space_input.text()) + except ValueError: + ConfirmationDialog.show_error(self.window(), "Invalid number", + "You've entered an invalid number for max disk space value") + return + settings_data['tunnel_community']['exitnode_enabled'] = self.window().allow_exit_node_checkbox.isChecked() settings_data['download_defaults']['number_hops'] = self.window().number_hops_slider.value() settings_data['download_defaults']['anonymity_enabled'] = \ From 55a9b7e58bea2e06feaf58fc28297022e7d8ef9c Mon Sep 17 00:00:00 2001 From: Sandip Pandey Date: Tue, 23 Oct 2018 12:09:25 +0200 Subject: [PATCH 11/13] Fixed issue with saving proxy server configuration --- Tribler/Core/Config/config.spec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tribler/Core/Config/config.spec b/Tribler/Core/Config/config.spec index d6f45159868..a51ee41e8a4 100644 --- a/Tribler/Core/Config/config.spec +++ b/Tribler/Core/Config/config.spec @@ -65,8 +65,8 @@ directory = string(default='') enabled = boolean(default=True) port = integer(min=-1, max=65536, default=-1) proxy_type = integer(min=0, max=5, default=0) -proxy_server = string(default='') -proxy_auth = string(default='') +proxy_server = string_list(default=list('', '')) +proxy_auth = string_list(default=list('', '')) max_connections_download = integer(default=-1) max_download_rate = integer(default=0) max_upload_rate = integer(default=0) From 16233803e5546a1dd9ebd27385ffca5e1ab13b5e Mon Sep 17 00:00:00 2001 From: Sandip Pandey Date: Wed, 24 Oct 2018 11:42:08 +0200 Subject: [PATCH 12/13] show active seeds and peers in downloads (#3978) Active seeds/peers vs Total seeds/peers --- .../Core/Libtorrent/LibtorrentDownloadImpl.py | 14 ++++++++++ .../Modules/restapi/downloads_endpoint.py | 2 ++ .../test_libtorrent_download_impl.py | 26 +++++++++++++++++++ TriblerGUI/widgets/downloadwidgetitem.py | 4 +-- 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/Tribler/Core/Libtorrent/LibtorrentDownloadImpl.py b/Tribler/Core/Libtorrent/LibtorrentDownloadImpl.py index 35047c1d119..f149d8a1a07 100644 --- a/Tribler/Core/Libtorrent/LibtorrentDownloadImpl.py +++ b/Tribler/Core/Libtorrent/LibtorrentDownloadImpl.py @@ -876,6 +876,20 @@ def get_peerlist(self): peers.append(peer_dict) return peers + def get_num_connected_seeds_peers(self): + """ Returns number of connected seeders and leechers """ + num_seeds = num_peers = 0 + if not self.handle or not self.handle.is_valid(): + return 0, 0 + + for peer_info in self.handle.get_peer_info(): + if peer_info.flags & peer_info.seed: + num_seeds += 1 + else: + num_peers += 1 + + return num_seeds, num_peers + @checkHandleAndSynchronize(default={}) def get_tracker_status(self): # Make sure all trackers are in the tracker_status dict diff --git a/Tribler/Core/Modules/restapi/downloads_endpoint.py b/Tribler/Core/Modules/restapi/downloads_endpoint.py index e441349db65..39d4dac9d77 100644 --- a/Tribler/Core/Modules/restapi/downloads_endpoint.py +++ b/Tribler/Core/Modules/restapi/downloads_endpoint.py @@ -212,6 +212,7 @@ def render_GET(self, request): tracker_info.append({"url": url, "peers": url_info[0], "status": url_info[1]}) num_seeds, num_peers = state.get_num_seeds_peers() + num_connected_seeds, num_connected_peers = download.get_num_connected_seeds_peers() download_json = {"name": tdef.get_name_utf8(), "progress": state.get_progress(), "infohash": tdef.get_infohash().encode('hex'), @@ -220,6 +221,7 @@ def render_GET(self, request): "status": dlstatus_strings[state.get_status()], "size": tdef.get_length(), "eta": state.get_eta(), "num_peers": num_peers, "num_seeds": num_seeds, + "num_connected_peers": num_connected_peers, "num_connected_seeds": num_connected_seeds, "total_up": state.get_total_transferred(UPLOAD), "total_down": state.get_total_transferred(DOWNLOAD), "ratio": state.get_seeding_ratio(), "trackers": tracker_info, "hops": download.get_hops(), diff --git a/Tribler/Test/Core/Libtorrent/test_libtorrent_download_impl.py b/Tribler/Test/Core/Libtorrent/test_libtorrent_download_impl.py index a007cae54b0..890c2dbde08 100644 --- a/Tribler/Test/Core/Libtorrent/test_libtorrent_download_impl.py +++ b/Tribler/Test/Core/Libtorrent/test_libtorrent_download_impl.py @@ -308,6 +308,32 @@ def mocked_set_share_mode(val): self.libtorrent_download_impl.set_share_mode(True) self.assertTrue(mocked_set_share_mode.called) + def test_get_num_connected_seeds_peers(self): + """ + Test whether connected peers and seeds are correctly returned + """ + def get_peer_info(seeders, leechers): + peer_info = [] + for _ in xrange(seeders): + seeder = MockObject() + seeder.flags = 140347 # some value where seed flag(1024) is true + seeder.seed = 1024 + peer_info.append(seeder) + for _ in xrange(leechers): + leecher = MockObject() + leecher.flags = 131242 # some value where seed flag(1024) is false + leecher.seed = 1024 + peer_info.append(leecher) + return peer_info + + mock_seeders = 15 + mock_leechers = 6 + self.libtorrent_download_impl.handle.get_peer_info = lambda: get_peer_info(mock_seeders, mock_leechers) + + num_seeds, num_peers = self.libtorrent_download_impl.get_num_connected_seeds_peers() + self.assertEqual(num_seeds, mock_seeders, "Expected seeders differ") + self.assertEqual(num_peers, mock_leechers, "Expected peers differ") + def test_set_priority(self): """ Test whether setting the priority calls the right methods in LibtorrentDownloadImpl diff --git a/TriblerGUI/widgets/downloadwidgetitem.py b/TriblerGUI/widgets/downloadwidgetitem.py index 93eb58fd2a4..3824e136005 100644 --- a/TriblerGUI/widgets/downloadwidgetitem.py +++ b/TriblerGUI/widgets/downloadwidgetitem.py @@ -65,8 +65,8 @@ def update_item(self): self.setText(3, "Streaming") else: self.setText(3, DLSTATUS_STRINGS[eval(self.download_info["status"])]) - self.setText(4, str(self.download_info["num_seeds"])) - self.setText(5, str(self.download_info["num_peers"])) + self.setText(4, "%s (%s)" % (self.download_info["num_connected_seeds"], self.download_info["num_seeds"])) + self.setText(5, "%s (%s)" % (self.download_info["num_connected_peers"], self.download_info["num_peers"])) self.setText(6, format_speed(self.download_info["speed_down"])) self.setText(7, format_speed(self.download_info["speed_up"])) self.setText(8, "%.3f" % float(self.download_info["ratio"])) From 904e78ce3ddce4137aa078a00c5ccf5acc80a469 Mon Sep 17 00:00:00 2001 From: Sandip Pandey Date: Wed, 24 Oct 2018 13:44:30 +0200 Subject: [PATCH 13/13] Updated IPv8 pointer --- Tribler/pyipv8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tribler/pyipv8 b/Tribler/pyipv8 index 921bf817aa1..a4ca98c5121 160000 --- a/Tribler/pyipv8 +++ b/Tribler/pyipv8 @@ -1 +1 @@ -Subproject commit 921bf817aa178e6082e0e343feb7b9609fe6d719 +Subproject commit a4ca98c51216a8d42f133f7f8dfe5124f88a1861