using System; using System.IO; using System.IO.Pipes; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Kniip.Infrastructure; /// /// Zorgt dat kniip maar één keer draait. Een tweede start stuurt zijn argumenten /// via een named pipe door naar de eerste instantie en sluit daarna af. /// internal sealed class SingleInstance : IDisposable { private static readonly string BaseName = "Kniip-" + Environment.UserName; private static readonly string PipeName = BaseName + "-pipe"; private readonly CancellationTokenSource _cts = new(); private Mutex? _mutex; public bool TryAcquire() { _mutex = new Mutex(true, BaseName + "-mutex", out bool createdNew); return createdNew; } public static bool SendToPrimary(string[] args) { try { using var client = new NamedPipeClientStream(".", PipeName, PipeDirection.Out); client.Connect(3000); using var writer = new StreamWriter(client, Encoding.UTF8); writer.Write(string.Join("\n", args)); writer.Flush(); return true; } catch (Exception) { return false; } } public void StartServer(Action onArguments) { Task.Run(async () => { while (!_cts.IsCancellationRequested) { try { await using var server = new NamedPipeServerStream(PipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.CurrentUserOnly); await server.WaitForConnectionAsync(_cts.Token); using var reader = new StreamReader(server, Encoding.UTF8); string content = await reader.ReadToEndAsync(_cts.Token); string[] args = content.Length == 0 ? Array.Empty() : content.Split('\n', StringSplitOptions.RemoveEmptyEntries); onArguments(args); } catch (OperationCanceledException) { break; } catch (Exception) { await Task.Delay(500); } } }); } public void Dispose() { _cts.Cancel(); if (_mutex != null) { try { _mutex.ReleaseMutex(); } catch (ApplicationException) { } _mutex.Dispose(); } } }