Forge
csharpdeeb25a2
1#nullable enable
2
3using System.IO.Pipes;
4using System.Text;
5
6namespace CascadeIDE.Features.MagicLink;
7
8/// <summary>Mutex + named pipe для передачи URI второму экземпляру (ADR 0157 §3).</summary>
9public static class CideMagicLinkSingleInstance
10{
11 public const string PipeName = "CascadeIDE.MagicLink.v1";
12
13 private const string MutexName = @"Local\CascadeIDE.MagicLink.SingleInstance";
14
15 public static bool TryAcquirePrimary(out IDisposable? release)
16 {
17 try
18 {
19 var mutex = new Mutex(initiallyOwned: true, name: MutexName, createdNew: out var createdNew);
20 if (!createdNew)
21 {
22 mutex.Dispose();
23 release = null;
24 return false;
25 }
26
27 release = mutex;
28 return true;
29 }
30 catch
31 {
32 release = null;
33 return false;
34 }
35 }
36
37 public static bool TryForwardToPrimary(string uri, int timeoutMs = 2500)
38 {
39 try
40 {
41 using var client = new NamedPipeClientStream(".", PipeName, PipeDirection.Out);
42 client.Connect(timeoutMs);
43 var bytes = Encoding.UTF8.GetBytes(uri);
44 client.Write(bytes, 0, bytes.Length);
45 client.Flush();
46 return true;
47 }
48 catch
49 {
50 return false;
51 }
52 }
53
54 public static void RunPipeServerLoop(Func<string, Task> onUri, CancellationToken cancellationToken)
55 {
56 _ = Task.Run(async () =>
57 {
58 while (!cancellationToken.IsCancellationRequested)
59 {
60 try
61 {
62 await using var server = new NamedPipeServerStream(
63 PipeName,
64 PipeDirection.In,
65 maxNumberOfServerInstances: 4,
66 PipeTransmissionMode.Byte,
67 PipeOptions.Asynchronous);
68
69 await server.WaitForConnectionAsync(cancellationToken).ConfigureAwait(false);
70 using var ms = new MemoryStream();
71 var buffer = new byte[4096];
72 while (server.IsConnected)
73 {
74 var read = await server.ReadAsync(buffer, cancellationToken).ConfigureAwait(false);
75 if (read <= 0)
76 break;
77 ms.Write(buffer, 0, read);
78 }
79
80 var text = Encoding.UTF8.GetString(ms.ToArray()).Trim();
81 if (text.Length > 0)
82 await onUri(text).ConfigureAwait(false);
83 }
84 catch (OperationCanceledException)
85 {
86 break;
87 }
88 catch
89 {
90 await Task.Delay(200, cancellationToken).ConfigureAwait(false);
91 }
92 }
93 }, cancellationToken);
94 }
95}
96
View only · write via MCP/CIDE