IPCClient.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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. internal 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. ev.Wait(timeout);
  61. }
  62. catch (Exception e)
  63. {
  64. Console.WriteLine(e);
  65. throw;
  66. }
  67. Responses.Remove(id, out result);
  68. Events.Remove(id, out ev);
  69. return result ?? PipeRequest.Error(RequestError.UNKNOWN);
  70. }
  71. private void Client_MessageReceived(object? sender, H.Pipes.Args.ConnectionMessageEventArgs<PipeRequest?> e)
  72. {
  73. if (Events.TryGetValue(e.Message.RequestID, out var ev))
  74. {
  75. Responses[e.Message.RequestID] = e.Message;
  76. ev.Set();
  77. }
  78. else
  79. {
  80. Responses[e.Message.RequestID] = e.Message;
  81. }
  82. }
  83. private void Client_Connected(object? sender, H.Pipes.Args.ConnectionEventArgs<PipeRequest> e)
  84. {
  85. Logger.Send(LogType.Information, "", "Connected to server");
  86. Disconnected = false;
  87. OnConnect?.Invoke();
  88. }
  89. private void Client_Disconnected(object? sender, H.Pipes.Args.ConnectionEventArgs<PipeRequest> e)
  90. {
  91. Logger.Send(LogType.Information, "", "Disconnected from server");
  92. foreach (var ev in Events)
  93. {
  94. Responses.TryAdd(ev.Key, PipeRequest.Error(RequestError.DISCONNECTED));
  95. ev.Value.Set();
  96. }
  97. Disconnected = true;
  98. OnDisconnect?.Invoke();
  99. }
  100. public void Dispose()
  101. {
  102. Client.DisposeAsync().AsTask().Wait();
  103. }
  104. ~IPCClient()
  105. {
  106. Dispose();
  107. }
  108. }
  109. }