Vive Streaming ment à SteamVR : son driver prétend qu'un HMD est présent
même quand la session Wi-Fi avec le casque physique est tombée. Donc
tous les signaux qui passent par SteamVR (VR_IsHmdPresent, vtable
IVRSystem, logs vrserver) sont contaminés et ne reflètent pas l'état
réel du casque. Le check qu'on a ajouté en v0.23.4 induisait l'utilisateur
en erreur ("vert" alors que le casque est éteint).
Pour l'instant on retire le check du default. Bookmark dans le code des
pistes Phase 2 qui ne passent PAS par SteamVR : connexions TCP/UDP de
HtcConnectionUtility via GetExtendedTcpTable, endpoint local de Vive
Console, compteurs IO, ARP avec OUIs HTC, logs Vive directs.
Le Kind « VrDevice » reste dispo dans l'éditeur pour les setups SteamVR
purs (Index/Vive Wand sur Lighthouse) où le signal est honnête, mais
n'est plus poussé par défaut.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
265 lines
12 KiB
C#
265 lines
12 KiB
C#
namespace PSLauncher.Models;
|
|
|
|
public sealed class LocalConfig
|
|
{
|
|
public int SchemaVersion { get; set; } = 1;
|
|
public string ServerBaseUrl { get; set; } = "https://example.com/PS_Launcher/api";
|
|
public string InstallRoot { get; set; } = string.Empty;
|
|
public string? LastLaunchedVersion { get; set; }
|
|
|
|
/// <summary>
|
|
/// Code de langue de l'UI : "auto" (suit la langue Windows), "fr", "en",
|
|
/// "zh", "th" ou "ar". Tout changement nécessite un redémarrage du launcher.
|
|
/// </summary>
|
|
public string Language { get; set; } = "auto";
|
|
|
|
/// <summary>
|
|
/// Nombre de connexions HTTP parallèles utilisées pour télécharger un build.
|
|
/// 1 = comportement legacy single-connection. 4-8 contourne le throttling
|
|
/// per-connection d'Apache/OVH mutualisé. 16 = défaut depuis v0.19 pour
|
|
/// raccourcir la « queue » en fin de DL : avec 8 segments sur 14 Go, le
|
|
/// dernier segment doit finir seul ~1.75 Go (visible comme un effondrement
|
|
/// du débit en fin de course) ; avec 16, c'est ~875 Mo. Push à 24/32 si
|
|
/// ton serveur l'accepte (OVH mutualisé tient bien jusqu'à 16-24).
|
|
/// </summary>
|
|
public int ParallelDownloadSegments { get; set; } = 16;
|
|
|
|
/// <summary>
|
|
/// Si false, ignore la vérification SHA-256 même si le manifest l'exige.
|
|
/// Utile sur les machines lentes ou pour gagner 30 s-3 min en fin de DL d'un gros build.
|
|
/// La sécurité repose alors uniquement sur la signature Ed25519 du manifest + HTTPS,
|
|
/// ce qui reste robuste.
|
|
/// </summary>
|
|
public bool VerifyDownloadHash { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// URL de l'outil de reporting local (page web embarquée dans le launcher,
|
|
/// onglet "Report"). Par défaut pointe vers l'install standard ASTERION
|
|
/// dans XAMPP. Surchargeable dans Settings → Avancés.
|
|
/// </summary>
|
|
public string ReportUrl { get; set; } = "http://localhost/ProserveReport/";
|
|
|
|
/// <summary>
|
|
/// URL de la documentation locale (onglet "Documentation"). Pointe par défaut
|
|
/// vers l'install standard ASTERION dans XAMPP. Surchargeable dans Settings →
|
|
/// Avancés. Si vide, l'onglet affiche un placeholder.
|
|
/// </summary>
|
|
public string DocumentationUrl { get; set; } = "http://localhost/ProserveDoc/";
|
|
|
|
public LicenseConfig License { get; set; } = new();
|
|
|
|
/// <summary>
|
|
/// Configuration du déploiement de l'outil Report (page web locale embarquée
|
|
/// dans l'onglet "Statistiques") vers la racine XAMPP htdocs.
|
|
/// Le launcher copie le dossier <c>_report/</c> bundled dans chaque ZIP
|
|
/// PROSERVE vers <c>{HtdocsRoot}\{FolderName}</c> à chaque install.
|
|
/// </summary>
|
|
public ReportToolConfig ReportTool { get; set; } = new();
|
|
|
|
/// <summary>
|
|
/// Configuration du déploiement de l'outil Documentation (page web locale
|
|
/// embarquée dans l'onglet "Documentation"). Même mécanisme que ReportTool :
|
|
/// copie de <c>_doc/</c> bundled dans le ZIP PROSERVE vers
|
|
/// <c>{HtdocsRoot}\{FolderName}</c> avec backups horodatés et revert.
|
|
/// </summary>
|
|
public DocToolConfig DocTool { get; set; } = new();
|
|
|
|
/// <summary>
|
|
/// Surveillance d'état système affichée en bandeau sous la top bar
|
|
/// (pings d'IP, processus requis comme SteamVR / Vive Business Streaming…).
|
|
/// Chaque check a un statut Vert (OK) / Orange (warn, ex. ping élevé) / Rouge
|
|
/// (KO). Tooltip détaillé au survol.
|
|
/// </summary>
|
|
public HealthChecksConfig HealthChecks { get; set; } = new();
|
|
|
|
/// <summary>
|
|
/// Connexion à la base MySQL locale (XAMPP) utilisée par PROSERVE pour ses
|
|
/// statistiques. Le launcher s'en sert pour appliquer les migrations bundled
|
|
/// dans <c>_migrations/</c> au moment de l'install d'une nouvelle version.
|
|
/// </summary>
|
|
public DatabaseConfig Database { get; set; } = new();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Paramètres de connexion à la base MySQL locale. Les valeurs par défaut
|
|
/// correspondent à un XAMPP standard fraîchement installé. Override possible
|
|
/// via Settings → Base de données.
|
|
/// </summary>
|
|
public sealed class DatabaseConfig
|
|
{
|
|
public string Host { get; set; } = "localhost";
|
|
public uint Port { get; set; } = 3306;
|
|
public string User { get; set; } = "root";
|
|
|
|
/// <summary>
|
|
/// Mot de passe MySQL stocké chiffré DPAPI (CurrentUser scope) en base64.
|
|
/// Vide = pas de password (config XAMPP par défaut). NE PAS écrire en clair.
|
|
/// </summary>
|
|
public string? EncryptedPassword { get; set; }
|
|
|
|
/// <summary>
|
|
/// Nom de la base de données qui contient les tables de PROSERVE.
|
|
/// Default "proserveapi" — c'est le nom utilisé par le script d'install ASTERION
|
|
/// qui provisionne XAMPP sur les machines clients. À surcharger seulement si la DB
|
|
/// a été créée sous un autre nom.
|
|
/// </summary>
|
|
public string Database { get; set; } = "proserveapi";
|
|
|
|
/// <summary>
|
|
/// Si true, le launcher applique automatiquement les migrations SQL bundled
|
|
/// dans <c>_migrations/</c> de chaque ZIP, juste après l'extraction.
|
|
/// Sécurité : on n'applique JAMAIS sans cette opt-in (au cas où certains users
|
|
/// auraient une config DB exotique non gérée par le defaut).
|
|
/// </summary>
|
|
public bool AutoApplyMigrations { get; set; } = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Paramètres de déploiement de l'outil Report local.
|
|
/// Le launcher cherche un sous-dossier <c>_report/</c> dans chaque ZIP PROSERVE
|
|
/// installé et le copie vers <c>{HtdocsRoot}\{FolderName}</c> via un rename
|
|
/// atomique (deploy en .new puis swap). L'URL de l'onglet Statistiques pointe
|
|
/// vers <c>http://localhost/{FolderName}/</c> ; les deux doivent matcher.
|
|
/// </summary>
|
|
public sealed class ReportToolConfig
|
|
{
|
|
public string HtdocsRoot { get; set; } = @"C:\xampp\htdocs";
|
|
public string FolderName { get; set; } = "ProserveReport";
|
|
public bool AutoDeploy { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// Nombre de backups horodatés à conserver dans htdocs après chaque deploy.
|
|
/// Format des dossiers : <c>{FolderName}.backup-yyyyMMdd-HHmmss</c>.
|
|
/// Permet le revert via Settings si le nouveau deploy a un bug visible.
|
|
/// 3 par défaut = couvre les dernières releases sans grossir trop le disque.
|
|
/// 0 = pas de backup (retourne au comportement v0.12.0).
|
|
/// </summary>
|
|
public int MaxBackups { get; set; } = 3;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Mêmes paramètres que <see cref="ReportToolConfig"/> mais pour la
|
|
/// documentation locale (sous-dossier <c>_doc/</c> du ZIP, déployé vers
|
|
/// <c>{HtdocsRoot}\ProserveDoc</c> par défaut).
|
|
/// </summary>
|
|
public sealed class DocToolConfig
|
|
{
|
|
public string HtdocsRoot { get; set; } = @"C:\xampp\htdocs";
|
|
public string FolderName { get; set; } = "ProserveDoc";
|
|
public bool AutoDeploy { get; set; } = true;
|
|
public int MaxBackups { get; set; } = 3;
|
|
}
|
|
|
|
public sealed class HealthChecksConfig
|
|
{
|
|
/// <summary>Période de re-vérification, en secondes. 0 = désactivé.</summary>
|
|
public int RefreshIntervalSeconds { get; set; } = 10;
|
|
|
|
/// <summary>
|
|
/// Liste des checks à effectuer. Defaults = exemples typiques setup VR
|
|
/// (SteamVR + Vive Business Streaming + ping casque). L'utilisateur édite
|
|
/// la liste via <c>%LocalAppData%\PSLauncher\config.json</c> pour ajuster
|
|
/// les noms de processus, IPs et seuils ; un éditeur Settings est prévu
|
|
/// en v2 si le besoin est récurrent.
|
|
/// </summary>
|
|
public List<HealthCheckEntry> Checks { get; set; } = new()
|
|
{
|
|
new HealthCheckEntry
|
|
{
|
|
Name = "SteamVR",
|
|
Icon = "🎮",
|
|
Kind = "Process",
|
|
Target = "vrserver",
|
|
},
|
|
new HealthCheckEntry
|
|
{
|
|
Name = "Vive Business Streaming",
|
|
Icon = "📡",
|
|
Kind = "Process",
|
|
Target = "HtcConnectionUtility",
|
|
},
|
|
// PAS de check « casque connecté » par défaut.
|
|
//
|
|
// Pourquoi : avec Vive Business Streaming dans la pile, le driver Vive
|
|
// ment à SteamVR — il prétend qu'un HMD est présent même quand la
|
|
// session Wi-Fi avec le casque physique est tombée. Donc tous les
|
|
// signaux qui passent par SteamVR (VR_IsHmdPresent, vtable IVRSystem,
|
|
// logs vrserver) sont contaminés par ce mensonge et ne reflètent pas
|
|
// l'état réel du casque.
|
|
//
|
|
// À traiter en Phase 2 via un signal authoritative qui ne passe PAS
|
|
// par SteamVR (pistes brainstormées : connexions TCP/UDP de
|
|
// HtcConnectionUtility via GetExtendedTcpTable, endpoint local de
|
|
// Vive Console, compteurs IO du process, ARP table avec OUIs HTC,
|
|
// logs Vive Streaming directs). Ajout d'un Kind dédié à ce moment-là.
|
|
};
|
|
}
|
|
|
|
public sealed class HealthCheckEntry
|
|
{
|
|
/// <summary>Libellé affiché dans le bandeau, ex. "SteamVR".</summary>
|
|
public string Name { get; set; } = "";
|
|
|
|
/// <summary>Pictogramme emoji affiché à côté du nom, ex. "🎮", "📡", "🥽".</summary>
|
|
public string Icon { get; set; } = "🔌";
|
|
|
|
/// <summary>"Process" ou "Ping" (case-insensitive).</summary>
|
|
public string Kind { get; set; } = "Process";
|
|
|
|
/// <summary>
|
|
/// Selon Kind : nom du processus (sans .exe) pour Process,
|
|
/// IP/hostname pour Ping. Vide = check ignoré (statut Unknown).
|
|
/// </summary>
|
|
public string Target { get; set; } = "";
|
|
|
|
/// <summary>
|
|
/// Période entre 2 vérifications de CE check, en millisecondes. Indépendant
|
|
/// pour chaque entry car un Process check est rapide (~1ms) et peut tourner
|
|
/// toutes les secondes, alors qu'un Ping coûte une requête réseau et peut
|
|
/// tourner toutes les 5-10 s. Default 5000 ms.
|
|
/// </summary>
|
|
public int RefreshIntervalMs { get; set; } = 5000;
|
|
|
|
/// <summary>Pour Ping : RTT au-dessus duquel le statut passe en Warning (Orange). Default 50 ms.</summary>
|
|
public int? PingWarnMs { get; set; } = 50;
|
|
|
|
/// <summary>Pour Ping : RTT au-dessus duquel le statut passe en Error (Rouge). Default 200 ms.</summary>
|
|
public int? PingErrorMs { get; set; } = 200;
|
|
|
|
/// <summary>Pour Ping : timeout de la requête ICMP. Default 1 s.</summary>
|
|
public int? PingTimeoutMs { get; set; } = 1000;
|
|
}
|
|
|
|
public sealed class LicenseConfig
|
|
{
|
|
public string? EncryptedKey { get; set; }
|
|
|
|
/// <summary>
|
|
/// Date UTC de la dernière validation online réussie. Utilise <c>response.ServerTime</c>
|
|
/// (signé Ed25519) plutôt que l'horloge locale, donc non manipulable par l'utilisateur.
|
|
/// Sert de point de départ au calcul d'expiration du cache offline.
|
|
/// </summary>
|
|
public DateTime? LastValidationAt { get; set; }
|
|
|
|
public DateTime? CachedEntitlementUntil { get; set; }
|
|
public string? CachedOwnerName { get; set; }
|
|
|
|
/// <summary>
|
|
/// Statut tel que renvoyé par le serveur lors de la dernière validation : "valid",
|
|
/// "expired", "revoked", "invalid", "machine_limit_exceeded". Persisté pour qu'une
|
|
/// révocation effectuée pendant que le user est offline soit toujours visible
|
|
/// même après son expiration de cache local. Le calcul "valid → expired" basé
|
|
/// sur la date est aussi appliqué côté lecture (sanity) si le temps a passé.
|
|
/// </summary>
|
|
public string? CachedStatus { get; set; }
|
|
|
|
/// <summary>
|
|
/// Compteur monotone : date UTC la plus récente jamais observée par le launcher
|
|
/// sur cette machine. Mise à jour à chaque démarrage si <c>now</c> est postérieur.
|
|
/// Sert d'anti-rollback : si l'utilisateur recule l'horloge PC, on détecte
|
|
/// (now < LastSeenUtc - grace) et on invalide le cache → forçage d'une
|
|
/// re-validation online la prochaine fois qu'il sera connecté.
|
|
/// </summary>
|
|
public DateTime? LastSeenUtc { get; set; }
|
|
}
|