IPCClient.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. using InABox.Client.IPC;
  2. using InABox.Clients;
  3. using InABox.Core;
  4. using NPOI.SS.Formula.Functions;
  5. namespace InABox.IPC
  6. {
  7. internal static class LocalCache
  8. {
  9. public static string Password { get; set; }
  10. }
  11. public class IPCClient<TEntity> : BaseClient<TEntity> where TEntity : Entity, new()
  12. {
  13. private IPCClientTransport _pipe;
  14. public IPCClient(string pipeName)
  15. {
  16. _pipe = IPCClientFactory.GetClient(pipeName);
  17. Timeout = TimeSpan.FromSeconds(300);
  18. }
  19. public override bool IsConnected() => _pipe?.Disconnected == false;
  20. private static string[]? _types;
  21. public override string[] SupportedTypes()
  22. {
  23. _types ??= CoreUtils.Entities
  24. .Where(x => x.GetInterfaces().Contains(typeof(IPersistent)))
  25. .Select(x => x.EntityName().Replace(".", "_"))
  26. .ToArray();
  27. return _types;
  28. }
  29. public override DatabaseInfo Info()
  30. {
  31. try
  32. {
  33. var request = new InfoRequest();
  34. PrepareRequest(request, false);
  35. var response = Send(IPCMessage.Info(request), 5000).GetResponse<InfoResponse>();
  36. return response.Info;
  37. }
  38. catch (Exception)
  39. {
  40. return new DatabaseInfo();
  41. }
  42. }
  43. private void PrepareRequest(Request request, bool doCredentials = true)
  44. {
  45. if(request is not ValidateRequest && _pipe.Disconnected)
  46. {
  47. ClientFactory.Validate(ClientFactory.UserID, LocalCache.Password);
  48. }
  49. if (doCredentials)
  50. {
  51. request.Credentials.Platform = ClientFactory.Platform;
  52. request.Credentials.Version = ClientFactory.Version;
  53. request.Credentials.Session = ClientFactory.SessionID;
  54. }
  55. Request.BeforeRequest?.Invoke(request);
  56. }
  57. private IPCMessage Send(IPCMessage request, int? timeout = null)
  58. {
  59. return _pipe.Send(request, timeout ?? Convert.ToInt32(Timeout.TotalMilliseconds));
  60. }
  61. protected override bool DoCheck2FA(string code, Guid? session)
  62. {
  63. var request = new Check2FARequest(code);
  64. PrepareRequest(request);
  65. var response = Send(IPCMessage.Check2FA(request)).GetResponse<Check2FAResponse>();
  66. if (response != null)
  67. {
  68. return response.Status switch
  69. {
  70. StatusCode.OK => response.Valid,
  71. StatusCode.Unauthenticated => false,
  72. _ => throw new IPCException(response.Messages),
  73. };
  74. }
  75. return false;
  76. }
  77. protected override bool DoPing()
  78. {
  79. try
  80. {
  81. var request = new PingRequest();
  82. PrepareRequest(request);
  83. var response = Send(IPCMessage.Ping(request), 10_000).GetResponse<PingResponse>();
  84. if (response != null)
  85. {
  86. return response.Status switch
  87. {
  88. StatusCode.Error or StatusCode.BadServer or StatusCode.Incomplete => throw new IPCException(response.Messages),
  89. _ => true
  90. };
  91. }
  92. }
  93. catch (Exception) { }
  94. return false;
  95. }
  96. protected override void DoDelete(TEntity entity, string auditnote)
  97. {
  98. var request = new DeleteRequest<TEntity>(entity, auditnote);
  99. PrepareRequest(request);
  100. var response = Send(IPCMessage.Delete(request)).GetResponse<DeleteResponse<TEntity>>();
  101. switch (response.Status)
  102. {
  103. case StatusCode.OK:
  104. break;
  105. case StatusCode.Unauthenticated:
  106. throw new IPCException("Client not authenticated");
  107. default:
  108. throw new IPCException(response.Messages);
  109. }
  110. }
  111. protected override void DoDelete(IEnumerable<TEntity> entities, string auditnote)
  112. {
  113. var items = entities.AsArray();
  114. var request = new MultiDeleteRequest<TEntity>(items, auditnote);
  115. PrepareRequest(request);
  116. var response = Send(IPCMessage.MultiDelete(request)).GetResponse<MultiDeleteResponse<TEntity>>();
  117. switch (response.Status)
  118. {
  119. case StatusCode.OK:
  120. break;
  121. case StatusCode.Unauthenticated:
  122. throw new IPCException("Client not authenticated");
  123. default:
  124. throw new IPCException(response.Messages);
  125. }
  126. }
  127. protected override TEntity[] DoLoad(Filter<TEntity>? filter = null, SortOrder<TEntity>? sort = null)
  128. {
  129. var request = new QueryRequest<TEntity>(filter, null, sort);
  130. PrepareRequest(request);
  131. var result = new List<TEntity>();
  132. var response = Send(IPCMessage.Query(request)).GetResponse<QueryResponse<TEntity>>();
  133. if (response.Items != null)
  134. foreach (var row in response.Items.Rows)
  135. result.Add(row.ToObject<TEntity>());
  136. return result.ToArray();
  137. }
  138. protected override CoreTable DoQuery(Filter<TEntity>? filter, Columns<TEntity>? columns, SortOrder<TEntity>? sort = null)
  139. {
  140. var request = new QueryRequest<TEntity>(filter, columns, sort);
  141. PrepareRequest(request);
  142. var response = Send(IPCMessage.Query(request)).GetResponse<QueryResponse<TEntity>>();
  143. if (response != null)
  144. {
  145. return response.Status switch
  146. {
  147. StatusCode.OK => response.Items,
  148. StatusCode.Unauthenticated => throw new IPCException("Client not authenticated", StatusCode.Unauthenticated),
  149. _ => throw new IPCException(response.Messages),
  150. };
  151. }
  152. return null;
  153. }
  154. protected override Dictionary<string, CoreTable> DoQueryMultiple(Dictionary<string, IQueryDef> queries)
  155. {
  156. var request = new MultiQueryRequest();
  157. foreach (var item in queries)
  158. {
  159. request.AddQuery(item.Key, item.Value);
  160. }
  161. PrepareRequest(request);
  162. var response = Send(IPCMessage.QueryMultiple(request)).GetResponse<MultiQueryResponse>();
  163. if (response != null)
  164. {
  165. return response.Status switch
  166. {
  167. StatusCode.OK => response.Tables,
  168. StatusCode.Unauthenticated => throw new IPCException("Client not authenticated"),
  169. _ => throw new IPCException(response.Messages),
  170. };
  171. }
  172. return null;
  173. }
  174. protected override void DoSave(TEntity entity, string auditnote)
  175. {
  176. var request = new SaveRequest<TEntity>(entity, auditnote)
  177. {
  178. ReturnOnlyChanged = true
  179. };
  180. PrepareRequest(request);
  181. var response = Send(IPCMessage.Save(request)).GetResponse<SaveResponse<TEntity>>();
  182. switch (response.Status)
  183. {
  184. case StatusCode.OK:
  185. /*var props = CoreUtils.PropertyList(typeof(TEntity), x => true, true);
  186. entity.SetObserving(false);
  187. foreach (var prop in props.Keys)
  188. {
  189. var value = CoreUtils.GetPropertyValue(response.Item, prop);
  190. CoreUtils.SetPropertyValue(entity, prop, value);
  191. }
  192. entity.CommitChanges();
  193. entity.SetObserving(true);*/
  194. entity.SetObserving(false);
  195. foreach (var (key, value) in response.ChangedValues)
  196. {
  197. if (CoreUtils.TryGetProperty<TEntity>(key, out var property))
  198. {
  199. CoreUtils.SetPropertyValue(entity, key, CoreUtils.ChangeType(value, property.PropertyType));
  200. }
  201. }
  202. entity.CommitChanges();
  203. entity.SetObserving(true);
  204. break;
  205. case StatusCode.Unauthenticated:
  206. throw new IPCException("Client not authenticated");
  207. default:
  208. throw new IPCException(response.Messages);
  209. }
  210. }
  211. protected override void DoSave(IEnumerable<TEntity> entities, string auditnote)
  212. {
  213. var items = entities.ToArray();
  214. var request = new MultiSaveRequest<TEntity>(items, auditnote)
  215. {
  216. ReturnOnlyChanged = true
  217. };
  218. PrepareRequest(request);
  219. var response = Send(IPCMessage.MultiSave(request)).GetResponse<MultiSaveResponse<TEntity>>();
  220. switch (response.Status)
  221. {
  222. case StatusCode.OK:
  223. /*var props = CoreUtils.PropertyList(typeof(TEntity), x => true, true);
  224. for (var i = 0; i < items.Length; i++)
  225. {
  226. items[i].SetObserving(false);
  227. foreach (var prop in props.Keys)
  228. {
  229. var value = CoreUtils.GetPropertyValue(response.Items[i], prop);
  230. CoreUtils.SetPropertyValue(items[i], prop, value);
  231. }
  232. //CoreUtils.DeepClone<TEntity>(response.Items[i], items[i]);
  233. items[i].CommitChanges();
  234. items[i].SetObserving(true);
  235. }*/
  236. for (int i = 0; i < items.Length; ++i)
  237. {
  238. var entity = items[i];
  239. var changedValues = response.ChangedValues[i];
  240. entity.SetObserving(false);
  241. foreach (var (key, value) in changedValues)
  242. {
  243. if (CoreUtils.TryGetProperty<TEntity>(key, out var property))
  244. {
  245. CoreUtils.SetPropertyValue(entity, key, CoreUtils.ChangeType(value, property.PropertyType));
  246. }
  247. }
  248. entity.CommitChanges();
  249. entity.SetObserving(true);
  250. }
  251. break;
  252. case StatusCode.Unauthenticated:
  253. throw new IPCException("Client not authenticated");
  254. default:
  255. throw new IPCException(response.Messages);
  256. }
  257. }
  258. protected override IValidationData DoValidate(Guid session)
  259. {
  260. return Validate(
  261. null, null, false, session);
  262. }
  263. protected override IValidationData DoValidate(string pin, Guid session)
  264. {
  265. return Validate(
  266. null, pin, true, session);
  267. }
  268. protected override IValidationData DoValidate(string userid, string password, Guid session)
  269. {
  270. return Validate(
  271. userid, password, false, session);
  272. }
  273. private IValidationData Validate(string? userid, string? password, bool usePin, Guid session = default)
  274. {
  275. var ticks = DateTime.Now.ToUniversalTime().Ticks.ToString();
  276. var request = new ValidateRequest { UsePIN = usePin };
  277. if (usePin)
  278. {
  279. request.UserID = Encryption.Encrypt(ticks, "wCq9rryEJEuHIifYrxRjxg", true);
  280. request.Password = Encryption.Encrypt(ticks, "7mhvLnqMwkCAzN+zNGlyyg", true);
  281. request.PIN = password;
  282. }
  283. else
  284. {
  285. request.UserID = userid;
  286. request.Password = password;
  287. }
  288. request.Credentials.Platform = ClientFactory.Platform;
  289. request.Credentials.Version = ClientFactory.Version;
  290. PrepareRequest(request, false);
  291. if(session != Guid.Empty)
  292. {
  293. request.Credentials.Session = session;
  294. }
  295. var response = Send(IPCMessage.Validate(request), 10000).GetResponse<ValidateResponse>();
  296. if (response != null)
  297. if (response.Status.Equals(StatusCode.OK))
  298. {
  299. LocalCache.Password = password;
  300. return new ValidationData(
  301. response.ValidationStatus,
  302. response.UserID,
  303. response.UserGuid,
  304. response.SecurityID,
  305. response.Session,
  306. response.Recipient2FA,
  307. response.PasswordExpiration
  308. );
  309. }
  310. else if (response.Status == StatusCode.BadServer)
  311. {
  312. throw new IPCException(response.Messages);
  313. }
  314. return new ValidationData(
  315. ValidationStatus.INVALID,
  316. "",
  317. Guid.Empty,
  318. Guid.Empty,
  319. Guid.Empty,
  320. null,
  321. DateTime.MinValue
  322. );
  323. }
  324. public override string Version()
  325. {
  326. try
  327. {
  328. var request = new VersionRequest();
  329. PrepareRequest(request, false);
  330. var response = Send(IPCMessage.Version(request)).GetResponse<VersionResponse>();
  331. return response.Version;
  332. }
  333. catch (Exception)
  334. {
  335. return "";
  336. }
  337. }
  338. public override string ReleaseNotes()
  339. {
  340. try
  341. {
  342. var request = new ReleaseNotesRequest();
  343. PrepareRequest(request, false);
  344. var response = Send(IPCMessage.ReleaseNotes(request)).GetResponse<ReleaseNotesResponse>();
  345. return response.ReleaseNotes;
  346. }
  347. catch (Exception)
  348. {
  349. return "";
  350. }
  351. }
  352. public override byte[]? Installer()
  353. {
  354. try
  355. {
  356. var request = new InstallerRequest();
  357. PrepareRequest(request, false);
  358. var response = Send(IPCMessage.Installer(request)).GetResponse<InstallerResponse>();
  359. return response.Installer;
  360. }
  361. catch (Exception)
  362. {
  363. return null;
  364. }
  365. }
  366. }
  367. }