def get(self, key: str): """ Memcached namespaces: - 'K' -> key: [peer_hash: str, ...] - 'P' -> peer_hash: (ip: str, port: int) - 'S' -> "%s!%s" % (key: str, param: str): int - 'D' -> Debug data This allows peer info to be shared and decay by itself, we will delete references to peers from the key namespace lazily. MAKE SURE YOU REFER TO doc/NTrack.rst FOR CONSISTENCY! :param key: :return: """ if len(key) > 128: pass # TODO Insanely long key, let them know peer_hash = self._peer_hash(self.request.remote_ip) event = self.get_argument('event', default=None) left = self.get_argument('left', default=None) if event == 'stopped': mdel(peer_hash, namespace='P') self._update_stats(key, event=event, left=left) self.write(bencode({'interval': self.interval, 'peers': []})) elif event == 'completed': self._update_stats(key, event=event, left=left) elif event == 'started': self._update_stats(key, event=event, left=left) peer_list = get(key, namespace='K') if peer_list: if peer_hash in peer_list: peer_list.remove(peer_hash) peers = get_multi(peer_list, namespace='P') lost_peers = [p_hash for p_hash, peer in zip(peer_list, peers) if peer is None] if lost_peers: for lost_peer in lost_peers: pass res = [encode_host_and_port(peer[0], peer[1]) for peer in peers] else: peer_list = res = [] self._update_stats(key, new_track=True) if not peer_hash in peer_list: mset(peer_hash, (self.request.remote_ip, self.port), namespace='P') peer_list.append(peer_hash) mset(key, peer_list, namespace='K') if self.stats: self.write(bencode({'interval': self.interval, 'peers': res, 'complete': get('%s!complete' % key, namespace='S') or 0, 'incomplete': get('%s!incomplete' % key, namespace='S') or 0})) else: self.write(bencode({'interval': self.interval, 'peers': res}))
def _update_stats(self, key, new_track=False, lost_peers=0, event=None, left=None) -> None: if not self.stats: return complete = '%s!complete' % key incomplete = '%s!incomplete' % key if new_track: mset(complete, '0', namespace='S') mset(incomplete, '0', namespace='S') elif lost_peers: decr(incomplete, lost_peers, namespace='S') elif event in ('stopped', 'started'): if left == '0': decr(complete, namespace='S') else: decr(incomplete, namespace='S') elif event in ('completed', ): decr(incomplete, namespace='S') incr(complete, namespace='S')
def get(self, key: str): """ Memcached namespaces: - 'K' -> key: [peer_hash: str, ...] - 'P' -> peer_hash: (ip: str, port: int) - 'S' -> "%s!%s" % (key: str, param: str): int - 'D' -> Debug data This allows peer info to be shared and decay by itself, we will delete references to peers from the key namespace lazily. MAKE SURE YOU REFER TO doc/NTrack.rst FOR CONSISTENCY! :param key: :return: """ if len(key) > 128: pass # TODO Insanely long key, let them know peer_hash = self._peer_hash(self.request.remote_ip) event = self.get_argument('event', default=None) left = self.get_argument('left', default=None) if event == 'stopped': mdel(peer_hash, namespace='P') self._update_stats(key, event=event, left=left) self.write(bencode({'interval': self.interval, 'peers': []})) elif event == 'completed': self._update_stats(key, event=event, left=left) elif event == 'started': self._update_stats(key, event=event, left=left) peer_list = get(key, namespace='K') if peer_list: if peer_hash in peer_list: peer_list.remove(peer_hash) peers = get_multi(peer_list, namespace='P') lost_peers = [ p_hash for p_hash, peer in zip(peer_list, peers) if peer is None ] if lost_peers: for lost_peer in lost_peers: pass res = [encode_host_and_port(peer[0], peer[1]) for peer in peers] else: peer_list = res = [] self._update_stats(key, new_track=True) if not peer_hash in peer_list: mset(peer_hash, (self.request.remote_ip, self.port), namespace='P') peer_list.append(peer_hash) mset(key, peer_list, namespace='K') if self.stats: self.write( bencode({ 'interval': self.interval, 'peers': res, 'complete': get('%s!complete' % key, namespace='S') or 0, 'incomplete': get('%s!incomplete' % key, namespace='S') or 0 })) else: self.write(bencode({'interval': self.interval, 'peers': res}))