diff --git a/.vs/ProjectSettings.json b/.vs/ProjectSettings.json new file mode 100644 index 0000000..f8b4888 --- /dev/null +++ b/.vs/ProjectSettings.json @@ -0,0 +1,3 @@ +{ + "CurrentProjectSetting": null +} \ No newline at end of file diff --git a/.vs/PythonSettings.json b/.vs/PythonSettings.json new file mode 100644 index 0000000..40738ec --- /dev/null +++ b/.vs/PythonSettings.json @@ -0,0 +1,3 @@ +{ + "Interpreter": "Global|PythonCore|3.11" +} \ No newline at end of file diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json new file mode 100644 index 0000000..6b61141 --- /dev/null +++ b/.vs/VSWorkspaceState.json @@ -0,0 +1,6 @@ +{ + "ExpandedNodes": [ + "" + ], + "PreviewInSolutionExplorer": false +} \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 0000000..20c232f Binary files /dev/null and b/.vs/slnx.sqlite differ diff --git a/.vs/speedtest-cli/FileContentIndex/52ea1fff-b95a-4a8a-b802-2ddc4ac591f9.vsidx b/.vs/speedtest-cli/FileContentIndex/52ea1fff-b95a-4a8a-b802-2ddc4ac591f9.vsidx new file mode 100644 index 0000000..7ea9467 Binary files /dev/null and b/.vs/speedtest-cli/FileContentIndex/52ea1fff-b95a-4a8a-b802-2ddc4ac591f9.vsidx differ diff --git a/.vs/speedtest-cli/v17/.wsuo b/.vs/speedtest-cli/v17/.wsuo new file mode 100644 index 0000000..345b993 Binary files /dev/null and b/.vs/speedtest-cli/v17/.wsuo differ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..a15689b --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,32 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: downloade single", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/speedtest.py", + "console": "integratedTerminal", + "args": [ + "--csv", + "--json" + ], + // "linux": { + // "MIMode": "gdb", + // "miDebuggerPath": "/usr/bin/gdb" + // }, + // "osx": { + // "MIMode": "lldb" + // }, + // "windows": { + // "MIMode": "gdb", + // "miDebuggerPath": "C:\\MinGw\\bin\\gdb.exe" + // } + // "cwd": "${workspaceFolder}", + "justMyCode": false + } + ] +} \ No newline at end of file diff --git a/output.csv b/output.csv new file mode 100644 index 0000000..ea7b55c --- /dev/null +++ b/output.csv @@ -0,0 +1,2 @@ +download,upload,ping,server_url,server_lat,server_lon,server_name,server_country,server_cc,server_sponsor,server_id,server_host,server_d,server_latency,timestamp,bytes_sent,bytes_received,share,client_ip,client_lat,client_lon,client_isp,client_isprating,client_rating,client_ispdlavg,client_ispulavg,client_loggedin,client_country +0,0,6.93,http://ookla-osl.net.avur.no:8080/speedtest/upload.php,59.9494,10.7564,Oslo,Norway,NO,AVUR AS,18967,ookla-osl.net.avur.no:8080,5.7463776547060155,6.93,2024-01-01T21:26:53.963606Z,0,0,,84.215.59.36,59.955,10.859,Telia Norge AS,3.7,0,0,0,0,NO diff --git a/speedtest.py b/speedtest.py index 186b529..ff7207a 100755 --- a/speedtest.py +++ b/speedtest.py @@ -28,6 +28,8 @@ import sys import threading import timeit import xml.parsers.expat +import utilities + try: import gzip @@ -1830,6 +1832,7 @@ def printer(string, quiet=False, debug=False, error=False, **kwargs): if not quiet: print_(out, **kwargs) + # return str(out) def shell(): @@ -1940,6 +1943,9 @@ def shell(): speedtest.get_best_server(speedtest.set_mini_server(args.mini)) results = speedtest.results + # print(dict(str(results))) + # os.makedirs('tmp', exist_ok=True) + utilities.write_to_csv(str(results)) printer('Hosted by %(sponsor)s (%(name)s) [%(d)0.2f km]: ' '%(latency)s ms' % results.server, quiet) diff --git a/tmp/speedtest.log b/tmp/speedtest.log new file mode 100644 index 0000000..93c2de5 --- /dev/null +++ b/tmp/speedtest.log @@ -0,0 +1 @@ +{'download': 0, 'upload': 0, 'ping': 9.319, 'server': {'url': 'http://speedtest.nextgentel.no:8080/speedtest/upload.php', 'lat': '59.9494', 'lon': '10.7564', 'name': 'Oslo', 'country': 'Norway', 'cc': 'NO', 'sponsor': 'NextGenTel AS', 'id': '8018', 'host': 'speedtest.nextgentel.no:8080', 'd': 5.7463776547060155, 'latency': 9.319}, 'timestamp': '2024-01-01T20:06:56.839888Z', 'bytes_sent': 0, 'bytes_received': 0, 'share': None, 'client': {'ip': '84.215.59.36', 'lat': '59.955', 'lon': '10.859', 'isp': 'Telia Norge AS', 'isprating': '3.7', 'rating': '0', 'ispdlavg': '0', 'ispulavg': '0', 'loggedin': '0', 'country': 'NO'}} diff --git a/utilities.py b/utilities.py new file mode 100644 index 0000000..37ca76b --- /dev/null +++ b/utilities.py @@ -0,0 +1,103 @@ +import logging +import os +import shutil +import time +import csv +import json + + +def remove_directory(directory_path, n=100): + directory_path = str(directory_path) + if os.path.islink(directory_path): + os.unlink(directory_path) + elif os.path.exists(directory_path): + deleted = False + for i in range(0, n - 1): + try: + shutil.rmtree(directory_path, onerror=on_error) + deleted = True + break + + except OSError as err: + logging.error( + "Error while deleting directory {}, on attempt number {}: {}. Retrying...".format( + directory_path, i, err.strerror + ) + ) + time.sleep(1) + + if not deleted: + shutil.rmtree(directory_path, onerror=on_error) + + +def on_error(func, path, exc_info): + """ + Error handler for ``shutil.rmtree``. + + If the error is due to an access error (read only file) + it attempts to add write permission and then retries. + + If the error is for another reason it re-raises the error. + + Usage : ``shutil.rmtree(path, onerror=on_error)`` + """ + import stat + + if not os.access(path, os.W_OK): + # Is the error an access error ? + os.chmod(path, stat.S_IWUSR) + func(path) + else: + raise + + +def make_directory(directory_path): + directory_path = str(directory_path) + if not os.path.exists(directory_path): + os.makedirs(directory_path) + + +def make_clean_directory(directory_path): + directory_path = str(directory_path) + remove_directory(directory_path) + while os.path.exists(directory_path): + pass + make_directory(directory_path) + while not os.path.exists(directory_path): + pass + + +def delete_file(file): + file = str(file) + if os.path.exists(file): + os.remove(file) + + +def write_to_csv(input_str): + # Convert single quotes to double quotes for valid JSON + input_str = input_str.replace("'", "\"") + + # Convert the input string to a dictionary + input_dict = eval(input_str) + + # Extract keys for the header row + header = [] + for key, value in input_dict.items(): + if isinstance(value, dict): + header.extend([f"{key}_{subkey}" for subkey in value.keys()]) + else: + header.append(key) + + # Extract values for the data row + values = [] + for key, value in input_dict.items(): + if isinstance(value, dict): + values.extend(value.values()) + else: + values.append(value) + + # Write to CSV + with open('output.csv', 'w', newline='') as csvfile: + csv_writer = csv.writer(csvfile) + csv_writer.writerow(header) + csv_writer.writerow(values)