LogikalClient.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Linq;
  6. using System.Threading;
  7. using Comal.Classes;
  8. using H.Formatters;
  9. using H.Pipes;
  10. using InABox.Clients;
  11. using InABox.Core;
  12. using InABox.Logikal;
  13. using Newtonsoft.Json;
  14. using Exception = System.Exception;
  15. using Process = System.Diagnostics.Process;
  16. namespace PRSDesktop;
  17. public class LogikalClient : IDisposable
  18. {
  19. private readonly PipeClient<LogikalMessage> _client;
  20. private ConcurrentDictionary<Guid, ManualResetEventSlim> Events = new();
  21. private ConcurrentDictionary<Guid, LogikalMessage> Responses = new();
  22. private const int DefaultRequestTimeout = 5 * 60 * 1000; // 5 minutes
  23. public LogikalSettings Settings { get; set; }
  24. public LogikalClient()
  25. {
  26. Settings = Client
  27. .Query(
  28. new Filter<LogikalSettings>().All(),
  29. Columns.All<LogikalSettings>(),
  30. null,
  31. CoreRange.Database(1)
  32. )
  33. .ToObjects<LogikalSettings>()
  34. .FirstOrDefault()
  35. ?? new LogikalSettings();
  36. var _basedirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) ?? "";
  37. var _logikalapp = System.IO.Path.Combine(_basedirectory, "PRSLogikal", "PRSLogikal.exe");
  38. var _info = new ProcessStartInfo(_logikalapp);
  39. _info.WindowStyle = ProcessWindowStyle.Minimized;
  40. Process.Start(_info);
  41. _client = new PipeClient<LogikalMessage>("$logikal", formatter: new NewtonsoftJsonFormatter());
  42. _client.Connected += Client_Connected;
  43. _client.Disconnected += Client_Disconnected;
  44. _client.MessageReceived += Client_MessageReceived;
  45. _client.ExceptionOccurred += Client_ExceptionOccurred;
  46. _client.ConnectAsync();
  47. }
  48. public void Dispose()
  49. {
  50. _client.DisposeAsync().AsTask().Wait();
  51. }
  52. private void Client_Connected(object? sender, H.Pipes.Args.ConnectionEventArgs<LogikalMessage> e)
  53. {
  54. Logger.Send(LogType.Information, "", $"Connected to Pipe: {e.Connection.PipeName}");
  55. //Disconnected = false;
  56. // Here we will register a Licence "Hit" for the Logikal interface
  57. }
  58. private void Client_Disconnected(object? sender, H.Pipes.Args.ConnectionEventArgs<LogikalMessage> e)
  59. {
  60. Logger.Send(LogType.Information, "", $"Disconnected from Pipe: {e.Connection.PipeName}");
  61. foreach (var ev in Events)
  62. {
  63. Responses.TryAdd(ev.Key, LogikalMessage.Error("Disconnected"));
  64. ev.Value.Set();
  65. }
  66. //Disconnected = true;
  67. }
  68. private void Client_ExceptionOccurred(object? sender, H.Pipes.Args.ExceptionEventArgs e)
  69. {
  70. Logger.Send(LogType.Error, "", $"Exception occured: {e.Exception.Message}");
  71. }
  72. private static Dictionary<LogikalMethod, Type> _methods = new Dictionary<LogikalMethod, Type>()
  73. {
  74. { LogikalMethod.Connect, typeof(LogikalConnectResponse) },
  75. { LogikalMethod.Login, typeof(LogikalLoginResponse) },
  76. { LogikalMethod.Logout, typeof(LogikalLogoutResponse) },
  77. { LogikalMethod.Disconnect, typeof(LogikalDisconnectResponse) },
  78. { LogikalMethod.Projects, typeof(LogikalProjectsResponse<LogikalProject, LogikalElevation, LogikalPart>) },
  79. { LogikalMethod.Project, typeof(LogikalProjectResponse<LogikalProject, LogikalElevation, LogikalPart>) },
  80. { LogikalMethod.Elevation, typeof(LogikalElevationResponse<LogikalElevation, LogikalPart>) },
  81. { LogikalMethod.Error, typeof(LogikalErrorResponse) },
  82. };
  83. private LogikalResponse FromMessage(LogikalMessage message)
  84. {
  85. try
  86. {
  87. LogikalResponse _result = null;
  88. if (_methods.TryGetValue(message.Method, out var _type))
  89. {
  90. _result = JsonConvert.DeserializeObject(message.Payload, _type) as LogikalResponse;
  91. if (_result != null)
  92. return _result;
  93. return new LogikalErrorResponse() { Status = LogikalStatus.Error, Message = $"Deserialize Failure: {message.Method}: {message.Payload}" };
  94. }
  95. else
  96. return new LogikalErrorResponse() { Status = LogikalStatus.Error, Message = $"Invalid Message Method: {message.Method}: {message.Payload}" };
  97. }
  98. catch (Exception e)
  99. {
  100. return new LogikalErrorResponse() { Status = LogikalStatus.Error, Message = $"Exception Deserializing Response: {e.Message}\n{e.StackTrace}" };
  101. }
  102. }
  103. public LogikalResponse Send(LogikalRequest request, int timeout = DefaultRequestTimeout)
  104. {
  105. var message = new LogikalMessage()
  106. {
  107. ID = Guid.NewGuid(),
  108. Method = request.Method(),
  109. Payload = Serialization.Serialize(request),
  110. };
  111. var ev = Queue(message.ID);
  112. _client.WriteAsync(message);
  113. var result = GetResult(message.ID, ev, timeout);
  114. return FromMessage(result);
  115. }
  116. public ManualResetEventSlim Queue(Guid id)
  117. {
  118. var ev = new ManualResetEventSlim();
  119. Events[id] = ev;
  120. return ev;
  121. }
  122. public LogikalMessage GetResult(Guid id, ManualResetEventSlim ev, int timeout)
  123. {
  124. if (Responses.TryRemove(id, out var result))
  125. {
  126. Events.TryRemove(id, out ev);
  127. return result;
  128. }
  129. try
  130. {
  131. if (!ev.Wait(timeout))
  132. {
  133. return LogikalMessage.Error("Timeout");
  134. }
  135. }
  136. catch (Exception e)
  137. {
  138. Console.WriteLine(e);
  139. throw;
  140. }
  141. Responses.TryRemove(id, out result);
  142. Events.TryRemove(id, out ev);
  143. return result ?? LogikalMessage.Error("Unknown");
  144. }
  145. private void Client_MessageReceived(object? sender, H.Pipes.Args.ConnectionMessageEventArgs<LogikalMessage?> e)
  146. {
  147. if (Events.TryGetValue(e.Message.ID, out var ev))
  148. {
  149. Responses[e.Message.ID] = e.Message;
  150. ev.Set();
  151. }
  152. }
  153. ~LogikalClient()
  154. {
  155. Dispose();
  156. }
  157. public LogikalResponse Connect()
  158. {
  159. var _request = new LogikalConnectRequest()
  160. {
  161. Path = Settings.Path
  162. };
  163. var _result = Send(_request);
  164. return _result;
  165. }
  166. public LogikalResponse Disconnect()
  167. {
  168. var _request = new LogikalDisconnectRequest();
  169. var _result = Send(_request);
  170. return _result;
  171. }
  172. public LogikalResponse Login()
  173. {
  174. var _request = new LogikalLoginRequest();
  175. var _result = Send(_request);
  176. return _result;
  177. }
  178. public LogikalResponse Logout()
  179. {
  180. var _request = new LogikalLogoutRequest();
  181. var _result = Send(_request);
  182. return _result;
  183. }
  184. public LogikalResponse ProjectList()
  185. {
  186. var _request = new LogikalProjectsRequest();
  187. var _result = Send(_request);
  188. return _result;
  189. }
  190. public LogikalResponse GetProject()
  191. {
  192. var _request = new LogikalProjectsRequest();
  193. var _result = Send(_request);
  194. return _result;
  195. }
  196. public LogikalResponse GetElevation()
  197. {
  198. var _request = new LogikalElevationRequest();
  199. var _result = Send(_request);
  200. return _result;
  201. }
  202. }