CatsMeowAlot

SpeedTest.py

Oct 19th, 2016
869
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 24.59 KB | None | 0 0
  1. #!/usr/bin/env python
  2. #simple speedtest type python speedtest.py
  3. # @CatsMeowAlot
  4. import os
  5. import re
  6. import sys
  7. import math
  8. import signal
  9. import socket
  10. import timeit
  11. import platform
  12. import threading
  13.  
  14. __version__ = '0.3.4'
  15.  
  16. # Some global variables we use
  17. user_agent = None
  18. source = None
  19. shutdown_event = None
  20. scheme = 'http'
  21.  
  22.  
  23. # Used for bound_interface
  24. socket_socket = socket.socket
  25.  
  26. try:
  27.     import xml.etree.cElementTree as ET
  28. except ImportError:
  29.     try:
  30.         import xml.etree.ElementTree as ET
  31.     except ImportError:
  32.         from xml.dom import minidom as DOM
  33.         ET = None
  34.  
  35. # Begin import game to handle Python 2 and Python 3
  36. try:
  37.     from urllib2 import urlopen, Request, HTTPError, URLError
  38. except ImportError:
  39.     from urllib.request import urlopen, Request, HTTPError, URLError
  40.  
  41. try:
  42.     from httplib import HTTPConnection, HTTPSConnection
  43. except ImportError:
  44.     e_http_py2 = sys.exc_info()
  45.     try:
  46.         from http.client import HTTPConnection, HTTPSConnection
  47.     except ImportError:
  48.         e_http_py3 = sys.exc_info()
  49.         raise SystemExit('Your python installation is missing required HTTP '
  50.                          'client classes:\n\n'
  51.                          'Python 2: %s\n'
  52.                          'Python 3: %s' % (e_http_py2[1], e_http_py3[1]))
  53.  
  54. try:
  55.     from Queue import Queue
  56. except ImportError:
  57.     from queue import Queue
  58.  
  59. try:
  60.     from urlparse import urlparse
  61. except ImportError:
  62.     from urllib.parse import urlparse
  63.  
  64. try:
  65.     from urlparse import parse_qs
  66. except ImportError:
  67.     try:
  68.         from urllib.parse import parse_qs
  69.     except ImportError:
  70.         from cgi import parse_qs
  71.  
  72. try:
  73.     from hashlib import md5
  74. except ImportError:
  75.     from md5 import md5
  76.  
  77. try:
  78.     from argparse import ArgumentParser as ArgParser
  79. except ImportError:
  80.     from optparse import OptionParser as ArgParser
  81.  
  82. try:
  83.     import builtins
  84. except ImportError:
  85.     def print_(*args, **kwargs):
  86.         """The new-style print function taken from
  87.        https://pypi.python.org/pypi/six/
  88.  
  89.        """
  90.         fp = kwargs.pop("file", sys.stdout)
  91.         if fp is None:
  92.             return
  93.  
  94.         def write(data):
  95.             if not isinstance(data, basestring):
  96.                 data = str(data)
  97.             fp.write(data)
  98.  
  99.         want_unicode = False
  100.         sep = kwargs.pop("sep", None)
  101.         if sep is not None:
  102.             if isinstance(sep, unicode):
  103.                 want_unicode = True
  104.             elif not isinstance(sep, str):
  105.                 raise TypeError("sep must be None or a string")
  106.         end = kwargs.pop("end", None)
  107.         if end is not None:
  108.             if isinstance(end, unicode):
  109.                 want_unicode = True
  110.             elif not isinstance(end, str):
  111.                 raise TypeError("end must be None or a string")
  112.         if kwargs:
  113.             raise TypeError("invalid keyword arguments to print()")
  114.         if not want_unicode:
  115.             for arg in args:
  116.                 if isinstance(arg, unicode):
  117.                     want_unicode = True
  118.                     break
  119.         if want_unicode:
  120.             newline = unicode("\n")
  121.             space = unicode(" ")
  122.         else:
  123.             newline = "\n"
  124.             space = " "
  125.         if sep is None:
  126.             sep = space
  127.         if end is None:
  128.             end = newline
  129.         for i, arg in enumerate(args):
  130.             if i:
  131.                 write(sep)
  132.             write(arg)
  133.         write(end)
  134. else:
  135.     print_ = getattr(builtins, 'print')
  136.     del builtins
  137.  
  138.  
  139. class SpeedtestCliServerListError(Exception):
  140.     """Internal Exception class used to indicate to move on to the next
  141.    URL for retrieving speedtest.net server details
  142.  
  143.    """
  144.  
  145.  
  146. def bound_socket(*args, **kwargs):
  147.     """Bind socket to a specified source IP address"""
  148.  
  149.     global source
  150.     sock = socket_socket(*args, **kwargs)
  151.     sock.bind((source, 0))
  152.     return sock
  153.  
  154.  
  155. def distance(origin, destination):
  156.     """Determine distance between 2 sets of [lat,lon] in km"""
  157.  
  158.     lat1, lon1 = origin
  159.     lat2, lon2 = destination
  160.     radius = 6371  # km
  161.  
  162.     dlat = math.radians(lat2 - lat1)
  163.     dlon = math.radians(lon2 - lon1)
  164.     a = (math.sin(dlat / 2) * math.sin(dlat / 2) +
  165.          math.cos(math.radians(lat1)) *
  166.          math.cos(math.radians(lat2)) * math.sin(dlon / 2) *
  167.          math.sin(dlon / 2))
  168.     c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
  169.     d = radius * c
  170.  
  171.     return d
  172.  
  173.  
  174. def build_user_agent():
  175.     """Build a Mozilla/5.0 compatible User-Agent string"""
  176.  
  177.     global user_agent
  178.     if user_agent:
  179.         return user_agent
  180.  
  181.     ua_tuple = (
  182.         'Mozilla/5.0',
  183.         '(%s; U; %s; en-us)' % (platform.system(), platform.architecture()[0]),
  184.         'Python/%s' % platform.python_version(),
  185.         '(KHTML, like Gecko)',
  186.         'speedtest-cli/%s' % __version__
  187.     )
  188.     user_agent = ' '.join(ua_tuple)
  189.     return user_agent
  190.  
  191.  
  192. def build_request(url, data=None, headers={}):
  193.     """Build a urllib2 request object
  194.  
  195.    This function automatically adds a User-Agent header to all requests
  196.  
  197.    """
  198.  
  199.     if url[0] == ':':
  200.         schemed_url = '%s%s' % (scheme, url)
  201.     else:
  202.         schemed_url = url
  203.  
  204.     headers['User-Agent'] = user_agent
  205.     return Request(schemed_url, data=data, headers=headers)
  206.  
  207.  
  208. def catch_request(request):
  209.     """Helper function to catch common exceptions encountered when
  210.    establishing a connection with a HTTP/HTTPS request
  211.  
  212.    """
  213.  
  214.     try:
  215.         uh = urlopen(request)
  216.         return uh, False
  217.     except (HTTPError, URLError, socket.error):
  218.         e = sys.exc_info()[1]
  219.         return None, e
  220.  
  221.  
  222. class FileGetter(threading.Thread):
  223.     """Thread class for retrieving a URL"""
  224.  
  225.     def __init__(self, url, start):
  226.         self.url = url
  227.         self.result = None
  228.         self.starttime = start
  229.         threading.Thread.__init__(self)
  230.  
  231.     def run(self):
  232.         self.result = [0]
  233.         try:
  234.             if (timeit.default_timer() - self.starttime) <= 10:
  235.                 request = build_request(self.url)
  236.                 f = urlopen(request)
  237.                 while 1 and not shutdown_event.isSet():
  238.                     self.result.append(len(f.read(10240)))
  239.                     if self.result[-1] == 0:
  240.                         break
  241.                 f.close()
  242.         except IOError:
  243.             pass
  244.  
  245.  
  246. def downloadSpeed(files, quiet=False):
  247.     """Function to launch FileGetter threads and calculate download speeds"""
  248.  
  249.     start = timeit.default_timer()
  250.  
  251.     def producer(q, files):
  252.         for file in files:
  253.             thread = FileGetter(file, start)
  254.             thread.start()
  255.             q.put(thread, True)
  256.             if not quiet and not shutdown_event.isSet():
  257.                 sys.stdout.write('.')
  258.                 sys.stdout.flush()
  259.  
  260.     finished = []
  261.  
  262.     def consumer(q, total_files):
  263.         while len(finished) < total_files:
  264.             thread = q.get(True)
  265.             while thread.isAlive():
  266.                 thread.join(timeout=0.1)
  267.             finished.append(sum(thread.result))
  268.             del thread
  269.  
  270.     q = Queue(6)
  271.     prod_thread = threading.Thread(target=producer, args=(q, files))
  272.     cons_thread = threading.Thread(target=consumer, args=(q, len(files)))
  273.     start = timeit.default_timer()
  274.     prod_thread.start()
  275.     cons_thread.start()
  276.     while prod_thread.isAlive():
  277.         prod_thread.join(timeout=0.1)
  278.     while cons_thread.isAlive():
  279.         cons_thread.join(timeout=0.1)
  280.     return (sum(finished) / (timeit.default_timer() - start))
  281.  
  282.  
  283. class FilePutter(threading.Thread):
  284.     """Thread class for putting a URL"""
  285.  
  286.     def __init__(self, url, start, size):
  287.         self.url = url
  288.         chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  289.         data = chars * (int(round(int(size) / 36.0)))
  290.         self.data = ('content1=%s' % data[0:int(size) - 9]).encode()
  291.         del data
  292.         self.result = None
  293.         self.starttime = start
  294.         threading.Thread.__init__(self)
  295.  
  296.     def run(self):
  297.         try:
  298.             if ((timeit.default_timer() - self.starttime) <= 10 and
  299.                     not shutdown_event.isSet()):
  300.                 request = build_request(self.url, data=self.data)
  301.                 f = urlopen(request)
  302.                 f.read(11)
  303.                 f.close()
  304.                 self.result = len(self.data)
  305.             else:
  306.                 self.result = 0
  307.         except IOError:
  308.             self.result = 0
  309.  
  310.  
  311. def uploadSpeed(url, sizes, quiet=False):
  312.     """Function to launch FilePutter threads and calculate upload speeds"""
  313.  
  314.     start = timeit.default_timer()
  315.  
  316.     def producer(q, sizes):
  317.         for size in sizes:
  318.             thread = FilePutter(url, start, size)
  319.             thread.start()
  320.             q.put(thread, True)
  321.             if not quiet and not shutdown_event.isSet():
  322.                 sys.stdout.write('.')
  323.                 sys.stdout.flush()
  324.  
  325.     finished = []
  326.  
  327.     def consumer(q, total_sizes):
  328.         while len(finished) < total_sizes:
  329.             thread = q.get(True)
  330.             while thread.isAlive():
  331.                 thread.join(timeout=0.1)
  332.             finished.append(thread.result)
  333.             del thread
  334.  
  335.     q = Queue(6)
  336.     prod_thread = threading.Thread(target=producer, args=(q, sizes))
  337.     cons_thread = threading.Thread(target=consumer, args=(q, len(sizes)))
  338.     start = timeit.default_timer()
  339.     prod_thread.start()
  340.     cons_thread.start()
  341.     while prod_thread.isAlive():
  342.         prod_thread.join(timeout=0.1)
  343.     while cons_thread.isAlive():
  344.         cons_thread.join(timeout=0.1)
  345.     return (sum(finished) / (timeit.default_timer() - start))
  346.  
  347.  
  348. def getAttributesByTagName(dom, tagName):
  349.     """Retrieve an attribute from an XML document and return it in a
  350.    consistent format
  351.  
  352.    Only used with xml.dom.minidom, which is likely only to be used
  353.    with python versions older than 2.5
  354.    """
  355.     elem = dom.getElementsByTagName(tagName)[0]
  356.     return dict(list(elem.attributes.items()))
  357.  
  358.  
  359. def getConfig():
  360.     """Download the speedtest.net configuration and return only the data
  361.    we are interested in
  362.    """
  363.  
  364.     request = build_request('://www.speedtest.net/speedtest-config.php')
  365.     uh, e = catch_request(request)
  366.     if e:
  367.         print_('Could not retrieve speedtest.net configuration: %s' % e)
  368.         sys.exit(1)
  369.     configxml = []
  370.     while 1:
  371.         configxml.append(uh.read(10240))
  372.         if len(configxml[-1]) == 0:
  373.             break
  374.     if int(uh.code) != 200:
  375.         return None
  376.     uh.close()
  377.     try:
  378.         try:
  379.             root = ET.fromstring(''.encode().join(configxml))
  380.             config = {
  381.                 'client': root.find('client').attrib,
  382.                 'times': root.find('times').attrib,
  383.                 'download': root.find('download').attrib,
  384.                 'upload': root.find('upload').attrib}
  385.         except AttributeError:  # Python3 branch
  386.             root = DOM.parseString(''.join(configxml))
  387.             config = {
  388.                 'client': getAttributesByTagName(root, 'client'),
  389.                 'times': getAttributesByTagName(root, 'times'),
  390.                 'download': getAttributesByTagName(root, 'download'),
  391.                 'upload': getAttributesByTagName(root, 'upload')}
  392.     except SyntaxError:
  393.         print_('Failed to parse speedtest.net configuration')
  394.         sys.exit(1)
  395.     del root
  396.     del configxml
  397.     return config
  398.  
  399.  
  400. def closestServers(client, all=False):
  401.     """Determine the 5 closest speedtest.net servers based on geographic
  402.    distance
  403.    """
  404.  
  405.     urls = [
  406.         '://www.speedtest.net/speedtest-servers-static.php',
  407.         '://c.speedtest.net/speedtest-servers-static.php',
  408.         '://www.speedtest.net/speedtest-servers.php',
  409.         '://c.speedtest.net/speedtest-servers.php',
  410.     ]
  411.     errors = []
  412.     servers = {}
  413.     for url in urls:
  414.         try:
  415.             request = build_request(url)
  416.             uh, e = catch_request(request)
  417.             if e:
  418.                 errors.append('%s' % e)
  419.                 raise SpeedtestCliServerListError
  420.             serversxml = []
  421.             while 1:
  422.                 serversxml.append(uh.read(10240))
  423.                 if len(serversxml[-1]) == 0:
  424.                     break
  425.             if int(uh.code) != 200:
  426.                 uh.close()
  427.                 raise SpeedtestCliServerListError
  428.             uh.close()
  429.             try:
  430.                 try:
  431.                     root = ET.fromstring(''.encode().join(serversxml))
  432.                     elements = root.getiterator('server')
  433.                 except AttributeError:  # Python3 branch
  434.                     root = DOM.parseString(''.join(serversxml))
  435.                     elements = root.getElementsByTagName('server')
  436.             except SyntaxError:
  437.                 raise SpeedtestCliServerListError
  438.             for server in elements:
  439.                 try:
  440.                     attrib = server.attrib
  441.                 except AttributeError:
  442.                     attrib = dict(list(server.attributes.items()))
  443.                 d = distance([float(client['lat']),
  444.                               float(client['lon'])],
  445.                              [float(attrib.get('lat')),
  446.                               float(attrib.get('lon'))])
  447.                 attrib['d'] = d
  448.                 if d not in servers:
  449.                     servers[d] = [attrib]
  450.                 else:
  451.                     servers[d].append(attrib)
  452.             del root
  453.             del serversxml
  454.             del elements
  455.         except SpeedtestCliServerListError:
  456.             continue
  457.  
  458.         # We were able to fetch and parse the list of speedtest.net servers
  459.         if servers:
  460.             break
  461.  
  462.     if not servers:
  463.         print_('Failed to retrieve list of speedtest.net servers:\n\n %s' %
  464.                '\n'.join(errors))
  465.         sys.exit(1)
  466.  
  467.     closest = []
  468.     for d in sorted(servers.keys()):
  469.         for s in servers[d]:
  470.             closest.append(s)
  471.             if len(closest) == 5 and not all:
  472.                 break
  473.         else:
  474.             continue
  475.         break
  476.  
  477.     del servers
  478.     return closest
  479.  
  480.  
  481. def getBestServer(servers):
  482.     """Perform a speedtest.net latency request to determine which
  483.    speedtest.net server has the lowest latency
  484.    """
  485.  
  486.     results = {}
  487.     for server in servers:
  488.         cum = []
  489.         url = '%s/latency.txt' % os.path.dirname(server['url'])
  490.         urlparts = urlparse(url)
  491.         for i in range(0, 3):
  492.             try:
  493.                 if urlparts[0] == 'https':
  494.                     h = HTTPSConnection(urlparts[1])
  495.                 else:
  496.                     h = HTTPConnection(urlparts[1])
  497.                 headers = {'User-Agent': user_agent}
  498.                 start = timeit.default_timer()
  499.                 h.request("GET", urlparts[2], headers=headers)
  500.                 r = h.getresponse()
  501.                 total = (timeit.default_timer() - start)
  502.             except (HTTPError, URLError, socket.error):
  503.                 cum.append(3600)
  504.                 continue
  505.             text = r.read(9)
  506.             if int(r.status) == 200 and text == 'test=test'.encode():
  507.                 cum.append(total)
  508.             else:
  509.                 cum.append(3600)
  510.             h.close()
  511.         avg = round((sum(cum) / 6) * 1000, 3)
  512.         results[avg] = server
  513.     fastest = sorted(results.keys())[0]
  514.     best = results[fastest]
  515.     best['latency'] = fastest
  516.  
  517.     return best
  518.  
  519.  
  520. def ctrl_c(signum, frame):
  521.     """Catch Ctrl-C key sequence and set a shutdown_event for our threaded
  522.    operations
  523.    """
  524.  
  525.     global shutdown_event
  526.     shutdown_event.set()
  527.     raise SystemExit('\nCancelling...')
  528.  
  529.  
  530. def version():
  531.     """Print the version"""
  532.  
  533.     raise SystemExit(__version__)
  534.  
  535.  
  536. def speedtest():
  537.     """Run the full speedtest.net test"""
  538.  
  539.     global shutdown_event, source, scheme
  540.     shutdown_event = threading.Event()
  541.  
  542.     signal.signal(signal.SIGINT, ctrl_c)
  543.  
  544.     description = (
  545.         'Command line interface for testing internet bandwidth using '
  546.         'speedtest.net.\n'
  547.         '------------------------------------------------------------'
  548.         '--------------\n'
  549.         'https://github.com/sivel/speedtest-cli')
  550.  
  551.     parser = ArgParser(description=description)
  552.     # Give optparse.OptionParser an `add_argument` method for
  553.     # compatibility with argparse.ArgumentParser
  554.     try:
  555.         parser.add_argument = parser.add_option
  556.     except AttributeError:
  557.         pass
  558.     parser.add_argument('--bytes', dest='units', action='store_const',
  559.                         const=('byte', 1), default=('bit', 8),
  560.                         help='Display values in bytes instead of bits. Does '
  561.                              'not affect the image generated by --share')
  562.     parser.add_argument('--share', action='store_true',
  563.                         help='Generate and provide a URL to the speedtest.net '
  564.                              'share results image')
  565.     parser.add_argument('--simple', action='store_true',
  566.                         help='Suppress verbose output, only show basic '
  567.                              'information')
  568.     parser.add_argument('--list', action='store_true',
  569.                         help='Display a list of speedtest.net servers '
  570.                              'sorted by distance')
  571.     parser.add_argument('--server', help='Specify a server ID to test against')
  572.     parser.add_argument('--mini', help='URL of the Speedtest Mini server')
  573.     parser.add_argument('--source', help='Source IP address to bind to')
  574.     parser.add_argument('--timeout', default=10, type=int,
  575.                         help='HTTP timeout in seconds. Default 10')
  576.     parser.add_argument('--secure', action='store_true',
  577.                         help='Use HTTPS instead of HTTP when communicating '
  578.                              'with speedtest.net operated servers')
  579.     parser.add_argument('--version', action='store_true',
  580.                         help='Show the version number and exit')
  581.  
  582.     options = parser.parse_args()
  583.     if isinstance(options, tuple):
  584.         args = options[0]
  585.     else:
  586.         args = options
  587.     del options
  588.  
  589.     # Print the version and exit
  590.     if args.version:
  591.         version()
  592.  
  593.     socket.setdefaulttimeout(args.timeout)
  594.  
  595.     # Pre-cache the user agent string
  596.     build_user_agent()
  597.  
  598.     # If specified bind to a specific IP address
  599.     if args.source:
  600.         source = args.source
  601.         socket.socket = bound_socket
  602.  
  603.     if args.secure:
  604.         scheme = 'https'
  605.  
  606.     if not args.simple:
  607.         print_('Retrieving speedtest.net configuration...')
  608.     try:
  609.         config = getConfig()
  610.     except URLError:
  611.         print_('Cannot retrieve speedtest configuration')
  612.         sys.exit(1)
  613.  
  614.     if not args.simple:
  615.         print_('Retrieving speedtest.net server list...')
  616.     if args.list or args.server:
  617.         servers = closestServers(config['client'], True)
  618.         if args.list:
  619.             serverList = []
  620.             for server in servers:
  621.                 line = ('%(id)4s) %(sponsor)s (%(name)s, %(country)s) '
  622.                         '[%(d)0.2f km]' % server)
  623.                 serverList.append(line)
  624.             print_('\n'.join(serverList).encode('utf-8', 'ignore'))
  625.             sys.exit(0)
  626.     else:
  627.         servers = closestServers(config['client'])
  628.  
  629.     if not args.simple:
  630.         print_('Testing from %(isp)s (%(ip)s)...' % config['client'])
  631.  
  632.     if args.server:
  633.         try:
  634.             best = getBestServer(filter(lambda x: x['id'] == args.server,
  635.                                         servers))
  636.         except IndexError:
  637.             print_('Invalid server ID')
  638.             sys.exit(1)
  639.     elif args.mini:
  640.         name, ext = os.path.splitext(args.mini)
  641.         if ext:
  642.             url = os.path.dirname(args.mini)
  643.         else:
  644.             url = args.mini
  645.         urlparts = urlparse(url)
  646.         try:
  647.             request = build_request(args.mini)
  648.             f = urlopen(request)
  649.         except:
  650.             print_('Invalid Speedtest Mini URL')
  651.             sys.exit(1)
  652.         else:
  653.             text = f.read()
  654.             f.close()
  655.         extension = re.findall('upload_extension: "([^"]+)"', text.decode())
  656.         if not extension:
  657.             for ext in ['php', 'asp', 'aspx', 'jsp']:
  658.                 try:
  659.                     request = build_request('%s/speedtest/upload.%s' %
  660.                                             (args.mini, ext))
  661.                     f = urlopen(request)
  662.                 except:
  663.                     pass
  664.                 else:
  665.                     data = f.read().strip()
  666.                     if (f.code == 200 and
  667.                             len(data.splitlines()) == 1 and
  668.                             re.match('size=[0-9]', data)):
  669.                         extension = [ext]
  670.                         break
  671.         if not urlparts or not extension:
  672.             print_('Please provide the full URL of your Speedtest Mini server')
  673.             sys.exit(1)
  674.         servers = [{
  675.             'sponsor': 'Speedtest Mini',
  676.             'name': urlparts[1],
  677.             'd': 0,
  678.             'url': '%s/speedtest/upload.%s' % (url.rstrip('/'), extension[0]),
  679.             'latency': 0,
  680.             'id': 0
  681.         }]
  682.         try:
  683.             best = getBestServer(servers)
  684.         except:
  685.             best = servers[0]
  686.     else:
  687.         if not args.simple:
  688.             print_('Selecting best server based on latency...')
  689.         best = getBestServer(servers)
  690.  
  691.     if not args.simple:
  692.         print_(('Hosted by %(sponsor)s (%(name)s) [%(d)0.2f km]: '
  693.                '%(latency)s ms' % best).encode('utf-8', 'ignore'))
  694.     else:
  695.         print_('Ping: %(latency)s ms' % best)
  696.  
  697.     sizes = [350, 500, 750, 1000, 1500, 2000, 2500, 3000, 3500, 4000]
  698.     urls = []
  699.     for size in sizes:
  700.         for i in range(0, 4):
  701.             urls.append('%s/random%sx%s.jpg' %
  702.                         (os.path.dirname(best['url']), size, size))
  703.     if not args.simple:
  704.         print_('Testing download speed', end='')
  705.     dlspeed = downloadSpeed(urls, args.simple)
  706.     if not args.simple:
  707.         print_()
  708.     print_('Download: %0.2f M%s/s' %
  709.            ((dlspeed / 1000 / 1000) * args.units[1], args.units[0]))
  710.  
  711.     sizesizes = [int(.25 * 1000 * 1000), int(.5 * 1000 * 1000)]
  712.     sizes = []
  713.     for size in sizesizes:
  714.         for i in range(0, 25):
  715.             sizes.append(size)
  716.     if not args.simple:
  717.         print_('Testing upload speed', end='')
  718.     ulspeed = uploadSpeed(best['url'], sizes, args.simple)
  719.     if not args.simple:
  720.         print_()
  721.     print_('Upload: %0.2f M%s/s' %
  722.            ((ulspeed / 1000 / 1000) * args.units[1], args.units[0]))
  723.  
  724.     if args.share and args.mini:
  725.         print_('Cannot generate a speedtest.net share results image while '
  726.                'testing against a Speedtest Mini server')
  727.     elif args.share:
  728.         dlspeedk = int(round((dlspeed / 1000) * 8, 0))
  729.         ping = int(round(best['latency'], 0))
  730.         ulspeedk = int(round((ulspeed / 1000) * 8, 0))
  731.  
  732.         # Build the request to send results back to speedtest.net
  733.         # We use a list instead of a dict because the API expects parameters
  734.         # in a certain order
  735.         apiData = [
  736.             'download=%s' % dlspeedk,
  737.             'ping=%s' % ping,
  738.             'upload=%s' % ulspeedk,
  739.             'promo=',
  740.             'startmode=%s' % 'pingselect',
  741.             'recommendedserverid=%s' % best['id'],
  742.             'accuracy=%s' % 1,
  743.             'serverid=%s' % best['id'],
  744.             'hash=%s' % md5(('%s-%s-%s-%s' %
  745.                              (ping, ulspeedk, dlspeedk, '297aae72'))
  746.                             .encode()).hexdigest()]
  747.  
  748.         headers = {'Referer': 'http://c.speedtest.net/flash/speedtest.swf'}
  749.         request = build_request('://www.speedtest.net/api/api.php',
  750.                                 data='&'.join(apiData).encode(),
  751.                                 headers=headers)
  752.         f, e = catch_request(request)
  753.         if e:
  754.             print_('Could not submit results to speedtest.net: %s' % e)
  755.             sys.exit(1)
  756.         response = f.read()
  757.         code = f.code
  758.         f.close()
  759.  
  760.         if int(code) != 200:
  761.             print_('Could not submit results to speedtest.net')
  762.             sys.exit(1)
  763.  
  764.         qsargs = parse_qs(response.decode())
  765.         resultid = qsargs.get('resultid')
  766.         if not resultid or len(resultid) != 1:
  767.             print_('Could not submit results to speedtest.net')
  768.             sys.exit(1)
  769.  
  770.         print_('Share results: %s://www.speedtest.net/result/%s.png' %
  771.                (scheme, resultid[0]))
  772.  
  773.  
  774. def main():
  775.     try:
  776.         speedtest()
  777.     except KeyboardInterrupt:
  778.         print_('\nCancelling...')
  779.  
  780.  
  781. if __name__ == '__main__':
  782.     main()
  783.  
  784. # vim:ts=4:sw=4:expandtab
Advertisement
Add Comment
Please, Sign In to add comment