ServerModSync
Klient dociąga mody serwera sam, po haszu pliku.
Problem
Wejście na serwer z modami zaczyna się od ręcznego dopasowania paczki: link gdzieś na Discordzie, wersje się rozjeżdżają, a jeden plik inny niż na serwerze to wyrzucenie przy drzwiach.
Rozwiązanie
Serwer po starcie liczy skrót SHA-256 każdego swojego moda i wystawia listę pod własnym adresem HTTP razem z plikami. Klient dorysowuje ikonę przy każdym wpisie na liście serwerów; po kliknięciu porównuje listę serwera z tym, co ma u siebie, i ściąga wyłącznie to, czego brakuje albo co się różni skrótem. Plik trafia na dysk dopiero po sprawdzeniu skrótu.
Co robi
- Ikona przy każdym wpisie na liście serwerów, wstrzyknięta mixinem w ekran gry
- Lista modów serwera jako JSON, pliki pod osobnym adresem
- Porównanie po identyfikatorze moda i skrócie SHA-256, nie po nazwie pliku
- Pasek postępu na pobieranym pliku, odświeżany co 48 kilobajtów
- Skrót sprawdzany po pobraniu; niezgodny plik jest kasowany, nie instalowany
- Trzy podejścia na plik z sekundą przerwy, zanim pobieranie zostanie uznane za nieudane
- Lista modów pomijanych przy synchronizacji, w pliku konfiguracyjnym
Na czym zbudowane
- Moduł wspólny nic nie wie o loaderze; Fabric i NeoForge to cztery cienkie warstwy nad nim
- Serwer HTTP z biblioteki standardowej Javy, dwa adresy: lista modów i pliki
- Lista budowana przy starcie serwera z tego, co widzi loader, każdy JAR haszowany
- Klient pobiera strumieniowo przez HttpClient z Javy 21, bez wczytywania pliku do pamięci
- Plik leci do .tmp, potem skrót, dopiero potem atomowa podmiana pod właściwą nazwę
- Watchdog na ciszę w strumieniu: brak bajtów przez ustalony czas zamyka połączenie
- Ekran klienta jako automat stanów: pobieranie listy, lista, pobieranie, błąd, koniec
Co to zmieniło
- Ręczne składanie paczki modów znika: klient porównuje listę po SHA-256 i ściąga wyłącznie to, czego brakuje albo co się różni
- Dwadzieścia osób tego używa; wydanie na CurseForge i Modrinth w przygotowaniu
- Poprawka idzie raz, nie cztery razy: jeden rdzeń obsługuje Fabric i NeoForge, po stronie serwera i klienta
- 29 testów i 40 asercji, wszystkie działające bez uruchamiania Minecrafta
- Transport bez jednej zależności zewnętrznej: serwer i klient HTTP z biblioteki standardowej Javy
Stack
- Java 21
- Fabric
- NeoForge
- Mixin
- Gradle
- Gson
Historia
Wyjście poza katalog jest zablokowane dwa razy, niezależnie po obu stronach. Serwer odrzuca nazwy ze znakami przejścia po katalogach i oddaje wyłącznie pliki ze swojej listy. Klient osobno odrzuca adres bezwzględny i każdą ścieżkę, która po rozwinięciu wypada poza katalog modów. Jedna z tych kontroli wystarczyłaby przy uczciwym drugim końcu — obie są po to, żeby uczciwość drugiego końca nie była założeniem. Poza liczbą osób, które tego używają, wpis nie podaje żadnych pomiarów z prawdziwego serwera — są tu wyłącznie rzeczy sprawdzalne w kodzie i w testach.