diff --git a/Tribler/Test/Community/popular/test_community.py b/Tribler/Test/Community/popular/test_community.py index 25ce2d5047b..bcb62c068ef 100644 --- a/Tribler/Test/Community/popular/test_community.py +++ b/Tribler/Test/Community/popular/test_community.py @@ -146,8 +146,8 @@ def test_publish_no_content(self): """ Tests publishing next content if no content is available. """ - original_logger = self.nodes[0].overlay._logger - self.nodes[0].overlay._logger.error = lambda *args, **kw: self.fake_logger_error(self.nodes[0], *args) + original_logger = self.nodes[0].overlay.logger + self.nodes[0].overlay.logger.error = lambda *args, **kw: self.fake_logger_error(self.nodes[0], *args) # Assume a subscribers exist self.nodes[0].overlay.subscribers = [self.create_node()] @@ -163,15 +163,15 @@ def test_publish_no_content(self): self.assertTrue(self.nodes[0].no_content) # Restore logger - self.nodes[0].overlay._logger = original_logger + self.nodes[0].overlay.logger = original_logger @twisted_wrapper def test_send_popular_content_subscribe(self): """ Tests sending popular content subscribe request. """ - original_logger = self.nodes[0].overlay._logger - self.nodes[0].overlay._logger.error = lambda *args, **kw: self.fake_logger_error(self.nodes[0], *args) + original_logger = self.nodes[0].overlay.logger + self.nodes[0].overlay.logger.error = lambda *args, **kw: self.fake_logger_error(self.nodes[0], *args) self.nodes[0].overlay.broadcast_message = lambda packet, peer: \ self.fake_broadcast_message(self.nodes[0], packet, peer) @@ -210,15 +210,15 @@ def test_send_popular_content_subscribe(self): self.assertTrue(default_peers[0] not in self.nodes[0].overlay.publishers) # Restore logger - self.nodes[0].overlay._logger = original_logger + self.nodes[0].overlay.logger = original_logger @twisted_wrapper def test_send_popular_content_subscription(self): """ Tests sending popular content subscription response. """ - original_logger = self.nodes[0].overlay._logger - self.nodes[0].overlay._logger.error = lambda *args, **kw: self.fake_logger_error(self.nodes[0], *args) + original_logger = self.nodes[0].overlay.logger + self.nodes[0].overlay.logger.error = lambda *args, **kw: self.fake_logger_error(self.nodes[0], *args) self.nodes[0].overlay.create_message_packet = lambda _type, _payload: \ self.fake_create_message_packet(self.nodes[0], _type, _payload) @@ -253,15 +253,15 @@ def test_send_popular_content_subscription(self): self.assertEqual(self.nodes[0].receiver, default_peers[0], "Intended receiver is different") # Restore logger - self.nodes[0].overlay._logger = original_logger + self.nodes[0].overlay.logger = original_logger @twisted_wrapper def test_send_torrent_health_response(self): """ Tests sending torrent health response. """ - original_logger = self.nodes[0].overlay._logger - self.nodes[0].overlay._logger.error = lambda *args, **kw: self.fake_logger_error(self.nodes[0], *args) + original_logger = self.nodes[0].overlay.logger + self.nodes[0].overlay.logger.error = lambda *args, **kw: self.fake_logger_error(self.nodes[0], *args) self.nodes[0].overlay.create_message_packet = lambda _type, _payload: \ self.fake_create_message_packet(self.nodes[0], _type, _payload) @@ -297,15 +297,15 @@ def test_send_torrent_health_response(self): self.assertEqual(self.nodes[0].receiver, default_peers[0], "Intended receiver is different") # Restore logger - self.nodes[0].overlay._logger = original_logger + self.nodes[0].overlay.logger = original_logger @twisted_wrapper def test_send_channel_health_response(self): """ Tests sending torrent health response. """ - original_logger = self.nodes[0].overlay._logger - self.nodes[0].overlay._logger.error = lambda *args, **kw: self.fake_logger_error(self.nodes[0], *args) + original_logger = self.nodes[0].overlay.logger + self.nodes[0].overlay.logger.error = lambda *args, **kw: self.fake_logger_error(self.nodes[0], *args) self.nodes[0].overlay.create_message_packet = lambda _type, _payload: \ self.fake_create_message_packet(self.nodes[0], _type, _payload) @@ -341,15 +341,15 @@ def test_send_channel_health_response(self): self.assertEqual(self.nodes[0].receiver, default_peers[0], "Intended receiver is different") # Restore logger - self.nodes[0].overlay._logger = original_logger + self.nodes[0].overlay.logger = original_logger @twisted_wrapper def test_on_torrent_health_response_from_unknown_peer(self): """ Tests receiving torrent health response from unknown peer """ - original_logger = self.nodes[0].overlay._logger - self.nodes[0].overlay._logger.error = lambda *args, **kw: self.fake_logger_error(self.nodes[0], *args) + original_logger = self.nodes[0].overlay.logger + self.nodes[0].overlay.logger.error = lambda *args, **kw: self.fake_logger_error(self.nodes[0], *args) def fake_unpack_auth(): mock_auth = MockObject() @@ -372,15 +372,15 @@ def fake_get_peer_from_auth(peer): self.assertTrue(self.nodes[0].unknown_response) # Restore logger - self.nodes[0].overlay._logger = original_logger + self.nodes[0].overlay.logger = original_logger @twisted_wrapper def test_on_popular_content_subscribe_unknown_peer(self): """ Tests receiving torrent health response from unknown peer """ - original_logger = self.nodes[0].overlay._logger - self.nodes[0].overlay._logger.error = lambda *args, **kw: self.fake_logger_error(self.nodes[0], *args) + original_logger = self.nodes[0].overlay.logger + self.nodes[0].overlay.logger.error = lambda *args, **kw: self.fake_logger_error(self.nodes[0], *args) def fake_unpack_auth(): mock_auth = MockObject() @@ -408,15 +408,15 @@ def fake_publish_latest_torrents(my_peer, _peer): self.assertTrue(self.nodes[0].unknown_peer_found) # Restore logger - self.nodes[0].overlay._logger = original_logger + self.nodes[0].overlay.logger = original_logger @twisted_wrapper(500) def test_on_popular_content_subscribe_ok(self): """ Tests receiving torrent health response from unknown peer """ - original_logger = self.nodes[0].overlay._logger - self.nodes[0].overlay._logger.error = lambda *args, **kw: self.fake_logger_error(self.nodes[0], *args) + original_logger = self.nodes[0].overlay.logger + self.nodes[0].overlay.logger.error = lambda *args, **kw: self.fake_logger_error(self.nodes[0], *args) def fake_unpack_auth(): mock_auth = MockObject() @@ -449,7 +449,7 @@ def fake_send_popular_content_subscription(my_peer): self.assertTrue(self.nodes[0].publish_latest_torrents_called) # Restore logger - self.nodes[0].overlay._logger = original_logger + self.nodes[0].overlay.logger = original_logger def fake_logger_error(self, my_peer, *args): if ERROR_UNKNOWN_PEER in args[0]: diff --git a/Tribler/Test/Community/popular/test_payload.py b/Tribler/Test/Community/popular/test_payload.py new file mode 100644 index 00000000000..4fe9432a446 --- /dev/null +++ b/Tribler/Test/Community/popular/test_payload.py @@ -0,0 +1,70 @@ +import random +import string +from unittest import TestCase + +from Tribler.community.popular.payload import SearchResponsePayload, SearchResponseItemPayload +from Tribler.pyipv8.ipv8.messaging.serialization import Serializer + + +class TestSerializer(TestCase): + + def setUp(self): + self.serializer = Serializer() + + def test_search_result_payload_serialization(self): + """ + Test serialization & deserialization of search payload + :return: + """ + + def random_string(size=6, chars=string.ascii_uppercase + string.digits): + return ''.join(random.choice(chars) for _ in range(size)) + + def random_infohash(): + return ''.join(random.choice('0123456789abcdef') for _ in range(20)) + + # sample search response items + sample_items = [] + for index in range(10): + infohash = random_infohash() + name = random_string() + length = random.randint(1000, 9999) + num_files = random.randint(1, 10) + category_list = ['video', 'audio'] + creation_date = random.randint(1000000, 111111111) + seeders = random.randint(10, 200) + leechers = random.randint(5, 1000) + cid = random_string(size=20) + + sample_items.append(SearchResponseItemPayload(infohash, name, length, num_files, category_list, + creation_date, seeders, leechers, cid)) + + # Search identifier + identifier = 111 + + # Serialize the results + results = '' + for item in sample_items: + results += self.serializer.pack_multiple(item.to_pack_list()) + serialized_results = self.serializer.pack_multiple(SearchResponsePayload(identifier, results).to_pack_list()) + + # De-serialize the response payload and check the identifier and get the results + response_format = SearchResponsePayload.format_list + (search_results, _) = self.serializer.unpack_multiple(response_format, serialized_results) + + # De-serialize each individual search result items + item_format = SearchResponseItemPayload.format_list + (all_items, _) = self.serializer.unpack_multiple_as_list(item_format, search_results[1]) + for index in xrange(len(all_items)): + response_item = SearchResponseItemPayload.from_unpack_list(*all_items[index]) + sample_item = sample_items[index] + + self.assertEqual(sample_item.infohash, response_item.infohash) + self.assertEqual(sample_item.name, response_item.name) + self.assertEqual(sample_item.length, response_item.length) + self.assertEqual(sample_item.num_files, response_item.num_files) + self.assertEqual(sample_item.creation_date, response_item.creation_date) + self.assertEqual(sample_item.category_list, response_item.category_list) + self.assertEqual(sample_item.seeders, response_item.seeders) + self.assertEqual(sample_item.leechers, response_item.leechers) + self.assertEqual(sample_item.cid, response_item.cid) diff --git a/Tribler/Test/Community/popular/test_repository.py b/Tribler/Test/Community/popular/test_repository.py index 15c85934c94..1e7b10b63b1 100644 --- a/Tribler/Test/Community/popular/test_repository.py +++ b/Tribler/Test/Community/popular/test_repository.py @@ -57,8 +57,11 @@ def fake_logger_error(repo, *args): repo.unknown_torrent = True repo.logger_error_called = True - original_logger = self.content_repository._logger - self.content_repository._logger.error = lambda *args, **kw: fake_logger_error(self.content_repository, *args) + def update_torrent(repo, _): + repo.update_torrent_called = True + + original_logger = self.content_repository.logger + self.content_repository.logger.error = lambda *args, **kw: fake_logger_error(self.content_repository, *args) # Assume a fake torrent response fake_torrent_health_payload = TorrentHealthPayload('a' * 20, 10, 4, time.time()) @@ -67,21 +70,22 @@ def fake_logger_error(repo, *args): self.content_repository.torrent_db = None self.content_repository.logger_error_called = False - self.content_repository.update_torrent(fake_torrent_health_payload, peer_trust=0) + self.content_repository.update_torrent_health(fake_torrent_health_payload, peer_trust=0) self.assertTrue(self.content_repository.torrent_db_none) self.assertTrue(self.content_repository.logger_error_called) # Case2: torrent db does not have torrent self.content_repository.torrent_db = MockObject() - self.content_repository.torrent_db.hasTorrent = lambda _: False + self.content_repository.torrent_db.updateTorrent = lambda infohash, *args, **kw: \ + update_torrent(self.content_repository, infohash) self.content_repository.logger_error_called = False + self.content_repository.has_torrent = lambda infohash: False - self.content_repository.update_torrent(fake_torrent_health_payload, peer_trust=0) - self.assertTrue(self.content_repository.logger_error_called) - self.assertTrue(self.content_repository.unknown_torrent) + self.content_repository.update_torrent_health(fake_torrent_health_payload, peer_trust=0) + self.assertTrue(self.content_repository.update_torrent_called) # restore logger - self.content_repository._logger = original_logger + self.content_repository.logger = original_logger def test_update_torrent_with_higher_trust(self): """ @@ -132,6 +136,6 @@ def get_torrent(infohash): lambda infohash, *args, **kw: update_torrent(self.content_repository, infohash) self.content_repository.update_torrent_called = False - self.content_repository.update_torrent(sample_payload, peer_trust=peer_trust) + self.content_repository.update_torrent_health(sample_payload, peer_trust=peer_trust) return self.content_repository.update_torrent_called diff --git a/Tribler/community/popular/community.py b/Tribler/community/popular/community.py index 658bf9777b1..50ac1c497e3 100644 --- a/Tribler/community/popular/community.py +++ b/Tribler/community/popular/community.py @@ -1,6 +1,9 @@ +import logging +import time from copy import copy -from twisted.internet.defer import inlineCallbacks +from twisted.internet.defer import inlineCallbacks, Deferred from twisted.internet.task import LoopingCall +from twisted.python.failure import Failure from Tribler.community.popular.payload import TorrentHealthPayload, ContentSubscription, TorrentInfoRequestPayload, \ TorrentInfoResponsePayload @@ -8,6 +11,7 @@ from Tribler.pyipv8.ipv8.deprecated.community import Community from Tribler.pyipv8.ipv8.deprecated.payload_headers import BinMemberAuthenticationPayload, GlobalTimeDistributionPayload from Tribler.pyipv8.ipv8.peer import Peer +from Tribler.pyipv8.ipv8.requestcache import RandomNumberCache, RequestCache MSG_POPULAR_CONTENT_SUBSCRIBE = 1 MSG_POPULAR_CONTENT_SUBSCRIPTION = 2 @@ -25,7 +29,37 @@ ERROR_NO_CONTENT = "Nothing to publish" +class Request(RandomNumberCache): + """ + This request cache keeps track of all outstanding requests within the PopularCommunity. + """ + def __init__(self, community, peer, params=None): + super(Request, self).__init__(community.request_cache, u'request') + self.peer = peer + self.params = params + self.deferred = Deferred() + self.start_time = time.time() + + @property + def timeout_delay(self): + return 5.0 + + def on_timeout(self): + if not self.deferred.called: + self._logger.error('Request to %s timed out', self.peer.address) + self.peer.failed += 1 + self.deferred.errback(Failure(RuntimeError("Peer timeout"))) + + def on_complete(self): + self.peer.last_response = time.time() + self.peer.failed = 0 + self.peer.rtt = time.time() - self.start_time + + class PopularCommunity(Community): + """ + Community for disseminating the content across the network. Follows publish-subscribe model. + """ master_peer = Peer("3081a7301006072a8648ce3d020106052b810400270381920004073beff7002b6a9fc2824a3b1bbb1c4fc32546261" "e3ef7537874560346c5fdc0c17fe654f67d23b08cbb44141879f79a7a4c8deddf9beb4fbc7a0f02ee1586ccebedb6" @@ -36,9 +70,11 @@ def __init__(self, *args, **kwargs): self.torrent_db = kwargs.pop('torrent_db', None) self.trustchain = kwargs.pop('trustchain_community', None) super(PopularCommunity, self).__init__(*args, **kwargs) + self.logger = logging.getLogger(self.__class__.__name__) # Handles database stuffs self.content_repository = ContentRepository(self.torrent_db) + self.request_cache = RequestCache() # Register messages self.decode_map.update({ @@ -55,6 +91,8 @@ def __init__(self, *args, **kwargs): self.subscribers = set() self.publishers = set() + self.logger.info('Popular Community initialized (peer mid %s)', self.my_peer.mid.encode('HEX')) + def start(self): """ Starts the community by subscribing to peers, and periodically publishing the content updates to @@ -74,6 +112,7 @@ def start_publishing(): @inlineCallbacks def unload(self): + self.request_cache.clear() self.content_repository.cleanup() self.content_repository = None @@ -114,12 +153,12 @@ def refresh_peer_list(self): peers to replenish the available publisher slots if necessary. """ peers = self.get_peers() - self._logger.info("Num peers: %d", len(peers)) + self.logger.info("Num peers: %d", len(peers)) self.publishers = set([peer for peer in self.publishers if peer in peers]) self.subscribers = set([peer for peer in self.subscribers if peer in peers]) # Log the number of subscribers and publishers - self._logger.info("Publishers: %d, Subscribers: %d", len(self.publishers), len(self.subscribers)) + self.logger.info("Publishers: %d, Subscribers: %d", len(self.publishers), len(self.subscribers)) # subscribe peers if necessary self.subscribe_peers() @@ -177,12 +216,12 @@ def on_torrent_health_response(self, source_address, data): dropped. In other case, a decision to accept or reject the message is made based on freshness of the message and the trustscore (check update_torrent in ContentRepository for the implementation). """ - self._logger.info("Got torrent health response from %s", source_address) + self.logger.info("Got torrent health response from %s", source_address) auth, _, payload = self._ez_unpack_auth(TorrentHealthPayload, data) peer = self.get_peer_from_auth(auth, source_address) if peer not in self.publishers: - self._logger.error(ERROR_UNKNOWN_RESPONSE) + self.logger.error(ERROR_UNKNOWN_RESPONSE) return infohash = payload.infohash @@ -201,26 +240,26 @@ def on_torrent_info_request(self, source_address, data): """ Message handler for torrent info request. """ - self._logger.info("Got torrent info request from %s", source_address) + self.logger.info("Got torrent info request from %s", source_address) auth, _, payload = self._ez_unpack_auth(TorrentInfoRequestPayload, data) peer = self.get_peer_from_auth(auth, source_address) if peer not in self.publishers: - self._logger.error(ERROR_UNKNOWN_RESPONSE) + self.logger.error(ERROR_UNKNOWN_RESPONSE) return - self.send_torrent_info_response(payload.infohash, peer=peer) + self.send_torrent_info_response(str(payload.infohash), peer=peer) def on_torrent_info_response(self, source_address, data): """ Message handler for torrent info response. """ - self._logger.info("Got torrent info response from %s", source_address) + self.logger.info("Got torrent info response from %s", source_address) auth, _, payload = self._ez_unpack_auth(TorrentHealthPayload, data) peer = self.get_peer_from_auth(auth, source_address) if peer not in self.publishers: - self._logger.error(ERROR_UNKNOWN_RESPONSE) + self.logger.error(ERROR_UNKNOWN_RESPONSE) return self.content_repository.update_torrent_info(payload) @@ -233,7 +272,7 @@ def send_popular_content_subscribe(self, peer, subscribe=True): want to subscribe/unsubscribe. """ if peer not in self.get_peers(): - self._logger.error(ERROR_UNKNOWN_PEER) + self.logger.error(ERROR_UNKNOWN_PEER) return # Add or remove the publisher peer @@ -253,7 +292,7 @@ def send_popular_content_subscription(self, peer, subscribed=True): subscribe or unsubscribe message. """ if peer not in self.get_peers(): - self._logger.error(ERROR_UNKNOWN_PEER) + self.logger.error(ERROR_UNKNOWN_PEER) return subscription = ContentSubscription(subscribed) @@ -266,7 +305,7 @@ def send_torrent_health_response(self, payload, peer=None): peer is specified then only that peer receives this message. """ if peer and peer not in self.get_peers(): - self._logger.error(ERROR_UNKNOWN_PEER) + self.logger.error(ERROR_UNKNOWN_PEER) return packet = self.create_message_packet(MSG_TORRENT_HEALTH_RESPONSE, payload) @@ -278,7 +317,7 @@ def send_channel_health_response(self, payload, peer=None): peer is specified then only that peer receives this message. """ if peer and peer not in self.get_peers(): - self._logger.error(ERROR_UNKNOWN_PEER) + self.logger.error(ERROR_UNKNOWN_PEER) return packet = self.create_message_packet(MSG_CHANNEL_HEALTH_RESPONSE, payload) @@ -289,7 +328,7 @@ def send_torrent_info_request(self, infohash, peer): Method to request information about a torrent with given infohash to a peer. """ if peer not in self.get_peers(): - self._logger.error(ERROR_UNKNOWN_PEER) + self.logger.error(ERROR_UNKNOWN_PEER) return info_request = TorrentInfoRequestPayload(infohash) @@ -301,7 +340,7 @@ def send_torrent_info_response(self, infohash, peer): Method to send information about a torrent with given infohash to the requesting peer. """ if peer not in self.get_peers(): - self._logger.error(ERROR_UNKNOWN_PEER) + self.logger.error(ERROR_UNKNOWN_PEER) return db_torrent = self.content_repository.get_torrent(infohash) @@ -364,17 +403,17 @@ def publish_next_content(self): Does nothing if there are none subscribers. Only Torrent health response is published at the moment. """ - self._logger.info("Content to publish: %d", self.content_repository.num_content()) + self.logger.info("Content to publish: %d", self.content_repository.num_content()) if not self.subscribers: - self._logger.info("No subscribers found. Not publishing anything") + self.logger.info("No subscribers found. Not publishing anything") return content_type, content = self.content_repository.pop_content() if content_type is None: - self._logger.error(ERROR_NO_CONTENT) + self.logger.error(ERROR_NO_CONTENT) return - self._logger.info("Publishing content[type:%d]", content_type) + self.logger.info("Publishing content[type:%d]", content_type) if content_type == TYPE_TORRENT_HEALTH: infohash, seeders, leechers, timestamp = content payload = TorrentHealthPayload(infohash, seeders, leechers, timestamp) @@ -385,7 +424,7 @@ def publish_latest_torrents(self, peer): Publishes the latest torrents in local database to the given peer. """ torrents = self.content_repository.get_top_torrents() - self._logger.info("Publishing %d torrents to peer %s", len(torrents), peer) + self.logger.info("Publishing %d torrents to peer %s", len(torrents), peer) for torrent in torrents: infohash, seeders, leechers, timestamp = torrent[:4] payload = TorrentHealthPayload(infohash, seeders, leechers, timestamp) diff --git a/Tribler/community/popular/payload.py b/Tribler/community/popular/payload.py index 34621f2ed36..41a9a7384ba 100644 --- a/Tribler/community/popular/payload.py +++ b/Tribler/community/popular/payload.py @@ -1,6 +1,23 @@ +from struct import pack, unpack_from, calcsize + from Tribler.pyipv8.ipv8.deprecated.payload import Payload +def encode_values(values): + return ''.join([pack('!H', len(value)) + value for value in values]) + + +def decode_values(values_str): + values = [] + index = 0 + while index < len(values_str): + length = unpack_from('!H', values_str)[0] + index += calcsize('!H') + values.append(values_str[index:index + length]) + index += length + return values + + class ContentSubscription(Payload): format_list = ['I'] @@ -32,7 +49,7 @@ def __init__(self, infohash, num_seeders, num_leechers, timestamp): self._timestamp = timestamp def to_pack_list(self): - data = [('20s', str(self.infohash)), + data = [('20s', self.infohash), ('I', self.num_seeders), ('I', self.num_leechers), ('f', self.timestamp)] @@ -77,7 +94,7 @@ def __init__(self, channel_id, num_votes, num_torrents, swarm_size_sum, timestam self.timestamp = timestamp def to_pack_list(self): - data = [('varlenI', str(self.channel_id)), + data = [('varlenI', self.channel_id), ('I', self.num_votes), ('I', self.num_torrents), ('I', self.swarm_size_sum), @@ -102,7 +119,7 @@ def __init__(self, infohash): self._infohash = infohash def to_pack_list(self): - data = [('20s', str(self.infohash))] + data = [('20s', self.infohash)] return data @classmethod @@ -131,12 +148,12 @@ def __init__(self, infohash, name, length, creation_date, num_files, comment): self._comment = comment def to_pack_list(self): - data = [('20s', str(self.infohash)), + data = [('20s', self.infohash), ('varlenH', str(self._name)), ('I', self._length), ('I', self._creation_date), ('I', self._num_files), - ('varlenH', self._comment)] + ('varlenH', str(self._comment))] return data @classmethod @@ -147,3 +164,93 @@ def from_unpack_list(cls, *args): @property def infohash(self): return self._infohash + + +class SearchRequestPayload(Payload): + """ + Payload for search request + """ + format_list = ['I', 'varlenH'] + + def __init__(self, timestamp, query): + super(SearchRequestPayload, self).__init__() + self._timestamp = timestamp + self._query = query + + def to_pack_list(self): + data = [('I', self._timestamp), + ('varlenH', str(self._query))] + return data + + @classmethod + def from_unpack_list(cls, *args): + (timestamp, query) = args + return SearchRequestPayload(timestamp, query) + + @property + def timestamp(self): + return self._timestamp + + @property + def query(self): + return self._query + + +class SearchResponseItemPayload(Payload): + """ + Payload for search response items + """ + + format_list = ['20s', 'varlenH', 'I', 'I', 'varlenH', 'I', 'I', 'I', '20s'] + is_list_descriptor = True + + def __init__(self, infohash, name, length, num_files, category_list, creation_date, seeders, leechers, cid): + self.infohash = infohash + self.name = name + self.length = length + self.num_files = num_files + self.category_list = category_list + self.creation_date = creation_date + self.seeders = seeders + self.leechers = leechers + self.cid = cid + + def to_pack_list(self): + data = [('20s', str(self.infohash)), + ('varlenH', self.name), + ('I', self.length), + ('I', self.num_files), + ('varlenH', encode_values(self.category_list)), + ('I', self.creation_date), + ('I', self.seeders), + ('I', self.leechers), + ('20s', self.cid)] + return data + + @classmethod + def from_unpack_list(cls, *args): + (infohash, name, length, num_files, category_list_str, creation_date, seeders, leechers, cid) = args + category_list = decode_values(category_list_str) + return SearchResponseItemPayload(infohash, name, length, num_files, category_list, creation_date, seeders, + leechers, cid) + + +class SearchResponsePayload(Payload): + """ + Payload for search response + """ + format_list = ['varlenI', 'varlenH'] + + def __init__(self, identifier, results): + self.identifier = identifier + self.results = results + + def to_pack_list(self): + data = [('varlenI', str(self.identifier)), + ('varlenH', self.results)] + return data + + @classmethod + def from_unpack_list(cls, *args): + (identifier, results) = args + return SearchResponsePayload(identifier, results) diff --git a/Tribler/community/popular/repository.py b/Tribler/community/popular/repository.py index 64fc3354208..a510d49bfa7 100644 --- a/Tribler/community/popular/repository.py +++ b/Tribler/community/popular/repository.py @@ -1,8 +1,5 @@ import logging import time -from binascii import unhexlify - -from Tribler.Core.CacheDB.sqlitecachedb import str2bin, bin2str from collections import deque from Tribler.community.popular.payload import TorrentHealthPayload @@ -20,7 +17,7 @@ class ContentRepository(object): def __init__(self, torrent_db): super(ContentRepository, self).__init__() - self._logger = logging.getLogger(self.__class__.__name__) + self.logger = logging.getLogger(self.__class__.__name__) self.torrent_db = torrent_db self.queue = deque(maxlen=MAX_CACHE) @@ -51,7 +48,7 @@ def update_torrent(db_handler, health_payload): status=u"good" if health_payload.num_seeders > 1 else u"unknown") if not self.torrent_db: - self._logger.error("Torrent DB is None") + self.logger.error("Torrent DB is None") return infohash = torrent_health_payload.infohash @@ -59,7 +56,7 @@ def update_torrent(db_handler, health_payload): db_torrent = self.get_torrent(infohash) is_fresh = time.time() - db_torrent['last_tracker_check'] < DEFAULT_FRESHNESS_LIMIT if is_fresh and peer_trust < 2: - self._logger.info("Database record is already fresh and the sending peer trust " + self.logger.info("Database record is already fresh and the sending peer trust " "score is too low so we just ignore the response.") return @@ -71,15 +68,15 @@ def update_torrent_info(self, torrent_info_response): if self.has_torrent(infohash): db_torrent = self.get_torrent(infohash) if db_torrent['name'] and db_torrent['name'] == torrent_info_response.name: - self._logger.info("Conflicting names for torrent. Ignoring the response") + self.logger.info("Conflicting names for torrent. Ignoring the response") return # Update local database self.torrent_db.updateTorrent(infohash, notify=False, name=torrent_info_response.name, - length=torrent_info_response.length, - creation_date=torrent_info_response.creation_date, - num_files=torrent_info_response.num_files, - comment=torrent_info_response.comment) + length=torrent_info_response.length, + creation_date=torrent_info_response.creation_date, + num_files=torrent_info_response.num_files, + comment=torrent_info_response.comment) def get_torrent(self, infohash): keys = ('name', 'length', 'creation_date', 'num_files', 'num_seeders', 'num_leechers', 'comment',