Projekt se jmenuje dice-counter, ale skoro všude vystupoval jako kostky.
Tohle je první ze dvou kroků podle #16: nová jména se zavádějí vedle
starých, aby běžící instalace nic nerozbilo.
Nově:
binárka a spec dice-counter.spec, dist/dice-counter
přílohy releasu dice-counter-linux-x86_64 a spol.
služba v LXC dice-counter.service
cesty v LXC /opt/dice-counter, /var/lib/dice-counter
uživatel dice-counter
hostname LXC dice-counter
instalátor deploy/pve-dice-counter.sh
datový adresář ~/.local/share/dice-counter a obdoby
co appka hlásí "dice-counter <verze>" v banneru i v patičce
Stará jména zatím fungují dál:
- Přílohy se na release věší pod oběma jmény.
- Instalátor umí stáhnout i kostky-*, takže starší vydání jdou
nainstalovat pořád.
- deploy/pve-kostky.sh zůstává jako přesměrování — příkaz `update`
v už založených kontejnerech chodí pro instalátor právě tam.
- Kontejnery z dřívějška se při aktualizaci přestěhují samy: služba
se přejmenuje a databáze se přesune do /var/lib/dice-counter, takže
o historii her nikdo nepřijde.
- Binárka sáhne po ~/.local/share/kostky/dice.db, dokud nová databáze
neexistuje.
Při zkoušení přechodu vyplavala chyba, která tu byla už předtím: příkaz
`update` si nový instalátor uloží do $HOME_DIR/install.sh a odtud ho
pustí, takže `install -m 755 "$0" "$HOME_DIR/install.sh"` kopírovalo
soubor sám na sebe. install to odmítne, se `set -e` spadl celý update.
Ošetřeno testem `-ef`.
Ověřeno v debianím kontejneru: přechod ze staré instalace (včetně běhu
instalátoru z adresáře, který se během něj maže), čistá instalace, běh
proti releasu, kde je jen stará příloha, a druhé spuštění za sebou.
Refs #16
Dokud se hrálo ze zdrojáků, ležel dice.db v pracovním adresáři a záloha byla
otázka zkopírování. Z binárky se schovává do systémového datového adresáře,
který na Windows běžný člověk nenajde — takže se teď dá stáhnout přes
prohlížeč.
VACUUM INTO udělá konzistentní kopii i uprostřed zápisu, na rozdíl od
prostého přečtení souboru. Kopie se přečte do paměti a hned zahodí, ať
nezůstane ležet v dočasném adresáři, když si ji někdo nestáhne celou.
Flask pod pěkně naformátovanou úvodní hlášku vysypal červené varování, že
tohle není produkční server. Waitress je čistě pythonní, takže ho PyInstaller
zabalí bez řečí, a osm vláken pobere telefony u stolu i tabuli, která se
doptává každé dvě vteřiny.
Cestou se ukázalo, že hláška se nikdy nedostala do přesměrovaného výstupu:
mimo konzoli drží Python výstup v bloku a pouští ho, až program skončí —
jenže server neskončí. Zkouška binárky u Gitey si logovala do souboru a pak
ho vypisovala, takže celou dobu tiskla prázdno. Řeší to řádkové bufferování
v console.utf8(), kam to patří vedle té kódové stránky.
Venku jsou čtyři soubory na release, tři systémy a k tomu zdrojáky. Když
někdo napíše, že mu něco nefunguje, není jak zjistit, co vlastně pustil.
Verzi zapisuje build.sh do verze.txt, kostky.spec ji přibalí a version.py ji
z rozbalené binárky přečte. Ze zdrojáků má přednost git describe, který ví
i o commitech nad tagem a o rozdělané práci. V CI se na tagu vnucuje
proměnnou, protože runner klonuje jeden commit bez značek.
Hlásí se přes --version, v úvodní hlášce serveru a v patičce každé stránky.
Zkouška v obou workflow ověří, že se do binárky opravdu dostala.
Bez zamčených verzí si každá stavba stáhne to, co je zrovna nejnovější:
binárka z dneška a binárka z příštího jara obsahují něco jiného a není jak
zjistit co. Zároveň může vydání kterékoli knihovny rozbít build, aniž by se
sáhlo na řádku kódu — a nejspíš zrovna ve chvíli, kdy se tagne release.
Volné seznamy jsou nově v `.in`, zamčené v `.txt`. Rozděleno na tři: běh,
testy a stavba. Pytest se tak přestane instalovat do prostředí, kde se
staví binárka, a PyInstaller má konečně taky zamčenou verzi — ta na podobu
výsledku sahá ze všech nejvíc.
Zůstává, že se verze píšou i v hlavičce PEP 723, jinak by přestalo fungovat
`uv run web.py`. Aby se ta dvě místa nerozešla, hlídá je test.
Windowsová binárka spadla dřív, než stihla vypsat adresu:
print("Počitadlo je dostupné na:")
UnicodeEncodeError: 'charmap' codec can't encode character 'č'
Windows sahá po historické kódové stránce všude, kde výstup není konzole —
přesměrovaný do souboru, puštěný ze skriptu, ve frontě CI. První háček nad
takovým proudem shodí celý program.
Oba vstupní body si teď výstup přepnou na UTF-8. Na konzoli i na ostatních
systémech je to prázdná operace, protože tam je UTF-8 dávno výchozí.
Pojistka errors="replace" je pro zbytek případů: rozsypaný háček je pořád
lepší než spadlý server.
Chytila to zkouška po stavbě, ne uživatel. Test to reprodukuje přes
TextIOWrapper s cp1252, takže se to bez opravy neprojde ani na Linuxu.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Tabule dosud zbylé adresy jen vypsala, ale naskenovat se dala pouze ta
první. Teď se na ně dá kliknout: vybraná se přesune nahoru velkým písmem,
QR kód se přepne na ni a ta předchozí se objeví v seznamu, takže se dá
kroužit dokola.
Kódy jsou vykreslené všechny předem a přepíná se jen ten viditelný —
žádné doptávání serveru, žádná QR knihovna na klientovi. Aby to stránku
nenafouklo, skládá se SVG ze souvislých úseků místo jednotlivých
čtverečků; tabule se třemi adresami má 23 kB.
Otisk v data-address zahrnuje všechny adresy, ne jen tu první. Když se
změní kterákoli z nich, nabídka i QR kódy jsou k ničemu a tabule se
načte znovu.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Stáhni a spusť: jednosouborová binárka pro Linux, uvnitř Python, Flask,
šablony i styly. Staví se ./build.sh v kontejneru na AlmaLinux 8, protože
binárka slinkovaná proti glibc z Fedory 44 by nešla spustit nikde se
starším systémem.
Databáze tím dostává dvě různá místa. Ze zdrojáků zůstává dice.db
v pracovním adresáři, ať se dá mít víc sad vedle sebe. Z binárky jde do
~/.local/share/kostky/ — binárka se rozbaluje do dočasného adresáře
a pouští se odkudkoli, takže relativní cesta by databázi rozsypala po
disku. DICE_DB přebije obojí.
Server teď cestu k databázi vypisuje při startu, ať se na ni nemusí ptát.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Trojice venv/pip/python byla zbytečná ceremonie pro appku, která se pouští
jednou za herní večer.
- web.py i dice.py si nesou závislosti v hlavičce podle PEP 723, takže
je uv obstará sám a není co instalovat ani aktivovat
- pytest.ini staví kořen repa na pythonpath, takže testy jdou spustit
i mimo připravené prostředí
- README nabízí uv jako hlavní cestu, venv a systémové balíčky jako
záložní
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Detekce vracela jedinou adresu podle výchozí trasy. Když ta nevede tam,
kam je připojený telefon, QR kód míří do prázdna a nezbývá než sahat do
konfigurace. Při ladění se ukázalo i to, že záložní větev může vrátit
127.0.0.1, tedy QR kód na localhost.
- net.py hledá adresy všech rozhraní přes if_nameindex a ioctl, se zálohou
přes getaddrinfo; DICE_HOST má poslední slovo
- řadí se podle rozsahu adresy a obecného typu rozhraní, ne podle seznamu
konkrétních jmen: výchozí trasa, místní sítě, tailnet, virtuální sítě
- loopback a link-local vypadnou, nic dalšího se nezahazuje — o tom, co
funguje, rozhoduje člověk u stolu
- tailnet adresu vědomě necháváme: funguje i napříč sítěmi
- adresy se hledají při každém načtení; když se notebook přesune na jinou
síť, tabule to pozná podle data-address a načte se znovu
- když se nenajde nic, tabule řekne, co s tím, místo QR kódu naslepo
- 20 testů nad klasifikací a řazením, nezávislých na aktuální síti
- README doplněn o řešení potíží s připojením
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Po sto kolech byla tabule k ničemu: na obrazovku se vešla kola 1–14
a řádek se součty skončil asi 4 500 pixelů pod okrajem. Tabule tedy
ukazovala nejstarší historii a nic z toho, co se právě děje.
- kola se řadí od nejnovějšího, poslední zápis je vždy nahoře
- součty se přesunuly z patičky nad historii, hned pod jména hráčů
- tabule ukazuje posledních 15 kol, zbytek shrne řádka "... a dalších
85 kol"; má ukazovat stav, ne archiv, a nepřekresluje se pak zbytečně
každé dvě vteřiny přes tři sta buněk
- skloňování kol podle češtiny (1 kolo / 2 kola / 5 kol)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- rekordy: nejvyšší tah, nejvyšší konečné skóre, nejrychlejší výhra
- kariéra: počet her, výher, úspěšnost, průměrné pořadí, průměr na tah
a kolikrát koho postihlo vynulování
- do statistik jdou jen dohrané hry, nedohrané a opuštěné se ignorují
- celkové skóre počítá SQL stejným pravidlem jako core.Game.totals(),
tedy součet tahů po posledním vynulování; testem ověřeno, že se obě
cesty shodují
- vědomě chybí celkový součet bodů napříč hrami — cílové skóre je u každé
hry jiné, metrika by odměňovala jen toho, kdo hrál nejvíc
- README se spuštěním a přehledem modulů
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Flask, server-rendered HTML, formuláře přes POST/redirect/GET.
Žádný build step, žádný JS framework.
- / zakládá hru výběrem známých hráčů v pořadí u stolu
- /game/<id> je zadávací pohled: kdo je na tahu, skóre, x/xx,
průběžné pořadí, vrácení posledního zápisu
- /board/<id> je zápisník po kolech; tahy před vynulováním se škrtnou
červeně, sloupec hráče na tahu drží zvýrazňovač
- tabule se doptává serveru každé dvě vteřiny a vyměňuje jen hlavičku
a zápisník, QR s adresou zůstává mimo obnovovanou část
- adresa pro telefon se hledá za běhu, QR se skládá ze čtverečků
přímo do SVG, takže není potřeba Pillow
- 16 funkčních testů přes Flask test client
Vizuálně to stojí na tom, co appka nahrazuje: čtverečkovaný papír,
modrá propiska zapisuje, červená škrtá, zvýrazňovač drží tah.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>