diff --git a/dokumentace.md b/dokumentace.md new file mode 100644 index 0000000000000000000000000000000000000000..28753e5d046d79e16b4aa68cd4e9c1e0ed8d7fd9 --- /dev/null +++ b/dokumentace.md @@ -0,0 +1,169 @@ +# Koncepce + +Projekt na zpracování a vizualizaci zaznamenaných skutečných poloh spojů PID. +Zdrojem dat je [Golemio open API](https://api.golemio.cz/pid/docs/openapi/#/%F0%9F%9B%A4%20PID%20Realtime%20Positions/get_vehiclepositions) a data z jízdních řádů ve formátu GTFS. + +Projekt se skládá ze dvou částí – serveru a klienta. +Server se stará o stahování dat, které pak poskytuje klientovi, který je graficky zobrazuje uživateli. + +Celý projekt je psaný v Pythonu3 pomocí asynchronní knihovny [asincio](https://docs.python.org/3/library/asyncio.html). +Grafické rozhraní je v [Qt5](https://doc.qt.io/qt-5/qt5-intro.html). +Pro mapovou část klienta je využit [QGis](https://www.qgis.org/), +jež lze pomocí [pythonního API](https://docs.qgis.org/3.34/en/docs/pyqgis_developer_cookbook/index.html) integrovat do Qt. + +Serverová část běží pod [pypy3](https://pypy.org/), klient z důvodu limitací QGisem je spouštěn klasicky pomocí [CPythonu](https://en.wikipedia.org/wiki/CPython). +Podporované verze Pythonu jsou 3.10 až 3.12. + +## Server + +Server periodicky stahuje data aktuálních poloh pomocí API a provádí na nich předzpracování. +Klientům pak nabízí zpracovaná data a případně dopočítá jednoduché výpočty z nich, aby +se snižoval objem přenesených dat. + +### Struktura dat + +Adresářová struktura serveru obsahuje následující data + +- Aktuální verzi jízdního řádu stahovaného z <https://data.pid.cz/PID_GTFS.zip> + uloženou v `data/gtfs/%Y-%m-%d`. + PID data každý den aktualizuje o výluky, takže dává smysl vždy pracovat s v + daný moment aktuální verzí. + + Na stažených datech se ještě dělá drobný preprocessing – zejména rozdělení + velkých souborů na menší, snadněji zpracovatelné, jako například rozdělení + plánovaných tras z `shapes.txt` na jednotlivé trasy do `shape_by_id/<id>`. + +- Data aktuálních poloh stažená z API v `data/realtime/%Y-%m-%d/%h/%m-%s.json.zst`. + Data jsou komprimovaná pomocí `zstd -8`, aby jejich skladování bylo úspornější. + API sice nově[^1] podporuje možnost komprimované odpovědi, ale pouze pomocí gzipu level 6, + který nemá tak dobrý kompresní poměr. + +- Předzpracovaná data pro rychlejší dotazy agregovaná přes jednotlivé linky (část `trip_id` po první `_`) + uložená v `data/realtime_by_route/%Y-%m-%d/%h/<route_id>` + K těmto datům se navíc doplňují informace o ujeté vzdálenosti po plánované trase spoje pomocí vlastního algoritmu[^2]. + +[^1]: V době odevzdání práce asi tři dny. + +[^2]: API již sice také tuto informaci obsahuje, ale moc není jasné, jak se počítá, proto byla doplněna vlastní, do budoucna rozšiřitelná, implementace. + +### Struktura serveru + +Server se skládá z několika procesů, které spolu komunikují jednak pomocí unix socketů, +druhak pomocí dat uložených ve file systému. + +Klient se k serveru připojuje pomocí [`MainServer`](`prog/server.py`). +Těch současně může být spuštěno několik. +`MainServer` některé požadavky od klienta vyřídí pohledem do uložených dat (jako například dotaz na polohy vozidel před několika dny), +jiné řeší přeposláním dotazu na některý z procesů serveru. + +O stahování dat z API se stará <prog/download_server.py>. +Ten jednou za 10 sekund pošle požadavek na API, výstup pak zkomprimuje a uloží. +Proces dále nabízí možnost připojení pomocí `DownloadServer`u, který +umožňuje ostatním procesům ptát se na poslední obdržená data, +případně si objednat dodání dalších dat, jakmile budou staženy. + +Generování předzpracovaných dat má na starosti <prog/preprocess.py>. +Ten si od DownloadServeru nebo z file systému získává data, na nich počítá mimo jiné polohy spoje na plánované trase. +Také nabízí klientům možnost dotazu na data, která zrovna uchovává – konkrétně na aktuálně tvořené soubory agregací. + +Pro lepší orientaci snad pomůže přiložený obrázek: + + + + +### Komunikační protokol + +Pro komunikaci mezi serverem a klientem a mezi procesu serveru se +využívá vlastní protokol, který může běhat po libovolné spojované binární spolehlivé vrstvě +(unix socket, SSH, TCP, TLS, dvojice pipe, ...). + +Referenční implementace protokolu je v <prog/communication.py>. + +#### Vrstva zpráv + +Viz `MsgParser` a `msg`. + +Komunikace se sestává ze zpráv – každá zpráva obsahuje hlavičku a samotná data. +serializace zprávy je následující: +- 5 bajtů délka hlavičky zapsaná a ASCII v desítkové soustavě +- 12 bajtů délka dat zapsaná a ASCII v desítkové soustavě +- hlavička určené délky +- data určené délky + +Hlavička se zpravidla medializuje jako json, data pomocí cbor2, +ovšem vyšší vrstvy mohou dle potřeby určit jinak. + +#### Vrstva odpovědí + +Viz `Client` a `Server`. + +Tázající v hlavičce nastaví pro dané spojení unikátní `['id']: int` +a se stejným `id` mu pak dorazí odpověď. + +V hlavičce dotazu i odpovědi se mohou nacházet i jiné klíče vyšších vrstev komunikace. + +#### Vrstva volání funkcí + +Viz `FuncCaller`. + +Hlavička dotazu obsahuje `['func_name']: str` – jméno volané funkce/endpointu a data pak obsahují +parametry dotazu uložené pomocí cbor2 struktury `{'args': args, 'kwargs': kwargs}`. +Odpověď pak obsahuje v datech `{'return': return_value}` serializované pomocí cbor2. + +Projekt do tohoto protokolu obaluje volaní metod objektů. +Každý server je implementovaný pomocí jedné třídy. +Její instance mohou být dvou typů – lokální, pak se volání všech funkcí vyhodnocuje ihned v daném +programu, nebo vzdálená pro daný server – pak se vyhodnocení metod dekorovaných pomocí `@server_exec()` vyhodnocuje na příslušném serveu +pomocí výše uvedeného protokolu. + +Dále je možné pořídit si druhý nezávislý server a pomocí <prog/data_mover.py> +pak z něj stahovat chybějící data na primárním serveru a odmazávat stará data. + +## Klient + + + + +# Instalace serveru + +Na serveru je nutné mít dostatek diskového prostoru (zhruba 2 GB na každý den archivované historie), +dostatečné množství RAM (alespoň 8 GB) a dostupného výkonu (zejména na počítání poloh na plánované trase). +Samotný download server bez předvýpočtů je méně náročný. + +Server předpokládá UNIXový operační systém (testováno na raspbianu a arch linuxu). + +Je nutné nainstalovat `pypy3` včetně vývojového balíčků nutného pro kompilaci numpy (pokud je vyčleněný). +Dále se od systému očekává nainstalované `zstd`. + +Celý server pak bude žít v adresáři tohoto gitového projektu. + +Dále je nutné vytvořit pythonní virtuální prostředí a nainstalovat do něj potřebné balíčky: + +``` +pypy3 -m venv venv + +pip install cbor2 caio numpy +``` + +... a vytvořit pracovní adresáře: + +``` +mkdir sockets data tmp data/{gtfs,realtime,realtime_by_route} +``` + +Pak už stačí jen spustit příslušné servery. V `systemd/init.sh` je script, který se vytvoří a spustí systemd user services na jejich běh. + +# Instalace klienta + + +Pro běh klienta je nutné nainstalovat python, QGis (pyqgis), Qt5 (PyQt), python-cbor2, python-qasync, python-matplotlib a zstd. + +Dále je nutné mít přístup na server, ten se konfiguruje v `prog/client-config.py` (vzor v `prog/client-config.py.example`). + +Klient se spouští pomocí `prog/main.py`. + +# Ovládání klienta + +TODO + +