EN /HU | Belépés

WarpEngine Client

A WarpEngine Client 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 WarpEngine Client ablaka: balra az áruházválasztó és a kategóriaszűrők, jobbra a katalógus játékkártyák rácsaként

Az áruházmotor az alkalmazás része. 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 az alkalmazáson belül történik. Semmit nem kell előbb telepíteni, nem kell értelmezőt keresni.

Az, hogy melyik áruházból telepít, nincs belefordítva: a kliens megkérdez egy nyilvántartást (GET /api/stores az oldalon), és egy ottani rekord egy név és egy katalógus, 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.

Mire van szüksége

  • Python 3, mert az áruház Python-program. Az alkalmazás megpróbálja a python3, python és py -3 parancsokat, és világosan megmondja, ha egyik sem válaszol.
  • Semmi másra. Nincs Node, nincs csomagkezelő, nincs rendszergazdai jog — a saját felhasználói fiókod alá telepít.

Telepítés

Vedd le a gépedhez való csomagot a kiadások közül, és nyisd meg. Az első indításkor, ha nincs áruház a gépen, az ablak felajánlja, hogy letölt egyet. Ennyi az egész beállítás.

Megnyitás macOS-en

A build ad hoc alá van írva, de nincs notarizálva, ezért a macOS rákérdez, mielőtt egy böngészőből érkezett példányt futtatna:

SH
xattr -dr com.apple.quarantine "/Applications/WarpEngine Client.app"

A Rendszerbeállítások ▸ Adatvédelem és biztonság alatti Megnyitá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: a Python nem állítja be a karanténjelzőt.

A v1.0.0-t egyáltalán nem lehetett megnyitni — azt jelentette, hogy „is damaged". 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 scripts/after-pack.js most build közben aláírja a csomagot, az eredmény pedig valid on disk státusszal ellenőrizhető.

Belépés, és a pénzbe kerülő címek

Ebben a kliensben semmi nem tud semmit egyetlen konkrét áruházról sem. 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 GET /api/service végponton megmondja, mit kínál, és minden bejegyzésre rátesz egy access blokkot. Ezért szolgál ki egyetlen build bármilyen boltot.

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 Fiók blokkot: Belépés…, majd Kilépés;
  • a belépés egy rövid kódot 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 operációs rendszer kulcstartójában él (Keychain, libsecret, DPAPI) az Electron safeStorage 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:

Állapot Mit kínál a kártya
birtokolt, vagy ingyenes Telepítés
nem birtokolt az ár, és a Megveszem, amely böngészőben nyitja meg az áruházi oldalt
kijelentkezve, a katalógus kapuzza Belépés a telepítéshez — a katalógus addig nem tudja megmondani, kié, amíg nem tudja, ki kérdez

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 Frissítés utána Telepítéssé alakítja a kártyát.

Ezzel jön két kategória is — Birtokolt és Megveendő —, mert a birtoklás nem ugyanaz, mint a telepítettség.

Egy meg nem vett cím nincs kiszürkítve. A kiszürkítés azt jelenti, hogy a gé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 Authorization fejlécet és aláírást is visz.

Melyik áruházból telepít

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.

JSON
[
  { "name": "Teletype Games", "catalogUrl": "https://teletypegames.org" },
  { "name": "Some Other Store", "catalogUrl": "https://games.example.org" }
]

Egy név és egy katalógus a teljes rekord. 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:

  • az áruházazonosító — a katalógushoszt slugja (teletypegames.orgteletypegames), 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.
  • a játékmappa — 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.
  • mely címek jelennek meg — a kiadott, az archivált és a demó. Az a katalógus, amely demót publikál, azt szánja is játszásra.

A nyilvántartás címe az utolsó oldalspecifikus dolog a kliensben, három helyen dönthető el, a legspecifikusabbal kezdve: egy futásidejű STORES_API, az a cím, amellyel a csomag épült, majd a miénk.

SH
STORES_API=http://127.0.0.1:8731/stores npm start            # kipróbálás
make dist STORES_API=https://games.example.org/api/stores    # kiadás

A buildváltozat a becsomagolt alkalmazás package.json fájljába kerül (warpEngine.registryUrl), í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.

Használat

Minden, ami nem cím, az oldalmenüben él; a menügomb becsukja, és az állapot túléli az újraindítást.

Szakasz Mit tartalmaz
Áruházak a gépen lévő összes áruház, a nyitottat megjelölve. Egy másikra kattintva vált a rács, a kategóriák és a mappák, és a kliens legközelebb ott nyílik meg. Ugyanabból a katalógusból származó, de más mappában lévő két áruház az azonosítója helyett a mappáját mutatja. Az Áruház hozzáadása megnyitja a nyilvántartás-választót.
Fiók Belépés… / Kilépés, csak ott, ahol a katalógus kínál belépést.
Műveletek Frissítés, amely újraolvassa a katalógust. A címek egyesével, a kártyájukról telepíthetők; nincs „telepíts mindent" gomb.
Kategóriák egyszerre egy, darabszámokkal: Minden, Telepített, Frissítések, Nincs telepítve, majd egy-egy sor platformonként és típusonként (natív vagy hosztolt). Abból épül, amit a katalógus tartalmaz, tehát az üres platform nem jelenik meg, és az eltűnő kategória visszaesik a Minden értékre. Egy WarpEngine-katalógusban nincs műfajmező.
Napló az áruház saját kimenete szó szerint, plusz az a két mappa, ahova minden kerül. Kérésig rejtve.
Nyelv a rendszert követi, átváltható: angol és magyar.

