using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Timers; using InABox.Core; namespace InABox.Clients { public enum SerializerProtocol { Rest, RPC } public class QueryMultipleResults { private readonly Dictionary Results; internal QueryMultipleResults(Dictionary results) { Results = results; } public CoreTable this[string name] => Results[name]; public CoreTable Get() => Results[typeof(T).Name]; /// /// Like , but calls on the table. /// /// /// public IEnumerable GetObjects() where T: BaseObject, new() => Results[typeof(T).Name].ToObjects(); public CoreTable Get(string name) => Results[name]; public CoreTable GetOrDefault(string name) => Results.GetValueOrDefault(name); } public abstract class Client { public abstract CoreTable Query(IFilter? filter = null, IColumns? columns = null, ISortOrder? sortOrder = null); public abstract void Save(Entity entity, string auditNote); public abstract void Save(IEnumerable entity, string auditNote); private static IClient CheckClient() { using (new Profiler(true)) return ClientFactory.CreateClient(); } public static Dictionary QueryMultiple(Dictionary queries) { try { using var timer = new Profiler(false); var result = CheckClient().QueryMultiple(queries); timer.Log(result.Sum(x => x.Value.Rows.Count)); return result; } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } private static IClient CheckClient() where TEntity : Entity, IRemotable, IPersistent, new() { return ClientFactory.CreateClient(); } public static void EnsureColumns(TEntity entity, Columns columns) where TEntity : Entity, IRemotable, IPersistent, new() { var newColumns = new Columns(); foreach(var column in columns) { if (!entity.HasColumn(column.Property)) { newColumns.Add(column); } } if (newColumns.Any()) { var row = Query(new Filter(x => x.ID).IsEqualTo(entity.ID), newColumns).Rows.FirstOrDefault(); row?.FillObject(entity); } } public static CoreTable Query(Filter? filter = null, Columns? columns = null, SortOrder? orderby = null) where TEntity : Entity, IRemotable, IPersistent, new() { return new Client().Query(filter, columns, orderby); } public static void Query(Filter? filter, Columns? columns, SortOrder? orderby, Action callback) where TEntity : Entity, IRemotable, IPersistent, new() { new Client().Query(filter, columns, orderby, callback); } public static void Save(TEntity entity, string auditNote) where TEntity : Entity, IRemotable, IPersistent, new() { new Client().Save(entity, auditNote); } public static void Save(IEnumerable entities, string auditNote) where TEntity : Entity, IRemotable, IPersistent, new() { new Client().Save(entities, auditNote); } public static void Save(TEntity entity, string auditNote, Action callback) where TEntity : Entity, IRemotable, IPersistent, new() { new Client().Save(entity, auditNote, callback); } public static void Save(IEnumerable entities, string auditNote, Action, Exception?> callback) where TEntity : Entity, IRemotable, IPersistent, new() { new Client().Save(entities, auditNote, callback); } public static void Delete(TEntity entity, string auditNote) where TEntity : Entity, IRemotable, IPersistent, new() { new Client().Delete(entity, auditNote); } public static void Delete(IEnumerable entities, string auditNote) where TEntity : Entity, IRemotable, IPersistent, new() { new Client().Delete(entities, auditNote); } public static void QueryMultiple( Action?, Exception?> callback, Dictionary queries) { try { using var timer = new Profiler(false); CheckClient().QueryMultiple((result, e) => { timer.Dispose(result != null ? result.Sum(x => x.Value.Rows.Count) : -1); callback?.Invoke(result, e); }, queries); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public static QueryMultipleResults QueryMultiple(params IKeyedQueryDef[] queries) => new QueryMultipleResults(QueryMultiple(queries.ToDictionary(x => x.Key, x => x as IQueryDef))); public static void QueryMultiple(Action callback, params IKeyedQueryDef[] queries) => QueryMultiple((results, e) => { if (results != null) { callback?.Invoke(new QueryMultipleResults(results), e); } else { callback?.Invoke(null, e); } }, queries.ToDictionary(x => x.Key, x => x as IQueryDef)); public static QueryMultipleResults QueryMultiple(IEnumerable queries) => new QueryMultipleResults(QueryMultiple(queries.ToDictionary(x => x.Key, x => x as IQueryDef))); public static void QueryMultiple(Action callback, IEnumerable queries) => QueryMultiple((results, e) => { if(results != null) { callback?.Invoke(new QueryMultipleResults(results), e); } else { callback?.Invoke(null, e); } }, queries.ToDictionary(x => x.Key, x => x as IQueryDef)); public static IValidationData Validate(Guid session) { try { using (new Profiler(true)) return CheckClient().Validate(session); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public static IValidationData Validate(string pin, Guid session = default) { try { using (new Profiler(true)) return CheckClient().Validate(pin, session); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public static IValidationData Validate(string userid, string password, Guid session = default) { try { using (new Profiler(true)) return CheckClient().Validate(userid, password, session); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public static bool Check2FA(string code, Guid? session = null) { try { using (new Profiler(true)) return CheckClient().Check2FA(code, session); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public static bool Ping() { try { using (new Profiler(true)) return CheckClient().Ping(); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public static DatabaseInfo Info() { try { using (new Profiler(true)) return CheckClient().Info(); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public static string Version() { try { using (new Profiler(true)) return CheckClient().Version(); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public static string ReleaseNotes() { try { using (new Profiler(true)) return CheckClient().ReleaseNotes(); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public static byte[]? Installer() { try { using (new Profiler(true)) return CheckClient().Installer(); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public static Client Create(Type TEntity) => (Activator.CreateInstance(typeof(Client<>).MakeGenericType(TEntity)) as Client)!; } public class Client : Client, IDisposable where TEntity : Entity, IPersistent, IRemotable, new() { private IClient _client; public Client() { _client = ClientFactory.CreateClient(); } public void Dispose() { } private void CheckSupported() { if (!ClientFactory.IsSupported()) throw new NotSupportedException(string.Format("{0} is not supported in this context", typeof(TEntity).EntityName())); } private string FilterToString(Filter filter) { return filter != null ? filter.AsOData() : ""; } private string OrderToString(SortOrder order) { return order != null ? order.AsOData() : ""; } public CoreTable Query(Filter? filter = null, Columns? columns = null, SortOrder? orderby = null) { try { using var timer = new Profiler(false); CheckSupported(); var result = _client.Query(filter, columns, orderby); timer.Log(result.Rows.Count); return result; } catch(RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public override CoreTable Query(IFilter? filter, IColumns? columns, ISortOrder? sortOrder) { return Query(filter as Filter, columns as Columns, sortOrder as SortOrder); } public void Query(Filter? filter, Columns? columns, SortOrder? sort, Action callback) { try { var timer = new Profiler(false); CheckSupported(); _client.Query(filter, columns, sort, (c, e) => { timer.Log(c != null ? c.Rows.Count : -1); callback?.Invoke(c, e); }); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public TEntity[] Load(Filter? filter = null, SortOrder? sort = null) { try { using (var timer = new Profiler(false)) { CheckSupported(); var result = _client.Load(filter, sort); foreach (var entity in result) entity.CommitChanges(); timer.Log(result.Length); return result; } } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public void Load(Filter filter, SortOrder sort, Action callback) { try { var timer = new Profiler(false); CheckSupported(); _client.Load(filter, sort, (i, e) => { timer.Dispose(i != null ? i.Length : -1); callback?.Invoke(i, e); }); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public override void Save(Entity entity, string auditNote) { try { Save((entity as TEntity)!, auditNote); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public override void Save(IEnumerable entities, string auditNote) { try { Save(entities.Cast(), auditNote); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public void Save(TEntity entity, string auditnote) { try { using (new Profiler(true)) { CheckSupported(); entity.LastUpdate = DateTime.Now; entity.LastUpdateBy = ClientFactory.UserID; _client.Save(entity, auditnote); entity.CommitChanges(); } } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public void Save(TEntity entity, string auditnote, Action callback) { try { var timer = new Profiler(false); CheckSupported(); _client.Save(entity, auditnote, (i, c) => { timer.Dispose(); callback?.Invoke(i, c); }); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public void Save(IEnumerable entities, string auditnote) { try { using var timer = new Profiler(false); CheckSupported(); var items = entities.AsArray(); if (items.Any()) _client.Save(items, auditnote); timer.Log(items.Length); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public void Save(IEnumerable entities, string auditnote, Action, Exception?> callback) { try { var timer = new Profiler(false); CheckSupported(); var items = entities.AsArray(); if (items.Any()) { _client.Save(items, auditnote, (i, e) => { timer.Dispose(i.Count()); callback?.Invoke(i, e); }); } else { timer.Dispose(0); callback?.Invoke(items, null); } } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public void Delete(TEntity entity, string auditnote) { try { using (new Profiler(true)) { CheckSupported(); _client.Delete(entity, auditnote); } } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public void Delete(TEntity entity, string auditnote, Action callback) { try { var timer = new Profiler(true); CheckSupported(); _client.Delete(entity, auditnote, (i, e) => { timer.Dispose(); callback?.Invoke(i, e); }); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public void Delete(IEnumerable entities, string auditnote) { try { using var timer = new Profiler(false); CheckSupported(); var items = entities.AsArray(); _client.Delete(items, auditnote); timer.Log(items.Length); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public void Delete(IEnumerable entities, string auditnote, Action, Exception?> callback) { try { var timer = new Profiler(false); CheckSupported(); var items = entities.AsArray(); _client.Delete(items, auditnote, (i, e) => { timer.Dispose(i.Count); callback?.Invoke(i, e); }); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public IEnumerable SupportedTypes() { try { using (new Profiler(true)) return _client.SupportedTypes(); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } public new DatabaseInfo Info() { try { using (new Profiler(true)) return _client.Info(); } catch (RequestException e) { ClientFactory.RaiseRequestError(e); throw; } } } }