mirror of
https://github.com/rfvgyhn/min-ed-launcher.git
synced 2026-02-04 12:45:45 +00:00
fix launcher not shutting down when a startup process doesn't properly/takes too long to shutdown
fixes #110
This commit is contained in:
@ -2,6 +2,11 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Bug Fixes
|
||||
- Fix launcher not shutting down when a startup process doesn't properly shutdown or takes too long to shutdown.
|
||||
The timeout for taking too long can be configured via the new `shutdownTimeout` property in the [settings file].
|
||||
It defaults to 10 seconds.
|
||||
|
||||
### Misc
|
||||
- Update Frontier auth API to use v3.0 endpoints to match changes in default launcher
|
||||
|
||||
|
||||
@ -190,6 +190,7 @@ Linux: `$XDG_CONFIG_HOME/min-ed-launcher/settings.json` (`~/.config` if `$XDG_CO
|
||||
| forceUpdate | By default, Steam and Epic updates are handled by their respective platform. In cases like the Odyssey alpha, FDev doesn't provide updates through Steam or Epic. This allows the launcher to force updates to be done via FDev servers by providing a comma delimited list of SKUs |
|
||||
| processes | Additional applications to launch before launching the game |
|
||||
| shutdownProcesses | Additional applications to launch after game has shutdown |
|
||||
| shutdownTimeout | Time, in seconds, to wait for additional applications to shutdown before forcefully terminating them |
|
||||
| filterOverrides | Manually override a product's filter for use with launch options filter flag (e.g. /edo, /edh, etc...) |
|
||||
| additionalProducts | Provide extra products to the authorized product list. Useful for launching Horizons 4.0 when you own the Odyssey DLC |
|
||||
|
||||
@ -222,6 +223,7 @@ double backslash (`\\`) instead of a single backslash (`\`).
|
||||
"arguments": "--arg1 --arg2"
|
||||
}
|
||||
],
|
||||
"shutdownTimeout": 10,
|
||||
"filterOverrides": [
|
||||
{ "sku": "FORC-FDEV-DO-1000", "filter": "edo" },
|
||||
{ "sku": "FORC-FDEV-DO-38-IN-40", "filter": "edh4" }
|
||||
|
||||
@ -416,7 +416,7 @@ let run settings launcherVersion cancellationToken = taskResult {
|
||||
if not cancellationToken.IsCancellationRequested then
|
||||
let startProcesses = Process.launchProcesses startProcesses
|
||||
launchProduct settings.DryRun settings.CompatTool processArgs settings.Restart selectedProduct.Name p
|
||||
Process.stopProcesses startProcesses
|
||||
Process.stopProcesses settings.ShutdownTimeout startProcesses
|
||||
settings.ShutdownProcesses |> List.iter (fun p -> Log.info $"Starting process %s{p.FileName}")
|
||||
Process.launchProcesses shutdownProcesses |> Process.writeOutput
|
||||
return 0
|
||||
|
||||
@ -26,7 +26,7 @@ let private terminate (p: Process) =
|
||||
if p.CloseMainWindow() then
|
||||
Ok ()
|
||||
else
|
||||
Error ""
|
||||
Error "Process has no main window or the main window is disabled"
|
||||
#else
|
||||
open Microsoft.FSharp.NativeInterop
|
||||
|
||||
@ -60,12 +60,18 @@ let private terminate (p: Process) =
|
||||
let ansiColorSupported() = not (String.IsNullOrEmpty(Environment.GetEnvironmentVariable("TERM")))
|
||||
#endif
|
||||
|
||||
let termProcess (p: Process) =
|
||||
let termProcess (timeout: TimeSpan) (p: Process) =
|
||||
if p.HasExited then
|
||||
Ok ()
|
||||
else
|
||||
match terminate p with
|
||||
| Ok _ -> Ok ()
|
||||
| Error msg ->
|
||||
terminate p
|
||||
|> Result.bind(fun _ ->
|
||||
if p.WaitForExit(timeout) then
|
||||
Ok ()
|
||||
else
|
||||
Error $"Process took longer than %f{timeout.TotalSeconds} seconds to shutdown"
|
||||
)
|
||||
|> Result.mapError (fun msg ->
|
||||
p.Kill(true)
|
||||
Error $"Unable to gracefully stop %s{p.ProcessName}. Killed process instead. %s{msg}"
|
||||
$"Unable to gracefully stop %s{p.ProcessName}. Killed process instead. %s{msg}"
|
||||
)
|
||||
@ -19,7 +19,7 @@ let launchProcesses (processes:ProcessStartInfo list) =
|
||||
Log.exn e $"Unable to start process %s{p.FileName}"
|
||||
None)
|
||||
|
||||
let stopProcesses (processes: Process list) =
|
||||
let stopProcesses timeout (processes: Process list) =
|
||||
processes
|
||||
|> List.iter (fun p ->
|
||||
use p = p
|
||||
@ -27,7 +27,7 @@ let stopProcesses (processes: Process list) =
|
||||
Log.debug $"Process %i{p.Id} already exited"
|
||||
else
|
||||
Log.debug $"Stopping process %s{p.ProcessName}"
|
||||
match Interop.termProcess p with
|
||||
match Interop.termProcess timeout p with
|
||||
| Ok () ->
|
||||
p.StandardOutput.ReadToEnd() |> ignore
|
||||
p.StandardError.ReadToEnd() |> ignore
|
||||
|
||||
@ -29,7 +29,8 @@ let defaults =
|
||||
ShutdownProcesses = List.empty
|
||||
FilterOverrides = OrdinalIgnoreCaseMap.empty
|
||||
AdditionalProducts = List.empty
|
||||
DryRun = false }
|
||||
DryRun = false
|
||||
ShutdownTimeout = TimeSpan.FromSeconds(10) }
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
type FrontierCredResult = Found of string * string * string option | NotFound of string | UnexpectedFormat of string | Error of string
|
||||
@ -171,7 +172,9 @@ type Config =
|
||||
Processes: ProcessConfig list
|
||||
ShutdownProcesses: ProcessConfig list
|
||||
FilterOverrides: FilterConfig list
|
||||
AdditionalProducts: AuthorizedProduct list }
|
||||
AdditionalProducts: AuthorizedProduct list
|
||||
[<DefaultValue("10")>]
|
||||
ShutdownTimeout: int }
|
||||
let parseConfig fileName =
|
||||
let configRoot = ConfigurationBuilder()
|
||||
.AddJsonFile(fileName, false)
|
||||
@ -254,4 +257,5 @@ let getSettings args appDir fileConfig = task {
|
||||
ShutdownProcesses = shutdownProcesses
|
||||
FilterOverrides = filterOverrides
|
||||
WatchForCrashes = fileConfig.WatchForCrashes
|
||||
AdditionalProducts = fileConfig.AdditionalProducts }) }
|
||||
AdditionalProducts = fileConfig.AdditionalProducts
|
||||
ShutdownTimeout = TimeSpan.FromSeconds(fileConfig.ShutdownTimeout) }) }
|
||||
@ -125,7 +125,8 @@ type LauncherSettings =
|
||||
ShutdownProcesses: ProcessStartInfo list
|
||||
FilterOverrides: OrdinalIgnoreCaseMap<string>
|
||||
AdditionalProducts: AuthorizedProduct list
|
||||
DryRun: bool }
|
||||
DryRun: bool
|
||||
ShutdownTimeout: TimeSpan }
|
||||
type ProductMode = Online | Offline
|
||||
type VersionInfo =
|
||||
{ Name: string
|
||||
|
||||
Reference in New Issue
Block a user