TITLE=WarpEngine Client ROUTE=/stores/warp-engine-client LOCALE=hu MODIFIED=1792417593 URL=https://wiki.teletypegames.org/hu/stores/warp-engine-client L=1 https://git.teletypegames.org/stores/warp-engine-client/releases L=2 #54 L=3 #68 A bWarpEngine Client0 egy WarpEngine-áruház asztali alkalmazása: a katalógus kártyarácsként, egy kattintás telepít egy címet az alkalmazásmenüdbe, egy elindítja, egy eltávolítja. Linux, macOS és Windows. A jelenlegi kiadás a b3.1.00, amely már ismeri a WarpEngine 1.0-t. i[Kép: A WarpEngine Client ablaka: balra az áruház és a szűrőtengelyek, jobbra ia katalógus játékkártyák rácsaként] bAz áruházmotor az alkalmazás része.0 A katalógus beolvasása, a géphez illő kiadás kiválasztása, a kicsomagolás, a menübejegyzés kiírása és annak nyilvántartása, hogy mi hova került, mind a folyamaton belül történik. Nincs értelmező, amit meg kellene keresni, és nincs gyerekfolyamat, amit értelmezni kellene: az alkalmazásnak begyetlen futásidejű függősége sincs0, még zip-könyvtára sem. Ami a lemezre kerül, az viszont nem változott: a cconfig.json0 és a cstate.json0 megtartja azt az alakot, amit a shell-áruház írt, így a CLI-vel telepített könyvtárat változtatás nélkül felismeri. Az, hogy melyik áruházból telepít, nincs belefordítva: a kliens megkérdez egy nyilvántartást (cGET /api/stores0 az oldalon), és egy ottani rekord egy bnév és begy katalógus0, semmi több. A viselkedés a kliens saját dolga, a játékmappa pedig a katalógushoszt slugja, így két áruház egy gépen soha nem nyúl egymás fájljaihoz. 1Mire van szüksége 1═════════════════ Semmire. Nincs értelmező, nincs csomagkezelő, nincs rendszergazdai jog: az alkalmazás a saját futtatókörnyezetét viszi, az áruház pedig a saját felhasználói fiókod alá települ. A ifejlesztéséhez0 Node 22 vagy újabb kell, az eszközláncot a cmake setup0 telepíti. 1Telepítés 1═════════ Vedd le a gépedhez való csomagot a 1kiadások közül, és nyisd meg. Az első indításkor, ha nincs áruház a gépen, az ablak felajánlja, amit a nyilvántartás publikál, vagy elfogad egy beírt katalóguscímet. Ennyi az egész beállítás. 2Megnyitás macOS-en 2────────────────── A build ad hoc alá van írva, de bnincs notarizálva0, ezért a macOS rákérdez, mielőtt egy böngészőből érkezett példányt futtatna: p xattr -dr com.apple.quarantine "/Applications/WarpEngine Client.app" A bRendszerbeállítások ▸ Adatvédelem és biztonság0 alatti iMegnyitás mindenképp is működik, egy blokkolt próbálkozás után. Ezt a lépést csak a notarizálás szünteti meg, ahhoz pedig fizetős Apple Developer ID kell. Az áruház által később letöltött fájlokat ez nem érinti: az alkalmazás a saját HTTP-kliensével tölti le őket, amely nem állítja be a karanténjelzőt. bA v1.0.0-t egyáltalán nem lehetett megnyitni0 — azt jelentette, hogy i„is idamaged"0. A csomag soha nem lett aláírva; csak a fő futtatható állományán volt rajta a linker ad hoc aláírása, tehát nem volt erőforrás-pecsét, és a Gatekeeper kérdés helyett elutasította. A cscripts/after-pack.js0 most build közben aláírja a csomagot, az eredmény pedig cvalid on disk0 státusszal ellenőrizhető. 1Belépés, és a pénzbe kerülő címek 1═════════════════════════════════ bEbben a kliensben semmi nem tud semmit egyetlen konkrét áruházról sem.0 Az ár, hogy kell-e fiók, hol lehet megvenni, hol lehet belépni — mindez a katalógus szerverétől jön: a WarpEngine 0.5 a cGET /api/service0 végponton megmondja, mit kínál, és minden bejegyzésre rátesz egy caccess0 blokkot. Ezért szolgál ki egyetlen build bármilyen boltot. A végpontok és alakok, amiket a kliens olvas, a bWECP — WarpEngine Catalog Protocol0, 2saját oldalán leírva. Ahol a szerver nem kínál belépést (minden 0.5 előtti WarpEngine, és minden olyan áruház, amely nem árul semmit), ott az ablak sem mutat ilyet. Ahol igen: • az oldalmenü kap egy bFiók0 blokkot: iBelépés…0, majd iKilépés0; • a belépés egy brövid kódot0 mutat. A böngésző megnyitja az áruház oldalát, a kódot oda kell beírni, és a jóváhagyás belépteti ezt az eszközt. Jelszó soha nem jut el a klienshez — pont ez a kerülőút értelme. • a token az boperációs rendszer kulcstartójában0 él (Keychain, libsecret, DPAPI) az Electron csafeStorage0 API-ján keresztül, áruházanként egy. Ha nincs kulcstartó, akkor egyáltalán nem tárolja el, nem pedig nyíltan kiírja; ennek az ára az, hogy a következő indításnál újra be kell lépni. Egy kártyán az, hogy egy ember mit tehet, elválik attól, hogy a gép mit tud futtatni: t┌────────────────────────────────────┬───────────────────────────────────────┐ t│h Állapot t│h Mit kínál a kártya t│ t├────────────────────────────────────┼───────────────────────────────────────┤ t│0 birtokolt, vagy ingyenes t│0 bTelepítés0 t│ t├────────────────────────────────────┼───────────────────────────────────────┤ t│0 nem birtokolt t│0 az bár0, és a bMegveszem0, amely t│ t│0 t│0 böngészőben nyitja meg az áruházi t│ t│0 t│0 oldalt t│ t├────────────────────────────────────┼───────────────────────────────────────┤ t│0 kijelentkezve, a katalógus kapuzza t│0 bBelépés a telepítéshez0 — a katalógus t│ t│0 t│0 addig nem tudja megmondani, kié, amíg t│ t│0 t│0 nem tudja, ki kérdez t│ t└────────────────────────────────────┴───────────────────────────────────────┘ A vásárlás a böngészőben történik: egy itt újraépített pénztár csak egy második hely lenne, ahol el lehet rontani a kártyakezelést. A bFrissítés0 utána iTelepítéssé0 alakítja a kártyát. Ezzel jön két állapotszűrő is — bBirtokolt0 és bMegveendő0 —, mert a birtoklás nem ugyanaz, mint a telepítettség. Egy meg nem vett cím bnincs0 kiszürkítve. A kiszürkítés azt jelenti, hogy a igép nem tudja futtatni; a géppel semmi baj, ha egy cím egyszerűen pénzbe kerül. Bearer token soha nem megy el olyan hosztra, amely nem adta ki. Egy kapuzott letöltés aláírt tárolóra irányít át — gyakran valaki más szerverére —, és egyes objektumtárolók visszautasítják azt a kérést, amely cAuthorization fejlécet és aláírást is visz. 1Melyik áruházból telepít 1════════════════════════ Az első indításkor a kliens lekéri a nyilvántartást. Egy áruház esetén nincs mit eldönteni; több esetén a beállítóképernyő választót mutat. p [ p { "name": "Teletype Games", "catalogUrl": "https://teletypegames.org" }, p { "name": "Some Other Store", "catalogUrl": "https://games.example.org" } p ] bEgy név és egy katalógus a teljes rekord.0 A kliens már tudja a hoszt–asset leképezést, a telepítési módokat, a platformokat és a viselkedést. Amit nem tudhat, az az identitás, és egy nyilvántartás csak az identitást mondja meg. Egy rekordból ezeket származtatja: • baz áruházazonosító0 — a katalógushoszt slugja (cteletypegames.org0 → cteletypegames0), vagy a megjelenített névé, ha az nem megy. Ez adja az áruház könyvtárának és a játékmappának a nevét. Két rekord, amely ugyanarra a katalógusra mutat, ugyanaz az áruház, és ugyanoda kerül, így az újratelepítés soha nem hagy árvát. • ba játékmappa0 — ez a slug az operációs rendszer szokásos helyén a telepített programoknak. Ez egyben az egyetlen részfa, ahonnan ez az áruház valaha töröl. • bmely címek jelennek meg0 — a kiadott, az archivált és a demó. Az a katalógus, amely demót publikál, azt szánja is játszásra. Egy katalógusnak egyáltalán nem kell a nyilvántartásban lennie: a beállításokból bbármilyen WarpEngine-katalóguscím0 hozzáadható. Egy csupasz hosztnév is elég (a chttps0 alapértelmezett), a nevet pedig belőle veszi. A nyilvántartás címe az utolsó oldalspecifikus dolog a kliensben, három helyen dönthető el, a legspecifikusabbal kezdve: egy futásidejű cSTORES_API0, az a cím, amellyel a csomag bépült0, majd a miénk. p STORES_API=http://127.0.0.1:8731/stores npm start # kipróbálás p make dist STORES_API=https://games.example.org/api/stores # kiadás A buildváltozat a becsomagolt alkalmazás cpackage.json0 fájljába kerül (cwarpEngine.registryUrl0), így egy más katalógusra épített kliens nem igényel forrásmódosítást, és a felhasználó gépén sem kell semmit beállítani. Egy áruház hozzáadása adatbázissor az oldalon, nem ennek az alkalmazásnak a kiadása. 1Brandelt build 1══════════════ Egy build bbrandet0 vihet: egy nevet és egy boltot. A cmake dist cBRAND_NAME="Teletype Games Store" BRAND_STORE=https://teletypegames.org cBRAND_ID=teletype-store0 belesüti a csomagba; a cBRAND_NAME=… BRAND_STORE=… npm cstart0 kipróbálja. A név az ablak címe, a sáv fejléce és a cproductName0 (Dock, c/Applications0, NSIS-mappa, c.desktop0 bejegyzés); a bolt az első indításnál nyilvántartás és választó nélkül települ, a brand nevén, ugyanabba a store home-ba, amit egy általános kliens is használna ehhez a katalógushoz. A brand balapértelmezés, nem ketrec0: a gépen lévő minden bolt látszik, és a beállítások továbbra is hozzáadnak és törölnek. A cBRAND_ID0 adja az cappId0-t és a csomagnevek előtagját, hogy a brandelt és az általános kliens egymás mellett élhessen; a cRELEASES_API0 a brandelt build saját kiadásaira irányítja a iFrissítések keresését0. A Beállítások Általános lapja azt mondja: iWarpEngine iClient 3.1.0 alapon0. A brand adat, amit a build ad — a forrásban semmi nem nevez meg boltot. 1Használat 1═════════ Minden, ami nem cím, az boldalmenüben0 él; a menügomb becsukja, és az állapot túléli az újraindítást. t┌──────────┬─────────────────────────────────────────────────────────────────┐ t│h Szakasz t│h Mit tartalmaz t│ t├──────────┼─────────────────────────────────────────────────────────────────┤ t│0 bÁruházak0 t│0 a gépen lévő összes áruház, a nyitottat megjelölve. Egy másikra t│ t│0 t│0 kattintva vált a rács, a szűrők és a mappák, és a kliens t│ t│0 t│0 legközelebb ott nyílik meg. Ugyanabból a katalógusból származó, t│ t│0 t│0 de más mappában lévő két áruház az azonosítója helyett a t│ t│0 t│0 mappáját mutatja. Áruházat hozzáadni, átnevezni és törölni a t│ t│0 t│0 beállításokban lehet. t│ t├──────────┼─────────────────────────────────────────────────────────────────┤ t│0 bFiók0 t│0 iBelépés…0 / iKilépés0, csak ott, ahol a katalógus kínál belépést. t│ t├──────────┼─────────────────────────────────────────────────────────────────┤ t│0 bSzűrők0 t│0 négy, egymással kombinálható tengely: a cím bállapota0 ezen a t│ t│0 t│0 gépen (iMinden0, iTelepített0, iFrissítések0, iNincs telepítve0, és t│ t│0 t│0 ahol a katalógus kapuz valamit, iBirtokolt0 és iMegveendő0), a t│ t│0 t│0 bplatform0, a btípus0 (natív vagy hosztolt) és a bkategória0, ha a t│ t│0 t│0 katalógus publikál ilyet — a WarpEngine 0.12 a metadata-fájl t│ t│0 t│0 ccategory0 mezőjét átviszi a katalógusba, így a tengely t│ t│0 t│0 megjelenik, amint a címek meg vannak címkézve, a 0.13 szótára t│ t│0 t│0 (cGET /api/software/vocabulary0) pedig címkét ad a chipeknek. t│ t│0 t│0 Minden darabszám azt mondja, hány címet mutatna az adott opció t│ t│0 t│0 a többi tengely mai állása mellett, és a iTörlés0 megjelenik, t│ t│0 t│0 amíg bármi szűkíti a katalógust. A tengelyek abból épülnek, t│ t│0 t│0 amit a katalógus tartalmaz: a címek nélküli platform nem t│ t│0 t│0 jelenik meg, az eltűnő választás pedig visszaesik a iMinden0 t│ t│0 t│0 értékre. t│ t├──────────┼─────────────────────────────────────────────────────────────────┤ t│0 bLábsor0 t│0 a bfogaskerék0 (beállítások), a verziószám, a bNapló0 és a t│ t│0 t│0 bFrissítés0. A iNapló0 az áruház saját kimenetét nyitja meg szó t│ t│0 t│0 szerint, plusz azt a két mappát, ahova minden kerül. A t│ t│0 t│0 iFrissítés0 újraolvassa a katalógust. A címek egyesével, a t│ t│0 t│0 kártyájukról telepíthetők; nincs „telepíts mindent" gomb. t│ t└──────────┴─────────────────────────────────────────────────────────────────┘ bA katalógus laponként érkezik, és a rács rajzol, ahogy jön.0 A WarpEngine 0.13 lapozza a cGET /api/software0-t; a kliens sorban olvassa a lapokat, és mindegyiket megmutatja, amint megjött, a sáv addig a címeket számolja. Ami az egészet igényli — a iFrissítések0 csoport, a iMind frissítése0, a prune — megvárja, és a cache mindig az összefűzött egészet tartja, részlegest soha. A rács bablakozott0: 48 címet rajzol, és 48-at még, amikor az aljához érsz, így egy nagy katalógus annyiba kerül, amennyi a képernyőn van. Egy szűrő vagy keresés elölről kezd; egy lap megérkezése nem mozdítja el a görgetést. A sávban van egy bkeresőmező0: ami bele van írva, azokra a címekre szűkíti a rácsot, amelyek címe vagy neve tartalmazza, kis- és nagybetűtől és ékezettől függetlenül, így a clove0 megtalálja a iLÖVE0-ot. A szűrő része — a chipek darabszámai számolnak vele, a iTörlés0 kiüríti, és az Escape is. A sáv kapcsolója a brács0 és egy blista0 között vált; a lista a kártya borítójával, verziójával és menüjével rajzol. 2Beállítások 2─────────── i[Kép: A beállítások ablaka az Áruházak lapon: a telepített áruház az iazonosítójával és a katalóguscímével, és a hozzáadás két módja] A fogaskerék egy párbeszédablakot nyit mindazzal, ami nem az előtted lévő katalógusról szól, három lapon: • bÁltalános0 — a bnyelv0 (a rendszert követi, átváltható: angol és magyar) és az balapértelmezett nézet0, rács vagy lista, ugyanaz a beállítás, amit a sáv kapcsolója ír. • bÁruházak0 — a gépen lévő összes áruház az azonosítójával és a katalóguscímével. A bceruza0 helyben átnevez: az Enter ment, az Escape elvet. Csak a név változhat, mert az azonosító, a mappa és a játékmappa mind a katalógusból származik, tehát egy másik katalógus másik áruház. A bkuka eltávolít egy áruházat. A lista alatt az bÁruház hozzáadása a listáról0 azt kínálja, amit a nyilvántartás publikál és ez a gép még nem tud, a bVagy egy bsaját katalógus0 pedig bármilyen katalóguscímet elfogad. A hozzáadás bezárja az ablakot, és megnyitja az új áruházat. • bFrissítések0 — két blokk, szándékosan külön, mert két különböző dologról szólnak. bEz a kliens0 a verziót mutatja, és egy bFrissítések keresése0 gombot, amely a kliens saját kiadáslistáját kérdezi le a forge-on, és helyben válaszol: iEz a legújabb verzió0, vagy iAz X verzió elérhető0 egy gombbal, amely böngészőben nyitja meg a kiadás oldalát. Az alkalmazás nem frissíti magát, és magától nem is kérdez; semmi nem történik, amíg nem kattintasz. bÚjabb bverziójú címek0: azok a telepített címek, amelyeknél a katalógus továbblépett, mindegyik egy bFrissítés0 gombbal, és bMind frissítése0, ha több van. bEgy áruház eltávolítása azt is eltávolítja, amit telepített.0 A kuka előbb rákérdez, és megmondja, hány cím megy vele. Az áruház cstate.json0 fájlja az egyetlen nyilvántartás arról, mely csomagok, ikonok és menübejegyzések tartoznak hozzá, ezért a játékok hátrahagyása olyan árvákat hagyna, amelyeket már semmi nem tudna azonosítani. A katalógus-cache, a beállítások és az esetleges belépési token is megy vele. 2Kártyák 2─────── Egy kártya gombja bTelepítés0, bFrissítés0, vagy telepítés után bJáték0 / bMegnyitás0. Egy telepített kártya hárompontos menüjében bFrissítés0 (csak akkor élő, ha a katalógusban van újabb), bÚjratelepítés0 és bEltávolítás0 van. Az újratelepítés annak a példánynak való, amely telepítettnek látszik, de nem működik: a Frissítés és az Upgrade békén hagy egy épnek látszó telepítést, az Újratelepítés viszont előbb eltávolítja, majd újra kicsomagolja a katalógusból, ikonnal és menübejegyzéssel együtt. Minden kártya megmondja, hogy bnatív0-e — kicsomagolva, helyben futtatva, offline is működik —, vagy bhosztolt0: a katalógus által kiszolgált böngészős build, amelynek a bejegyzése oldalt nyit meg, és hálózatot igényel. bA katalógus teljes tartalma megjelenik, azt is beleértve, amit ez a gép nem btud telepíteni.0 Ezek a kártyák ki vannak szürkítve, inem támogatott platform vagy iehhez a géphez nincs build0 jelvényt viselnek a motor magyarázatával, és nincs rajtuk mit megnyomni — mondjuk egy Raspberry Pi egy csak x86-os builddel szemben. Az az áruház, amely elrejti őket, találgatni hagyja a látogatót, hogy a katalógus kicsi-e, vagy a gépe fura. Saját állapotuk van, a iNem ehhez a igéphez0, és kimaradnak a natív/hosztolt darabszámokból, mert az a cím, amelyhez nincs build, nem tartozik egyik módhoz sem. A 2.7.0-tól a bCommodore 64-es és Plus/4-es0 címek is települnek: a WarpEngine 0.11-től a kiadásaik yapeSDL-csomagot visznek egy, a játékról elnevezett indítóval, amely beállítja a gépet és elindítja a kazettát, és a programkeresésben a játékról elnevezett program nyer. A kártyák minden platformot úgy neveznek, ahogy a katalógus — iPlus/40, iTIC-800, iLÖVE0 —, a szerver build-mátrixából olvasva (cGET /api/builds0), így egy katalógus új kliens nélkül is felvehet platformot; a végpont nélküli motor a slugoknál marad. Minden kártya azonos magasságú borítóképsávot visel — kép híján a cím első betűjét —, hogy a gombok soron belül egy vonalba essenek. Ez csendben el volt rontva addig, amíg le nem fényképeztük az ablakot: a sorok a tartalmuk követése helyett egyenlően osztották el az ablakmagasságot, ami összenyomta a képet és levágta a gombokat, miközben minden automatikus darabszám-ellenőrzés átment, mert a csomópontok mind ott voltak az oldalon. Amíg az áruház dolgozik, csak azok a dolgok vannak letiltva, amelyek egy második hívást indítanának. A menü, a naplófiók és a szűrők tovább működnek, mert a képernyőt változtatják, a lemezen semmit. Bármi, ami itt települ, normál menübejegyzés, tehát az indítódban, a Dockban vagy a Start menüben is megjelenik. A játékhoz nem kell futnia az alkalmazásnak. 1Fejlesztés 1══════════ A cmake0 a bejárati ajtó; az npm-szkripteket csomagolja be. A cmake0 önmagában mindent kilistáz. t┌────────────────┬───────────────────────────────────────────────────────────┐ t│h Cél t│h Mit csinál t│ t├────────────────┼───────────────────────────────────────────────────────────┤ t│0 cmake setup0 t│0 függőségek telepítése (előbb ellenőrzi a Node verzióját) t│ t├────────────────┼───────────────────────────────────────────────────────────┤ t│0 cmake build0 t│0 TypeScript fordítása, a preload és a renderer t│ t│0 t│0 bundle-ölése t│ t├────────────────┼───────────────────────────────────────────────────────────┤ t│0 cmake typecheck0 t│0 típusellenőrzés, kimenet nélkül t│ t├────────────────┼───────────────────────────────────────────────────────────┤ t│0 cmake lint0 t│0 a szigorú szabálykészlet (a cmake lint-fix0 javítja, amit t│ t│0 t│0 tud) t│ t├────────────────┼───────────────────────────────────────────────────────────┤ t│0 cmake check0 t│0 típusellenőrzés, lintelés és minden tesztkészlet — ez a t│ t│0 t│0 kapu t│ t├────────────────┼───────────────────────────────────────────────────────────┤ t│0 cmake start0 t│0 futtatás a telepített áruház ellen t│ t├────────────────┼───────────────────────────────────────────────────────────┤ t│0 cmake icons0 t│0 minden ikonformátum kirenderelése a cresources/icon.svg0 t│ t│0 t│0 fájlból t│ t├────────────────┼───────────────────────────────────────────────────────────┤ t│0 cmake smoke0 t│0 az áruház meghajtása ablak és Electron nélkül t│ t├────────────────┼───────────────────────────────────────────────────────────┤ t│0 cmake storetest0 t│0 áruház hozzáadása, átnevezése és törlése homokozóban — az t│ t│0 t│0 egyetlen kód, amely fát töröl t│ t├────────────────┼───────────────────────────────────────────────────────────┤ t│0 cmake uitest0 t│0 az ablak egyszeri betöltése, és jelentés arról, mi t│ t│0 t│0 rajzolódott ki (cSELFTEST_SHOT=shot.png0 le is fényképezi, t│ t│0 t│0 a beállítások lapjaival együtt) t│ t├────────────────┼───────────────────────────────────────────────────────────┤ t│0 cmake test0 t│0 a három tesztkészlet t│ t├────────────────┼───────────────────────────────────────────────────────────┤ t│0 cmake dist0 t│0 csomagolás ehhez a géphez (cdist-mac0, cdist-win0, t│ t│0 t│0 cdist-linux0) t│ t├────────────────┼───────────────────────────────────────────────────────────┤ t│0 cmake publish0 t│0 a cdist/0 alatti csomagok feltöltése a Gitea-kiadásra t│ t├────────────────┼───────────────────────────────────────────────────────────┤ t│0 cmake release0 t│0 csomagolás és publikálás egy menetben t│ t├────────────────┼───────────────────────────────────────────────────────────┤ t│0 cmake clean0 t│0 a cbuild/0 és a csomagok törlése (a cdistclean0 a t│ t│0 t│0 cnode_modules0 mappát is elhagyja) t│ t├────────────────┼───────────────────────────────────────────────────────────┤ t│0 cmake version0 t│0 az érintett verziók, azt is beleértve, hogy megvan-e a t│ t│0 t│0 ctea0 t│ t└────────────────┴───────────────────────────────────────────────────────────┘ Az npm-szkriptek továbbra is működnek közvetlenül (cnpm start0, cnpm run cdist:mac0). A Makefile a kiadási lépésen kívül nem tesz hozzá logikát, és minden alkalmazást futtató szkript előbb buildel, így nem lehet elavult bundle-t tesztelni. 2Folyamatos integráció 2───────────────────── A c.woodpecker.yaml0 ebben a repóban van, nem az update szerver konfigurációs kiterjesztésében: az a kiterjesztés játékplatform-pipeline-okat szolgál ki, amelyek kazettát építenek és az oldal katalógusába publikálnak, míg ez alkalmazást épít, és egy kiadásba publikál. t┌─────────┬────────────────────────────────┬─────────────────────────────────┐ t│h Lépés t│h Image t│h Mit csinál t│ t├─────────┼────────────────────────────────┼─────────────────────────────────┤ t│0 ccheck0 t│0 cwarp-engine-client-ci:node220 t│0 cnode_modules0 (lásd lent), t│ t│0 t│0 t│0 típusellenőrzés, lintelés, t│ t│0 t│0 t│0 füstpróba és az t│ t│0 t│0 t│0 áruház-életciklus teszt t│ t├─────────┼────────────────────────────────┼─────────────────────────────────┤ t│0 clinux0 t│0 celectronuserland/builder:220 t│0 AppImage és deb t│ t├─────────┼────────────────────────────────┼─────────────────────────────────┤ t│0 cwindows0 t│0 celectronuserland/builder:22-0 t│0 NSIS-telepítő és hordozható t│ t│0 t│0 cwine0 t│0 exe, Wine-on keresztül t│ t├─────────┼────────────────────────────────┼─────────────────────────────────┤ t│0 crelease0 t│0 cci-tools0 (digest szerint) t│0 csak tagre: létrehozza a t│ t│0 t│0 t│0 kiadást, és hozzácsatolja, amit t│ t│0 t│0 t│0 épített; a curl, a jq, a zip és t│ t│0 t│0 t│0 a git benne van az image-ben, t│ t│0 t│0 t│0 így semmit nem telepít t│ t└─────────┴────────────────────────────────┴─────────────────────────────────┘ A ccheck0 image az celectronuserland/builder:220, a repó cnode_modules0-ával előtelepítve a c/ci0 alatt, mellette annak a cpackage-lock.json0-nak a sha256-jával, amelyből készült. A 3teletypegames repó cci/warp-engine-client.Dockerfile0-ja építi, és az éjszakai cron újraépíti, ha a cmaster0 lockjára még nincs clock-0 image; a tag mozog, ezért a lépés mindig pullolja. A cscripts/ci-npm.sh0 átmásolja ezeket a modulokat, ha a lock egyezik (egy másodperc a 15 s-os cnpm ci0 helyett), és cnpm ci0-t futtat, ha nem. bA macOS helyi build marad0 — az Apple eszközlánca csak Macen létezik —, így egy kiadásnak két fele van: egy cvX.Y.Z0 tag pusholása felépíti a Linuxot és a Windowst, és blétrehozza a kiadást0 a cRELEASE_NOTES.md0 törzsével, a Macen futtatott cmake release0 pedig felteszi a macOS-csomagot ugyanarra a kiadásra. Bármelyik fél mehet előbb. Az ablakteszt is helyi: kijelző és a gépen lévő áruház kell hozzá. A publikáláshoz cgitea_token0 repótitok kell írási joggal. A Woodpecker ad a lépéseknek forge-hitelesítő adatot, és a szkript ezt használja, ha a titok hiányzik, de nem lehet rá támaszkodni: egy kézi buildnek megvan, a tag-webhook által indítottnak nincs. Két publikáló létezik — a cscripts/release.sh0 a ctea bejelentkezést vezérli egy munkaállomáson, a cscripts/ci-upload.sh0 pedig az API-val beszél azzal a hitelesítő adattal, ami a CI-nak van. Mindkét buildlépés azzal zárul, hogy ellenőrzi, mit gyártott: egy 10 MB alatti csomag nem készült el. Egy félbemaradt Wine-build a valódi telepítő inevével hagy ott egy csonkot, és az cls0 ezzel tökéletesen elégedett. A windowsos lépést Apple Silicon Macen nem lehet elpróbálni: a Wine 4 KB-os memórialapokat feltételez, a gépnek pedig 16 KB-osak vannak. A windowsos telepítő bnincs aláírva0: a Windows ismeretlen kiadóra figyelmeztet, amíg nincs kódaláíró tanúsítvány. A Linux-csomagok konvenció szerint nem visznek aláírást. 2Kiadás publikálása 2────────────────── p make release p make publish TAG=v1.0.2 # a package.json-tól eltérő tag p scripts/release.sh dist/one-file.dmg # csak egy csomag A tag a cpackage.json0 fájlból jön, tehát az cnpm version patch0 az egyetlen hely, ahol verziót állítunk. A kiadás létrejön, ha nincs, és az a melléklet, amelynek a neve már szerepel, blecserélődik0, így egy újraépítés plusz egy második cmake publish0 felkerül, nem hibázik. A kiadási jegyzetek a cRELEASE_NOTES.md0 fájlból jönnek, ha van. A repót az corigin0 alapján olvassa, tehát egy fork a forkba publikál. A csomagnevekben nincs szóköz (cWarpEngineClient-2.3.0-arm64.dmg0), mert egy kiadási melléklet szóköze minden ccurl0-ben szóköz, ami valaha hozzáér. Telepített és bejelentkezett ctea0 kell hozzá — a devarea repóban van cmake tea0. Felülbírálható: cTAG0, cREPO0, cTEA_LOGIN0, cNOTES0, cDIST0. bA telepítéshez Node 22+ kell0, a futtatáshoz nem: az Electron telepítője csak ESM, a régebbi Node pedig nem tudja crequire()0-elni. A becsomagolt alkalmazás a saját futtatókörnyezetét viszi. Az cnpm run uitest0 saját felhasználóiadat-könyvtárat használ, és kihagyja az egypéldány-zárat. Különben a felhasználónál már nyitva lévő példány elnyelné a tesztfolyamatot, amely 0-val lép ki, és sikeresnek látszik. A tesztszkriptek elfogadnak egy homokozó-áruházat, így lehet ezt a repót anélkül tesztelni, hogy egy működő telepítéshez hozzányúlnánk. A cSTORE_ROOT blecseréli0 a keresési utat, nem elé fűz: most, hogy áruházat törölni is lehet, az a homokozó, amely elér egy működő telepítést, nem homokozó. p STORE_ROOT=/tmp/sandbox-root npm start p SMOKE_HOME=/tmp/sandbox-root/ttg-desktop npm run smoke p SMOKE_HOME= SMOKE_TOKEN= npm run smoke # belépett felhaszn» p álóként 2Hogyan áll össze 2──────────────── TypeScript rétegekben, a függőségek befelé mutatnak. A repóban lévő cSTRUCTURE.md0 a térkép — rétegek, minden használt minta, elnevezési szabályok —, és ez az a fájl, amit el kell olvasni, mielőtt bármit hozzáadnál. t┌─────────────────────┬──────────────────────────────────────────────────────┐ t│h Réteg t│h Mi él ott t│ t├─────────────────────┼──────────────────────────────────────────────────────┤ t│0 csrc/shared/0 t│0 az IPC-csatornatábla, a hídszerződés, a DTO-k, az t│ t│0 t│0 üzenetkészletek t│ t├─────────────────────┼──────────────────────────────────────────────────────┤ t│0 csrc/domain/0 t│0 modellek, portok és hibák — se Electron, se Node t│ t├─────────────────────┼──────────────────────────────────────────────────────┤ t│0 csrc/application/0 t│0 szolgáltatások és a domain–DTO leképezők t│ t├─────────────────────┼──────────────────────────────────────────────────────┤ t│0 csrc/infrastructure/0 t│0 adapterek: az áruházmotor, a HTTP, az t│ t│0 t│0 archívumolvasó, a fájlrendszer, az Electron t│ t├─────────────────────┼──────────────────────────────────────────────────────┤ t│0 csrc/main/0 t│0 az ablak, az IPC-kontrollerek, a kompozíciós gyökér, t│ t│0 t│0 az önteszt t│ t├─────────────────────┼──────────────────────────────────────────────────────┤ t│0 csrc/preload/0 t│0 a híd, egyetlen fájlba bundle-ölve — egy homokozott t│ t│0 t│0 preload nem tud modult behúzni t│ t├─────────────────────┼──────────────────────────────────────────────────────┤ t│0 csrc/renderer/0 t│0 az állapottár, a nézetek és a renderer-kontrollerek t│ t├─────────────────────┼──────────────────────────────────────────────────────┤ t│0 csrc/scripts/0 t│0 a füstpróba és az áruház-életciklus teszt: ugyanazok t│ t│0 t│0 a szolgáltatások ablak nélkül t│ t└─────────────────────┴──────────────────────────────────────────────────────┘ Két tulajdonság, amit a rétegek megvesznek: • a katalógus bablak és Electron nélkül0 is meghajtható — a füstpróba ugyanazokat a szolgáltatásokat állítja össze ugyanazokra a portokra; • az ablak bsoha nem kap fájlrendszer-útvonalat0. Egy cím anélkül kel át a hídon, az indítást pedig név alapján kérjük, és a fő folyamat oldja fel az áruház saját állapotából. Az ablak kizárólag az állapotából rajzol: a napló, a kapu, a beállítások ablaka és a szűrő egy tár mezői, minden nézetnek egyetlen crender(state) metódusa van, és a bekötés csak a három kompozíciós gyökérben történik (az alkalmazás, a füstpróba, az életciklus-teszt). Ami a hídon vagy a lemezről jön, ellenőrzött olvasón megy át, soha nem castolással. A linter szándékosan szigorú: explicit típusok minden szignatúrán, nincs cany0, nincs non-null assertion, kimerítő switchek. Az a fordítás, amelyből hiányzik egy kulcs, nem fordul le, és az a csatorna sem, amelyet a preload nem valósít meg. bAz áruházmotor0 az csrc/infrastructure/engine/0, a cStoreCatalogGateway0 port mögött: a katalóguskliens a cache-ével, a felmérő, amely megmondja, mely címeket tudja ez a gép telepíteni és a többit miért nem, a kiadásválasztó, a hosztfelismerő, a csomagtelepítő, a c.desktop0 / c.app0 / c.lnk0 indítóírók és az állapotfájl. A port fölött semmi nem tud arról, hogy ezek léteznek. Egy RetroArch-áruház menübejegyzés helyett lejátszási listát írna, tehát az egy második gateway és egy második bejegyzés lenne a cSTORE_ENGINES0 listában, nem egy második kódút. bZip olvasása függőség nélkül.0 A Node-nak nincs zip-olvasója, ezért a cZipArchive0 egy a cnode:zlib0 fölött: végigjárja a központi könyvtárat, kibontja a cstored0 és cdeflate0 bejegyzéseket, visszaállítja a futtatható bitet és a szimbolikus linkeket a bejegyzések attribútumaiból — a yapeSDL c.app0-jában lévő SDL2 framework ilyenek fája. Visszautasítja a zip64-et, az ismeretlen tömörítési módot és a célból kiszökő útvonalat. bMelyik WarpEngine szolgálta ki a katalógust.0 Minden WarpEngine API-válasz visz egy cWarpEngine-Version0 fejlécet. A cSUPPORTED_WARP_ENGINE_VERSIONS0 felsorolja, mely verziókra írták ezt a klienst, és mindegyik arra a cCatalogDialect0-re képződik le, amely az adott katalógusalakot olvassa. A switch kimerítő, tehát egy új verzió felvétele megállítja a buildet, amíg valaki meg nem mondja, hogyan kell olvasni. t┌─────────────────────────────────────┬──────────────────────────────────────┐ t│h Mit mond a fejléc t│h Mi történik t│ t├─────────────────────────────────────┼──────────────────────────────────────┤ t│0 támogatott verzió (ma 0.2-től t│0 a dialektusa olvassa a katalógust, a t│ t│0 1.0-ig, két dialektussal) t│0 napló megnevezi t│ t├─────────────────────────────────────┼──────────────────────────────────────┤ t│0 semmi t│0 a legrégebbi támogatott verzióként t│ t│0 t│0 olvassa — egy 0.4.0-nál régebbi t│ t│0 t│0 motor t│ t├─────────────────────────────────────┼──────────────────────────────────────┤ t│0 régebbi bárminél, ami támogatott t│0 ugyanaz, és a napló megmondja t│ t├─────────────────────────────────────┼──────────────────────────────────────┤ t│0 újabb bárminél, ami támogatott t│0 a legújabb dialektust próbálja, t│ t│0 t│0 figyelmeztetéssel, hogy címek t│ t│0 t│0 maradhatnak ki t│ t└─────────────────────────────────────┴──────────────────────────────────────┘ ccontextIsolation0 be, cnodeIntegration0 ki, csandbox0 be, és olyan CSP, amely csak az alkalmazás saját szkriptjét és stíluslapját, valamint HTTPS-en érkező képeket enged. A linkek a valódi böngészőben nyílnak; az ablak soha nem navigál. 1Amit ellenőriztünk, és amit nem 1═══════════════════════════════ Minden verziót a cmake check0 mér — nincs típushiba, nincs lint-találat, három zöld tesztkészlet —, és az ablak a cSELFTEST_SHOT0-tal lefényképezi magát; így találtuk meg az összenyomott rácssorokat (1.x) és a 2.6.0 üres ablakát: egy inline c0 nem cHTMLElement0, ezért az elemellenőrzés az első konstruktorban dobott, és utána semmi nem futott. A fej nélküli füstpróba ezt nem láthatta; az ablakellenőrzés az első másodpercben elbukik rajta. • bAz áruház életciklusa0 — hozzáadás, átnevezés, törlés — minden cmake check0-nél lefut egy ideiglenes gyökérben, és az átnevezést visszaolvassa a fájlból. • bAz önteszt0 megszámolja a kártyákat, a szűrősorokat és a kártyamenüket, megnyitja a beállításokat, összeveti az áruházsorait az oldalmenüével, és bezárja. • bA nyilvántartási utat0 helyi végponton próbáltuk ki, amely az oldal payloadját szolgálta ki; a slug cteletypegames0 lett a katalógushosztból, és ugyanannak a rekordnak a kétszeri telepítése ugyanoda került. • bAz aláírást0 mértük, nem feltételeztük: karanténjelző beállítva a kiadási artifactból kicsomagolt példányon, a ccodesign --verify --deep --strict tiszta, a csyspolicy_check0 pedig csak a várt i„adhoc signed"0 figyelmeztetést jelentette. bLinuxon és Windowson nem próbáltuk ki.0 Az útvonalak és az indítási viselkedés meg vannak írva rájuk, és a CI megépíti a csomagokat, de a c.desktop0 és c.lnk indítók generálódtak és olvashatók, nem kattintottak rájuk. A notarizálás, a windowsos aláíró tanúsítvány és az alkalmazáson belüli frissítés mind nyitott — a 1kiadások mondják el, melyik verzió mit változtatott.