Browse Source

Auto unzip dello stato di factory

main
Lorenzo Pollutri 2 weeks ago
parent
commit
4a8f9e73ad
4 changed files with 67 additions and 0 deletions
  1. +8
    -0
      README.md
  2. BIN
      factory/preset.zip
  3. +15
    -0
      instrumentation.ts
  4. +44
    -0
      lib/bootstrap.ts

+ 8
- 0
README.md View File

@@ -285,6 +285,14 @@ Stato "di fabbrica" ripristinabile con un click. Pensato per preparare preset st

Il preset è un file fisso: **`factory/preset.zip`** alla radice del progetto (fuori da `data/`, quindi non viene toccato dai reset; fuori da `public/`, quindi non scaricabile via web).

### Bootstrap automatico all'avvio

All'avvio del processo Next, un hook ([instrumentation.ts](instrumentation.ts) → [lib/bootstrap.ts](lib/bootstrap.ts)) controlla `data/cards.txt`:
- Se è **assente o `[]` (zero card)** **E** esiste `factory/preset.zip`, il preset viene estratto automaticamente sopra a `data/` (stessa logica del Factory Reset; la eventuale `data/` precedente viene rinominata `data.bak-<timestamp>/`).
- In tutti gli altri casi (cards.txt esiste con contenuto, o il preset manca) il bootstrap non fa nulla.

Questo permette di committare nel repo un `factory/preset.zip` e avere ogni macchina appena clonata/distribuita che parte direttamente nello stato standard, senza interventi manuali in admin. Le righe `[bootstrap]` nei log del server segnalano se ha agito.

### Dall'interfaccia
- **Factory Reset** — sempre visibile. Ripristina tutto al preset (disabilitato se il preset non esiste). La `data/` precedente resta come `data.bak-<timestamp>/`.
- **Save as Factory Preset (dev)** — visibile solo con `FACTORY_PRESET_SAVE_ENABLED = true`. Congela lo stato corrente in `factory/preset.zip`.


BIN
factory/preset.zip View File


+ 15
- 0
instrumentation.ts View File

@@ -0,0 +1,15 @@
// Hook eseguito una sola volta all'avvio del server Next.
// L'unico compito attuale è il bootstrap del factory preset quando data/ è vuoto.

export async function register() {
// Esegui solo nel runtime Node (l'instrumentation può girare anche su Edge,
// dove fs/spawn non esistono).
if (process.env.NEXT_RUNTIME !== 'nodejs') return;

const { bootstrapFromFactoryPresetIfEmpty } = await import('@/lib/bootstrap');
try {
await bootstrapFromFactoryPresetIfEmpty();
} catch (err) {
console.warn('[instrumentation] Bootstrap error:', err);
}
}

+ 44
- 0
lib/bootstrap.ts View File

@@ -0,0 +1,44 @@
// Bootstrap "stato di fabbrica" automatico all'avvio.
//
// Se all'avvio del server NON ci sono card in data/cards.txt (file mancante o `[]`)
// E esiste factory/preset.zip, il preset viene estratto sopra a data/.
// È quello che permette a una macchina appena clonata/distribuita di partire con
// lo stato standard senza interventi manuali.

import { readFile, access } from 'node:fs/promises';
import path from 'node:path';
import { restoreFromZipFile } from './restore-zip';

const PROJECT_ROOT = process.cwd();
const CARDS_FILE = path.join(PROJECT_ROOT, 'data', 'cards.txt');
const PRESET_PATH = path.join(PROJECT_ROOT, 'factory', 'preset.zip');

async function hasCards(): Promise<boolean> {
try {
const raw = await readFile(CARDS_FILE, 'utf-8');
const parsed = JSON.parse(raw || '[]');
return Array.isArray(parsed) && parsed.length > 0;
} catch {
return false;
}
}

export async function bootstrapFromFactoryPresetIfEmpty(): Promise<void> {
// Niente preset di fabbrica → niente da fare, sezione opzionale.
try {
await access(PRESET_PATH);
} catch {
return;
}

// Stato non vuoto → l'admin ha già contenuti, non sovrascriviamo.
if (await hasCards()) return;

console.log('[bootstrap] No cards found; restoring factory preset from factory/preset.zip');
const result = await restoreFromZipFile(PRESET_PATH);
if (result.ok) {
console.log(`[bootstrap] Restored ${result.cards} cards, ${result.portals} portals from factory preset`);
} else {
console.warn(`[bootstrap] Factory restore failed: ${result.error}${result.detail ? ` (${result.detail})` : ''}`);
}
}

Loading…
Cancel
Save