Files
ogame_db/DOCUMENTAZIONE.md
2026-09-23 18:59:27 +02:00

352 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# OGame Galaxy Viewer — Documentazione tecnica
Visualizzatore di galassie per **OGame (s170-ar, universo "Rosalind")** con archivio
personale dei rapporti di spionaggio e classifiche filtrate.
Questa documentazione descrive l'architettura, i sorgenti e, per ciascuno, funzioni
e metodi.
---
## 1. Panoramica
Il progetto è una **web app personale** composta da:
| Componente | Tecnologia | Ruolo |
|---|---|---|
| Backend | Python 3 + Flask | API REST, aggiornamento dati, archivio rapporti |
| Frontend | HTML/CSS/JS vanilla | Galaxy view, dettagli rapporti, classifiche |
| Dati | File JSON su disco | Nessun database: snapshot + rapporti come file |
| Servizi | systemd (utente) | App sempre attiva + aggiornamenti schedulati |
**Flusso dati (dati universo)**:
```
Gameforge API pubblica (XML + ?toJson=1)
│ ogni giorno (03:30)
▼
update_data.py ──► data/latest/*.json ──► world.json (indici)
│ ▲
└── highscore ── ogni ora (:17) ─────┘
│
app.py (Flask :8899) ──► browser (galassia/classifiche)
```
**Flusso dati (rapporti di spionaggio)**:
```
In gioco (pulsante "API" del rapporto) ──► API string "sr-ar-170-<40 hex>"
│ incollata nella pagina
▼
POST /api/reports ──► report_store.py ──► proxy community (ogapi.faw-kes.de)
▼
data/reports/<sr_id>.json (+ index.json)
▼
clic sul pianeta in galassia ──► dettagli archiviati
```
---
## 2. Struttura delle directory
```
/opt/ogame_db/
├── app.py # Backend Flask: pagine + API + aggiornamento all'avvio
├── update_data.py # Download snapshot pubblici + classifiche + world.json
├── report_store.py # Import/archivio/consultazione rapporti di spionaggio
├── technames.py # Nomi tecnologici (edifici/ricerche/navi/difese) lato server
├── config.json # Configurazione (universo, proxy, account personale)
├── requirements.txt # Dipendenze Python
├── README.md # Guida rapida d'uso
├── DOCUMENTAZIONE.md # (questo file)
├── data/
│ ├── latest/ # Snapshot correnti + world.json
│ ├── snapshots/ # Storico giornaliero (ritenzione: keep_snapshots)
│ └── reports/ # Rapporti importati (1 file = 1 rapporto) + index.json
└── static/
├── index.html # Pagina galassia
├── rankings.html # Pagina classifiche
├── style.css # Stili (tema spaziale, responsive)
├── common.js # Utility condivise (fetch, avatar SVG, icone, stelle)
├── app.js # Logica della galassia e dei rapporti
├── rankings.js # Logica della pagina classifiche
├── icons.js # Icone SVG incorporate (game-icons, CC BY 3.0)
└── icons/ # (riservata a eventuali svg esterni; non usata a runtime)
```
---
## 3. `config.json` — configurazione
```json
{
"server_number": 170, // numero universo
"community": "ar", // community (lingua/regione)
"domain": "s170-ar.ogame.gameforge.com",
"my_player_id": 100634, // tuo account: pianeti evidenziati in verde
"my_player_name": "MaNaki",
"proxy_base": "https://ogapi.faw-kes.de", // proxy ufficiale per i rapporti
"refresh_hours": 24, // dati "stale" oltre N ore → update all'avvio
"keep_snapshots": 30 // giorni di storico conservati
}
```
---
## 4. Backend — moduli Python
### 4.1 `app.py` — server Flask (porta 8899)
Avviato da systemd come `ogame-galaxy.service`. All'avvio verifica l'età dei dati
(`_ensure_fresh_data`) e, se più vecchi di `refresh_hours`, lancia `update_data.main()`.
**Middleware**
| Funzione | Descrizione |
|---|---|
| `_no_cache(resp)` | `after_request`: imposta `Cache-Control: no-store` su pagine e file statici (niente cache nel browser) |
**Helper**
| Funzione | Descrizione |
|---|---|
| `load_config()` | Legge `config.json` |
| `load_world()` | Legge `data/latest/world.json` e vi fonde i **pianeti noti solo dai rapporti** (player recenti assenti da `universe.xml`), marcandoli `report_only` |
| `fmt_ts(epoch)` | Converte epoch in stringa `YYYY-MM-DD HH:MM UTC` |
| `_report_view(rec, full)` | Trasforma un record d'archivio + payload in una **vista sintetica** per la UI (date, attività, risorse, conteggi per categoria, flag `failed_*`) |
| `_ensure_fresh_data()` | Aggiornamento automatico all'avvio se i dati sono datati |
**Endpoint HTTP**
| Rotte | Descrizione |
|---|---|
| `GET /` | Pagina galassia (`static/index.html`) |
| `GET /rankings` | Pagina classifiche (`static/rankings.html`) |
| `GET /api/bootstrap` | Stato: `server` (nome, galassie, sistemi, velocità…), `myPlayer`, `fetched` (date ultimo aggiornamento per fonte), `reportStats` (n. rapporti/pianeti) |
| `GET /api/galaxy?g=&s=` | Celle del sistema (15 posizioni): per ogni cella pianeta, luna, giocatore (+stato, alleanza, **rank totale/armamenti**), rapporti disponibili |
| `GET /api/planet?g=&s=&p=` | Dettaglio pianeta: info, giocatore con rank, altri pianeti dello stesso giocatore, rapporti del pianeta e della luna |
| `GET /api/player?id=` | Dettaglio giocatore: tutti i suoi pianeti e **tutti** i rapporti (su qualunque pianeta o luna), ordinati per data |
| `POST /api/reports` | Importa un rapporto: body `{"token": "sr-ar-170-<id>"}` (o solo l'id a 40 hex). Idempotente: se già presente ritorna `created:false` |
| `GET /api/reports/<sr_id>` | JSON completo di un rapporto archiviato (`{meta, report}`) |
| `DELETE /api/reports/<sr_id>` | Elimina un rapporto archiviato (file su disco + voce in `index.json`) |
| `GET /api/rankings?type=&status=&start=&end=&q=` | Classifiche filtrate (vedi 4.4) |
| `POST /api/refresh` | Forza `update_data.main()` in background |
### 4.2 `update_data.py` — aggiornamento dati
Scarica l'API pubblica ufficiale di Gameforge (endpoint XML con `?toJson=1`).
**Costanti**
| Costante | Valore |
|---|---|
| `ENDPOINTS` | `serverData`, `universe`, `players`, `alliances`, `localization` |
| `HIGHSCORES` | `highscore_total` (cat.1, type 0), `highscore_military` (cat.1, type 3) |
| `UA` | User-Agent dichiarato nelle richieste |
**Funzioni**
| Funzione | Descrizione |
|---|---|
| `load_config()` | Legge `config.json` |
| `http_get(url, timeout)` | GET con User-Agent |
| `fetch_xml_json(cfg, name, query)` | Scarica `https://s<num>-<comm>.ogame.gameforge.com/api/<name>.xml?toJson=1<query>` e aggiunge `_fetched_at` |
| `fetch_endpoint(cfg, name)` | Wrapper per gli endpoint semplici |
| `fetch_highscore(...)` | *(helper storico)* scarica un highscore |
| `save_latest(name, data)` | Salva in `data/latest/<name>.json` |
| `save_snapshot(name, data)` | Copia giornaliera in `data/snapshots/<name>_<AAAA-MM-GG>.json` (una per giorno; prune oltre `keep_snapshots`) |
| `_as_dict(payload, key, attr_key)` | Normalizza `{"player":[{"@attributes":{...}}]}` → `{id: {...}}` |
| `build_world(cfg)` | Costruisce `world.json` (vedi §6) |
| `_file_time(name)` | Epoch dell'ultimo fetch di un file `latest` |
| `update_highscores(cfg, with_snapshot)` | Scarica i 2 highscore |
| `main()` | Esegue l'aggiornamento; con argomento `--highscore-only` aggiorna **solo** le classifiche (usato dal timer orario) |
### 4.3 `report_store.py` — archivio rapporti di spionaggio
Gestisce il ciclo di vita dei rapporti: parsing API string → recupero dal proxy →
salvataggio JSON → indicizzazione per coordinate.
**Funzioni**
| Funzione | Descrizione |
|---|---|
| `load_config()` | Legge `config.json` |
| `_load_index()` / `_save_index(idx)` | Legge/scrive `data/reports/index.json` |
| `parse_token(token, cfg)` | Valida l'API string `(cr\|sr\|rr\|mr)-<comm>-<num>-<40hex>`; verifica che community/server combacino con la config; accetta anche il solo id esadecimale (assunto `sr`) |
| `fetch_from_proxy(api_string, cfg)` | `GET {proxy}/v1/report/{api_string}/1`; gestisce 429 (limite proxy ~10 req/min) e `RESULT_CODE != 1000` |
| `_defender_info(report)` | Estrae dal payload `generic` i dati del bersaglio (coordinate, tipo pianeta/luna, nomi, data evento, attività, % bottino) |
| `import_report(api_string, cfg)` | Parsa → scarica → salva `data/reports/<sr_id>.json` → aggiorna `index.json`. Ritorna `(record, creato?)`. Idempotente |
| `get_report(rid)` | Legge il file completo `{meta, report}` |
| `delete_report(rid)` | Elimina un rapporto (file + indice, ripulisce `by_coords`). Ritorna `True` se rimosso |
| `list_by_coords(coords, scope)` | Elenca i rapporti di un pianeta. `scope`: `planet` \| `moon` \| `all`, ordinati per `event_timestamp` desc |
| `summary(rec)` | *(utilità)* alias del record sintetico |
| `stats(cfg)` | Conta rapporti totali e pianeti coperti |
### 4.4 Filtri `/api/rankings`
Parametri: `type` (`total`|`military`|`fleet`), `status`, `start`/`end` (range posizione), `q` (testo su nome giocatore, tag o nome alleanza).
Con `type=fleet` (**Top Flotte**) la classifica non usa gli highscore: elenca solo i
giocatori che hanno almeno un rapporto importato, ordinati per **numero di navi**.
Le navi sono sommate prendendo, per ogni pianeta/luna spiato, il **rapporto più
recente** (campo `total_ship_count`, memorizzato nell'indice all'import); la
posizione `rank` è quella della classifica flotte e il valore è in `score`.
Valori di `status` e relativa condizione sullo stato API:
| status | stato API ammesso |
|---|---|
| `all` | qualsiasi |
| `active` | *(vuoto)* |
| `inactive` | `i`, `I` |
| `vacation` | `v` |
| `vacation_inactive` | `vi`, `vI` |
| `admin` | `a` |
> **Nota UI:** la pagina `/rankings` espone solo le voci **Tutti** (`all`),
> **Attivi** (`active`) e **Inattivi** (`inactive`). Gli altri valori restano
> accettati dall'API per compatibilità, ma non sono più selezionabili
> dall'interfaccia.
Le righe restituite includono: id, nome, stato, alleanza (tag+nome), posizione, punteggio, coordinate del primo pianeta (per l'avatar), numero pianeti, flag `mine`, numero di rapporti di spionaggio sul giocatore (`reports`) e coordinate del rapporto più recente (`report_coords`, usata per il salto dal badge "Spie").
### 4.5 `technames.py` — dizionario nomi tech (server)
Mappe `id → nome` per la numerazione **client attuale** (diversa da quella storica):
edifici 1–44, ricerca 106–199, navi 202–219, difese 401–503, edifici lifeform 11101+.
Nota: il frontend ha una copia aggiornata nei propri sorgenti (vedi §5.4, `NAMES`);
`technames.py` resta come riferimento/utilità lato server.
| Funzione | Descrizione |
|---|---|
| `_localized_names()` | Carica i nomi localizzati da `data/latest/localization.json` (fallback) |
| `item_name(category, tid)` | Nome di un elemento (IT → localizzato → `"Categoria #id"`) |
| `category_name(cat)` | Etichetta della categoria |
---
## 5. Frontend — `static/`
### 5.1 `common.js` — utility condivise
| Funzione | Descrizione |
|---|---|
| `esc(s)` | Escape HTML |
| `num(v)` | Formatta numeri in stile italiano (`1.234.567`), `—` se nullo |
| `hashStr(s)` | Hash deterministico (per i colori degli avatar) |
| `api(path, opts)` | `fetch` JSON con gestione errori (`{ok:false, error}`) |
| `icon(name, size)` | Ritorna l'SVG inline dell'icona da `window.ICONS` (icons.js) con `currentColor` |
| `artSVG(seedKey, size, moon)` | Avatar pianeta/luna in SVG: colore scelto da palette in base all'hash, con ombra e (per la luna) crateri |
| `initStars()` | Sfondo stellare su canvas (twinkle); **non bloccante** se canvas non disponibile |
### 5.2 `app.js` — galassia e rapporti
| Funzione | Descrizione |
|---|---|
| `loadBootstrap()` | Popola header: nome universo, range galassie/sistemi, date dati, conteggio spie |
| `loadGalaxy()` | `GET /api/galaxy` e render della tabella |
| `renderGalaxy(data)` | Costruisce le 15 righe: posizione, pianeta (avatar SVG + nome), luna, giocatore (colore per stato + 🏆/⚔ rank), alleanza, badge "spie" |
| `openPlanet(pos, focusMoon)` | Apre il popup del pianeta (`GET /api/planet`) |
| `openPlanetAt(coords, focusMoon)` | Apre il popup di un pianeta date le coordinate `g:s:p`, anche di un altro sistema |
| `openPlayer(pid)` / `renderPlayerPopup(d)` | Apre la finestra **giocatore** (`GET /api/player`): elenco di tutti i pianeti + tutti i rapporti di spionaggio sul giocatore, in un'unica vista |
| `renderPlanetPopup(data, focusMoon)` | Header con avatar; chip giocatore/stato/classifica/luna; altri pianeti del giocatore (cliccabili); **griglia di card** per gli spionaggi del pianeta e della luna |
| `rptCard(rec)` | Card riepilogo di un rapporto (data, attività colorata, bersaglio con **coordinate** `[g:s:p]`, attaccante, conteggi con icone categoria) |
| `openReport(srId)` / `renderReportDetail(meta, rep)` | Vista dettaglio: risorse in tile colorate, meta (difensore/attaccante/attività/bottino/detriti), avvisi `failed_*`, sezioni in **griglia di card** con icona per ogni edificio/ricerca/nave/difesa |
| `techSection(...)` | Griglia card per categoria |
| `itemName(cat, id)` / `itemIconName(cat, id)` | Nome e chiave-icona di un elemento (fallback sulla categoria) |
| `actClass/actLabel(activity)` | Colore/etichetta dell'attività rilevata (0/15/30/60 min) |
| `fmtEv(evt)` | Data evento in formato locale italiano |
| `setSystem/setGalaxy/closePopup/goToCoords` | Navigazione (con clamp sui limiti universo) |
| `setMsg(kind, text)` | Messaggi di stato nella barra di import |
| `importReport()` | Legge l'API string, `POST /api/reports`, aggiorna la vista |
Stato globale: `state = {galaxy, system, maxGalaxy, maxSystem, boot}`.
All'avvio legge `?g=` e `?s=` dalla URL (usato dai click dalle classifiche).
**Colori stato giocatore** (come in galaxy OGame): attivo = giallo · inattivo (`i/I`) =
grigio · vacanza+inattivo = grigio · in vacanza = celeste · admin = rosso.
### 5.3 `rankings.js` — classifiche
| Funzione | Descrizione |
|---|---|
| `initHead()` | Header con nome universo e data aggiornamento classifiche |
| `load()` | `GET /api/rankings` con i filtri correnti |
| `render(d)` | Tabella: posizione (top3 colorati oro/argento/bronzo), avatar pianeta, giocatore (colore stato, ● = tu), alleanza, stato, pianeti, **Spie** (badge col numero di rapporti sul giocatore, cliccabile verso il pianeta del rapporto più recente), punti |
| `goGalaxy(coords)` | Salta alla galassia `/?g=..&s=..` al pianeta del giocatore |
| `readFilters()` | Legge i controlli (stato, range, testo) |
Tabs: **Generale** (total), **Armamenti** (military) e **Top Flotte** (fleet — solo
giocatori con rapporti, ordinati per navi), con icone SVG.
### 5.4 Mappe dati nel frontend (`NAMES`, `ITEM_ICON`)
`NAMES[buildings|research|ships|defense|lfbuildings]` → `{id: nome}` e
`ITEM_ICON[...]` → `{id: chiave icona}`. Nomi allineati al client attuale
(es. `213 → "Corazzata"`, `215 → "Incrociatore da battaglia"`,
`210 → "Sonda di spionaggio"`).
### 5.5 `icons.js` / icone
`window.ICONS = { chiave: {vb, body} }` con **87 icone**: 79 da game-icons.net
(CC BY 3.0, attribuzione nei footer) + icone UI custom (refresh, chevron, chiusura,
logo, avviso). Tutte usano `fill="currentColor"`: il colore segue il CSS di categoria
(`--tc`), quindi **nessuna dipendenza dai font emoji del sistema**.
---
## 6. Dati su disco — `data/`
### 6.1 `data/latest/*.json`
Snapshot grezzi dell'API (`serverData`, `universe`, `players`, `alliances`,
`localization`, `highscore_total`, `highscore_military`), ciascuno con `_fetched_at`.
### 6.2 `data/latest/world.json` (indici precompilati)
| Chiave | Contenuto |
|---|---|
| `server` | numero, community, dominio, nome universo, galassie, sistemi, velocità, versione, lingua, timezone, ACS |
| `fetched` | epoch dell'ultimo fetch per ogni fonte |
| `players` | `{id: {name, status, alliance, alliance_tag, alliance_name}}` |
| `alliances` | `{id: {name, tag, founder}}` |
| `planets` | `{"g:s:p": {id, player, name, coords, moon:{...}}}`. Le voci con `report_only: true` non vengono dall'API pubblica ma da un rapporto di spionaggio (pianeti di player recenti assenti da `universe.xml`) |
| `avatar` | `{playerId: prime-coordinate}` (per gli avatar in classifica) |
| `ranks` | `{playerId: {total, military, total_score, military_score}}` |
### 6.3 `data/snapshots/`
Copie giornaliere `*_AAAA-MM-GG.json` per fonte (ritenzione configurabile).
### 6.4 `data/reports/`
- `index.json`: `{by_coords: {"g:s:p": [sr_id,…], "g:s:p#moon": [… ]}, reports: {sr_id: {meta…}}}` → ricerca immediata per pianeta/luna.
- `<sr_id>.json`: `{"meta": {…}, "report": {generic, details}}` (payload completo del proxy).
---
## 7. Servizi systemd (utente)
| Unità | Quando | Cosa fa |
|---|---|---|
| `ogame-galaxy.service` | sempre attivo | web app su `0.0.0.0:8899` (restart on failure) |
| `ogame-data-update.timer` | giornaliero 03:30 | `update_data.py` (pianeti/giocatori/alleanze + highscore) |
| `ogame-highscore.timer` | ogni ora (:17) | `update_data.py --highscore-only` (classifiche) |
Comandi utili: `systemctl --user status/restart <unità>`,
`journalctl --user -u ogame-galaxy.service -f`, `loginctl show-user principale | grep Linger`
(linger=yes ⇒ i servizi partono al boot senza login).
---
## 8. API esterne utilizzate
| Sorgente | Uso | Note |
|---|---|---|
| `https://s170-ar.ogame.gameforge.com/api/*.xml?toJson=1` | API **pubblica** ufficiale: universe, players, alliances, serverData, localization, highscore | `highscore.xml?category=1&type=0\|3`; cadenze server: universe ~settimanale, players ~giornaliero, highscore ~orario |
| `https://ogapi.faw-kes.de/v1/report/{api_string}/1` | **Proxy community ufficiale** per il recupero dei rapporti (CR/SR/RR/MR) | Nessuna API key necessaria; limite ~10 richieste/min |
| `https://forum.origin.ogame.gameforge.com` | Documentazione ufficiale (thread "OGame API", procedure accesso) | Riferimento del protocollo |
---
## 9. Note operative e di sicurezza
1. **Accesso**: app su `0.0.0.0:8899` **senza autenticazione**: se la rete non è
privata, mettere un reverse proxy con login.
2. **Backup**: copiare `data/` (report inclusi) e `config.json`.
3. **Cache**: i file statici sono serviti con `no-store`: un refresh basta dopo ogni
modifica (nessun `Ctrl+F5` necessario, ma non guasta).
4. **Privacy**: i rapporti restano su questo server; il proxy viene contattato solo
al momento dell'import di un nuovo token (che il giocatore controlla e condivide
volontariamente).
5. **Licenza icone**: game-icons.net, CC BY 3.0 (attribuzione nei footer di pagina).