Advertisement
koriar

Untitled

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