Fonctionne entièrement offline si un PC du LAN a fetché OVH récemment :
les autres PCs récupèrent le manifest + les ZIPs depuis lui sans Internet.
Discovery des peers quasi-instantanée au cold start, fail-fast partout sur
les fetch OVH pour ne pas bloquer la UI.
== Manifest fallback offline ==
- IManifestCache + ManifestCache (Core/Manifests/) : cache disque du dernier
manifest réussi (JSON brut byte-for-byte pour préserver la signature Ed25519).
Path : %LocalAppData%\PSLauncher\manifest-cache.json
- IPeerManifestFetcher + PeerManifestFetcher (Core/Lan/) : récupère le
manifest brut depuis un peer LAN via GET /v1/manifest. Probe parallèle
avec timeout court par peer.
- LanCacheServer : nouvelle route GET /v1/manifest qui sert le cache disque
byte-for-byte aux clients sans Internet.
- ManifestService.FetchAsync : online check d'abord (ping ICMP 8.8.8.8 +
fallback TCP connect au serveur OVH si firewall bloque ICMP, timeout
800ms × 2). Si online → OVH only (canonique, voit toutes les versions).
Si offline → peer LAN puis cache disque local.
- ManifestSource enum exposé via IManifestService.LastSource → call sites
peuvent prendre des décisions éclairées (skip release notes, badge UI).
== Discovery active des peers (cold start instantané) ==
- LanCacheServer : nouvelle route GET /v1/info qui retourne {host, port,
versions} (même payload que les beacons UDP).
- LanDiscoveryService : bootstrap au démarrage qui probe en parallèle tous
les peers connus (cache disque) + manuels (config) via /v1/info, timeout
1s par peer. Les peers qui répondent sont injectés dans _peers avec
lastSeen=now → apparaissent immédiatement dans ListDiscovered() et donc
dans la sidebar + PeerSourceResolver. Plus besoin d'attendre les 15s du
prochain beacon UDP.
- ILanDiscoveryService.ListKnown() exposé pour que les fetchers puissent
utiliser le cache disque comme seed.
- LocalConfig.LanCache.ManualPeerUrls : default ["http://10.0.4.100:47623"]
(IP fixe du serveur ASTERION dans toutes les salles VR).
== Timeouts courts sur tous les fetch OVH (fail-fast offline) ==
- ManifestService : 3s pour le manifest fetch (vs 100s par défaut)
- LicenseService.ValidateAsync : 3s (résolvait le délai de ~15s pendant
CheckForUpdates en offline — HttpClient global a Timeout=Infinite,
sans CTS court ça hangait jusqu'à l'abandon SYN TCP par l'OS)
- LicenseService.GetSignedDownloadUrlAsync : 5s
- ManifestService.FetchReleaseNotesAsync : 5s
== UI ==
- StatusMessage post-Check Updates suffixé avec la source du manifest :
"🌐 OVH (en ligne)" / "📡 Peer LAN (hors ligne)" / "💾 Cache local (hors ligne)"
- InstallVersionAsync : skip le fetch release notes si manifest source
!= OVH → dialog s'ouvre instantanément avec "indisponible" au lieu
d'attendre 5s de timeout.
== Latences attendues ==
| Scénario | Avant | Après |
|---|---|---|
| Vérifier MAJ online | ~5s | ~500ms |
| Vérifier MAJ offline | ~15-20s | ~5s |
| Cold start discovery (1 peer connu) | jusqu'à 15s | ~200ms |
| Click Install offline | ~5s release notes timeout | instantané |
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
95 lines
4.9 KiB
Plaintext
95 lines
4.9 KiB
Plaintext
; Script Inno Setup pour PS_Launcher
|
|
; Compilation : ouvrir avec Inno Setup Compiler (https://jrsoftware.org/isdl.php)
|
|
; ou en ligne de commande :
|
|
; "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" PSLauncher.iss
|
|
;
|
|
; Avant compile :
|
|
; 1. Faire `dotnet publish src/PSLauncher.App -c Release` (génère PS_Launcher.exe ~77 Mo)
|
|
; 2. Faire `dotnet publish src/PSLauncher.Updater -c Release` (génère PS_Launcher.Updater.exe ~10 Mo)
|
|
;
|
|
; Le script picore directement les binaires dans bin/Release/.../publish/.
|
|
|
|
#define MyAppName "PROSERVE Launcher"
|
|
#define MyAppShortName "PS_Launcher"
|
|
#define MyAppVersion "0.25.10"
|
|
#define MyAppPublisher "ASTERION VR"
|
|
#define MyAppURL "https://asterionvr.com"
|
|
#define MyAppExeName "PS_Launcher.exe"
|
|
#define MyUpdaterExeName "PS_Launcher.Updater.exe"
|
|
|
|
[Setup]
|
|
; AppId est UNIQUE pour PSLauncher — ne pas changer entre deux versions sinon
|
|
; chaque release créera une nouvelle entrée dans Programmes et fonctionnalités.
|
|
AppId={{8A4F3E1B-9D2C-4A6B-8F5E-3C7A1D9B4E2F}
|
|
AppName={#MyAppName}
|
|
AppVersion={#MyAppVersion}
|
|
AppVerName={#MyAppName} {#MyAppVersion}
|
|
AppPublisher={#MyAppPublisher}
|
|
AppPublisherURL={#MyAppURL}
|
|
AppSupportURL={#MyAppURL}
|
|
AppUpdatesURL={#MyAppURL}
|
|
; Installation system-wide dans Program Files. {autopf} résout vers
|
|
; "C:\Program Files" sur cible 64-bit (cf. ArchitecturesInstallIn64BitMode=x64
|
|
; ci-dessous). PrivilegesRequired=admin → UAC à l'install, et UAC à chaque
|
|
; self-update du launcher (LauncherSelfUpdater détecte automatiquement le
|
|
; dossier non-writable et lance PS_Launcher.Updater.exe avec Verb="runas").
|
|
; Le staging du nouveau .exe avant swap reste dans %LocalAppData%\PSLauncher\
|
|
; selfupdate\, user-writable et lisible depuis l'updater élevé.
|
|
DefaultDirName={autopf}\{#MyAppPublisher}\{#MyAppShortName}
|
|
DefaultGroupName={#MyAppName}
|
|
DisableProgramGroupPage=yes
|
|
OutputDir=output
|
|
OutputBaseFilename=PS_Launcher-Setup-{#MyAppVersion}
|
|
SetupIconFile=..\src\PSLauncher.App\Resources\favicon.ico
|
|
Compression=lzma2/ultra
|
|
SolidCompression=yes
|
|
WizardStyle=modern
|
|
PrivilegesRequired=admin
|
|
UsedUserAreasWarning=no
|
|
ArchitecturesAllowed=x64
|
|
ArchitecturesInstallIn64BitMode=x64
|
|
UninstallDisplayName={#MyAppName}
|
|
UninstallDisplayIcon={app}\{#MyAppExeName}
|
|
VersionInfoVersion={#MyAppVersion}
|
|
VersionInfoCompany={#MyAppPublisher}
|
|
VersionInfoProductName={#MyAppName}
|
|
|
|
[Languages]
|
|
Name: "french"; MessagesFile: "compiler:Languages\French.isl"
|
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
|
|
|
[Tasks]
|
|
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
|
|
|
|
[Files]
|
|
Source: "..\src\PSLauncher.App\bin\Release\net8.0-windows10.0.17763.0\win-x64\publish\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
|
|
Source: "..\src\PSLauncher.Updater\bin\Release\net8.0-windows\win-x64\publish\{#MyUpdaterExeName}"; DestDir: "{app}"; Flags: ignoreversion
|
|
Source: "..\docs\PS_Launcher-Guide-Utilisateur.pptx"; DestDir: "{app}\docs"; Flags: ignoreversion
|
|
|
|
[Icons]
|
|
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
|
Name: "{group}\Guide utilisateur"; Filename: "{app}\docs\PS_Launcher-Guide-Utilisateur.pptx"; IconFilename: "{app}\{#MyAppExeName}"
|
|
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
|
|
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
|
|
|
|
[Run]
|
|
; Règles firewall pour le cache LAN P2P. Profile=private,domain (PAS public) =
|
|
; safety net : même si l'utilisateur connecte le PC à un Wi-Fi public, le port
|
|
; reste fermé. Le filtre RFC1918 dans LanCacheServer.cs est la première barrière,
|
|
; ces règles sont la deuxième. runhidden = pas de console visible à l'install.
|
|
Filename: "{sys}\netsh.exe"; Parameters: "advfirewall firewall add rule name=""PSLauncher LAN Cache HTTP"" dir=in action=allow program=""{app}\{#MyAppExeName}"" protocol=TCP localport=47623 profile=private,domain"; Flags: runhidden
|
|
Filename: "{sys}\netsh.exe"; Parameters: "advfirewall firewall add rule name=""PSLauncher LAN Discovery"" dir=in action=allow program=""{app}\{#MyAppExeName}"" protocol=UDP localport=47624 profile=private,domain"; Flags: runhidden
|
|
|
|
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#MyAppName}}"; Flags: nowait postinstall skipifsilent
|
|
|
|
[UninstallRun]
|
|
Filename: "{sys}\netsh.exe"; Parameters: "advfirewall firewall delete rule name=""PSLauncher LAN Cache HTTP"""; Flags: runhidden
|
|
Filename: "{sys}\netsh.exe"; Parameters: "advfirewall firewall delete rule name=""PSLauncher LAN Discovery"""; Flags: runhidden
|
|
|
|
[UninstallDelete]
|
|
; Ne touche PAS au cache utilisateur (%LocalAppData%\PSLauncher) ni aux versions installées
|
|
; (qui peuvent vivre dans n'importe quel installRoot configuré). On supprime uniquement les
|
|
; binaires installés et le dossier d'install s'il est vide après.
|
|
Type: filesandordirs; Name: "{app}\*.bak"
|
|
Type: dirifempty; Name: "{app}"
|