Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e715ef3008 | ||
|
|
9384255634 | ||
|
|
72ed585c6f | ||
|
|
41e599f9c3 | ||
|
|
c7530bb143 | ||
|
|
4ceae77401 | ||
|
|
9e185e8f88 |
@ -42,7 +42,10 @@ before_install:
|
|||||||
install:
|
install:
|
||||||
- if [[ $(echo "$TOXENV" | egrep -c "py32") != 0 ]]; then pip install setuptools==17.1.1; fi;
|
- if [[ $(echo "$TOXENV" | egrep -c "py32") != 0 ]]; then pip install setuptools==17.1.1; fi;
|
||||||
- if [[ $(echo "$TOXENV" | egrep -c "(py2[45]|py3[12])") != 0 ]]; then pip install virtualenv==1.7.2 tox==1.3; fi;
|
- if [[ $(echo "$TOXENV" | egrep -c "(py2[45]|py3[12])") != 0 ]]; then pip install virtualenv==1.7.2 tox==1.3; fi;
|
||||||
- if [[ $(echo "$TOXENV" | egrep -c "(py2[45]|py3[12])") == 0 ]]; then pip install tox; fi;
|
- if [[ $(echo "$TOXENV" | egrep -c "(py26|py33)") != 0 ]]; then pip install virtualenv==15.2.0 tox==2.9.1; fi;
|
||||||
|
- if [[ $(echo "$TOXENV" | egrep -c "(py2[456]|py3[123])") == 0 ]]; then pip install tox; fi;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- tox
|
- tox
|
||||||
|
|||||||
@ -1,3 +1,7 @@
|
|||||||
|
#Usage
|
||||||
|
|
||||||
|
$ curl -s https://git.spectre5.com/adamcruz/speedtest-cli-pub/raw/branch/master/speedtest.py | python -
|
||||||
|
|
||||||
speedtest-cli
|
speedtest-cli
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|||||||
581
speedtest.py
581
speedtest.py
@ -36,7 +36,7 @@ except ImportError:
|
|||||||
gzip = None
|
gzip = None
|
||||||
GZIP_BASE = object
|
GZIP_BASE = object
|
||||||
|
|
||||||
__version__ = '2.0.1a'
|
__version__ = '2.0.2'
|
||||||
|
|
||||||
|
|
||||||
class FakeShutdownEvent(object):
|
class FakeShutdownEvent(object):
|
||||||
@ -85,9 +85,9 @@ except ImportError:
|
|||||||
HTTPErrorProcessor, OpenerDirector)
|
HTTPErrorProcessor, OpenerDirector)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from httplib import HTTPConnection
|
from httplib import HTTPConnection, BadStatusLine
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from http.client import HTTPConnection
|
from http.client import HTTPConnection, BadStatusLine
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from httplib import HTTPSConnection
|
from httplib import HTTPSConnection
|
||||||
@ -266,10 +266,13 @@ try:
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
CERT_ERROR = tuple()
|
CERT_ERROR = tuple()
|
||||||
|
|
||||||
HTTP_ERRORS = ((HTTPError, URLError, socket.error, ssl.SSLError) +
|
HTTP_ERRORS = (
|
||||||
CERT_ERROR)
|
(HTTPError, URLError, socket.error, ssl.SSLError, BadStatusLine) +
|
||||||
|
CERT_ERROR
|
||||||
|
)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
HTTP_ERRORS = (HTTPError, URLError, socket.error)
|
ssl = None
|
||||||
|
HTTP_ERRORS = (HTTPError, URLError, socket.error, BadStatusLine)
|
||||||
|
|
||||||
|
|
||||||
class SpeedtestException(Exception):
|
class SpeedtestException(Exception):
|
||||||
@ -318,16 +321,6 @@ class InvalidSpeedtestMiniServer(SpeedtestException):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class SpeedtestCustomConnectFailure(SpeedtestException):
|
|
||||||
"""Could not connect to the provided speedtest custom server"""
|
|
||||||
|
|
||||||
|
|
||||||
class InvalidSpeedtestCustomServer(SpeedtestException):
|
|
||||||
"""Server provided as a speedtest custom server does not actually appear
|
|
||||||
to be a speedtest custom server
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class ShareResultsConnectFailure(SpeedtestException):
|
class ShareResultsConnectFailure(SpeedtestException):
|
||||||
"""Could not connect to speedtest.net API to POST results"""
|
"""Could not connect to speedtest.net API to POST results"""
|
||||||
|
|
||||||
@ -352,14 +345,6 @@ class SpeedtestMissingBestServer(SpeedtestException):
|
|||||||
"""get_best_server not called or not able to determine best server"""
|
"""get_best_server not called or not able to determine best server"""
|
||||||
|
|
||||||
|
|
||||||
def make_source_address_tuple(source_address):
|
|
||||||
if isinstance(source_address, (list, tuple)):
|
|
||||||
return source_address
|
|
||||||
elif source_address:
|
|
||||||
return (source_address, 0)
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
|
def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
|
||||||
source_address=None):
|
source_address=None):
|
||||||
"""Connect to *address* and return the socket object.
|
"""Connect to *address* and return the socket object.
|
||||||
@ -401,44 +386,33 @@ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
|
|||||||
raise socket.error("getaddrinfo returns an empty list")
|
raise socket.error("getaddrinfo returns an empty list")
|
||||||
|
|
||||||
|
|
||||||
def connection_factory(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
|
|
||||||
source_address=None):
|
|
||||||
try:
|
|
||||||
return socket.create_connection(
|
|
||||||
address,
|
|
||||||
timeout,
|
|
||||||
source_address
|
|
||||||
)
|
|
||||||
except (AttributeError, TypeError):
|
|
||||||
return create_connection(
|
|
||||||
address,
|
|
||||||
timeout,
|
|
||||||
source_address
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SpeedtestHTTPConnection(HTTPConnection):
|
class SpeedtestHTTPConnection(HTTPConnection):
|
||||||
"""Custom HTTPConnection to support source_address across
|
"""Custom HTTPConnection to support source_address across
|
||||||
Python 2.4 - Python 3
|
Python 2.4 - Python 3
|
||||||
"""
|
"""
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
source_address = kwargs.pop('source_address', None)
|
source_address = kwargs.pop('source_address', None)
|
||||||
context = kwargs.pop('context', None)
|
|
||||||
timeout = kwargs.pop('timeout', 10)
|
timeout = kwargs.pop('timeout', 10)
|
||||||
|
|
||||||
HTTPConnection.__init__(self, *args, **kwargs)
|
HTTPConnection.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
self.source_address = source_address
|
self.source_address = source_address
|
||||||
self._context = context
|
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
"""Connect to the host and port specified in __init__."""
|
"""Connect to the host and port specified in __init__."""
|
||||||
self.sock = connection_factory(
|
try:
|
||||||
(self.host, self.port),
|
self.sock = socket.create_connection(
|
||||||
self.timeout,
|
(self.host, self.port),
|
||||||
self.source_address
|
self.timeout,
|
||||||
)
|
self.source_address
|
||||||
|
)
|
||||||
|
except (AttributeError, TypeError):
|
||||||
|
self.sock = create_connection(
|
||||||
|
(self.host, self.port),
|
||||||
|
self.timeout,
|
||||||
|
self.source_address
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if HTTPSConnection:
|
if HTTPSConnection:
|
||||||
@ -447,16 +421,28 @@ if HTTPSConnection:
|
|||||||
"""Custom HTTPSConnection to support source_address across
|
"""Custom HTTPSConnection to support source_address across
|
||||||
Python 2.4 - Python 3
|
Python 2.4 - Python 3
|
||||||
"""
|
"""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
source_address = kwargs.pop('source_address', None)
|
||||||
|
timeout = kwargs.pop('timeout', 10)
|
||||||
|
|
||||||
|
HTTPSConnection.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
self.timeout = timeout
|
||||||
|
self.source_address = source_address
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
"Connect to a host on a given (SSL) port."
|
"Connect to a host on a given (SSL) port."
|
||||||
|
|
||||||
SpeedtestHTTPConnection.connect(self)
|
SpeedtestHTTPConnection.connect(self)
|
||||||
|
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
if hasattr(ssl, 'SSLContext'):
|
if ssl:
|
||||||
kwargs['server_hostname'] = self.host
|
if hasattr(ssl, 'SSLContext'):
|
||||||
|
kwargs['server_hostname'] = self.host
|
||||||
self.sock = self._context.wrap_socket(self.sock, **kwargs)
|
try:
|
||||||
|
self.sock = self._context.wrap_socket(self.sock, **kwargs)
|
||||||
|
except AttributeError:
|
||||||
|
self.sock = ssl.wrap_socket(self.sock, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def _build_connection(connection, source_address, timeout, context=None):
|
def _build_connection(connection, source_address, timeout, context=None):
|
||||||
@ -533,16 +519,18 @@ def build_opener(source_address=None, timeout=10):
|
|||||||
|
|
||||||
printer('Timeout set to %d' % timeout, debug=True)
|
printer('Timeout set to %d' % timeout, debug=True)
|
||||||
|
|
||||||
source_address = make_source_address_tuple(source_address)
|
|
||||||
if source_address:
|
if source_address:
|
||||||
printer('Binding to source address: %r' % (source_address,),
|
source_address_tuple = (source_address, 0)
|
||||||
|
printer('Binding to source address: %r' % (source_address_tuple,),
|
||||||
debug=True)
|
debug=True)
|
||||||
|
else:
|
||||||
|
source_address_tuple = None
|
||||||
|
|
||||||
handlers = [
|
handlers = [
|
||||||
ProxyHandler(),
|
ProxyHandler(),
|
||||||
SpeedtestHTTPHandler(source_address=source_address,
|
SpeedtestHTTPHandler(source_address=source_address_tuple,
|
||||||
timeout=timeout),
|
timeout=timeout),
|
||||||
SpeedtestHTTPSHandler(source_address=source_address,
|
SpeedtestHTTPSHandler(source_address=source_address_tuple,
|
||||||
timeout=timeout),
|
timeout=timeout),
|
||||||
HTTPDefaultErrorHandler(),
|
HTTPDefaultErrorHandler(),
|
||||||
HTTPRedirectHandler(),
|
HTTPRedirectHandler(),
|
||||||
@ -738,7 +726,7 @@ class HTTPDownloader(threading.Thread):
|
|||||||
shutdown_event=None):
|
shutdown_event=None):
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
self.request = request
|
self.request = request
|
||||||
self.result = 0
|
self.result = [0]
|
||||||
self.starttime = start
|
self.starttime = start
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
self.i = i
|
self.i = i
|
||||||
@ -759,69 +747,14 @@ class HTTPDownloader(threading.Thread):
|
|||||||
while (not self._shutdown_event.isSet() and
|
while (not self._shutdown_event.isSet() and
|
||||||
(timeit.default_timer() - self.starttime) <=
|
(timeit.default_timer() - self.starttime) <=
|
||||||
self.timeout):
|
self.timeout):
|
||||||
data = len(f.read(10240))
|
self.result.append(len(f.read(10240)))
|
||||||
if data == 0:
|
if self.result[-1] == 0:
|
||||||
break
|
break
|
||||||
self.result += data
|
|
||||||
f.close()
|
f.close()
|
||||||
except IOError:
|
except IOError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class SocketTestBase(threading.Thread):
|
|
||||||
def __init__(self, i, address, size, start, timeout, shutdown_event=None,
|
|
||||||
source_address=None):
|
|
||||||
threading.Thread.__init__(self)
|
|
||||||
self.result = 0
|
|
||||||
self.starttime = start
|
|
||||||
self.timeout = timeout
|
|
||||||
self.i = i
|
|
||||||
self.size = size
|
|
||||||
self.remaining = self.size
|
|
||||||
|
|
||||||
self._address = address
|
|
||||||
|
|
||||||
if shutdown_event:
|
|
||||||
self._shutdown_event = shutdown_event
|
|
||||||
else:
|
|
||||||
self._shutdown_event = FakeShutdownEvent()
|
|
||||||
|
|
||||||
self.sock = connection_factory(
|
|
||||||
address,
|
|
||||||
timeout=timeout,
|
|
||||||
source_address=source_address
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SocketDownloader(SocketTestBase):
|
|
||||||
def run(self):
|
|
||||||
try:
|
|
||||||
if (timeit.default_timer() - self.starttime) <= self.timeout:
|
|
||||||
self.sock.sendall('HI\n'.encode())
|
|
||||||
self.sock.recv(1024)
|
|
||||||
|
|
||||||
while (self.remaining and not self._shutdown_event.isSet() and
|
|
||||||
(timeit.default_timer() - self.starttime) <=
|
|
||||||
self.timeout):
|
|
||||||
|
|
||||||
if self.remaining > 1000000:
|
|
||||||
ask = 1000000
|
|
||||||
else:
|
|
||||||
ask = self.remaining
|
|
||||||
|
|
||||||
down = 0
|
|
||||||
self.sock.sendall(('DOWNLOAD %d\n' % ask).encode())
|
|
||||||
while down < ask:
|
|
||||||
down += len(self.sock.recv(10240))
|
|
||||||
|
|
||||||
self.result += down
|
|
||||||
self.remaining -= down
|
|
||||||
|
|
||||||
self.sock.close()
|
|
||||||
except IOError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class HTTPUploaderData(object):
|
class HTTPUploaderData(object):
|
||||||
"""File like object to improve cutting off the upload once the timeout
|
"""File like object to improve cutting off the upload once the timeout
|
||||||
has been reached
|
has been reached
|
||||||
@ -839,7 +772,7 @@ class HTTPUploaderData(object):
|
|||||||
|
|
||||||
self._data = None
|
self._data = None
|
||||||
|
|
||||||
self.total = 0
|
self.total = [0]
|
||||||
|
|
||||||
def pre_allocate(self):
|
def pre_allocate(self):
|
||||||
chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||||
@ -867,7 +800,7 @@ class HTTPUploaderData(object):
|
|||||||
if ((timeit.default_timer() - self.start) <= self.timeout and
|
if ((timeit.default_timer() - self.start) <= self.timeout and
|
||||||
not self._shutdown_event.isSet()):
|
not self._shutdown_event.isSet()):
|
||||||
chunk = self.data.read(n)
|
chunk = self.data.read(n)
|
||||||
self.total += len(chunk)
|
self.total.append(len(chunk))
|
||||||
return chunk
|
return chunk
|
||||||
else:
|
else:
|
||||||
raise SpeedtestUploadTimeout()
|
raise SpeedtestUploadTimeout()
|
||||||
@ -915,41 +848,11 @@ class HTTPUploader(threading.Thread):
|
|||||||
f = self._opener(request)
|
f = self._opener(request)
|
||||||
f.read(11)
|
f.read(11)
|
||||||
f.close()
|
f.close()
|
||||||
self.result = self.request.data.total
|
self.result = sum(self.request.data.total)
|
||||||
else:
|
else:
|
||||||
self.result = 0
|
self.result = 0
|
||||||
except (IOError, SpeedtestUploadTimeout):
|
except (IOError, SpeedtestUploadTimeout):
|
||||||
self.result = self.request.data.total
|
self.result = sum(self.request.data.total)
|
||||||
|
|
||||||
|
|
||||||
class SocketUploader(SocketTestBase):
|
|
||||||
def run(self):
|
|
||||||
try:
|
|
||||||
if (timeit.default_timer() - self.starttime) <= self.timeout:
|
|
||||||
self.sock.sendall('HI\n'.encode())
|
|
||||||
self.sock.recv(1024)
|
|
||||||
|
|
||||||
while (self.remaining and not self._shutdown_event.isSet() and
|
|
||||||
(timeit.default_timer() - self.starttime) <=
|
|
||||||
self.timeout):
|
|
||||||
|
|
||||||
if self.remaining > 100000:
|
|
||||||
give = 100000
|
|
||||||
else:
|
|
||||||
give = self.remaining
|
|
||||||
|
|
||||||
header = ('UPLOAD %d 0\n' % give).encode()
|
|
||||||
data = '0'.encode() * (give - len(header))
|
|
||||||
|
|
||||||
self.sock.sendall(header)
|
|
||||||
self.sock.sendall(data)
|
|
||||||
self.sock.recv(24)
|
|
||||||
self.result += give
|
|
||||||
self.remaining -= give
|
|
||||||
|
|
||||||
self.sock.close()
|
|
||||||
except IOError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class SpeedtestResults(object):
|
class SpeedtestResults(object):
|
||||||
@ -1107,7 +1010,7 @@ class Speedtest(object):
|
|||||||
"""Class for performing standard speedtest.net testing operations"""
|
"""Class for performing standard speedtest.net testing operations"""
|
||||||
|
|
||||||
def __init__(self, config=None, source_address=None, timeout=10,
|
def __init__(self, config=None, source_address=None, timeout=10,
|
||||||
secure=False, shutdown_event=None, use_socket=False):
|
secure=False, shutdown_event=None):
|
||||||
self.config = {}
|
self.config = {}
|
||||||
|
|
||||||
self._source_address = source_address
|
self._source_address = source_address
|
||||||
@ -1121,19 +1024,16 @@ class Speedtest(object):
|
|||||||
else:
|
else:
|
||||||
self._shutdown_event = FakeShutdownEvent()
|
self._shutdown_event = FakeShutdownEvent()
|
||||||
|
|
||||||
self._use_socket = use_socket
|
self.get_config()
|
||||||
|
|
||||||
if config is not None:
|
if config is not None:
|
||||||
self.config.update(config)
|
self.config.update(config)
|
||||||
else:
|
|
||||||
self.get_config()
|
|
||||||
|
|
||||||
self.servers = {}
|
self.servers = {}
|
||||||
self.closest = []
|
self.closest = []
|
||||||
self._best = {}
|
self._best = {}
|
||||||
|
|
||||||
self.results = SpeedtestResults(
|
self.results = SpeedtestResults(
|
||||||
client=self.config.get('client'),
|
client=self.config['client'],
|
||||||
opener=self._opener,
|
opener=self._opener,
|
||||||
secure=secure,
|
secure=secure,
|
||||||
)
|
)
|
||||||
@ -1218,14 +1118,9 @@ class Speedtest(object):
|
|||||||
up_sizes = [32768, 65536, 131072, 262144, 524288, 1048576, 7340032]
|
up_sizes = [32768, 65536, 131072, 262144, 524288, 1048576, 7340032]
|
||||||
sizes = {
|
sizes = {
|
||||||
'upload': up_sizes[ratio - 1:],
|
'upload': up_sizes[ratio - 1:],
|
||||||
|
'download': [350, 500, 750, 1000, 1500, 2000, 2500,
|
||||||
|
3000, 3500, 4000]
|
||||||
}
|
}
|
||||||
if self._use_socket:
|
|
||||||
sizes['download'] = [245388, 505544, 1118012, 1986284, 4468241,
|
|
||||||
7907740, 12407926, 17816816, 24262167,
|
|
||||||
31625365]
|
|
||||||
else:
|
|
||||||
sizes['download'] = [350, 500, 750, 1000, 1500, 2000, 2500,
|
|
||||||
3000, 3500, 4000]
|
|
||||||
|
|
||||||
size_count = len(sizes['upload'])
|
size_count = len(sizes['upload'])
|
||||||
|
|
||||||
@ -1370,9 +1265,6 @@ class Speedtest(object):
|
|||||||
or int(attrib.get('id')) in exclude):
|
or int(attrib.get('id')) in exclude):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
host, port = attrib['host'].split(':')
|
|
||||||
attrib['host'] = (host, int(port))
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
d = distance(self.lat_lon,
|
d = distance(self.lat_lon,
|
||||||
(float(attrib.get('lat')),
|
(float(attrib.get('lat')),
|
||||||
@ -1451,87 +1343,6 @@ class Speedtest(object):
|
|||||||
|
|
||||||
return self.servers
|
return self.servers
|
||||||
|
|
||||||
def set_custom_server(self, url, include=None, exclude=None):
|
|
||||||
request = build_request(url)
|
|
||||||
uh, e = catch_request(request, opener=self._opener)
|
|
||||||
if e:
|
|
||||||
raise SpeedtestCustomConnectFailure(
|
|
||||||
'Failed to connect to %s' % url
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
text = uh.read()
|
|
||||||
uh.close()
|
|
||||||
|
|
||||||
match = re.search('window.ST_PARAMS = (\{.*\});'.encode(), text)
|
|
||||||
|
|
||||||
try:
|
|
||||||
params = json.loads(match.group(1))
|
|
||||||
except (TypeError, ValueError):
|
|
||||||
e = get_exception()
|
|
||||||
printer('ERROR: %r' % e, debug=True)
|
|
||||||
raise InvalidSpeedtestCustomServer(
|
|
||||||
'Invalid Speedtest Custom Server: %s' % url
|
|
||||||
)
|
|
||||||
|
|
||||||
test_globals = params['testGlobals']
|
|
||||||
|
|
||||||
config = {
|
|
||||||
'client': {
|
|
||||||
'ip': test_globals['ipAddress'],
|
|
||||||
'lat': test_globals['location']['latitude'],
|
|
||||||
'lon': test_globals['location']['longitude'],
|
|
||||||
'country': test_globals['location']['countryCode'],
|
|
||||||
'isp': test_globals['ispName'],
|
|
||||||
},
|
|
||||||
'ignore_servers': [],
|
|
||||||
'sizes': {
|
|
||||||
'upload': [524288, 1048576, 7340032],
|
|
||||||
},
|
|
||||||
'counts': {
|
|
||||||
'upload': 17,
|
|
||||||
'download': 4
|
|
||||||
},
|
|
||||||
'threads': {
|
|
||||||
'upload': 2,
|
|
||||||
'download': 8
|
|
||||||
},
|
|
||||||
'length': {
|
|
||||||
'upload': 10,
|
|
||||||
'download': 10
|
|
||||||
},
|
|
||||||
'upload_max': 51,
|
|
||||||
}
|
|
||||||
|
|
||||||
if self._use_socket:
|
|
||||||
config['sizes']['download'] = [245388, 505544, 1118012, 1986284,
|
|
||||||
4468241, 7907740, 12407926,
|
|
||||||
17816816, 24262167, 31625365]
|
|
||||||
else:
|
|
||||||
config['sizes']['download'] = [350, 500, 750, 1000, 1500, 2000,
|
|
||||||
2500, 3000, 3500, 4000]
|
|
||||||
self.config = config
|
|
||||||
self.results.client = config['client']
|
|
||||||
|
|
||||||
servers = {}
|
|
||||||
for server in params['serverList']:
|
|
||||||
if include and int(server.get('id')) not in include:
|
|
||||||
continue
|
|
||||||
if exclude and int(server.get('id')) in exclude:
|
|
||||||
continue
|
|
||||||
|
|
||||||
host, port = server['host'].split(':')
|
|
||||||
server['host'] = (host, int(port))
|
|
||||||
server['country'] = server['cc']
|
|
||||||
d = server.pop('distance')
|
|
||||||
server['d'] = d
|
|
||||||
try:
|
|
||||||
servers[d].append(server)
|
|
||||||
except KeyError:
|
|
||||||
servers[d] = [server]
|
|
||||||
|
|
||||||
self.servers = servers
|
|
||||||
return self.servers
|
|
||||||
|
|
||||||
def get_closest_servers(self, limit=5):
|
def get_closest_servers(self, limit=5):
|
||||||
"""Limit servers to the closest speedtest.net servers based on
|
"""Limit servers to the closest speedtest.net servers based on
|
||||||
geographic distance
|
geographic distance
|
||||||
@ -1552,8 +1363,20 @@ class Speedtest(object):
|
|||||||
printer('Closest Servers:\n%r' % self.closest, debug=True)
|
printer('Closest Servers:\n%r' % self.closest, debug=True)
|
||||||
return self.closest
|
return self.closest
|
||||||
|
|
||||||
def _http_latency(self, servers):
|
def get_best_server(self, servers=None):
|
||||||
source_address = make_source_address_tuple(self._source_address)
|
"""Perform a speedtest.net "ping" to determine which speedtest.net
|
||||||
|
server has the lowest latency
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not servers:
|
||||||
|
if not self.closest:
|
||||||
|
servers = self.get_closest_servers()
|
||||||
|
servers = self.closest
|
||||||
|
|
||||||
|
if self._source_address:
|
||||||
|
source_address_tuple = (self._source_address, 0)
|
||||||
|
else:
|
||||||
|
source_address_tuple = None
|
||||||
|
|
||||||
user_agent = build_user_agent()
|
user_agent = build_user_agent()
|
||||||
|
|
||||||
@ -1572,14 +1395,12 @@ class Speedtest(object):
|
|||||||
if urlparts[0] == 'https':
|
if urlparts[0] == 'https':
|
||||||
h = SpeedtestHTTPSConnection(
|
h = SpeedtestHTTPSConnection(
|
||||||
urlparts[1],
|
urlparts[1],
|
||||||
source_address=source_address,
|
source_address=source_address_tuple
|
||||||
timeout=self._timeout,
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
h = SpeedtestHTTPConnection(
|
h = SpeedtestHTTPConnection(
|
||||||
urlparts[1],
|
urlparts[1],
|
||||||
source_address=source_address,
|
source_address=source_address_tuple
|
||||||
timeout=self._timeout,
|
|
||||||
)
|
)
|
||||||
headers = {'User-Agent': user_agent}
|
headers = {'User-Agent': user_agent}
|
||||||
path = '%s?%s' % (urlparts[2], urlparts[4])
|
path = '%s?%s' % (urlparts[2], urlparts[4])
|
||||||
@ -1603,77 +1424,11 @@ class Speedtest(object):
|
|||||||
avg = round((sum(cum) / 6) * 1000.0, 3)
|
avg = round((sum(cum) / 6) * 1000.0, 3)
|
||||||
results[avg] = server
|
results[avg] = server
|
||||||
|
|
||||||
return results
|
|
||||||
|
|
||||||
def _socket_latency(self, servers):
|
|
||||||
source_address = make_source_address_tuple(self._source_address)
|
|
||||||
|
|
||||||
results = {}
|
|
||||||
for server in servers:
|
|
||||||
cum = []
|
|
||||||
try:
|
|
||||||
sock = connection_factory(
|
|
||||||
server['host'],
|
|
||||||
timeout=self._timeout,
|
|
||||||
source_address=source_address
|
|
||||||
)
|
|
||||||
sock.sendall('HI\n'.encode())
|
|
||||||
sock.recv(1024)
|
|
||||||
except socket.error:
|
|
||||||
e = get_exception()
|
|
||||||
printer('ERROR: %r' % e, debug=True)
|
|
||||||
cum.append(3600 * 3)
|
|
||||||
continue
|
|
||||||
|
|
||||||
for _ in range(0, 3):
|
|
||||||
printer('%s %s' % ('PING', server['host']),
|
|
||||||
debug=True)
|
|
||||||
start = timeit.default_timer()
|
|
||||||
try:
|
|
||||||
sock.sendall(
|
|
||||||
('PING %d\n' %
|
|
||||||
(int(timeit.time.time()) * 1000,)).encode()
|
|
||||||
)
|
|
||||||
resp = sock.recv(1024)
|
|
||||||
except socket.errror:
|
|
||||||
e = get_exception()
|
|
||||||
printer('ERROR: %r' % e, debug=True)
|
|
||||||
cum.append(3600)
|
|
||||||
continue
|
|
||||||
total = (timeit.default_timer() - start)
|
|
||||||
if resp.startswith('PONG '.encode()):
|
|
||||||
cum.append(total)
|
|
||||||
else:
|
|
||||||
cum.append(3600)
|
|
||||||
|
|
||||||
avg = round((sum(cum) / 3) * 1000.0, 3)
|
|
||||||
results[avg] = server
|
|
||||||
|
|
||||||
return results
|
|
||||||
|
|
||||||
def get_best_server(self, servers=None):
|
|
||||||
"""Perform a speedtest.net "ping" to determine which speedtest.net
|
|
||||||
server has the lowest latency
|
|
||||||
"""
|
|
||||||
if not servers:
|
|
||||||
if not self.closest:
|
|
||||||
servers = self.get_closest_servers()
|
|
||||||
servers = self.closest
|
|
||||||
|
|
||||||
if self._use_socket:
|
|
||||||
results = self._socket_latency(servers)
|
|
||||||
else:
|
|
||||||
results = self._http_latency(servers)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
fastest = sorted(results.keys())[0]
|
fastest = sorted(results.keys())[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
if self._use_socket:
|
|
||||||
extra = ' Try the HTTP based tests by removing --socket.'
|
|
||||||
else:
|
|
||||||
extra = ''
|
|
||||||
raise SpeedtestBestServerFailure('Unable to connect to servers to '
|
raise SpeedtestBestServerFailure('Unable to connect to servers to '
|
||||||
'test latency.%s' % extra)
|
'test latency.')
|
||||||
best = results[fastest]
|
best = results[fastest]
|
||||||
best['latency'] = fastest
|
best['latency'] = fastest
|
||||||
|
|
||||||
@ -1687,54 +1442,29 @@ class Speedtest(object):
|
|||||||
def download(self, callback=do_nothing):
|
def download(self, callback=do_nothing):
|
||||||
"""Test download speed against speedtest.net"""
|
"""Test download speed against speedtest.net"""
|
||||||
|
|
||||||
if self._use_socket:
|
urls = []
|
||||||
requests = []
|
for size in self.config['sizes']['download']:
|
||||||
for size in self.config['sizes']['download']:
|
for _ in range(0, self.config['counts']['download']):
|
||||||
for _ in range(0, self.config['counts']['download']):
|
urls.append('%s/random%sx%s.jpg' %
|
||||||
requests.append(size)
|
(os.path.dirname(self.best['url']), size, size))
|
||||||
printer(
|
|
||||||
'DOWNLOAD %s %s' % (self.best['host'], size),
|
|
||||||
debug=True
|
|
||||||
)
|
|
||||||
|
|
||||||
request_count = len(requests)
|
request_count = len(urls)
|
||||||
else:
|
requests = []
|
||||||
urls = []
|
for i, url in enumerate(urls):
|
||||||
for size in self.config['sizes']['download']:
|
requests.append(
|
||||||
for _ in range(0, self.config['counts']['download']):
|
build_request(url, bump=i, secure=self._secure)
|
||||||
urls.append(
|
)
|
||||||
'%s/random%sx%s.jpg' %
|
|
||||||
(os.path.dirname(self.best['url']), size, size)
|
|
||||||
)
|
|
||||||
|
|
||||||
request_count = len(urls)
|
|
||||||
requests = []
|
|
||||||
for i, url in enumerate(urls):
|
|
||||||
requests.append(
|
|
||||||
build_request(url, bump=i, secure=self._secure)
|
|
||||||
)
|
|
||||||
|
|
||||||
def producer(q, requests, request_count):
|
def producer(q, requests, request_count):
|
||||||
for i, request in enumerate(requests):
|
for i, request in enumerate(requests):
|
||||||
if self._use_socket:
|
thread = HTTPDownloader(
|
||||||
thread = SocketDownloader(
|
i,
|
||||||
i,
|
request,
|
||||||
self.best['host'],
|
start,
|
||||||
request,
|
self.config['length']['download'],
|
||||||
start,
|
opener=self._opener,
|
||||||
self.config['length']['download'],
|
shutdown_event=self._shutdown_event
|
||||||
shutdown_event=self._shutdown_event,
|
)
|
||||||
source_address=self._source_address
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
thread = HTTPDownloader(
|
|
||||||
i,
|
|
||||||
request,
|
|
||||||
start,
|
|
||||||
self.config['length']['download'],
|
|
||||||
opener=self._opener,
|
|
||||||
shutdown_event=self._shutdown_event
|
|
||||||
)
|
|
||||||
thread.start()
|
thread.start()
|
||||||
q.put(thread, True)
|
q.put(thread, True)
|
||||||
callback(i, request_count, start=True)
|
callback(i, request_count, start=True)
|
||||||
@ -1746,7 +1476,7 @@ class Speedtest(object):
|
|||||||
thread = q.get(True)
|
thread = q.get(True)
|
||||||
while thread.isAlive():
|
while thread.isAlive():
|
||||||
thread.join(timeout=0.1)
|
thread.join(timeout=0.1)
|
||||||
finished.append(thread.result)
|
finished.append(sum(thread.result))
|
||||||
callback(thread.i, request_count, end=True)
|
callback(thread.i, request_count, end=True)
|
||||||
|
|
||||||
q = Queue(self.config['threads']['download'])
|
q = Queue(self.config['threads']['download'])
|
||||||
@ -1785,56 +1515,34 @@ class Speedtest(object):
|
|||||||
|
|
||||||
requests = []
|
requests = []
|
||||||
for i, size in enumerate(sizes):
|
for i, size in enumerate(sizes):
|
||||||
if self._use_socket:
|
# We set ``0`` for ``start`` and handle setting the actual
|
||||||
requests.append(size)
|
# ``start`` in ``HTTPUploader`` to get better measurements
|
||||||
printer(
|
data = HTTPUploaderData(
|
||||||
'UPLOAD %s %s' % (self.best['host'], size),
|
size,
|
||||||
debug=True
|
0,
|
||||||
)
|
self.config['length']['upload'],
|
||||||
else:
|
shutdown_event=self._shutdown_event
|
||||||
# We set ``0`` for ``start`` and handle setting the actual
|
)
|
||||||
# ``start`` in ``HTTPUploader`` to get better measurements
|
if pre_allocate:
|
||||||
data = HTTPUploaderData(
|
data.pre_allocate()
|
||||||
size,
|
requests.append(
|
||||||
0,
|
(
|
||||||
self.config['length']['upload'],
|
build_request(self.best['url'], data, secure=self._secure),
|
||||||
shutdown_event=self._shutdown_event
|
size
|
||||||
)
|
|
||||||
if pre_allocate:
|
|
||||||
data.pre_allocate()
|
|
||||||
requests.append(
|
|
||||||
(
|
|
||||||
build_request(
|
|
||||||
self.best['url'],
|
|
||||||
data,
|
|
||||||
secure=self._secure
|
|
||||||
),
|
|
||||||
size
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def producer(q, requests, request_count):
|
def producer(q, requests, request_count):
|
||||||
for i, request in enumerate(requests[:request_count]):
|
for i, request in enumerate(requests[:request_count]):
|
||||||
if self._use_socket:
|
thread = HTTPUploader(
|
||||||
thread = SocketUploader(
|
i,
|
||||||
i,
|
request[0],
|
||||||
self.best['host'],
|
start,
|
||||||
request,
|
request[1],
|
||||||
start,
|
self.config['length']['upload'],
|
||||||
self.config['length']['upload'],
|
opener=self._opener,
|
||||||
shutdown_event=self._shutdown_event,
|
shutdown_event=self._shutdown_event
|
||||||
source_address=self._source_address
|
)
|
||||||
)
|
|
||||||
else:
|
|
||||||
thread = HTTPUploader(
|
|
||||||
i,
|
|
||||||
request[0],
|
|
||||||
start,
|
|
||||||
request[1],
|
|
||||||
self.config['length']['upload'],
|
|
||||||
opener=self._opener,
|
|
||||||
shutdown_event=self._shutdown_event
|
|
||||||
)
|
|
||||||
thread.start()
|
thread.start()
|
||||||
q.put(thread, True)
|
q.put(thread, True)
|
||||||
callback(i, request_count, start=True)
|
callback(i, request_count, start=True)
|
||||||
@ -1951,15 +1659,12 @@ def parse_args():
|
|||||||
help='Exclude a server from selection. Can be '
|
help='Exclude a server from selection. Can be '
|
||||||
'supplied multiple times')
|
'supplied multiple times')
|
||||||
parser.add_argument('--mini', help='URL of the Speedtest Mini server')
|
parser.add_argument('--mini', help='URL of the Speedtest Mini server')
|
||||||
parser.add_argument('--custom', help='URL of the Speedtest Custom Server')
|
|
||||||
parser.add_argument('--source', help='Source IP address to bind to')
|
parser.add_argument('--source', help='Source IP address to bind to')
|
||||||
parser.add_argument('--timeout', default=10, type=PARSER_TYPE_FLOAT,
|
parser.add_argument('--timeout', default=10, type=PARSER_TYPE_FLOAT,
|
||||||
help='HTTP timeout in seconds. Default 10')
|
help='HTTP timeout in seconds. Default 10')
|
||||||
parser.add_argument('--secure', action='store_true',
|
parser.add_argument('--secure', action='store_true',
|
||||||
help='Use HTTPS instead of HTTP when communicating '
|
help='Use HTTPS instead of HTTP when communicating '
|
||||||
'with speedtest.net operated servers')
|
'with speedtest.net operated servers')
|
||||||
parser.add_argument('--socket', action='store_true',
|
|
||||||
help='Use socket test instead of HTTP based tests')
|
|
||||||
parser.add_argument('--no-pre-allocate', dest='pre_allocate',
|
parser.add_argument('--no-pre-allocate', dest='pre_allocate',
|
||||||
action='store_const', default=True, const=False,
|
action='store_const', default=True, const=False,
|
||||||
help='Do not pre allocate upload data. Pre allocation '
|
help='Do not pre allocate upload data. Pre allocation '
|
||||||
@ -1989,7 +1694,6 @@ def validate_optional_args(args):
|
|||||||
"""
|
"""
|
||||||
optional_args = {
|
optional_args = {
|
||||||
'json': ('json/simplejson python module', json),
|
'json': ('json/simplejson python module', json),
|
||||||
'custom': ('json/simplejson python module', json),
|
|
||||||
'secure': ('SSL support', HTTPSConnection),
|
'secure': ('SSL support', HTTPSConnection),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2070,33 +1774,18 @@ def shell():
|
|||||||
|
|
||||||
printer('Retrieving speedtest.net configuration...', quiet)
|
printer('Retrieving speedtest.net configuration...', quiet)
|
||||||
try:
|
try:
|
||||||
kwargs = {}
|
|
||||||
if args.custom:
|
|
||||||
kwargs['config'] = {}
|
|
||||||
speedtest = Speedtest(
|
speedtest = Speedtest(
|
||||||
source_address=args.source,
|
source_address=args.source,
|
||||||
timeout=args.timeout,
|
timeout=args.timeout,
|
||||||
secure=args.secure,
|
secure=args.secure
|
||||||
use_socket=args.socket,
|
|
||||||
**kwargs
|
|
||||||
)
|
)
|
||||||
except (ConfigRetrievalError,) + HTTP_ERRORS:
|
except (ConfigRetrievalError,) + HTTP_ERRORS:
|
||||||
printer('Cannot retrieve speedtest configuration', error=True)
|
printer('Cannot retrieve speedtest configuration', error=True)
|
||||||
raise SpeedtestCLIError(get_exception())
|
raise SpeedtestCLIError(get_exception())
|
||||||
|
|
||||||
if args.custom:
|
|
||||||
kwargs = {}
|
|
||||||
if not args.list:
|
|
||||||
kwargs.update({
|
|
||||||
'include': args.server,
|
|
||||||
'exclude': args.exclude,
|
|
||||||
})
|
|
||||||
speedtest.set_custom_server(args.custom, **kwargs)
|
|
||||||
|
|
||||||
if args.list:
|
if args.list:
|
||||||
try:
|
try:
|
||||||
if not args.custom:
|
speedtest.get_servers()
|
||||||
speedtest.get_servers()
|
|
||||||
except (ServersRetrievalError,) + HTTP_ERRORS:
|
except (ServersRetrievalError,) + HTTP_ERRORS:
|
||||||
printer('Cannot retrieve speedtest server list', error=True)
|
printer('Cannot retrieve speedtest server list', error=True)
|
||||||
raise SpeedtestCLIError(get_exception())
|
raise SpeedtestCLIError(get_exception())
|
||||||
@ -2118,25 +1807,21 @@ def shell():
|
|||||||
|
|
||||||
if not args.mini:
|
if not args.mini:
|
||||||
printer('Retrieving speedtest.net server list...', quiet)
|
printer('Retrieving speedtest.net server list...', quiet)
|
||||||
if not args.custom:
|
try:
|
||||||
try:
|
speedtest.get_servers(servers=args.server, exclude=args.exclude)
|
||||||
speedtest.get_servers(
|
except NoMatchedServers:
|
||||||
servers=args.server,
|
raise SpeedtestCLIError(
|
||||||
exclude=args.exclude
|
'No matched servers: %s' %
|
||||||
)
|
', '.join('%s' % s for s in args.server)
|
||||||
except NoMatchedServers:
|
)
|
||||||
raise SpeedtestCLIError(
|
except (ServersRetrievalError,) + HTTP_ERRORS:
|
||||||
'No matched servers: %s' %
|
printer('Cannot retrieve speedtest server list', error=True)
|
||||||
', '.join('%s' % s for s in args.server)
|
raise SpeedtestCLIError(get_exception())
|
||||||
)
|
except InvalidServerIDType:
|
||||||
except (ServersRetrievalError,) + HTTP_ERRORS:
|
raise SpeedtestCLIError(
|
||||||
printer('Cannot retrieve speedtest server list', error=True)
|
'%s is an invalid server type, must '
|
||||||
raise SpeedtestCLIError(get_exception())
|
'be an int' % ', '.join('%s' % s for s in args.server)
|
||||||
except InvalidServerIDType:
|
)
|
||||||
raise SpeedtestCLIError(
|
|
||||||
'%s is an invalid server type, must '
|
|
||||||
'be an int' % ', '.join('%s' % s for s in args.server)
|
|
||||||
)
|
|
||||||
|
|
||||||
if args.server and len(args.server) == 1:
|
if args.server and len(args.server) == 1:
|
||||||
printer('Retrieving information for the selected server...', quiet)
|
printer('Retrieving information for the selected server...', quiet)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user