IPCClient.cs 15 KB

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