using System.Diagnostics; using System.Text.Json; using MeetingAssistant.LaunchProfiles; using Microsoft.Extensions.Options; namespace MeetingAssistant.MacOs; public sealed class MacOsDesktopControlService : IHostedService, IDisposable { private readonly ILaunchProfileOptionsProvider launchProfiles; private readonly IOptions options; private readonly IHostApplicationLifetime applicationLifetime; private readonly ILogger logger; private Process? helper; private string? manifestPath; public MacOsDesktopControlService( ILaunchProfileOptionsProvider launchProfiles, IOptions options, IHostApplicationLifetime applicationLifetime, ILogger logger) { this.launchProfiles = launchProfiles; this.options = options; this.applicationLifetime = applicationLifetime; this.logger = logger; } public Task StartAsync(CancellationToken cancellationToken) { if (!OperatingSystem.IsMacOS()) { return Task.CompletedTask; } var helperPath = Path.Combine(AppContext.BaseDirectory, "Native", "macos-desktop-controls"); if (!File.Exists(helperPath)) { logger.LogWarning("macOS desktop controls helper was not found at {HelperPath}", helperPath); return Task.CompletedTask; } var manifest = MacOsDesktopControlManifest.Create( options.Value.Api.PublicBaseUrl, launchProfiles.GetProfiles(), launchProfiles.GetHotkeys()); manifestPath = Path.Combine( Path.GetTempPath(), $"meeting-assistant-desktop-{Environment.ProcessId}.json"); File.WriteAllText( manifestPath, JsonSerializer.Serialize( manifest, new JsonSerializerOptions(JsonSerializerDefaults.Web))); helper = Process.Start(new ProcessStartInfo { FileName = helperPath, ArgumentList = { manifestPath }, UseShellExecute = false, CreateNoWindow = true }); if (helper is null) { throw new InvalidOperationException("Could not start the macOS desktop controls helper."); } helper.EnableRaisingEvents = true; helper.Exited += (_, _) => { if (!applicationLifetime.ApplicationStopping.IsCancellationRequested) { logger.LogWarning("macOS desktop controls helper exited unexpectedly"); } }; logger.LogInformation("Started macOS menu-bar controls with {HotkeyCount} global hotkeys", manifest.Hotkeys.Count); return Task.CompletedTask; } public Task StopAsync(CancellationToken cancellationToken) { if (helper is { HasExited: false }) { helper.Kill(); helper.WaitForExit(TimeSpan.FromSeconds(2)); } DeleteManifest(); return Task.CompletedTask; } public void Dispose() { helper?.Dispose(); DeleteManifest(); } private void DeleteManifest() { if (manifestPath is not null && File.Exists(manifestPath)) { File.Delete(manifestPath); manifestPath = null; } } }