Blog ·
Automatizzare la fatturazione WISP
WISP applica una sospensione, ma non sa se qualcuno ha pagato. Il ciclo di vita, la trappola delle due chiavi e le forme che rompono la prima integrazione.
Di Provibr
WISP sospende un server al posto suo, e fa in modo che quella sospensione tenga: un cliente che possiede ancora le credenziali del pannello non può premere il pulsante di avvio. Ciò che WISP non ha, e non pretende di avere, è una qualsiasi idea del fatto che quel cliente le abbia pagato.
Questa pagina parla dello strato che sta in mezzo. Tratta anche l’unica cosa che rende WISP diverso da ogni altro pannello di gioco qui presente, e che non ha nulla a che vedere con la sua API: il pannello non è suo.
Il pannello è ospitato, il nodo è suo
WISP è venduto come servizio ospitato. wisp.gg fa girare il pannello; il nodo che porta i suoi server di gioco gira sul suo hardware. Un agente all’interno della sua rete parla verso l’esterno con il pannello tramite la sua API e con il daemon del suo nodo per la console, quindi non serve aprire nulla verso internet.
Per un’integrazione di fatturazione quella separazione ha una conseguenza concreta: non c’è nulla da aggiornare e nulla da fissare. WISP può cambiare la propria API senza una release che lei controlla. Provibr è testato su v3.7.5 e legge dal pannello stesso la versione in esecuzione, quindi uno scostamento salta fuori nel test di connessione anziché in un ordine fallito alle due di notte.
Un dettaglio collegato che vale la pena conoscere prima di dare la colpa al proprio codice. La porta d’ingresso del pannello sta dietro una challenge di Cloudflare; ogni percorso /api/… passa dritto. È stato misurato con tre user agent diversi e tutti e tre hanno risposto 200. È un’impostazione di wisp.gg, non sua e nemmeno nostra, quindi se un giorno WISP mettesse la stessa challenge sull’API, ogni integrazione WISP si fermerebbe di colpo e non ci sarebbe nulla da correggere in locale. Il guasto ha una forma riconoscibile (403, un’intestazione Cf-Mitigated: challenge e HTML anziché JSON) e merita un messaggio proprio, così il pannello dice non ci lascia entrare anziché chiave errata.
Il ciclo di vita, in corrispondenza
| Evento di fatturazione | Cosa deve accadere | Effetto lato WISP |
|---|---|---|
| Ordine pagato | Creare il server dall’egg con i limiti del piano | Server creato, allocazione assegnata, viene eseguito l’installer dell’egg |
| Fattura scaduta | Sospendere | suspended impostato, e il pannello lo tiene lì |
| Pagamento ricevuto | Riattivare | suspended rimosso |
| Cancellazione | Eliminare | Server rimosso, allocazione liberata |
| Reinstallazione | Rieseguire lo script di installazione dell’egg | container.installed passa a false, poi a true |
Cinque azioni, e tutte e cinque rispondono con un 204 vuoto. Nel corpo non c’è letteralmente nulla, quindi la regola della casa vale senza eccezioni: nessuna mutazione si fida della propria risposta. Dopo, rileggere il server.
La sospensione è reale, ed è idempotente
Questa combinazione è più rara di quanto dovrebbe essere tra i pannelli di gioco, ed è l’intera ragione per cui un ciclo di solleciti su WISP è noioso nel senso buono.
Una seconda sospensione su un server già sospeso risponde di nuovo 204. Nessun caso speciale da gestire, nulla da trattare come «era già così», nessun errore da inghiottire. Lo si confronti con i pannelli di controllo dove sospendere due volte è un errore di autenticazione, e si vede quanta parte di un’integrazione di solleciti se ne va di solito a scusarsi per il pannello.
Anche l’eliminazione funziona su un server sospeso, e questo conta per la cancellazione che arriva un mese dopo la sospensione. Una seconda eliminazione risponde 404, che è l’esito corretto per un hook di risoluzione: non è rimasto nulla da ripulire.
Le regole di stato dal lato Provibr sono più severe di quelle del pannello, di proposito:
| Azione | Consentita da |
|---|---|
| start | stopped, error, unknown |
| stop / restart / kill | running, error, unknown |
| suspend | running, stopped, installing, error, unknown |
| resume | suspended |
| reinstall | running, stopped, error |
Si legga due volte la riga della sospensione. Si può sospendere un server già fermo, e anche uno ancora in installazione. Se la sospensione funzionasse solo sui server in esecuzione, un cliente potrebbe fermare il proprio server, smettere di pagare e restare intoccabile. Un’applicazione della regola che si può aggirare premendo «stop» non è tale, e una cancellazione che arriva a metà installazione non dovrebbe aspettare che l’installazione finisca.
Due chiavi, nessun prefisso, e l’errore che ne segue
WISP mantiene la divisione di Pterodactyl tra due superfici API, e nessuna singola chiave le copre entrambe. La chiave application crea, sospende, reinstalla e rimuove; la chiave client si occupa dell’alimentazione, delle statistiche live e della console. Entrambe si creano su un account amministratore.
Ecco la trappola. Le chiavi WISP non portano alcun prefisso, a differenza di ptla_ di Pterodactyl o di papp_ di Pelican: sono 48 caratteri senza una testa riconoscibile, quindi nulla può dirle che le ha incollate al contrario. Né noi, né il pannello, perché WISP risponde a una chiave errata con 403 e un messaggio vuoto. Un 403 di norma significa questa chiave non è autorizzata a farlo, quindi un cliente che ha scambiato le due chiavi entra nel pannello e comincia a spuntare permessi che non erano mai il problema. Se il test di connessione fallisce, invertire le due chiavi prima di cambiare qualsiasi altra cosa.
L’altra metà di quella credenziale merita una riga nel proprio runbook: la chiave application non è solo gestione dei server. Lo stesso elenco dei nodi che legge un’integrazione porta anche la chiave di licenza del suo nodo e il token del daemon. La si tratti come una credenziale per l’intero pannello, e la si revochi in WISP se un giorno scollega l’integrazione.
Nulla è istantaneo, e l’API lo dice
Il suo pannello vive nella sua rete e l’agente si connette verso l’esterno, quindi un endpoint che modifica una macchina non può rispondere con il risultato. Risponde che l’ordine è stato accettato e consegna qualcosa da seguire:
POST /v1/servers/{serverId}/actions/suspend
Authorization: Bearer pvk_...
Idempotency-Key: dunning-inv-10482{
"command": {
"id": "cmd_...",
"kind": "game.suspend",
"status": "pending"
}
}Si ottiene 202 Accepted, non 200. Poi si legge il comando finché il suo stato non è definitivo: done, failed, timed_out o cancelled. La lettura non funziona mai così, perché un inventario o una fattura viene da un database e non dal suo host.
Tutto ciò che crea qualcosa accetta un Idempotency-Key di propria composizione. Lo si indicizzi su qualcosa di stabile dal proprio lato, per esempio l’ID della fattura più la fase di sollecito, e un cron ogni quindici minuti, un webhook rinviato e un amministratore che clicca due volte diventano tutti innocui.
Due forme che hanno rotto questa integrazione prima che lei la incontrasse
Vale la pena leggerle entrambe anche se non toccherà mai WISP, perché entrambe sono il tipo di guasto che segnala successo.
Ogni identità è una stringa con prefisso, non un numero. Un server WISP è server_01m0n8m94afcj2kk5mzt9z379q; nodi, egg e allocazioni hanno lo stesso aspetto. La piattaforma aveva un controllo secondo cui l’ID esterno di un server di gioco era fatto di lettere e cifre, cosa vera per ogni altro pannello di gioco e falsa qui. Il risultato non è stato un messaggio di errore: i clienti WISP fuori limite venivano segnalati al worker di applicazione e poi saltati, a ogni singolo giro, per sempre. Erano contrassegnati e non venivano mai sospesi. Ora un unico controllo di identità condiviso copre entrambe le forme.
Un peso del disco pari a zero viene rifiutato. WISP richiede limits.io e pretende un valore compreso tra 10 e 1000. Il campo del piano sulla piattaforma vale zero per impostazione predefinita, quindi ogni ordine WISP sarebbe finito in un 422 relativo a un campo di cui la maggior parte delle persone non ha mai sentito parlare. Adesso ci sono due barriere: il modulo del piano rifiuta uno zero e ne spiega il motivo, e l’agente porta uno zero al peso predefinito prima di inviare. Due barriere per un solo errore sono volute, perché una delle due sta dal lato che si vede.
Ciò che non si può vedere, e che non si deve fingere di vedere
Questa è la parte onesta, ed è breve.
- Su un server WISP non c’è alcun campo di stato. Pterodactyl ne ha uno, con dentro
installingeinstall_failed. WISP hasuspendedecontainer.installed, entrambi booleani. Un’installazione fallita ha quindi esattamente lo stesso aspetto di una in corso:installedresta false in entrambi i casi. In costruzione e rotto sono la stessa immagine su questa superficie, e un prodotto che sostiene il contrario sta tirando a indovinare. - Un nodo non riporta la propria occupazione. Il campo che gli altri pannelli usano per questo è assente, anche quando lo si richiede esplicitamente. L’occupazione viene invece sommata a partire dai server, cosa che funziona e costa una chiamata in più.
- Nelle statistiche live non c’è l’uptime. Un container che si è riavviato tra due letture non può essere riconosciuto con certezza. In compenso, WISP non mette in cache quelle statistiche per venti secondi come fa Pterodactyl, quindi i grafici non inventano un calo che non è mai avvenuto. Nel complesso è meglio, con un bordo tagliente.
La capacità, e come incontra i solleciti
Provibr le fattura la capacità, non i suoi clienti. Ciò che addebita per un server di gioco resta interamente all’interno del suo sistema di fatturazione; noi non vediamo mai la fattura di un cliente e non parliamo mai con i suoi clienti.
La regola che coglie tutti il primo mese: ogni server conta, in esecuzione o no. Uno sospeso non conta, e nemmeno uno eliminato. Arrestare una macchina non libera nulla.
Questo si allinea piuttosto bene con i solleciti. Si sospende un cliente per mancato pagamento e da quel momento smette di contare nella sua capacità; lo si riattiva quando paga e torna a contare. Non sta pagando capacità di piattaforma per qualcuno che non sta pagando lei.
Ciò che di proposito non è automatizzato
Provibr gestisce i server, non il pannello. Non installa WISP, non tocca il daemon del suo nodo oltre alla console, e su questo provider non gestisce backup, regole del firewall o assegnazione degli IP: quelle capacità sono spente nel registro anziché implementate a metà. Non c’è fatturazione a consumo sull’uso di WISP, perché le statistiche per server sono mostrate nel pannello e non esposte tramite l’API, e su un endpoint che non esiste non si può fatturare.
Se sta ancora scegliendo, il confronto da leggere per primo è Scegliere un pannello di gioco dalla sua API, che misura sei pannelli su esattamente una domanda: se una sospensione faccia davvero qualcosa. La connessione in sé, le due chiavi e il campo dell’impronta sono trattati sulla pagina dell’integrazione WISP.
Domande frequenti
WISP ha una fatturazione propria?
No. WISP ospita e controlla server di gioco; non ha ordini, non ha fatture, non ha solleciti e non ha idea di quale cliente stia dietro a quale server. Lo strato commerciale è quello che aggiunge lei.
Sospendere un server in WISP ferma davvero il cliente?
Sì. WISP ha una vera primitiva di sospensione sulla sua API application, e un cliente con le credenziali del pannello non può avviare un server sospeso. Non vale per ogni pannello di gioco: PufferPanel non ha alcuna sospensione, e GameAP ha un flag che, misurato, non cambia nulla.
È sicuro che un ciclo di solleciti sospenda due volte lo stesso server?
Sì. Una seconda sospensione risponde 204 esattamente come la prima. Non c’è alcun errore «già sospeso» da intercettare e nessuno stato da controllare prima, ed è questo che rende semplice un lavoro notturno di solleciti su WISP.
Perché le due chiavi API di WISP vengono scambiate così spesso?
Perché non portano alcun prefisso. Pterodactyl e Pelican etichettano le proprie chiavi; quelle di WISP sono 48 caratteri senza una testa riconoscibile. Una coppia invertita produce un 403 con un messaggio vuoto, che si legge come un problema di permessi anziché come l’errore di incollaggio che è.
Posso fatturare ai clienti WISP quello che hanno consumato?
Non tramite l’API. L’uso per server è visibile nel pannello ma non è esposto come endpoint, quindi la fatturazione a consumo non ha nulla da leggere. Ciò che funziona oggi è un prezzo basato sulla capacità per server.