Advertisement
ardann

[PYTHON] [SPEED TEST] [LINUX]

Dec 27th, 2017
204
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 15.86 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # Copyright 2013 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. try:
  19.     from urllib2 import urlopen, Request
  20. except ImportError:
  21.     from urllib.request import urlopen, Request
  22.  
  23. import math
  24. import time
  25. import os
  26. import sys
  27. import threading
  28. import re
  29. from xml.dom import minidom as DOM
  30.  
  31. try:
  32.     from Queue import Queue
  33. except ImportError:
  34.     from queue import Queue
  35.  
  36. try:
  37.     from urlparse import urlparse
  38. except ImportError:
  39.     from urllib.parse import urlparse
  40.  
  41. try:
  42.     from urlparse import parse_qs
  43. except ImportError:
  44.     try:
  45.         from urllib.parse import parse_qs
  46.     except ImportError:
  47.         from cgi import parse_qs
  48.  
  49. try:
  50.     from hashlib import md5
  51. except ImportError:
  52.     from md5 import md5
  53.  
  54. try:
  55.     from argparse import ArgumentParser as ArgParser
  56. except ImportError:
  57.     from optparse import OptionParser as ArgParser
  58.  
  59. try:
  60.     import builtins
  61. except ImportError:
  62.     def print_(*args, **kwargs):
  63.         """The new-style print function taken from
  64.        https://pypi.python.org/pypi/six/
  65.  
  66.        """
  67.         fp = kwargs.pop("file", sys.stdout)
  68.         if fp is None:
  69.             return
  70.  
  71.         def write(data):
  72.             if not isinstance(data, basestring):
  73.                 data = str(data)
  74.             fp.write(data)
  75.  
  76.         want_unicode = False
  77.         sep = kwargs.pop("sep", None)
  78.         if sep is not None:
  79.             if isinstance(sep, unicode):
  80.                 want_unicode = True
  81.             elif not isinstance(sep, str):
  82.                 raise TypeError("sep must be None or a string")
  83.         end = kwargs.pop("end", None)
  84.         if end is not None:
  85.             if isinstance(end, unicode):
  86.                 want_unicode = True
  87.             elif not isinstance(end, str):
  88.                 raise TypeError("end must be None or a string")
  89.         if kwargs:
  90.             raise TypeError("invalid keyword arguments to print()")
  91.         if not want_unicode:
  92.             for arg in args:
  93.                 if isinstance(arg, unicode):
  94.                     want_unicode = True
  95.                     break
  96.         if want_unicode:
  97.             newline = unicode("\n")
  98.             space = unicode(" ")
  99.         else:
  100.             newline = "\n"
  101.             space = " "
  102.         if sep is None:
  103.             sep = space
  104.         if end is None:
  105.             end = newline
  106.         for i, arg in enumerate(args):
  107.             if i:
  108.                 write(sep)
  109.             write(arg)
  110.         write(end)
  111. else:
  112.     print_ = getattr(builtins, 'print')
  113.     del builtins
  114.  
  115.  
  116. def distance(origin, destination):
  117.     """Determine distance between 2 sets of [lat,lon] in km"""
  118.  
  119.     lat1, lon1 = origin
  120.     lat2, lon2 = destination
  121.     radius = 6371  # km
  122.  
  123.     dlat = math.radians(lat2-lat1)
  124.     dlon = math.radians(lon2-lon1)
  125.     a = (math.sin(dlat / 2) * math.sin(dlat / 2) + math.cos(math.radians(lat1))
  126.          * math.cos(math.radians(lat2)) * math.sin(dlon / 2)
  127.          * math.sin(dlon / 2))
  128.     c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
  129.     d = radius * c
  130.  
  131.     return d
  132.  
  133.  
  134. class FileGetter(threading.Thread):
  135.     def __init__(self, url, start):
  136.         self.url = url
  137.         self.result = None
  138.         self.starttime = start
  139.         threading.Thread.__init__(self)
  140.  
  141.     def get_result(self):
  142.         return self.result
  143.  
  144.     def run(self):
  145.         self.result = [0]
  146.         try:
  147.             if (time.time() - self.starttime) <= 10:
  148.                 f = urlopen(self.url)
  149.                 while 1:
  150.                     self.result.append(len(f.read(10240)))
  151.                     if self.result[-1] == 0:
  152.                         break
  153.                 f.close()
  154.         except IOError:
  155.             pass
  156.  
  157.  
  158. def downloadSpeed(files, quiet=False):
  159.     start = time.time()
  160.  
  161.     def producer(q, files):
  162.         for file in files:
  163.             thread = FileGetter(file, start)
  164.             thread.start()
  165.             q.put(thread, True)
  166.             if not quiet:
  167.                 sys.stdout.write('.')
  168.                 sys.stdout.flush()
  169.  
  170.     finished = []
  171.  
  172.     def consumer(q, total_files):
  173.         while len(finished) < total_files:
  174.             thread = q.get(True)
  175.             thread.join()
  176.             finished.append(sum(thread.result))
  177.             del thread
  178.  
  179.     q = Queue(6)
  180.     start = time.time()
  181.     prod_thread = threading.Thread(target=producer, args=(q, files))
  182.     cons_thread = threading.Thread(target=consumer, args=(q, len(files)))
  183.     prod_thread.start()
  184.     cons_thread.start()
  185.     prod_thread.join()
  186.     cons_thread.join()
  187.     return (sum(finished)/(time.time()-start))
  188.  
  189.  
  190. class FilePutter(threading.Thread):
  191.     def __init__(self, url, start, size):
  192.         self.url = url
  193.         chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  194.         data = chars * (int(round(int(size) / 36.0)))
  195.         self.data = ('content1=%s' % data[0:int(size)-9]).encode()
  196.         del data
  197.         self.result = None
  198.         self.starttime = start
  199.         threading.Thread.__init__(self)
  200.  
  201.     def get_result(self):
  202.         return self.result
  203.  
  204.     def run(self):
  205.         try:
  206.             if (time.time() - self.starttime) <= 10:
  207.                 f = urlopen(self.url, self.data)
  208.                 f.read(11)
  209.                 f.close()
  210.                 self.result = len(self.data)
  211.             else:
  212.                 self.result = 0
  213.         except IOError:
  214.             self.result = 0
  215.  
  216.  
  217. def uploadSpeed(url, sizes, quiet=False):
  218.     start = time.time()
  219.  
  220.     def producer(q, sizes):
  221.         for size in sizes:
  222.             thread = FilePutter(url, start, size)
  223.             thread.start()
  224.             q.put(thread, True)
  225.             if not quiet:
  226.                 sys.stdout.write('.')
  227.                 sys.stdout.flush()
  228.  
  229.     finished = []
  230.  
  231.     def consumer(q, total_sizes):
  232.         while len(finished) < total_sizes:
  233.             thread = q.get(True)
  234.             thread.join()
  235.             finished.append(thread.result)
  236.             del thread
  237.  
  238.     q = Queue(6)
  239.     start = time.time()
  240.     prod_thread = threading.Thread(target=producer, args=(q, sizes))
  241.     cons_thread = threading.Thread(target=consumer, args=(q, len(sizes)))
  242.     prod_thread.start()
  243.     cons_thread.start()
  244.     prod_thread.join()
  245.     cons_thread.join()
  246.     return (sum(finished)/(time.time()-start))
  247.  
  248.  
  249. def getAttributesByTagName(dom, tagName):
  250.     elem = dom.getElementsByTagName(tagName)[0]
  251.     return dict(list(elem.attributes.items()))
  252.  
  253.  
  254. def getConfig():
  255.     """Download the speedtest.net configuration and return only the data
  256.    we are interested in
  257.    """
  258.  
  259.     uh = urlopen('http://www.speedtest.net/speedtest-config.php')
  260.     configxml = uh.read()
  261.     if int(uh.code) != 200:
  262.         return None
  263.     uh.close()
  264.     root = DOM.parseString(configxml)
  265.     config = {
  266.         'client': getAttributesByTagName(root, 'client'),
  267.         'times': getAttributesByTagName(root, 'times'),
  268.         'download': getAttributesByTagName(root, 'download'),
  269.         'upload': getAttributesByTagName(root, 'upload')}
  270.  
  271.     del root
  272.     return config
  273.  
  274.  
  275. def closestServers(client, all=False):
  276.     """Determine the 5 closest speedtest.net servers based on geographic
  277.    distance
  278.    """
  279.  
  280.     uh = urlopen('http://www.speedtest.net/speedtest-servers.php')
  281.     serversxml = uh.read()
  282.     if int(uh.code) != 200:
  283.         return None
  284.     uh.close()
  285.     root = DOM.parseString(serversxml)
  286.     servers = {}
  287.     for server in root.getElementsByTagName('server'):
  288.         attrib = dict(list(server.attributes.items()))
  289.         d = distance([float(client['lat']), float(client['lon'])],
  290.                      [float(attrib.get('lat')), float(attrib.get('lon'))])
  291.         attrib['d'] = d
  292.         if d not in servers:
  293.             servers[d] = [attrib]
  294.         else:
  295.             servers[d].append(attrib)
  296.     del root
  297.  
  298.     closest = []
  299.     for d in sorted(servers.keys()):
  300.         for s in servers[d]:
  301.             closest.append(s)
  302.             if len(closest) == 5 and not all:
  303.                 break
  304.         else:
  305.             continue
  306.         break
  307.  
  308.     del servers
  309.     return closest
  310.  
  311.  
  312. def getBestServer(servers):
  313.     """Perform a speedtest.net "ping" to determine which speedtest.net
  314.    server has the lowest latency
  315.    """
  316.  
  317.     results = {}
  318.     for server in servers:
  319.         cum = []
  320.         url = os.path.dirname(server['url'])
  321.         for i in range(0, 3):
  322.             uh = urlopen('%s/latency.txt' % url)
  323.             start = time.time()
  324.             text = uh.read(9)
  325.             total = time.time() - start
  326.             if int(uh.code) == 200 and text == 'test=test'.encode():
  327.                 cum.append(total)
  328.             else:
  329.                 cum.append(3600)
  330.             uh.close()
  331.         avg = round((sum(cum) / 3) * 1000000, 3)
  332.         results[avg] = server
  333.  
  334.     fastest = sorted(results.keys())[0]
  335.     best = results[fastest]
  336.     best['latency'] = fastest
  337.  
  338.     return best
  339.  
  340.  
  341. def speedtest():
  342.     """Run the full speedtest.net test"""
  343.  
  344.     description = (
  345.         'Command line interface for testing internet bandwidth using '
  346.         'speedtest.net.\n'
  347.         '------------------------------------------------------------'
  348.         '--------------\n'
  349.         'https://github.com/sivel/speedtest-cli')
  350.  
  351.     parser = ArgParser(description=description)
  352.     try:
  353.         parser.add_argument = parser.add_option
  354.     except AttributeError:
  355.         pass
  356.     parser.add_argument('--share', action='store_true',
  357.                         help='Generate and provide a URL to the speedtest.net '
  358.                              'share results image')
  359.     parser.add_argument('--simple', action='store_true',
  360.                         help='Suppress verbose output, only show basic '
  361.                              'information')
  362.     parser.add_argument('--list', action='store_true',
  363.                         help='Display a list of speedtest.net servers '
  364.                              'sorted by distance')
  365.     parser.add_argument('--server', help='Specify a server ID to test against')
  366.     parser.add_argument('--mini', help='URL of the Speedtest Mini server')
  367.  
  368.     options = parser.parse_args()
  369.     if isinstance(options, tuple):
  370.         args = options[0]
  371.     else:
  372.         args = options
  373.     del options
  374.  
  375.     if not args.simple:
  376.         print_('================= TEST KECEPATAN SERVER =====================')
  377.     config = getConfig()
  378.  
  379.     if not args.simple:
  380.         print_('Menyambungkan ke Jaringan...')
  381.     if args.list or args.server:
  382.         servers = closestServers(config['client'], True)
  383.         if args.list:
  384.             serverList = []
  385.             for server in servers:
  386.                 line = ('%(id)4s) %(sponsor)s (%(name)s, %(country)s) '
  387.                         '[%(d)0.2f km]' % server)
  388.                 serverList.append(line)
  389.             try:
  390.                 print_('\n'.join(serverList).encode('utf-8', 'ignore'))
  391.             except IOError:
  392.                 pass
  393.             sys.exit(0)
  394.     else:
  395.         servers = closestServers(config['client'])
  396.  
  397.     if not args.simple:
  398.         print_('Testing from %(isp)s (%(ip)s)...' % config['client'])
  399.  
  400.     if args.server:
  401.         try:
  402.             best = getBestServer(filter(lambda x: x['id'] == args.server,
  403.                                         servers))
  404.         except IndexError:
  405.             print_('Invalid server ID')
  406.             sys.exit(1)
  407.     elif args.mini:
  408.         name, ext = os.path.splitext(args.mini)
  409.         if ext:
  410.             url = os.path.dirname(args.mini)
  411.         else:
  412.             url = args.mini
  413.         urlparts = urlparse(url)
  414.         try:
  415.             f = urlopen(args.mini)
  416.         except:
  417.             print_('Invalid Speedtest Mini URL')
  418.             sys.exit(1)
  419.         else:
  420.             text = f.read()
  421.             f.close()
  422.         extension = re.findall('upload_extension: "([^"]+)"', text.decode())
  423.         if not urlparts or not extension:
  424.             print_('Please provide the full URL of your Speedtest Mini server')
  425.             sys.exit(1)
  426.         servers = [{
  427.             'sponsor': 'Speedtest Mini',
  428.             'name': urlparts[1],
  429.             'd': 0,
  430.             'url': '%s/speedtest/upload.%s' % (url.rstrip('/'), extension[0]),
  431.             'latency': 0,
  432.             'id': 0
  433.         }]
  434.         try:
  435.             best = getBestServer(servers)
  436.         except:
  437.             best = servers[0]
  438.     else:
  439.         if not args.simple:
  440.             print_('Mencari Pilihan Server Terdekat...')
  441.         best = getBestServer(servers)
  442.  
  443.     if not args.simple:
  444.         print_('Menghubungkan ke Server %(sponsor)s (%(name)s) [%(d)0.2f km]: '
  445.                '%(latency)s ms' % best)
  446.     else:
  447.         print_('Ping: %(latency)s ms' % best)
  448.  
  449.     sizes = [350, 500, 750, 1000, 1500, 2000, 2500, 3000, 3500, 4000]
  450.     urls = []
  451.     for size in sizes:
  452.         for i in range(0, 4):
  453.             urls.append('%s/random%sx%s.jpg' %
  454.                         (os.path.dirname(best['url']), size, size))
  455.     if not args.simple:
  456.         print_('Test Kecepatan Download...', end='')
  457.     dlspeed = downloadSpeed(urls, args.simple)
  458.     if not args.simple:
  459.         print_()
  460.     print_('Download: %0.2f Mbit/s' % ((dlspeed / 1000 / 1000) * 8))
  461.  
  462.     sizesizes = [int(.25 * 1000 * 1000), int(.5 * 1000 * 1000)]
  463.     sizes = []
  464.     for size in sizesizes:
  465.         for i in range(0, 25):
  466.             sizes.append(size)
  467.     if not args.simple:
  468.         print_('Test Kecepatan Upload...', end='')
  469.     ulspeed = uploadSpeed(best['url'], sizes, args.simple)
  470.     if not args.simple:
  471.         print_()
  472.     print_('Upload: %0.2f Mbit/s' % ((ulspeed / 1000 / 1000) * 8))
  473.  
  474.     if args.share and args.mini:
  475.         print_('Cannot generate a speedtest.net share results image while '
  476.                'testing against a Speedtest Mini server')
  477.     elif args.share:
  478.         dlspeedk = int(round((dlspeed / 1000) * 8, 0))
  479.         ping = int(round(best['latency'], 0))
  480.         ulspeedk = int(round((ulspeed / 1000) * 8, 0))
  481.  
  482.         apiData = [
  483.             'download=%s' % dlspeedk,
  484.             'ping=%s' % ping,
  485.             'upload=%s' % ulspeedk,
  486.             'promo=',
  487.             'startmode=%s' % 'pingselect',
  488.             'recommendedserverid=%s' % best['id'],
  489.             'accuracy=%s' % 1,
  490.             'serverid=%s' % best['id'],
  491.             'hash=%s' % md5(('%s-%s-%s-%s' %
  492.                              (ping, ulspeedk, dlspeedk, '297aae72'))
  493.                             .encode()).hexdigest()]
  494.  
  495.         req = Request('http://www.speedtest.net/api/api.php',
  496.                       data='&'.join(apiData).encode())
  497.         req.add_header('Referer', 'http://c.speedtest.net/flash/speedtest.swf')
  498.         f = urlopen(req)
  499.         response = f.read()
  500.         code = f.code
  501.         f.close()
  502.  
  503.         if int(code) != 200:
  504.             print_('Could not submit results to speedtest.net')
  505.             sys.exit(1)
  506.  
  507.         qsargs = parse_qs(response.decode())
  508.         resultid = qsargs.get('resultid')
  509.         if not resultid or len(resultid) != 1:
  510.             print_('Gagal Melakukan Test Speed')
  511.             sys.exit(1)
  512.  
  513.         print_('Berhasil Melakukan Test Speed. Hasil Bisa dilihat di : https://www.speedtest.net/result/%s.png' %
  514.                resultid[0])
  515.  
  516.  
  517. def main():
  518.     try:
  519.         speedtest()
  520.     except KeyboardInterrupt:
  521.         print_('\nCancelling...')
  522.  
  523. if __name__ == '__main__':
  524.     main()
  525.  
  526. # vim:ts=4:sw=4:expandtab
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement