IPCClient.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. using H.Pipes;
  2. using InABox.Core;
  3. using InABox.IPC.Shared;
  4. using System;
  5. using System.Collections.Concurrent;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10. namespace InABox.Client.IPC
  11. {
  12. public class IPCClient : IDisposable
  13. {
  14. private PipeClient<PipeRequest> Client;
  15. private ConcurrentDictionary<Guid, ManualResetEventSlim> Events = new();
  16. private ConcurrentDictionary<Guid, PipeRequest> Responses = new();
  17. private const int DefaultRequestTimeout = 5 * 60 * 1000; // 5 minutes
  18. public delegate void ConnectEvent();
  19. public delegate void DisconnectEvent();
  20. public bool Disconnected { get; private set; }
  21. public event ConnectEvent? OnConnect;
  22. public event DisconnectEvent? OnDisconnect;
  23. public IPCClient(string name)
  24. {
  25. Client = new PipeClient<PipeRequest>(name);
  26. Client.Connected += Client_Connected;
  27. Client.Disconnected += Client_Disconnected;
  28. Client.MessageReceived += Client_MessageReceived;
  29. Client.ExceptionOccurred += Client_ExceptionOccurred;
  30. Client.ConnectAsync();
  31. }
  32. private void Client_ExceptionOccurred(object? sender, H.Pipes.Args.ExceptionEventArgs e)
  33. {
  34. Logger.Send(LogType.Error, "", $"Exception occured: {e.Exception.Message}");
  35. }
  36. public PipeRequest Send(PipeRequest request, int timeout = DefaultRequestTimeout)
  37. {
  38. var start = DateTime.Now;
  39. var ev = Queue(request.RequestID);
  40. Client.WriteAsync(request);
  41. var result = GetResult(request.RequestID, ev, timeout);
  42. return result;
  43. }
  44. public ManualResetEventSlim Queue(Guid id)
  45. {
  46. var ev = new ManualResetEventSlim();
  47. Events[id] = ev;
  48. return ev;
  49. }
  50. public PipeRequest GetResult(Guid id, ManualResetEventSlim ev, int timeout)
  51. {
  52. if (Responses.TryGetValue(id, out var result))
  53. {
  54. Responses.Remove(id, out result);
  55. Events.Remove(id, out ev);
  56. return result;
  57. }
  58. try
  59. {
  60. if (!ev.Wait(timeout))
  61. {
  62. return PipeRequest.Error(RequestError.TIMEOUT);
  63. }
  64. }
  65. catch (Exception e)
  66. {
  67. Console.WriteLine(e);
  68. throw;
  69. }
  70. Responses.Remove(id, out result);
  71. Events.Remove(id, out ev);
  72. return result ?? PipeRequest.Error(RequestError.UNKNOWN);
  73. }
  74. private void Client_MessageReceived(object? sender, H.Pipes.Args.ConnectionMessageEventArgs<PipeRequest?> e)
  75. {
  76. if (Events.TryGetValue(e.Message.RequestID, out var ev))
  77. {
  78. Responses[e.Message.RequestID] = e.Message;
  79. ev.Set();
  80. }
  81. else
  82. {
  83. Responses[e.Message.RequestID] = e.Message;
  84. }
  85. }
  86. private void Client_Connected(object? sender, H.Pipes.Args.ConnectionEventArgs<PipeRequest> e)
  87. {
  88. Logger.Send(LogType.Information, "", $"Connected to Pipe: {e.Connection.PipeName}");
  89. Disconnected = false;
  90. OnConnect?.Invoke();
  91. }
  92. private void Client_Disconnected(object? sender, H.Pipes.Args.ConnectionEventArgs<PipeRequest> e)
  93. {
  94. Logger.Send(LogType.Information, "", $"Disconnected from Pipe: {e.Connection.PipeName}");
  95. foreach (var ev in Events)
  96. {
  97. Responses.TryAdd(ev.Key, PipeRequest.Error(RequestError.DISCONNECTED));
  98. ev.Value.Set();
  99. }
  100. Disconnected = true;
  101. OnDisconnect?.Invoke();
  102. }
  103. public void Dispose()
  104. {
  105. Client.DisposeAsync().AsTask().Wait();
  106. }
  107. ~IPCClient()
  108. {
  109. Dispose();
  110. }
  111. }
  112. }