v3.0.0: Umschalten wartet nicht mehr aufs Auffrischen (abbrechbar, CA-Abruf zuletzt), schnellere Prüfintervalle

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Nico Meister
2026-10-19 21:13:44 +02:00
co-authored by Claude Opus 5.5
parent c384c20558
commit f5fc0861c7
11 changed files with 113 additions and 53 deletions
+59 -19
View File
@@ -18,6 +18,7 @@
#include "ftpctl.h"
#include "spotpass.h"
#include "shopctl.h"
#include "olvpatch.h"
#define TOP_W 400
#define BOT_W 320
@@ -271,32 +272,65 @@ static void draw_bottom(int selected, PatchState st, bool admin)
#define UNLINKED_MARKER "sdmc:/3ds/mbmnet/nnid-geloest"
static bool old_mbmnet_link(void) { FILE *f = fopen(UNLINKED_MARKER, "r"); if (f) fclose(f); return f != NULL; }
// Auffrischen beim Start (SpotPass anmelden, Patches neu bauen) läuft im Hintergrund: Dabei holt die App
// das Miiverse-Zertifikat vom Server, und solange das WLAN noch verbindet, dauert das Sekunden.
static volatile bool maintaining;
// Auffrischen beim Start läuft im Hintergrund, in Schritten. Tippt man auf Umschalten, bricht es ab, wo es kann:
// Das Umschalten wartet nur, solange Patch-Dateien geschrieben werden oder der Konto-Dienst beschäftigt ist.
static volatile bool maintaining; // Thread läuft noch (evtl. nur noch das Zertifikat vom Server holen)
static volatile bool maintenanceBusy; // schreibt Patches / gleicht das Konto ab: Umschalten muss warten
static volatile bool switchRequested; // jemand will umschalten: nichts Neues mehr anfangen
static volatile bool maintenanceChanged;
static Thread maintenanceThread;
// Erst "beschäftigt" melden, dann nachsehen, ob umgeschaltet werden soll (sonst könnten beide gleichzeitig schreiben)
static bool begin_busy(void)
{
maintenanceBusy = true;
if (!switchRequested) return true;
maintenanceBusy = false;
return false;
}
static bool refresh_patches(void)
{
char detail[160];
bool changed = false;
if (!begin_busy()) return false;
if (patch_enable(MBMNET_SERVER, &changed, detail, sizeof(detail)) && changed) maintenanceChanged = true;
maintenanceBusy = false;
return changed;
}
static void maintenance_worker(void *arg)
{
(void)arg;
char ignore[96], detail[160];
spotpass_register(MBMNET_SERVER, ignore, sizeof(ignore));
// Konto mit dem MBMNET-Server abgleichen: holt u. a. den Mii, den man auf der Webseite eingestellt hat
char ignore[96];
// 1. Patches auffrischen (Miiverse-CA aus dem Zwischenspeicher; nur beim allerersten Mal vom Server)
bool hadCa = olvpatch_ca_cached();
refresh_patches();
// 2. SpotPass-Aufgabe anmelden
if (begin_busy()) {
spotpass_register(MBMNET_SERVER, ignore, sizeof(ignore));
maintenanceBusy = false;
}
// 3. Konto mit dem MBMNET-Server abgleichen (holt u. a. den Mii von der Webseite). Höchstens 5 s,
// bei einem Umschalt-Wunsch sofort abbrechen.
u8 slot = frdswitch_slot_of(FRIEND_ACCOUNT_MBMNET);
char id[20];
if (slot && frdswitch_slot_linked(FRIEND_ACCOUNT_MBMNET, id, sizeof(id))) {
Handle done;
if (R_SUCCEEDED(svcCreateEvent(&done, RESET_ONESHOT))) {
if (R_SUCCEEDED(ACTA_SyncAccountInfo(slot, done))) svcWaitSynchronization(done, 15ULL * 1000 * 1000 * 1000);
svcCloseHandle(done);
Handle done;
if (slot && frdswitch_slot_linked(FRIEND_ACCOUNT_MBMNET, id, sizeof(id)) && begin_busy()
&& R_SUCCEEDED(svcCreateEvent(&done, RESET_ONESHOT))) {
if (R_SUCCEEDED(ACTA_SyncAccountInfo(slot, done))) {
// Warten in 100-ms-Schritten (eine Zeitüberschreitung ist kein Fehlercode, nur != 0)
for (int i = 0; i < 50 && svcWaitSynchronization(done, 100ULL * 1000 * 1000) != 0; i++) {
if (switchRequested) { ACT_Cancel(); svcWaitSynchronization(done, 2ULL * 1000 * 1000 * 1000); break; }
}
}
svcCloseHandle(done);
}
bool changed = false;
patchFreshCa = true; // im Hintergrund darf es dauern: Miiverse-CA frisch vom Server
// Patches auffrischen: neue Versionen bringen neue Ziele mit (z. B. Miiverse ab v2.8.0)
if (patch_enable(MBMNET_SERVER, &changed, detail, sizeof(detail)) && changed) maintenanceChanged = true;
patchFreshCa = false;
maintenanceBusy = false;
// 4. Miiverse-CA frisch vom Server (nur Netz; Patches nur neu bauen, wenn sie sich geändert hat)
bool caChanged = false;
if (!switchRequested && olvpatch_refresh_ca(MBMNET_SERVER, &caChanged) && caChanged && hadCa)
refresh_patches(); // prüft selbst noch einmal, ob umgeschaltet werden soll
maintaining = false;
}
@@ -621,10 +655,14 @@ int main(int argc, char **argv)
// Umschalten & Co. warten, bis das Auffrischen im Hintergrund durch ist (meist nur einen Moment)
bool waitForMaintenance = maintaining && queued >= 0 && queued != BTN_FTP && queued != BTN_SPOTPASS
&& queued != BTN_SHOP && queued != BTN_SHOP_DEL;
if (waitForMaintenance) {
switchRequested = true; // Auffrischen: nichts Neues mehr anfangen
waitForMaintenance = maintenanceBusy; // nur warten, solange es Dateien schreibt / das Konto abgleicht
}
if (queued >= 0 && !waitForMaintenance) {
int a = queued;
queued = -1;
if (run(a, msg, sizeof(msg))) rebootIn = 45; // ca. 0,75 Sekunden zum Lesen
if (run(a, msg, sizeof(msg))) rebootIn = 15; // ca. 0,25 Sekunden zum Lesen
st = patch_state();
} else if (action >= 0 && rebootIn == 0 && queued < 0) {
queued = action;
@@ -695,8 +733,10 @@ int main(int argc, char **argv)
// ist es ohnehin schon fertig, Aktionen warten darauf).
bool clean = true;
if (maintenanceThread) {
if (R_SUCCEEDED(threadJoin(maintenanceThread, 20ULL * 1000 * 1000 * 1000))) threadFree(maintenanceThread);
else clean = false;
switchRequested = true;
for (int i = 0; i < 2000 && maintenanceBusy; i++) svcSleepThread(10ULL * 1000 * 1000); // höchstens 20 s
if (R_SUCCEEDED(threadJoin(maintenanceThread, 100ULL * 1000 * 1000))) threadFree(maintenanceThread);
else clean = false; // holt nur noch das Zertifikat: hart beenden ist ungefährlich (atomar geschrieben)
}
clean = admin_finish() && clean;
clean = update_finish() && clean;