-
Notifications
You must be signed in to change notification settings - Fork 450
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1230 from corpaul/bartercast_refactor
Bartercast statistics community
- Loading branch information
Showing
13 changed files
with
746 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
# Written by Cor-Paul Bezemer | ||
from conversion import StatisticsConversion | ||
from payload import StatisticsRequestPayload, StatisticsResponsePayload | ||
|
||
from Tribler.dispersy.authentication import MemberAuthentication | ||
from Tribler.dispersy.community import Community | ||
from Tribler.dispersy.conversion import DefaultConversion | ||
from Tribler.dispersy.destination import CandidateDestination | ||
from Tribler.dispersy.distribution import DirectDistribution | ||
from Tribler.dispersy.message import Message, DelayMessageByProof | ||
from Tribler.dispersy.resolution import PublicResolution | ||
from .statistics import BartercastStatisticTypes, _barter_statistics | ||
from twisted.internet.task import LoopingCall | ||
from twisted.python import log | ||
|
||
BARTERCAST_PERSIST_INTERVAL = 120.0 | ||
|
||
|
||
class BarterCommunity(Community): | ||
@classmethod | ||
def get_master_members(cls, dispersy): | ||
# generated: Thu Oct 30 12:59:19 2014 | ||
# curve: NID_sect571r1 | ||
# len: 571 bits ~ 144 bytes signature | ||
# pub: 170 3081a7301006072a8648ce3d020106052b81040027038192000405ef988346197abe009065e6f9f517263063495554e4d278074feb1be3e81586b44f90b8a11f170f0a059d8f26c259118e6afc775f3d1e7c46462c9de0ec2bb94e480390622056b002c1f121acc52c18a0857ce59e79cf73642a4787fcdc5398d332000fbd44b16f14b005c0910d81cb85392fd036f32a242044c8263e0c6b9dc10b68f9c30540cfbd8a6bb5ccec786e | ||
# pub-sha1 59accbc05521d8b894e8e6ef8d686411384cdec9 | ||
#-----BEGIN PUBLIC KEY----- | ||
# MIGnMBAGByqGSM49AgEGBSuBBAAnA4GSAAQF75iDRhl6vgCQZeb59RcmMGNJVVTk | ||
# 0ngHT+sb4+gVhrRPkLihHxcPCgWdjybCWRGOavx3Xz0efEZGLJ3g7Cu5TkgDkGIg | ||
# VrACwfEhrMUsGKCFfOWeec9zZCpHh/zcU5jTMgAPvUSxbxSwBcCRDYHLhTkv0Dbz | ||
# KiQgRMgmPgxrncELaPnDBUDPvYprtczseG4= | ||
#-----END PUBLIC KEY----- | ||
master_key = "3081a7301006072a8648ce3d020106052b81040027038192000405ef988346197abe009065e6f9f517263063495554e4d278074feb1be3e81586b44f90b8a11f170f0a059d8f26c259118e6afc775f3d1e7c46462c9de0ec2bb94e480390622056b002c1f121acc52c18a0857ce59e79cf73642a4787fcdc5398d332000fbd44b16f14b005c0910d81cb85392fd036f32a242044c8263e0c6b9dc10b68f9c30540cfbd8a6bb5ccec786e".decode("HEX") | ||
master = dispersy.get_member(public_key=master_key) | ||
return [master] | ||
|
||
def __init__(self, dispersy, master, my_member): | ||
super(BarterCommunity, self).__init__(dispersy, master, my_member) | ||
self._dispersy = dispersy | ||
log.msg("joined BC community") | ||
self.init_database() | ||
|
||
# add task for persisting bartercast statistics every BARTERCAST_PERSIST_INTERVAL seconds | ||
self._logger.debug("bartercast persist task started") | ||
self.register_task("bartercast persist", | ||
LoopingCall(self.backup_bartercast_statistics)).start(BARTERCAST_PERSIST_INTERVAL, now=False) | ||
|
||
def init_database(self): | ||
log.msg("loading BC statistics from database") | ||
_barter_statistics.load_statistics(self._dispersy) | ||
|
||
def initiate_meta_messages(self): | ||
return super(BarterCommunity, self).initiate_meta_messages() + [ | ||
Message(self, u"stats-request", | ||
MemberAuthentication(), | ||
PublicResolution(), | ||
DirectDistribution(), | ||
CandidateDestination(), | ||
StatisticsRequestPayload(), | ||
self.check_stats_request, | ||
self.on_stats_request), | ||
Message(self, u"stats-response", | ||
MemberAuthentication(), | ||
PublicResolution(), | ||
DirectDistribution(), | ||
CandidateDestination(), | ||
StatisticsResponsePayload(), | ||
self.check_stats_response, | ||
self.on_stats_response) | ||
] | ||
|
||
def initialize(self, integrate_with_tribler=False, auto_join_channel=False): | ||
super(BarterCommunity, self).initialize() | ||
|
||
def initiate_conversions(self): | ||
return [DefaultConversion(self), StatisticsConversion(self)] | ||
|
||
@property | ||
def dispersy_sync_response_limit(self): | ||
return 1 | ||
|
||
@property | ||
def dispersy_sync_skip_enable(self): | ||
return False | ||
|
||
@property | ||
def dispersy_sync_cache_enable(self): | ||
return False | ||
|
||
def create_stats_request(self, candidate, stats_type): | ||
log.msg("Creating stats-request for type %d to member: %s" % (stats_type, candidate._association.mid.encode("hex"))) | ||
meta = self.get_meta_message(u"stats-request") | ||
message = meta.impl(authentication=(self._my_member,), | ||
distribution=(self.claim_global_time(),), | ||
destination=(candidate,), | ||
payload=(stats_type,)) | ||
self._dispersy._forward([message]) | ||
|
||
def check_stats_request(self, messages): | ||
for message in messages: | ||
allowed, _ = self._timeline.check(message) | ||
if allowed: | ||
yield message | ||
else: | ||
yield DelayMessageByProof(message) | ||
|
||
def on_stats_request(self, messages): | ||
log.msg("IN: stats-request") | ||
for message in messages: | ||
log.msg("stats-request: %s %s" % (message._distribution.global_time, message.payload.stats_type)) | ||
# send back stats-response | ||
self.create_stats_response(message.payload.stats_type, message.candidate) | ||
|
||
def create_stats_response(self, stats_type, candidate): | ||
log.msg("OUT: stats-response") | ||
meta = self.get_meta_message(u"stats-response") | ||
records = _barter_statistics.get_top_n_bartercast_statistics(stats_type, 5) | ||
log.msg("sending stats for type %d: %s" % (stats_type, records)) | ||
|
||
message = meta.impl(authentication=(self._my_member,), | ||
distribution=(self.claim_global_time(),), | ||
destination=(candidate,), | ||
payload=(stats_type, records)) | ||
self._dispersy._forward([message]) | ||
|
||
def check_stats_response(self, messages): | ||
for message in messages: | ||
allowed, _ = self._timeline.check(message) | ||
if allowed: | ||
yield message | ||
else: | ||
yield DelayMessageByProof(message) | ||
|
||
def on_stats_response(self, messages): | ||
log.msg("IN: stats-response") | ||
for message in messages: | ||
log.msg("stats-response: %s %s %s" | ||
% (message._distribution.global_time, message.payload.stats_type, message.payload.records)) | ||
for r in message.payload.records: | ||
_barter_statistics.log_interaction(self._dispersy, | ||
message.payload.stats_type, | ||
message.authentication.member.mid.encode('hex'), | ||
r[0], int(r[1].encode('hex'), 16)) | ||
|
||
# bartercast accounting stuff | ||
def backup_bartercast_statistics(self): | ||
self._logger.debug("merging bartercast statistics") | ||
_barter_statistics.persist(self, 1) | ||
|
||
|
||
class BarterCommunityCrawler(BarterCommunity): | ||
|
||
def __init__(self, *args, **kargs): | ||
super(BarterCommunityCrawler, self).__init__(*args, **kargs) | ||
|
||
def on_introduction_response(self, messages): | ||
super(BarterCommunity, self).on_introduction_response(messages) | ||
for message in messages: | ||
log.msg("in on_introduction_response: Requesting stats from %s" % message.candidate) | ||
for t in BartercastStatisticTypes.reverse_mapping: | ||
self.create_stats_request(message.candidate, t) | ||
|
||
def start_walking(self): | ||
self.register_task("take step", LoopingCall(self.take_step)).start(1.0, now=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
from struct import pack, unpack_from | ||
from Tribler.dispersy.conversion import BinaryConversion | ||
|
||
|
||
class StatisticsConversion(BinaryConversion): | ||
|
||
MTU_SIZE = 1500 | ||
|
||
def __init__(self, community): | ||
super(StatisticsConversion, self).__init__(community, "\x02") | ||
self.define_meta_message(chr(1), community.get_meta_message(u"stats-request"), | ||
self._encode_statistics_request, self._decode_statistics_request) | ||
self.define_meta_message(chr(2), community.get_meta_message(u"stats-response"), | ||
self._encode_statistics_response, self._decode_statistics_response) | ||
|
||
def _encode_statistics_request(self, message): | ||
stats_type = message.payload.stats_type | ||
return pack("!i", stats_type), | ||
|
||
def _decode_statistics_request(self, placeholder, offset, data): | ||
stats_type, = unpack_from("!i", data, offset) | ||
offset += 4 | ||
return offset, placeholder.meta.payload.implement(stats_type) | ||
|
||
# TODO fix for dictionaries larger than MTU (split message) | ||
def _encode_statistics_response(self, message): | ||
stats_type = message.payload.stats_type | ||
records = message.payload.records | ||
packed = pack("!i", stats_type) | ||
for r in records: | ||
peer_id = r[0].encode('utf8') | ||
value = r[1] | ||
packed = packed + pack("!H%dsi" % len(peer_id), len(peer_id), peer_id, value) | ||
return packed, | ||
|
||
def _decode_statistics_response(self, placeholder, offset, data): | ||
stats_type, = unpack_from("!i", data, offset) | ||
offset += 4 | ||
records = [] | ||
while offset < len(data): | ||
len_key, = unpack_from("!H", data, offset) | ||
if len_key < 1: | ||
break | ||
offset += 2 | ||
key, = unpack_from("!%ds" % len_key, data, offset) | ||
offset += len_key | ||
value = data[offset: offset + 4] | ||
offset += 4 | ||
r = [key, value] | ||
records.append(r) | ||
return offset, placeholder.meta.payload.implement(stats_type, records) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
from Tribler.dispersy.payload import Payload | ||
|
||
|
||
class StatisticsRequestPayload(Payload): | ||
''' | ||
Request statistics for key 'key' from peer. | ||
''' | ||
|
||
class Implementation(Payload.Implementation): | ||
|
||
def __init__(self, meta, stats_type): | ||
super(StatisticsRequestPayload.Implementation, self).__init__(meta) | ||
self.stats_type = stats_type | ||
|
||
|
||
class StatisticsResponsePayload(Payload): | ||
|
||
class Implementation(Payload.Implementation): | ||
|
||
def __init__(self, meta, stats_type, records): | ||
super(StatisticsResponsePayload.Implementation, self).__init__(meta) | ||
self.stats_type = stats_type | ||
self.records = records |
Oops, something went wrong.