RPCClient.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. using System.Collections.Concurrent;
  2. using InABox.Clients;
  3. using InABox.Core;
  4. namespace InABox.IPC
  5. {
  6. public class RPCClient<TEntity> : BaseClient<TEntity> where TEntity : Entity, new()
  7. {
  8. private IRPCClientTransport _transport;
  9. private ConcurrentDictionary<Guid, ManualResetEventSlim> Events = new();
  10. private ConcurrentDictionary<Guid, RPCMessage> Responses = new();
  11. private const int DefaultRequestTimeout = 5 * 60 * 1000; // 5 minutes
  12. public delegate void ConnectEvent();
  13. public delegate void DisconnectEvent();
  14. public bool Disconnected { get; private set; }
  15. public event ConnectEvent? OnConnect;
  16. public event DisconnectEvent? OnDisconnect;
  17. public RPCClient(Func<IRPCClientTransport> transport)
  18. {
  19. _transport = transport();
  20. _transport.OnOpen += Transport_Opened;
  21. _transport.OnClose += Transport_Closed;
  22. _transport.OnException += Transport_Exception;
  23. _transport.OnMessage += Transport_Message;
  24. _transport.Connect();
  25. }
  26. ~RPCClient()
  27. {
  28. _transport.OnOpen -= Transport_Opened;
  29. _transport.OnClose -= Transport_Closed;
  30. _transport.OnException -= Transport_Exception;
  31. _transport.OnMessage -= Transport_Message;
  32. }
  33. #region TransportManagement
  34. private void Transport_Opened(IRPCTransport transport, RPCTransportOpenArgs e)
  35. {
  36. Logger.Send(LogType.Information, "", $"Client Connected");
  37. Disconnected = false;
  38. OnConnect?.Invoke();
  39. }
  40. private void Transport_Message(IRPCTransport transport, RPCTransportMessageArgs e)
  41. {
  42. Logger.Send(LogType.Error, "", $"Message received: ({e.Message.Command}) -> {e.Message.Payload}");
  43. }
  44. private void Transport_Exception(IRPCTransport transport, RPCTransportExceptionArgs e)
  45. {
  46. Logger.Send(LogType.Error, "", $"Exception occured: {e.Exception.Message}");
  47. }
  48. private void Transport_Closed(IRPCTransport transport, RPCTransportCloseArgs e)
  49. {
  50. Logger.Send(LogType.Information, "", $"Client Disconnected");
  51. Disconnected = true;
  52. OnDisconnect?.Invoke();
  53. }
  54. public TResult Send<TCommand, TParameters, TResult>(TParameters properties) where TCommand : IRPCCommand<TParameters,TResult>
  55. {
  56. var request = new RPCMessage(
  57. new Guid(),
  58. typeof(TCommand).Name,
  59. Serialization.Serialize(properties)
  60. );
  61. var response = Send(request);
  62. if (response.Error != RPCError.NONE)
  63. throw new Exception($"Exception in {typeof(TCommand).Name}({request.ID}): {response.Error}");
  64. var result = Serialization.Deserialize<TResult>(response.Payload);
  65. if (result == null)
  66. throw new Exception($"{typeof(TCommand).Name}({request.ID}) returned NULL");
  67. return result;
  68. }
  69. public RPCMessage Send(RPCMessage request, int timeout = DefaultRequestTimeout)
  70. {
  71. var start = DateTime.Now;
  72. var ev = Queue(request.ID);
  73. _transport.Send(request);
  74. var result = GetResult(request.ID, ev, timeout);
  75. return result;
  76. }
  77. public ManualResetEventSlim Queue(Guid id)
  78. {
  79. var ev = new ManualResetEventSlim();
  80. Events[id] = ev;
  81. return ev;
  82. }
  83. public RPCMessage GetResult(Guid id, ManualResetEventSlim ev, int timeout)
  84. {
  85. if (Responses.TryGetValue(id, out var result))
  86. {
  87. Responses.Remove(id, out result);
  88. Events.Remove(id, out ev);
  89. return result;
  90. }
  91. try
  92. {
  93. if (!ev.Wait(timeout))
  94. {
  95. return new RPCMessage(id,"","",RPCError.TIMEOUT);
  96. }
  97. }
  98. catch (Exception e)
  99. {
  100. Logger.Send(LogType.Error, "", e.Message);
  101. throw;
  102. }
  103. Responses.Remove(id, out result);
  104. Events.Remove(id, out ev);
  105. return result ?? new RPCMessage(id,"","",RPCError.UNKNOWN);
  106. }
  107. #endregion
  108. #region Client Interface
  109. public override DatabaseInfo Info()
  110. {
  111. var result = _transport.Send<RPCInfoCommand, RPCInfoParameters, RPCInfoResponse>(new RPCInfoParameters());
  112. return result.Info;
  113. }
  114. private static string[]? _types;
  115. public override string[] SupportedTypes()
  116. {
  117. _types ??= CoreUtils.Entities
  118. .Where(x => x.GetInterfaces().Contains(typeof(IPersistent)))
  119. .Select(x => x.EntityName().Replace(".", "_"))
  120. .ToArray();
  121. return _types;
  122. }
  123. protected override ValidationData DoValidate(string userid, string password, Guid session = default)
  124. {
  125. throw new NotImplementedException();
  126. }
  127. protected override ValidationData DoValidate(string pin, Guid session = default)
  128. {
  129. throw new NotImplementedException();
  130. }
  131. protected override ValidationData DoValidate(Guid session = default)
  132. {
  133. throw new NotImplementedException();
  134. }
  135. protected override CoreTable DoQuery(Filter<TEntity>? filter, Columns<TEntity>? columns, SortOrder<TEntity>? sort = null)
  136. {
  137. throw new NotImplementedException();
  138. }
  139. protected override TEntity[] DoLoad(Filter<TEntity>? filter = null, SortOrder<TEntity>? sort = null)
  140. {
  141. throw new NotImplementedException();
  142. }
  143. protected override void DoSave(TEntity entity, string auditnote)
  144. {
  145. throw new NotImplementedException();
  146. }
  147. protected override void DoSave(IEnumerable<TEntity> entities, string auditnote)
  148. {
  149. throw new NotImplementedException();
  150. }
  151. protected override void DoDelete(TEntity entity, string auditnote)
  152. {
  153. throw new NotImplementedException();
  154. }
  155. protected override void DoDelete(IList<TEntity> entities, string auditnote)
  156. {
  157. throw new NotImplementedException();
  158. }
  159. protected override Dictionary<string, CoreTable> DoQueryMultiple(Dictionary<string, IQueryDef> queries)
  160. {
  161. throw new NotImplementedException();
  162. }
  163. protected override bool DoCheck2FA(string code, Guid? session)
  164. {
  165. throw new NotImplementedException();
  166. }
  167. protected override bool DoPing()
  168. {
  169. throw new NotImplementedException();
  170. }
  171. #endregion
  172. }
  173. }