Skip to content
Snippets Groups Projects
Commit 3fe02852 authored by Jiří Kalvoda's avatar Jiří Kalvoda
Browse files

Init dokumentace

parent cd71ff3d
No related branches found
No related tags found
No related merge requests found
# 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:
![Schéma projektu](schema.pdf)
### 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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment