Skip to content

Commit 120dedb

Browse files
committed
properly shutdown flatpaks
if `fileName` ends with "flatpak", capture app id and then use `flatpak kill appId` to shutdown rather than sending SIGTERM. SIGTERM by itself doesn't work since flatpaks are run inside a container which also needs to be shutdown fixes #196
1 parent 90bb567 commit 120dedb

File tree

4 files changed

+51
-22
lines changed

4 files changed

+51
-22
lines changed

src/MinEdLauncher/App.fs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ let rec private launchLoop initialLaunch settings playableProducts (session: EdS
313313
| Console.ProductSelection.Product selectedProduct ->
314314
let! p = Product.validateForRun settings.CbLauncherDir settings.WatchForCrashes selectedProduct |> Result.mapError InvalidProductState
315315
let pArgs() = processArgs selectedProduct
316-
let logStart (ps: ProcessStartInfo list) = ps |> List.iter (fun p -> Log.info $"Starting process %s{p.FileName}")
316+
let logStart (ps: LauncherProcess list) = ps |> List.iter (fun p -> Log.info $"Starting process %s{p.Name}")
317317
let persistentStartInfos, relaunchStartInfos =
318318
let relaunchProcesses = settings.Processes |> List.filter _.RestartOnRelaunch |> List.map _.Info
319319
match persistentRunning with
@@ -580,14 +580,14 @@ let run settings launcherVersion cancellationToken = taskResult {
580580

581581
let processesToStop =
582582
runningProcesses
583-
|> List.filter (fun p ->
583+
|> List.choose (fun (p, l) ->
584584
settings.Processes
585-
|> List.tryFind (fun s -> s.Info.FileName = p.StartInfo.FileName && s.KeepOpen = false)
586-
|> Option.isSome)
585+
|> List.tryFind (fun s -> s.Info.StartInfo.FileName = p.StartInfo.FileName && s.KeepOpen = false)
586+
|> Option.map (fun _ -> p, l))
587587

588588
Process.stopProcesses settings.ShutdownTimeout processesToStop
589-
settings.ShutdownProcesses |> List.iter (fun p -> Log.info $"Starting process %s{p.FileName}")
590-
Process.launchProcesses true settings.ShutdownProcesses |> Process.waitForExit
589+
settings.ShutdownProcesses |> List.iter (fun p -> Log.info $"Starting process %s{p.Name}")
590+
Process.launchProcesses true settings.ShutdownProcesses |> List.map fst |> Process.waitForExit
591591

592592
return didLoop
593593
}

src/MinEdLauncher/Process.fs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,56 @@
11
module MinEdLauncher.Process
22

3+
open System
34
open System.ComponentModel
45
open System.Diagnostics
6+
open MinEdLauncher.Types
57

6-
let launchProcesses printOutput (processes:ProcessStartInfo list) =
8+
let launchProcesses printOutput (processes:LauncherProcess list) =
79
processes
8-
|> List.choose (fun p ->
10+
|> List.choose (fun l ->
911
try
10-
let p = Process.Start(p)
12+
let p = Process.Start(l.StartInfo)
1113
p.BeginErrorReadLine()
1214
p.BeginOutputReadLine()
1315

1416
if printOutput then
1517
p.OutputDataReceived.Add(fun a -> if a.Data <> null then printfn $" %s{a.Data}")
1618
p.ErrorDataReceived.Add(fun a -> if a.Data <> null then printfn $" %s{a.Data}")
1719

18-
p |> Some
20+
(p, l) |> Some
1921
with
2022
| :? Win32Exception as e ->
21-
Log.exn e $"""Unable to start process %s{p.FileName}
23+
Log.exn e $"""Unable to start process %s{l.Name}
2224
HRESULT: 0x{e.ErrorCode:X}
2325
Win32 Error Code: {e.NativeErrorCode}
2426
"""
2527
None
2628
| e ->
27-
Log.exn e $"Unable to start process %s{p.FileName}"
29+
Log.exn e $"Unable to start process %s{l.Name}"
2830
None)
2931

30-
let stopProcesses timeout (processes: Process list) =
32+
let stopProcesses (timeout: TimeSpan) (processes: (Process * LauncherProcess) list) =
3133
processes
32-
|> List.iter (fun p ->
34+
|> List.iter (fun (p, l) ->
3335
use p = p
3436
if p.HasExited then
3537
Log.debug $"Process %i{p.Id} already exited"
3638
else
37-
Log.debug $"Stopping process %s{p.ProcessName}"
38-
match Interop.termProcess timeout p with
39-
| Ok () ->
40-
Log.info $"Stopped process %s{p.ProcessName}"
41-
| Error msg -> Log.warn msg)
39+
let name = match l with Host _ -> p.ProcessName | Flatpak _ -> l.Name
40+
Log.debug $"Stopping process %s{name}"
41+
match l.ShutdownCommand with
42+
| Some startInfo ->
43+
try
44+
use p = Process.Start(startInfo)
45+
if not (p.WaitForExit(timeout)) then
46+
Log.warn $"Process did not exit within %i{int timeout.TotalSeconds} seconds"
47+
else
48+
Log.info $"Stopped process %s{name}"
49+
with e -> Log.exn e $"Failed to stop process %s{name}"
50+
| None ->
51+
match Interop.termProcess timeout p with
52+
| Ok () -> Log.info $"Stopped process %s{name}"
53+
| Error msg -> Log.warn msg)
4254

4355
let waitForExit (processes: Process list) =
4456
processes

src/MinEdLauncher/Settings.fs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,17 @@ let private mapProcessConfig p =
259259
pInfo.UseShellExecute <- false
260260
pInfo.RedirectStandardOutput <- true
261261
pInfo.RedirectStandardError <- true
262-
pInfo
262+
if p.FileName.EndsWith("flatpak") then
263+
match pInfo.Arguments.Split(' ', StringSplitOptions.RemoveEmptyEntries ||| StringSplitOptions.TrimEntries) |> Array.toList with
264+
| "run" :: args ->
265+
args
266+
|> Seq.skipWhile _.StartsWith('-')
267+
|> Seq.tryHead
268+
|> Option.map (fun appId -> Flatpak (appId, pInfo))
269+
|> Option.defaultWith (fun () -> (Host pInfo))
270+
| _ -> (Host pInfo)
271+
else
272+
Host pInfo
263273
let getSettings args appDir fileConfig = task {
264274
let findCbLaunchDir paths =
265275
appDir :: paths

src/MinEdLauncher/Types.fs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@ type AuthorizedProduct =
108108
SortKey: int
109109
Sku: string
110110
TestApi: bool }
111+
type LauncherProcess = Host of ProcessStartInfo | Flatpak of appId: string * startInfo: ProcessStartInfo with
112+
member this.Name = match this with Host startInfo -> startInfo.FileName | Flatpak (appId, _) -> appId
113+
member this.StartInfo = match this with Host startInfo -> startInfo | Flatpak (_, startInfo) -> startInfo
114+
member this.ShutdownCommand =
115+
match this with
116+
| Host _ -> None
117+
| Flatpak (appId, startInfo) -> Some(ProcessStartInfo(startInfo.FileName, $"kill %s{appId}"))
111118
type LauncherSettings =
112119
{ Platform: Platform
113120
DisplayMode: DisplayMode
@@ -126,8 +133,8 @@ type LauncherSettings =
126133
CheckForLauncherUpdates: bool
127134
MaxConcurrentDownloads: int
128135
ForceUpdate: string Set
129-
Processes: {| Info: ProcessStartInfo; RestartOnRelaunch: bool; KeepOpen: bool |} list
130-
ShutdownProcesses: ProcessStartInfo list
136+
Processes: {| Info: LauncherProcess; RestartOnRelaunch: bool; KeepOpen: bool |} list
137+
ShutdownProcesses: LauncherProcess list
131138
FilterOverrides: OrdinalIgnoreCaseMap<string>
132139
AdditionalProducts: AuthorizedProduct list
133140
DryRun: bool

0 commit comments

Comments
 (0)