Egy kártya gombja Telepítés, Frissítés, vagy telepítés után Játék / Megnyitás. Az Eltávolítás visszaveszi a címet. Minden kártya megmondja, hogy natív-e — kicsomagolva, helyben futtatva, offline is működik —, vagy hosztolt: a katalógus által kiszolgált böngészős build, amelynek a bejegyzése oldalt nyit meg, és hálózatot igényel.

A katalógus teljes tartalma megjelenik, azt is beleértve, amit ez a gép nem tud telepíteni. Ezek a kártyák ki vannak szürkítve, nem támogatott platform vagy ehhez a géphez nincs build jelvényt viselnek a motor magyarázatával, és nincs rajtuk mit megnyomni — mondjuk egy C64-kazetta egy asztali gépen. 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 kategóriájuk van, a Nem ehhez a géphez, és kimaradnak a natív/hosztolt darabszámokból, mert az a cím, amelyhez nincs build, nem tartozik egyik módhoz sem. Ehhez asztali áruházmotor 1.2.0 kell warpstore 1.4.0-n; régebbi motorral a lista mindenestül telepíthető, mint korábban.

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.

Fejlesztés

A make a bejárati ajtó; az npm-szkripteket csomagolja be. A make önmagában mindent kilistáz.

Cél Mit csinál
make setup függőségek telepítése (előbb ellenőrzi a Node verzióját)
make build TypeScript fordítása, a preload és a renderer bundle-ölése
make typecheck típusellenőrzés, kimenet nélkül
make lint a szigorú szabálykészlet (a make lint-fix javítja, amit tud)
make check típusellenőrzés, lintelés és mindkét tesztkészlet — ez a kapu
make start futtatás a telepített áruház ellen
make smoke az áruházhíd meghajtása ablak nélkül
make uitest az ablak egyszeri betöltése, és jelentés arról, mi rajzolódott ki
make test mindkét ellenőrzés
make dist csomagolás ehhez a géphez (dist-mac, dist-win, dist-linux)
make publish a dist/ alatti csomagok feltöltése a Gitea-kiadásra
make release csomagolás és publikálás egy menetben
make clean a megépített csomagok törlése (a distclean a node_modules mappát is elhagyja)
make version az érintett verziók, azt is beleértve, hogy megvan-e a tea

Az npm-szkriptek továbbra is működnek közvetlenül (npm start, npm run dist:mac). A Makefile a kiadási lépésen kívül nem tesz hozzá logikát.

Folyamatos integráció

A .woodpecker.yaml 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.

Lépés Image Mit csinál
check electronuserland/builder:22 telepítés, típusellenőrzés, lintelés, füstpróba
linux electronuserland/builder:22 AppImage és deb
windows electronuserland/builder:22-wine NSIS-telepítő és hordozható exe, Wine-on keresztül
release alpine csak tagre: létrehozza a kiadást, és hozzácsatolja, amit épített

A macOS helyi build marad — az Apple eszközlánca csak Macen létezik —, így egy kiadásnak két fele van: egy vX.Y.Z tag pusholása felépíti a Linuxot és a Windowst, és létrehozza a kiadást, a Macen futtatott make release 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 gitea_token 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 scripts/release.sh a tea bejelentkezést vezérli egy munkaállomáson, a scripts/ci-upload.sh pedig az API-val beszél azzal a hitelesítő adattal, ami a CI-nak van.

A windowsos telepítő nincs aláírva: 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.

Kiadás publikálása

SH
make release
make publish TAG=v1.0.2                 # a package.json-tól eltérő tag
scripts/release.sh dist/one-file.dmg    # csak egy csomag

A tag a package.json fájlból jön, tehát az npm version patch 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, lecserélődik, így egy újraépítés plusz egy második make publish felkerül, nem hibázik. A kiadási jegyzetek a RELEASE_NOTES.md fájlból jönnek, ha van. A repót az origin alapján olvassa, tehát egy fork a forkba publikál.

Telepített és bejelentkezett tea kell hozzá — a devarea repóban van make tea. Felülbírálható: TAG, REPO, TEA_LOGIN, NOTES, DIST.

A telepítéshez Node 22+ kell, a futtatáshoz nem: az Electron telepítője csak ESM, a régebbi Node pedig nem tudja require()-elni. A becsomagolt alkalmazás a saját futtatókörnyezetét viszi.

Az npm run uitest 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.

Mindkét tesztszkript elfogad 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:

SH
STORE_ROOT=/tmp/sandbox-root npm start
SMOKE_HOME=/tmp/sandbox-root/ttg-desktop npm run smoke

Hogyan áll össze

