socks proxy support, disable udp connections support, http bittorrent tracker support, port opened, external ip to stats, only need zeroname site if dont have, dont try to download file that not in content.json, store external ip even if port closed, recreate uirequest class to avoid unfinished requests in some cases
This commit is contained in:
parent
b414a75885
commit
4f7e048413
36 changed files with 1927 additions and 80 deletions
7
src/lib/bencode/__init__.py
Normal file
7
src/lib/bencode/__init__.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
try:
|
||||
string_type = basestring
|
||||
except NameError:
|
||||
string_type = str
|
||||
|
||||
from .encode import encode
|
||||
from .decode import decode
|
141
src/lib/bencode/decode.py
Normal file
141
src/lib/bencode/decode.py
Normal file
|
@ -0,0 +1,141 @@
|
|||
import itertools
|
||||
import collections
|
||||
|
||||
from . import string_type
|
||||
|
||||
try:
|
||||
range = xrange
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
def decode(data):
|
||||
'''
|
||||
Bdecodes data into Python built-in types.
|
||||
'''
|
||||
|
||||
return consume(LookaheadIterator(data))
|
||||
|
||||
class LookaheadIterator(collections.Iterator):
|
||||
'''
|
||||
An iterator that lets you peek at the next item.
|
||||
'''
|
||||
|
||||
def __init__(self, iterator):
|
||||
self.iterator, self.next_iterator = itertools.tee(iter(iterator))
|
||||
|
||||
# Be one step ahead
|
||||
self._advance()
|
||||
|
||||
def _advance(self):
|
||||
self.next_item = next(self.next_iterator, None)
|
||||
|
||||
def __next__(self):
|
||||
self._advance()
|
||||
|
||||
return next(self.iterator)
|
||||
|
||||
# Python 2 compatibility
|
||||
next = __next__
|
||||
|
||||
def consume(stream):
|
||||
item = stream.next_item
|
||||
|
||||
if item is None:
|
||||
raise ValueError('Encoding empty data is undefined')
|
||||
elif item == 'i':
|
||||
return consume_int(stream)
|
||||
elif item == 'l':
|
||||
return consume_list(stream)
|
||||
elif item == 'd':
|
||||
return consume_dict(stream)
|
||||
elif item is not None and item[0].isdigit():
|
||||
return consume_str(stream)
|
||||
else:
|
||||
raise ValueError('Invalid bencode object type: ', item)
|
||||
|
||||
def consume_number(stream):
|
||||
result = ''
|
||||
|
||||
while True:
|
||||
chunk = stream.next_item
|
||||
|
||||
if not chunk.isdigit():
|
||||
return result
|
||||
elif result.startswith('0'):
|
||||
raise ValueError('Invalid number')
|
||||
|
||||
next(stream)
|
||||
result += chunk
|
||||
|
||||
def consume_int(stream):
|
||||
if next(stream) != 'i':
|
||||
raise ValueError()
|
||||
|
||||
negative = stream.next_item == '-'
|
||||
|
||||
if negative:
|
||||
next(stream)
|
||||
|
||||
result = int(consume_number(stream))
|
||||
|
||||
if negative:
|
||||
result *= -1
|
||||
|
||||
if result == 0:
|
||||
raise ValueError('Negative zero is not allowed')
|
||||
|
||||
if next(stream) != 'e':
|
||||
raise ValueError('Unterminated integer')
|
||||
|
||||
return result
|
||||
|
||||
def consume_str(stream):
|
||||
length = int(consume_number(stream))
|
||||
|
||||
if next(stream) != ':':
|
||||
raise ValueError('Malformed string')
|
||||
|
||||
result = ''
|
||||
|
||||
for i in range(length):
|
||||
try:
|
||||
result += next(stream)
|
||||
except StopIteration:
|
||||
raise ValueError('Invalid string length')
|
||||
|
||||
return result
|
||||
|
||||
def consume_list(stream):
|
||||
if next(stream) != 'l':
|
||||
raise ValueError()
|
||||
|
||||
l = []
|
||||
|
||||
while stream.next_item != 'e':
|
||||
l.append(consume(stream))
|
||||
|
||||
if next(stream) != 'e':
|
||||
raise ValueError('Unterminated list')
|
||||
|
||||
return l
|
||||
|
||||
def consume_dict(stream):
|
||||
if next(stream) != 'd':
|
||||
raise ValueError()
|
||||
|
||||
d = {}
|
||||
|
||||
while stream.next_item != 'e':
|
||||
key = consume(stream)
|
||||
|
||||
if not isinstance(key, string_type):
|
||||
raise ValueError('Dictionary keys must be strings')
|
||||
|
||||
value = consume(stream)
|
||||
|
||||
d[key] = value
|
||||
|
||||
if next(stream) != 'e':
|
||||
raise ValueError('Unterminated dictionary')
|
||||
|
||||
return d
|
22
src/lib/bencode/encode.py
Normal file
22
src/lib/bencode/encode.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
from . import string_type
|
||||
|
||||
def encode(obj):
|
||||
'''
|
||||
Bencodes the object. The object must be an instance of: str, int, list, or dict.
|
||||
'''
|
||||
|
||||
if isinstance(obj, string_type):
|
||||
return '{0}:{1}'.format(len(obj), obj)
|
||||
elif isinstance(obj, int):
|
||||
return 'i{0}e'.format(obj)
|
||||
elif isinstance(obj, list):
|
||||
values = ''.join([encode(o) for o in obj])
|
||||
|
||||
return 'l{0}e'.format(values)
|
||||
elif isinstance(obj, dict):
|
||||
items = sorted(obj.items())
|
||||
values = ''.join([encode(str(key)) + encode(value) for key, value in items])
|
||||
|
||||
return 'd{0}e'.format(values)
|
||||
else:
|
||||
raise TypeError('Unsupported type: {0}. Must be one of: str, int, list, dict.'.format(type(obj)))
|
Loading…
Add table
Add a link
Reference in a new issue