Skip to content

Commit

Permalink
A bit of work towards supporting multiple backends + set the user age…
Browse files Browse the repository at this point in the history
…nt's version properly
  • Loading branch information
Ketok4321 committed Sep 10, 2023
1 parent db0bf1a commit ca60a06
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 123 deletions.
114 changes: 114 additions & 0 deletions src/backends/librespeed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import time
import io
import os
import asyncio
import aiohttp

from urllib.parse import urljoin

DOWNLOAD_SIZE = 100
UPLOAD_SIZE = 20

garbage = os.urandom(UPLOAD_SIZE * 1000 * 1000)

class GarbageReader(io.IOBase):
def __init__(self, read_callback=None):
self.__read_callback = read_callback
super().__init__()
self.length = len(garbage)
self.pos = 0

def seekable(self):
return True

def writable(self):
return False

def readable(self):
return True

def tell(self):
return self.pos

def read(self, size=None):
if not size:
size = self.length - self.tell()

old_pos = self.tell()
self.pos = old_pos + size

if self.__read_callback:
self.__read_callback(size)

return garbage[old_pos:self.pos]

class LibrespeedServer:
def __init__(self, name, server, pingURL, dlURL, ulURL, **_):
if not (server.startswith("https:") or server.startswith("http:")):
server = "https:" + server

self.name = name
self.server = server
self.pingURL = urljoin(server + "/", pingURL)
self.downloadURL = urljoin(server + "/", dlURL)
self.uploadURL = urljoin(server + "/", ulURL)

class LibrespeedBackend:
def __init__(self, user_agent):
self.headers = {
"Accept-Encoding": "identity",
"User-Agent": user_agent,
}

async def get_servers(self):
async def check_server(server):
async with aiohttp.ClientSession() as session:
try:
start = time.time()
async with session.get(server.pingURL, timeout=aiohttp.ClientTimeout(total=0.75)) as _:
server.ping = time.time() - start # TODO: Don't mutate.
except (aiohttp.ClientError, asyncio.TimeoutError):
server.ping = -1

async with aiohttp.ClientSession() as session:
async with session.get("https://librespeed.org/backend-servers/servers.php") as response:
servers = await response.json()
servers = list(map(lambda x: LibrespeedServer(**x), servers))

await asyncio.gather(*[check_server(s) for s in servers])

servers = list(filter(lambda s: s.ping != -1, servers))

servers.sort(key=lambda s: s.ping)

return servers

async def ping(self, server):
async with aiohttp.ClientSession() as session:
pings = []
jitters = []
for i in range(10):
start = time.time()
async with session.get(server.pingURL, headers=self.headers) as _:
pings.append(time.time() - start)

if i != 0:
jitters.append(abs(pings[i] - pings[i - 1]))
return sum(pings) / len(pings) * 1000, sum(jitters) / len(jitters) * 1000

async def download(self, server, total):
async with aiohttp.ClientSession() as session:
while True:
async with session.get(server.downloadURL + "?ckSize=" + str(DOWNLOAD_SIZE), headers=self.headers) as response:
async for data in response.content.iter_any():
total[0] += len(data)

async def upload(self, server, total):
def callback(size):
total[0] += size

async with aiohttp.ClientSession() as session:
while True:
reader = GarbageReader(callback)
async with session.post(server.uploadURL, headers=self.headers, data=reader) as response:
await response.read()
7 changes: 4 additions & 3 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@

from .window import SpeedtestWindow
from .gauge import Gauge # This class isn't used there but it the widget needs to be registered
from .speedtest import get_servers
from .backends.librespeed import LibrespeedBackend
from .speedtest_worker import SpeedtestWorker

class SpeedtestApplication(Adw.Application):
def __init__(self, version):
super().__init__(application_id="xyz.ketok.Speedtest", flags=Gio.ApplicationFlags.DEFAULT_FLAGS)

self.backend = LibrespeedBackend(f"KetokSpeedtest/{version}")
self.servers = None
self.win = None
self.version = version
Expand Down Expand Up @@ -46,7 +47,7 @@ def fetch_servers(self):
self.servers = []
while len(self.servers) == 0: # A proper fix would probably be better but this works too
print("Trying to fetch servers...")
self.servers = event_loop.run_until_complete(get_servers())
self.servers = event_loop.run_until_complete(self.backend.get_servers())

event_loop.close()

Expand Down Expand Up @@ -79,7 +80,7 @@ def on_start_action(self, widget, _):
self.win.test_view.reset()
self.win.test_view.server = server.name

self.worker = SpeedtestWorker(self.win, server)
self.worker = SpeedtestWorker(self.backend, self.win, server)
self.worker.start()

def on_back_action(self, widget, _):
Expand Down
6 changes: 5 additions & 1 deletion src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,13 @@ configure_file(
speedtest_sources = [
'main.py',
'window.py',
'speedtest.py',
'gauge.py',
'speedtest_worker.py',
]

backends_sources = [
'backends/librespeed.py',
]

install_data(speedtest_sources, install_dir: moduledir)
install_data(backends_sources, install_dir: join_paths(moduledir, 'backends'))
112 changes: 0 additions & 112 deletions src/speedtest.py

This file was deleted.

13 changes: 6 additions & 7 deletions src/speedtest_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@

from gi.repository import GLib

from .speedtest import ping, download, upload

DURATION = 15
DL_STREAMS = 6
UP_STREAMS = 3
OVERHEAD_COMPENSATION = 1.06

class SpeedtestWorker(threading.Thread):
def __init__(self, win, server):
def __init__(self, backend, win, server):
super().__init__(name="SpeedtestWorker", daemon=True)

self.stop_event = threading.Event()
self.backend = backend
self.win = win
self.server = server

Expand Down Expand Up @@ -47,23 +46,23 @@ async def do_run(self):
try:
view = self.win.test_view

_ping, jitter = await ping(self.server)
ping, jitter = await self.backend.ping(self.server)

GLib.idle_add(view.update_ping, _ping, jitter)
GLib.idle_add(view.update_ping, ping, jitter)

GLib.idle_add(view.progress.remove_css_class, "up")
GLib.idle_add(view.progress.add_css_class, "dl")
GLib.idle_add(view.download.add_css_class, "active")
timeout = GLib.timeout_add(1000 / 30, lambda: self.update(view.download, False))
await self.perform_test(download, DL_STREAMS)
await self.perform_test(self.backend.download, DL_STREAMS)
GLib.idle_add(view.download.remove_css_class, "active")
GLib.source_remove(timeout)

GLib.idle_add(view.progress.remove_css_class, "dl")
GLib.idle_add(view.progress.add_css_class, "up")
GLib.idle_add(view.upload.add_css_class, "active")
timeout = GLib.timeout_add(1000 / 30, lambda: self.update(view.upload, True))
await self.perform_test(upload, UP_STREAMS)
await self.perform_test(self.backend.upload, UP_STREAMS)
GLib.idle_add(view.upload.remove_css_class, "active")
GLib.source_remove(timeout)
except Exception as e:
Expand Down

0 comments on commit ca60a06

Please sign in to comment.