TypeScript rétegekben, a függőségek befelé mutatnak. A repóban lévő STRUCTURE.md a térkép — rétegek, minták, elnevezési szabályok —, és ez az a fájl, amit el kell olvasni, mielőtt bármit hozzáadnál.

Réteg Mi él ott
src/shared/ az IPC-csatornatábla, a hídszerződés, a DTO-k, az üzenetkészletek
src/domain/ modellek, portok és hibák — se Electron, se Node, se Python
src/application/ szolgáltatások és a domain–DTO leképezők
src/infrastructure/ adapterek: a Python-parancssor, a HTTP, a fájlrendszer, az Electron
src/main/ az ablak, az IPC-kontrollerek, a kompozíciós gyökér, az önteszt
src/preload/ a híd, egyetlen fájlba bundle-ölve — egy homokozott preload nem tud modult behúzni
src/renderer/ az állapottár, a nézetek és a renderer-kontrollerek
src/scripts/ a füstpróba: ugyanazok a szolgáltatások ablak nélkül

Két tulajdonság, amit a rétegek megvesznek:

  • a katalógus ablak és Electron nélkül is meghajtható — a füstpróba ugyanazokat a szolgáltatásokat állítja össze ugyanazokra a portokra;
  • az ablak soha nem kap fájlrendszer-útvonalat. 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.

A linter szándékosan szigorú: explicit típusok minden szignatúrán, nincs any, nincs non-null assertion, kimerítő switchek, a kívülről jövő adat típuscastolás helyett ellenőrzött olvasókon át. 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.

Fájl Mit csinál
main.js az ablak, az IPC, az egyszerre-egy-hívás őr
preload.js a teljes felület, amit a renderer megkap — Node nem jut el hozzá
lib/store.js megkeresi az áruházat és a Pythont, futtatja a parancssort, feldolgozza a JSON-t
lib/bootstrap.js beolvassa a nyilvántartást, letölti a motort, a magot és egy konfigurációt
lib/i18n.js a két szövegtábla
renderer/ sima HTML, CSS és JS — nincs keretrendszer, nincs buildlépés
scripts/release.sh létrehozza a Gitea-kiadást, és lecseréli a mellékleteit
scripts/after-pack.js csomagolás közben ad hoc aláírja a macOS-csomagot

contextIsolation be, nodeIntegration ki, sandbox 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.

A lib/store.js a --json kapcsolón keresztül beszél a parancssorral: adat a stdouton, az emberi napló a stderren. Ez a kapcsoló az 1.1.0-s motorverzióval érkezett, és a kliens ellenőrzi is — egy régebbi áruházat elbukott hívás helyett frissítési ajánlat fogad.

A híd egy ENGINES listát tart, ma egyetlen bejegyzéssel. A RetroArch-áruház parancsalakja ugyanez, tehát egy második bejegyzés a teljes változtatás ahhoz, hogy azt is meghajtsa.

Amit ellenőriztünk, és amit nem

macOS-en (arm64) végigpróbálva a kiadás becsomagolt alkalmazásával, nem fejlesztői futással: az áruházat megtalálja, a katalógus kilistázódik, egy szinkron telepít, az ablak kirajzolja a telepített állapotot, és az npm run uitest átmegy kirajzolt ráccsal és mindkét nyelvvel a választóban. A bootstrap-letöltést üres könyvtárba futtattuk, és a keletkezett áruház válaszolt a hídnak.

  • A rácsot ránézéssel ellenőriztük. SELFTEST_SHOT beállításával az ablak PNG-be fényképezi magát, így találtuk meg az összenyomott sorokat, és így igazoltuk a javítást — mindkét nyelven, nyitott és csukott menüvel.
  • Az oldalmenüt két áruházzal, egy gyökérben mértük (homokozó-másolat a valódi telepítés mellett); az ablakellenőrzés a nem nyitott áruházra kattint, és ellenőrzi, hogy a sáv, a rács és a kategóriák követik-e. Egy áruház esetén a váltás kimarad.
  • A nyilvántartási utat helyi végponton próbáltuk ki, amely az oldal payloadját szolgálta ki két rekorddal, egy config.json fájllal rendelkező és egy anélküli áruházrepóval. Mindkettő települt, és a motor mind a tíz címet kilistázta a szintetizált konfigurációval. Az uitest lefutott áruházzal (rács), áruház nélkül (beállítókapu, mindkét név a választóban), és elérhetetlen nyilvántartással (újrapróbálási kapu).
  • Az aláírást mértük, nem feltételeztük: karanténjelző beállítva a kiadási artifactból kicsomagolt példányon, a codesign --verify --deep --strict tiszta, a syspolicy_check pedig csak a várt „adhoc signed" figyelmeztetést jelentette. Egy karanténos példányt jóváhagyásig továbbra is megállít — ez Gatekeeper-szabályzat, nem a csomag hibája.

Linuxon és Windowson nem próbáltuk ki. Az útvonalak és az indítási viselkedés meg vannak írva rájuk, és az áruház parancssorában ugyanez a hiányosság: .desktop és .lnk indítók generálódtak és olvashatók, de még senki nem kattintott rájuk.