diff --git a/Esiur.Stores.EntityCore/EntityResource.cs b/Esiur.Stores.EntityCore/EntityResource.cs index 930c5fa..0bb79b6 100644 --- a/Esiur.Stores.EntityCore/EntityResource.cs +++ b/Esiur.Stores.EntityCore/EntityResource.cs @@ -32,44 +32,42 @@ using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel; using System.Runtime.CompilerServices; -namespace Esiur.Stores.EntityCore +namespace Esiur.Stores.EntityCore; + +public class EntityResource : IResource { - - public class EntityResource : IResource + //[NotMapped] + //internal object _PrimaryId; + + public event DestroyedEvent OnDestroy; + //public event PropertyChangedEventHandler PropertyChanged; + + [NotMapped] + public Instance Instance { get; set; } + + public EntityResource() { - //[NotMapped] - //internal object _PrimaryId; - - public event DestroyedEvent OnDestroy; - //public event PropertyChangedEventHandler PropertyChanged; - - [NotMapped] - public Instance Instance { get; set; } - - public EntityResource() - { - - } - - - protected virtual void Create() - { - - } - - public AsyncReply Trigger(ResourceTrigger trigger) - { - if (trigger == ResourceTrigger.Initialize) - Create(); - - return new AsyncReply(true); - } - - public void Destroy() - { - OnDestroy?.Invoke(this); - } - } + + + protected virtual void Create() + { + + } + + public AsyncReply Trigger(ResourceTrigger trigger) + { + if (trigger == ResourceTrigger.Initialize) + Create(); + + return new AsyncReply(true); + } + + public void Destroy() + { + OnDestroy?.Invoke(this); + } + + } \ No newline at end of file diff --git a/Esiur.Stores.EntityCore/EntityStore.cs b/Esiur.Stores.EntityCore/EntityStore.cs index 9a5159f..f7d38b3 100644 --- a/Esiur.Stores.EntityCore/EntityStore.cs +++ b/Esiur.Stores.EntityCore/EntityStore.cs @@ -34,209 +34,207 @@ using System.Linq; using Microsoft.EntityFrameworkCore.Metadata; using System.Reflection; -namespace Esiur.Stores.EntityCore +namespace Esiur.Stores.EntityCore; +public class EntityStore : IStore { - public class EntityStore : IStore + public Instance Instance { get; set; } + + public event DestroyedEvent OnDestroy; + + Dictionary> DB = new Dictionary>(); + object DBLock = new object(); + + Dictionary TypesByName = new Dictionary(); + internal Dictionary TypesByType = new Dictionary(); + + [Attribute] + public Func Getter { get; set; } + + + public AsyncReply Get(string path) { - public Instance Instance { get; set; } + var p = path.Split('/'); + var ti = TypesByName[p[0]]; + var id = Convert.ChangeType(p[1], ti.PrimaryKey.PropertyType); - public event DestroyedEvent OnDestroy; + // Get db + var db = Getter(); + var res = db.Find(ti.Type.ClrType, id); - Dictionary> DB = new Dictionary>(); - object DBLock = new object(); + // load navigation properties + var ent = db.Entry(res); + foreach (var rf in ent.References) + rf.Load(); - Dictionary TypesByName = new Dictionary(); - internal Dictionary TypesByType = new Dictionary(); - - [Attribute] - public Func Getter { get; set; } - - - public AsyncReply Get(string path) - { - var p = path.Split('/'); - var ti = TypesByName[p[0]]; - var id = Convert.ChangeType(p[1], ti.PrimaryKey.PropertyType); - - // Get db - var db = Getter(); - var res = db.Find(ti.Type.ClrType, id); - - // load navigation properties - var ent = db.Entry(res); - foreach (var rf in ent.References) - rf.Load(); - - return new AsyncReply(res as IResource); - } - - public AsyncReply Put(IResource resource) - { - if (resource == this) - return new AsyncReply(true); - - var type = ResourceProxy.GetBaseType(resource); - - - var eid = TypesByType[type].PrimaryKey.GetValue(resource); - - lock (DBLock) - { - if (DB[type].ContainsKey(eid)) - DB[type].Remove(eid); - - DB[type].Add(eid, new WeakReference(resource)); - } + return new AsyncReply(res as IResource); + } + public AsyncReply Put(IResource resource) + { + if (resource == this) return new AsyncReply(true); + + var type = ResourceProxy.GetBaseType(resource); + + + var eid = TypesByType[type].PrimaryKey.GetValue(resource); + + lock (DBLock) + { + if (DB[type].ContainsKey(eid)) + DB[type].Remove(eid); + + DB[type].Add(eid, new WeakReference(resource)); } - public IResource GetById(Type type, object id) + return new AsyncReply(true); + } + + public IResource GetById(Type type, object id) + { + lock (DBLock) { - lock (DBLock) - { - if (!DB[type].ContainsKey(id)) - return null; + if (!DB[type].ContainsKey(id)) + return null; - if (!DB[type][id].IsAlive) - return null; + if (!DB[type][id].IsAlive) + return null; - return DB[type][id].Target as IResource; - } - } - - - - //public T CreateDB() - //{ - - //} - - //DbContext dbContext; - //[Attribute] - //public DbContext DbContext { get; set; } - - public string Link(IResource resource) - { - var type = ResourceProxy.GetBaseType(resource.GetType()); - - var id = TypesByType[type].PrimaryKey.GetValue(resource); - //DbContext.Model.FindEntityType(type).DisplayName(); - - - // DbContext.Model.FindEntityType(type).DisplayName - //var entityType = DbContext.Model.FindEntityType(type); - //var id = entityType.FindPrimaryKey().Properties - // .FirstOrDefault()?.PropertyInfo - // .GetValue(resource); - // var id = Types - - if (id != null) - return this.Instance.Name + "/" + type.Name + "/" + id.ToString(); - else - return this.Instance.Name + "/" + type.Name; - } - - public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) - { - return true; - //throw new NotImplementedException(); - } - - public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) - { - return true; - //throw new NotImplementedException(); - } - - public bool Remove(IResource resource) - { - throw new NotImplementedException(); - } - - public AsyncReply AddChild(IResource parent, IResource child) - { - throw new NotImplementedException(); - } - - public AsyncReply RemoveChild(IResource parent, IResource child) - { - throw new NotImplementedException(); - } - - public AsyncReply AddParent(IResource child, IResource parent) - { - throw new NotImplementedException(); - } - - public AsyncReply RemoveParent(IResource child, IResource parent) - { - throw new NotImplementedException(); - } - - public AsyncBag Children(IResource resource, string name) where T : IResource - { - throw new NotImplementedException(); - } - - public AsyncBag Parents(IResource resource, string name) where T : IResource - { - throw new NotImplementedException(); - } - - public AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate) - { - throw new NotImplementedException(); - } - - internal DbContextOptions Options { get; set; } - - public AsyncReply Trigger(ResourceTrigger trigger) - { - if (trigger == ResourceTrigger.Initialize)// SystemInitialized && DbContext != null) - { - - if (Getter == null) - throw new Exception("Getter is not set for the store."); - // DbContextProvider = () => Activator.CreateInstance(Options.Options.ContextType, Options.Options) as DbContext; - - - ReloadModel(); - } - - return new AsyncReply(true); - } - - public void ReloadModel() - { - - TypesByName.Clear(); - TypesByType.Clear(); - - var context = Getter(); - - var types = context.Model.GetEntityTypes(); - foreach (var t in types) - { - var ti = new EntityTypeInfo() - { - Name = t.ClrType.Name, - PrimaryKey = t.FindPrimaryKey().Properties.FirstOrDefault()?.PropertyInfo, - Type = t, - //Getter = getter - }; - - TypesByName.Add(t.ClrType.Name, ti); - TypesByType.Add(t.ClrType, ti); - - if (!DB.ContainsKey(t.ClrType)) - DB.Add(t.ClrType, new Dictionary()); - } - } - - public void Destroy() - { - OnDestroy?.Invoke(this); + return DB[type][id].Target as IResource; } } + + + + //public T CreateDB() + //{ + + //} + + //DbContext dbContext; + //[Attribute] + //public DbContext DbContext { get; set; } + + public string Link(IResource resource) + { + var type = ResourceProxy.GetBaseType(resource.GetType()); + + var id = TypesByType[type].PrimaryKey.GetValue(resource); + //DbContext.Model.FindEntityType(type).DisplayName(); + + + // DbContext.Model.FindEntityType(type).DisplayName + //var entityType = DbContext.Model.FindEntityType(type); + //var id = entityType.FindPrimaryKey().Properties + // .FirstOrDefault()?.PropertyInfo + // .GetValue(resource); + // var id = Types + + if (id != null) + return this.Instance.Name + "/" + type.Name + "/" + id.ToString(); + else + return this.Instance.Name + "/" + type.Name; + } + + public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + { + return true; + //throw new NotImplementedException(); + } + + public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + { + return true; + //throw new NotImplementedException(); + } + + public bool Remove(IResource resource) + { + throw new NotImplementedException(); + } + + public AsyncReply AddChild(IResource parent, IResource child) + { + throw new NotImplementedException(); + } + + public AsyncReply RemoveChild(IResource parent, IResource child) + { + throw new NotImplementedException(); + } + + public AsyncReply AddParent(IResource child, IResource parent) + { + throw new NotImplementedException(); + } + + public AsyncReply RemoveParent(IResource child, IResource parent) + { + throw new NotImplementedException(); + } + + public AsyncBag Children(IResource resource, string name) where T : IResource + { + throw new NotImplementedException(); + } + + public AsyncBag Parents(IResource resource, string name) where T : IResource + { + throw new NotImplementedException(); + } + + public AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate) + { + throw new NotImplementedException(); + } + + internal DbContextOptions Options { get; set; } + + public AsyncReply Trigger(ResourceTrigger trigger) + { + if (trigger == ResourceTrigger.Initialize)// SystemInitialized && DbContext != null) + { + + if (Getter == null) + throw new Exception("Getter is not set for the store."); + // DbContextProvider = () => Activator.CreateInstance(Options.Options.ContextType, Options.Options) as DbContext; + + + ReloadModel(); + } + + return new AsyncReply(true); + } + + public void ReloadModel() + { + + TypesByName.Clear(); + TypesByType.Clear(); + + var context = Getter(); + + var types = context.Model.GetEntityTypes(); + foreach (var t in types) + { + var ti = new EntityTypeInfo() + { + Name = t.ClrType.Name, + PrimaryKey = t.FindPrimaryKey().Properties.FirstOrDefault()?.PropertyInfo, + Type = t, + //Getter = getter + }; + + TypesByName.Add(t.ClrType.Name, ti); + TypesByType.Add(t.ClrType, ti); + + if (!DB.ContainsKey(t.ClrType)) + DB.Add(t.ClrType, new Dictionary()); + } + } + + public void Destroy() + { + OnDestroy?.Invoke(this); + } } diff --git a/Esiur.Stores.EntityCore/EntityTypeInfo.cs b/Esiur.Stores.EntityCore/EntityTypeInfo.cs index 7fc1e4d..3452b8c 100644 --- a/Esiur.Stores.EntityCore/EntityTypeInfo.cs +++ b/Esiur.Stores.EntityCore/EntityTypeInfo.cs @@ -5,13 +5,12 @@ using System.Collections.Generic; using System.Reflection; using System.Text; -namespace Esiur.Stores.EntityCore +namespace Esiur.Stores.EntityCore; + +struct EntityTypeInfo { - struct EntityTypeInfo - { - public string Name; - public IEntityType Type; - public PropertyInfo PrimaryKey; - // public Func Getter; - } + public string Name; + public IEntityType Type; + public PropertyInfo PrimaryKey; + // public Func Getter; } diff --git a/Esiur.Stores.EntityCore/Esiur.Stores.EntityCore.csproj b/Esiur.Stores.EntityCore/Esiur.Stores.EntityCore.csproj index 3640eee..e8489f9 100644 --- a/Esiur.Stores.EntityCore/Esiur.Stores.EntityCore.csproj +++ b/Esiur.Stores.EntityCore/Esiur.Stores.EntityCore.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + net6.0 Esiur.Stores.EntityCore Ahmed Kh. Zamil Esiur Foundation @@ -10,6 +10,7 @@ true Esiur.Stores.EntityCore 1.2.5 + latest @@ -21,7 +22,7 @@ - + diff --git a/Esiur.Stores.EntityCore/EsiurExtensionOptions.cs b/Esiur.Stores.EntityCore/EsiurExtensionOptions.cs index 058fd3f..408c533 100644 --- a/Esiur.Stores.EntityCore/EsiurExtensionOptions.cs +++ b/Esiur.Stores.EntityCore/EsiurExtensionOptions.cs @@ -36,79 +36,83 @@ using System.Reflection; using Esiur.Proxy; using Microsoft.EntityFrameworkCore; -namespace Esiur.Stores.EntityCore +namespace Esiur.Stores.EntityCore; + +public class EsiurExtensionOptions : IDbContextOptionsExtension { - public class EsiurExtensionOptions : IDbContextOptionsExtension + + //public Dictionary Cache { get; } = new Dictionary(); + //public void AddType(IEntityType type) + //{ + // if (!Cache.ContainsKey(type.ClrType)) + // Cache.Add(type.ClrType, type.FindPrimaryKey().Properties[0].PropertyInfo); + //} + + + + private DbContextOptionsExtensionInfo _info; + EntityStore _store; + + public DbContextOptionsExtensionInfo Info => _info; + + public EntityStore Store => _store; + + + public void ApplyServices(IServiceCollection services) + { + // services.AddEntityFrameworkProxies(); + + new EntityFrameworkServicesBuilder(services) + .TryAdd(); + } + + public void Validate(IDbContextOptions options) + { + var internalServiceProvider = options.FindExtension()?.InternalServiceProvider; + if (internalServiceProvider != null) + { + var scope = internalServiceProvider.CreateScope(); + var conventionPlugins = scope.ServiceProvider.GetService>(); + if (conventionPlugins?.Any(s => s is EsiurPlugin) == false) + { + throw new InvalidOperationException(""); + } + } + } + + public EsiurExtensionOptions(EntityStore store) + { + _info = new ExtensionInfo(this); + _store = store; + } + + + private sealed class ExtensionInfo : DbContextOptionsExtensionInfo { - //public Dictionary Cache { get; } = new Dictionary(); - //public void AddType(IEntityType type) - //{ - // if (!Cache.ContainsKey(type.ClrType)) - // Cache.Add(type.ClrType, type.FindPrimaryKey().Properties[0].PropertyInfo); - //} - - - - private DbContextOptionsExtensionInfo _info; - EntityStore _store; - - public DbContextOptionsExtensionInfo Info => _info; - - public EntityStore Store => _store; - - - public void ApplyServices(IServiceCollection services) + public ExtensionInfo(IDbContextOptionsExtension extension) + : base(extension) { - // services.AddEntityFrameworkProxies(); - - new EntityFrameworkServicesBuilder(services) - .TryAdd(); } - public void Validate(IDbContextOptions options) - { - var internalServiceProvider = options.FindExtension()?.InternalServiceProvider; - if (internalServiceProvider != null) - { - var scope = internalServiceProvider.CreateScope(); - var conventionPlugins = scope.ServiceProvider.GetService>(); - if (conventionPlugins?.Any(s => s is EsiurPlugin) == false) - { - throw new InvalidOperationException(""); - } - } - } + private new EsiurExtensionOptions Extension + => (EsiurExtensionOptions)base.Extension; - public EsiurExtensionOptions(EntityStore store) - { - _info = new ExtensionInfo(this); - _store = store; - } + public override bool IsDatabaseProvider => false; + public override string LogFragment => "Esiur"; - private sealed class ExtensionInfo : DbContextOptionsExtensionInfo + public override int GetServiceProviderHashCode() => 2312; + + public override void PopulateDebugInfo(IDictionary debugInfo) { - public ExtensionInfo(IDbContextOptionsExtension extension) - : base(extension) - { - } - - private new EsiurExtensionOptions Extension - => (EsiurExtensionOptions)base.Extension; - - public override bool IsDatabaseProvider => false; - - public override string LogFragment => "Esiur"; - - public override long GetServiceProviderHashCode() => 2312; - - public override void PopulateDebugInfo(IDictionary debugInfo) - { - - } } + public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other) + { + return true; + } } + } diff --git a/Esiur.Stores.EntityCore/EsiurExtensions.cs b/Esiur.Stores.EntityCore/EsiurExtensions.cs index a9a99e0..fbdaaa9 100644 --- a/Esiur.Stores.EntityCore/EsiurExtensions.cs +++ b/Esiur.Stores.EntityCore/EsiurExtensions.cs @@ -37,74 +37,62 @@ using System.Linq; using System.Reflection; using System.Text; -namespace Esiur.Stores.EntityCore +namespace Esiur.Stores.EntityCore; + +public static class EsiurExtensions { - public static class EsiurExtensions + //public static T CreateResource(this DbContext dbContext, object properties = null) where T:class,IResource + //{ + // return dbContext.GetInfrastructure().CreateResource(properties); + + //} + + public static T AddResource(this DbSet dbSet, T resource) where T : class, IResource + => AddResourceAsync(dbSet, resource).Wait(); + + public static async AsyncReply AddResourceAsync(this DbSet dbSet, T resource) where T : class, IResource { - //public static T CreateResource(this DbContext dbContext, object properties = null) where T:class,IResource - //{ - // return dbContext.GetInfrastructure().CreateResource(properties); + var store = dbSet.GetInfrastructure().GetService().FindExtension().Store; - //} - public static T AddResource(this DbSet dbSet, T resource) where T : class, IResource - => AddResourceAsync(dbSet, resource).Wait(); + var manager = store.Instance.Managers.FirstOrDefault();// > 0 ? store.Instance.Managers.First() : null; - public static async AsyncReply AddResourceAsync(this DbSet dbSet, T resource) where T : class, IResource + //var db = dbSet.GetService().Context; + + //var resource = dbSet.GetInfrastructure().CreateResource(properties); + //var resource = Warehouse.New("", options.Store, null, null, null, properties); + + var resType = typeof(T); + var proxyType = ResourceProxy.GetProxy(resType); + + + IResource res; + + if (proxyType == resType) { - var store = dbSet.GetInfrastructure().GetService().FindExtension().Store; + res = resource; + } + else + { + res = Activator.CreateInstance(proxyType) as IResource; + var ps = Structure.FromObject(resource); - - var manager = store.Instance.Managers.FirstOrDefault();// > 0 ? store.Instance.Managers.First() : null; - - //var db = dbSet.GetService().Context; - - //var resource = dbSet.GetInfrastructure().CreateResource(properties); - //var resource = Warehouse.New("", options.Store, null, null, null, properties); - - var resType = typeof(T); - var proxyType = ResourceProxy.GetProxy(resType); - - - IResource res; - - if (proxyType == resType) + foreach (var p in ps) { - res = resource; - } - else - { - res = Activator.CreateInstance(proxyType) as IResource; - var ps = Structure.FromObject(resource); - foreach (var p in ps) + var mi = resType.GetMember(p.Key, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance) + .FirstOrDefault(); + + if (mi != null) { - - var mi = resType.GetMember(p.Key, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance) - .FirstOrDefault(); - - if (mi != null) + if (mi is PropertyInfo) { - if (mi is PropertyInfo) - { - var pi = mi as PropertyInfo; - if (pi.CanWrite) - { - try - { - pi.SetValue(res, p.Value); - } - catch (Exception ex) - { - Global.Log(ex); - } - } - } - else if (mi is FieldInfo) + var pi = mi as PropertyInfo; + if (pi.CanWrite) { try { - (mi as FieldInfo).SetValue(res, p.Value); + pi.SetValue(res, p.Value); } catch (Exception ex) { @@ -112,90 +100,101 @@ namespace Esiur.Stores.EntityCore } } } + else if (mi is FieldInfo) + { + try + { + (mi as FieldInfo).SetValue(res, p.Value); + } + catch (Exception ex) + { + Global.Log(ex); + } + } } } - - //await Warehouse.Put("", null, null, null, null, properties); - var entity = dbSet.Add((T)res); - await entity.Context.SaveChangesAsync(); - - var id = store.TypesByType[typeof(T)].PrimaryKey.GetValue(resource); - - await Warehouse.Put(id.ToString(), res, store, null, null, 0, manager); - - return (T)res; } - //public static async AsyncReply CreateResourceAsync(this IServiceProvider serviceProvider, T properties = null) where T : class, IResource - //{ - // var options = serviceProvider.GetService().FindExtension>(); + //await Warehouse.Put("", null, null, null, null, properties); + var entity = dbSet.Add((T)res); + await entity.Context.SaveChangesAsync(); - // var resource = await Warehouse.New("", options.Store, null, null, null, properties); + var id = store.TypesByType[typeof(T)].PrimaryKey.GetValue(resource); - // resource.Instance.Managers.AddRange(options.Store.Instance.Managers.ToArray()); + await Warehouse.Put(id.ToString(), res, store, null, null, 0, manager); - // return resource; - //} + return (T)res; + } - //public static T CreateResource(this IServiceProvider serviceProvider, object properties = null) where T : class, IResource - // => CreateResourceAsync(serviceProvider, properties).Wait(); + //public static async AsyncReply CreateResourceAsync(this IServiceProvider serviceProvider, T properties = null) where T : class, IResource + //{ + // var options = serviceProvider.GetService().FindExtension>(); - public static DbContextOptionsBuilder UseEsiur(this DbContextOptionsBuilder optionsBuilder, - EntityStore store, - Func getter = null + // var resource = await Warehouse.New("", options.Store, null, null, null, properties); - //IServiceCollection services = null - //string name = null, - //IResource parent = null, - //IPermissionsManager manager = null, - //Func dbContextProvider = null - ) + // resource.Instance.Managers.AddRange(options.Store.Instance.Managers.ToArray()); + + // return resource; + //} + + //public static T CreateResource(this IServiceProvider serviceProvider, object properties = null) where T : class, IResource + // => CreateResourceAsync(serviceProvider, properties).Wait(); + + public static DbContextOptionsBuilder UseEsiur(this DbContextOptionsBuilder optionsBuilder, + EntityStore store, + Func getter = null + + //IServiceCollection services = null + //string name = null, + //IResource parent = null, + //IPermissionsManager manager = null, + //Func dbContextProvider = null + ) + { + var extension = optionsBuilder.Options.FindExtension(); + + if (extension == null) { - var extension = optionsBuilder.Options.FindExtension(); - - if (extension == null) - { - if (store == null) - return optionsBuilder; - - store.Options = optionsBuilder.Options; - extension = new EsiurExtensionOptions(store); - } - - ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension); - - return optionsBuilder; + if (store == null) + return optionsBuilder; + store.Options = optionsBuilder.Options; + extension = new EsiurExtensionOptions(store); } - //public static DbContextOptionsBuilder UseEsiur( - // this DbContextOptionsBuilder optionsBuilder, - // //DbContext context, - // string name = null, - // IResource parent = null, - // IPermissionsManager manager = null, - // Func dbContextProvider = null) - // where TContext : DbContext - //{ + ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension); - - // var extension = optionsBuilder.Options.FindExtension(); - - // if (extension == null) - // { - // var store = Warehouse.New(name, null, parent, manager, new { Options = optionsBuilder, DbContextProvider = dbContextProvider }).Wait(); - // extension = new EsiurExtensionOptions(store); - // //store.Options = optionsBuilder; - // //store.Options = extension; - // //store.DbContext = context; - // } - - - // ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension); - - // return optionsBuilder; - - //} + return optionsBuilder; } + + //public static DbContextOptionsBuilder UseEsiur( + // this DbContextOptionsBuilder optionsBuilder, + // //DbContext context, + // string name = null, + // IResource parent = null, + // IPermissionsManager manager = null, + // Func dbContextProvider = null) + // where TContext : DbContext + //{ + + + // var extension = optionsBuilder.Options.FindExtension(); + + // if (extension == null) + // { + // var store = Warehouse.New(name, null, parent, manager, new { Options = optionsBuilder, DbContextProvider = dbContextProvider }).Wait(); + // extension = new EsiurExtensionOptions(store); + // //store.Options = optionsBuilder; + // //store.Options = extension; + // //store.DbContext = context; + // } + + + // ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension); + + // return optionsBuilder; + + //} + } diff --git a/Esiur.Stores.EntityCore/EsiurPlugin.cs b/Esiur.Stores.EntityCore/EsiurPlugin.cs index a29e5f4..173abf4 100644 --- a/Esiur.Stores.EntityCore/EsiurPlugin.cs +++ b/Esiur.Stores.EntityCore/EsiurPlugin.cs @@ -30,31 +30,29 @@ using System; using System.Collections.Generic; using System.Text; -namespace Esiur.Stores.EntityCore +namespace Esiur.Stores.EntityCore; +public class EsiurPlugin : IConventionSetPlugin { - public class EsiurPlugin : IConventionSetPlugin + private readonly IDbContextOptions _options; + private readonly ProviderConventionSetBuilderDependencies _conventionSetBuilderDependencies; + + public EsiurPlugin( + IDbContextOptions options, + ProviderConventionSetBuilderDependencies conventionSetBuilderDependencies) { - private readonly IDbContextOptions _options; - private readonly ProviderConventionSetBuilderDependencies _conventionSetBuilderDependencies; - - public EsiurPlugin( - IDbContextOptions options, - ProviderConventionSetBuilderDependencies conventionSetBuilderDependencies) - { - _options = options; - _conventionSetBuilderDependencies = conventionSetBuilderDependencies; - } - - - public ConventionSet ModifyConventions(ConventionSet conventionSet) - { - var extension = _options.FindExtension(); - conventionSet.ModelFinalizingConventions.Add(new EsiurProxyRewrite( - extension, - _conventionSetBuilderDependencies)); - return conventionSet; - - } + _options = options; + _conventionSetBuilderDependencies = conventionSetBuilderDependencies; } + + public ConventionSet ModifyConventions(ConventionSet conventionSet) + { + var extension = _options.FindExtension(); + conventionSet.ModelFinalizingConventions.Add(new EsiurProxyRewrite( + extension, + _conventionSetBuilderDependencies)); + return conventionSet; + + } } + diff --git a/Esiur.Stores.EntityCore/EsiurProxyRewrite.cs b/Esiur.Stores.EntityCore/EsiurProxyRewrite.cs index 5feb859..316505b 100644 --- a/Esiur.Stores.EntityCore/EsiurProxyRewrite.cs +++ b/Esiur.Stores.EntityCore/EsiurProxyRewrite.cs @@ -39,135 +39,157 @@ using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata.Internal; using Esiur.Data; -namespace Esiur.Stores.EntityCore +namespace Esiur.Stores.EntityCore; + +public class EsiurProxyRewrite : IModelFinalizingConvention { - public class EsiurProxyRewrite : IModelFinalizingConvention + private static readonly MethodInfo _createInstance += typeof(EsiurProxyRewrite).GetTypeInfo().GetDeclaredMethod(nameof(EsiurProxyRewrite.CreateInstance)); + + private readonly ConstructorBindingConvention _directBindingConvention; + + + + public static object CreateInstance(IDbContextOptions dbContextOptions, + IEntityType entityType, + object[] properties) { - private static readonly MethodInfo _createInstance - = typeof(EsiurProxyRewrite).GetTypeInfo().GetDeclaredMethod(nameof(EsiurProxyRewrite.CreateInstance)); + var id = properties.First(); - private readonly ConstructorBindingConvention _directBindingConvention; + var options = dbContextOptions.FindExtension(); + var manager = options.Store.Instance.Managers.Count > 0 ? options.Store.Instance.Managers.First() : null; - //public static object CreateInstance(IDbContextOptions dbContextOptions, IEntityType entityType, - // object[] constructorArguments, DbContext context, long id) - //{ - // return CreateInstance(dbContextOptions, entityType, - // constructorArguments, context, id); - //} + var cache = options.Store.GetById(entityType.ClrType, id); - public static object CreateInstance( - IDbContextOptions dbContextOptions, - IEntityType entityType, - //object id - object[] properties + if (cache != null) + return cache; - // ILazyLoader loader, - // object[] constructorArguments, - //DbContext context, - ) + if (Codec.ImplementsInterface(entityType.ClrType, typeof(IResource))) { - var id = properties.First(); - - var options = dbContextOptions.FindExtension(); - var manager = options.Store.Instance.Managers.Count > 0 ? options.Store.Instance.Managers.First() : null; - - var cache = options.Store.GetById(entityType.ClrType, id); - - if (cache != null) - return cache; - - if (Codec.ImplementsInterface(entityType.ClrType, typeof(IResource))) - { - // check if the object exists - var obj = Warehouse.New(entityType.ClrType).Wait() as IResource; - options.Store.TypesByType[entityType.ClrType].PrimaryKey.SetValue(obj, id); - Warehouse.Put(id.ToString(), obj, options.Store, null, null, 0, manager).Wait(); - return obj; - - } - else - { - // record - var obj = Activator.CreateInstance(entityType.ClrType); - options.Store.TypesByType[entityType.ClrType].PrimaryKey.SetValue(obj, id); - - return obj; - } - } - - - public EsiurProxyRewrite(EsiurExtensionOptions ext, ProviderConventionSetBuilderDependencies conventionSetBuilderDependencies) - { - _directBindingConvention = new ConstructorBindingConvention(conventionSetBuilderDependencies); + // check if the object exists + var obj = Warehouse.New(entityType.ClrType).Wait() as IResource; + options.Store.TypesByType[entityType.ClrType].PrimaryKey.SetValue(obj, id); + Warehouse.Put(id.ToString(), obj, options.Store, null, null, 0, manager).Wait(); + return obj; } - - - public void ProcessModelFinalizing(IConventionModelBuilder modelBuilder, IConventionContext context) + else { - foreach (var entityType in modelBuilder.Metadata.GetEntityTypes()) + // record + var obj = Activator.CreateInstance(entityType.ClrType); + options.Store.TypesByType[entityType.ClrType].PrimaryKey.SetValue(obj, id); + + return obj; + } + } + + + public EsiurProxyRewrite(EsiurExtensionOptions ext, ProviderConventionSetBuilderDependencies conventionSetBuilderDependencies) + { + _directBindingConvention = new ConstructorBindingConvention(conventionSetBuilderDependencies); + + } + + + public void ProcessModelFinalizing(IConventionModelBuilder modelBuilder, IConventionContext context) + { + foreach (var entityType in modelBuilder.Metadata.GetEntityTypes()) + { + + if (!Codec.ImplementsInterface(entityType.ClrType, typeof(IResource))) + continue; + + var proxyType = ResourceProxy.GetProxy(entityType.ClrType); + + // var ann = entityType.GetAnnotation(CoreAnnotationNames.ConstructorBinding); + +#pragma warning disable EF1001 // Internal EF Core API usage. + var binding = ((EntityType)entityType).ConstructorBinding;// (InstantiationBinding)entityType[CoreAnnotationNames.ConstructorBinding]; +#pragma warning restore EF1001 // Internal EF Core API usage. + if (binding == null) + { + _directBindingConvention.ProcessModelFinalizing(modelBuilder, context); + +#pragma warning disable EF1001 // Internal EF Core API usage. + binding = ((EntityType)entityType).ConstructorBinding; // (InstantiationBinding)entityType[CoreAnnotationNames.ConstructorBinding]; +#pragma warning restore EF1001 // Internal EF Core API usage. + } + + try { - if (!Codec.ImplementsInterface(entityType.ClrType, typeof(IResource))) + var key = entityType.FindPrimaryKey().Properties.First(); + if (key == null) continue; - var proxyType = ResourceProxy.GetProxy(entityType.ClrType); - // var ann = entityType.GetAnnotation(CoreAnnotationNames.ConstructorBinding); + ((EntityType)entityType).SetConstructorBinding( + UpdateConstructorBindings(key, proxyType), + ConfigurationSource.Convention); -#pragma warning disable EF1001 // Internal EF Core API usage. - var binding = (InstantiationBinding)entityType[CoreAnnotationNames.ConstructorBinding]; -#pragma warning restore EF1001 // Internal EF Core API usage. - if (binding == null) - _directBindingConvention.ProcessModelFinalizing(modelBuilder, context); - -#pragma warning disable EF1001 // Internal EF Core API usage. - binding = (InstantiationBinding)entityType[CoreAnnotationNames.ConstructorBinding]; -#pragma warning restore EF1001 // Internal EF Core API usage. - - - try + binding = ((EntityType)entityType).ServiceOnlyConstructorBinding; + if (binding != null) { - - var key = entityType.FindPrimaryKey().Properties.First(); - if (key == null) - continue; - - //var keys = entityType.FindPrimaryKey().Properties.Select(x=>new PropertyParameterBinding(x)); - - entityType.SetAnnotation( -#pragma warning disable EF1001 // Internal EF Core API usage. - CoreAnnotationNames.ConstructorBinding, -#pragma warning restore EF1001 // Internal EF Core API usage. - new FactoryMethodBinding( - _createInstance, - new List - { - new DependencyInjectionParameterBinding(typeof(IDbContextOptions), typeof(IDbContextOptions)), - new EntityTypeParameterBinding(), - //new PropertyParameterBinding(key) - // constructor arguments - //new ObjectArrayParameterBinding(binding.ParameterBindings), - //new ContextParameterBinding(typeof(DbContext)), - //new ObjectArrayParameterBinding(entityType.FindPrimaryKey().Properties.Select(x=>new PropertyParameterBinding(x)).ToArray()) - new ObjectArrayParameterBinding(new ParameterBinding[]{ - new PropertyParameterBinding(key) }) - //}) - // new Microsoft.EntityFrameworkCore.Metadata.ObjectArrayParameterBinding(), - //new ObjectArrayParameterBinding() - - }, - proxyType)); - + ((EntityType)entityType).SetServiceOnlyConstructorBinding( + UpdateConstructorBindings(key, proxyType), + ConfigurationSource.Convention); } - catch - { - } + + // entityType.SetAnnotation( + //#pragma warning disable EF1001 // Internal EF Core API usage. + // CoreAnnotationNames.ConstructorBinding, + //#pragma warning restore EF1001 // Internal EF Core API usage. + // new FactoryMethodBinding( + // _createInstance, + // new List + // { + // new DependencyInjectionParameterBinding(typeof(IDbContextOptions), typeof(IDbContextOptions)), + // new EntityTypeParameterBinding(), + // //new PropertyParameterBinding(key) + // // constructor arguments + // //new ObjectArrayParameterBinding(binding.ParameterBindings), + // //new ContextParameterBinding(typeof(DbContext)), + // //new ObjectArrayParameterBinding(entityType.FindPrimaryKey().Properties.Select(x=>new PropertyParameterBinding(x)).ToArray()) + // new ObjectArrayParameterBinding(new ParameterBinding[]{ + // new PropertyParameterBinding(key) }) + // //}) + // // new Microsoft.EntityFrameworkCore.Metadata.ObjectArrayParameterBinding(), + // //new ObjectArrayParameterBinding() + + // }, + // proxyType)); } + catch + { + + } + + + + } - + + + } + + + private InstantiationBinding UpdateConstructorBindings( + IConventionProperty key, + Type proxyType) + { + return new FactoryMethodBinding( + _createInstance, + new List + { + new DependencyInjectionParameterBinding(typeof(IDbContextOptions), typeof(IDbContextOptions)), + new EntityTypeParameterBinding(), + new ObjectArrayParameterBinding(new ParameterBinding[]{ + new PropertyParameterBinding((IProperty)key) }) + + }, + proxyType); } } diff --git a/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj b/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj index eaa469a..57a5d85 100644 --- a/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj +++ b/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj @@ -13,6 +13,7 @@ True 1.5.2 Esiur.Stores.MongoDB + latest diff --git a/Esiur.Stores.MongoDB/MongoDBStore.cs b/Esiur.Stores.MongoDB/MongoDBStore.cs index c796963..3d72ec7 100644 --- a/Esiur.Stores.MongoDB/MongoDBStore.cs +++ b/Esiur.Stores.MongoDB/MongoDBStore.cs @@ -37,595 +37,595 @@ using System.Linq; using Esiur.Security.Permissions; using Esiur.Proxy; -namespace Esiur.Stores.MongoDB +namespace Esiur.Stores.MongoDB; + +public class MongoDBStore : IStore { - public class MongoDBStore : IStore + public Instance Instance { get; set; } + + public event DestroyedEvent OnDestroy; + MongoClient client; + IMongoDatabase database; + IMongoCollection resourcesCollection; + + KeyList resources = new KeyList(); + + + [Public] + public event ResourceEventHandler ResourceAdded; + + [Public] + public event ResourceEventHandler ResourceRemoved; + + int count = 0; + + [Public] + public virtual int Count { - public Instance Instance { get; set; } - - public event DestroyedEvent OnDestroy; - MongoClient client; - IMongoDatabase database; - IMongoCollection resourcesCollection; - - KeyList resources = new KeyList(); - - - [Public] - public event ResourceEventHandler ResourceAdded; - - [Public] - public event ResourceEventHandler ResourceRemoved; - - int count = 0; - - [Public] - public virtual int Count + get { - get - { - return count; + return count; - //return (int)resourcesCollection.Count(x => true); - } + //return (int)resourcesCollection.Count(x => true); } + } - public void Destroy() - { + public void Destroy() + { - } + } - /* - public IResource[] Query(string json) - { - //var json = "{ SendId: 4, 'Events.Code' : { $all : [2], $nin : [3] } }"; - resourcesCollection.Find(new QueryDocument(BsonDocument.Parse(json))); + /* + public IResource[] Query(string json) + { + //var json = "{ SendId: 4, 'Events.Code' : { $all : [2], $nin : [3] } }"; + resourcesCollection.Find(new QueryDocument(BsonDocument.Parse(json))); - }*/ + }*/ - public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime date) - { - var objectId = resource.Instance.Variables["objectId"].ToString(); - //var bsonObjectId = new BsonObjectId(new ObjectId(objectId)); + public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime date) + { + var objectId = resource.Instance.Variables["objectId"].ToString(); + //var bsonObjectId = new BsonObjectId(new ObjectId(objectId)); - var record = this.database.GetCollection("record_" + objectId); + var record = this.database.GetCollection("record_" + objectId); - record.InsertOne(new BsonDocument() + record.InsertOne(new BsonDocument() { {"property", propertyName}, {"age", BsonValue.Create(age) }, {"date", date}, {"value", Compose(value) } }); - //var col = this.database.GetCollection(collectionName); + //var col = this.database.GetCollection(collectionName); - var filter = Builders.Filter.Eq("_id", new BsonObjectId(new ObjectId(objectId))); - var update = Builders.Update - .Set("values." + propertyName, new BsonDocument { { "age", BsonValue.Create(age) }, + var filter = Builders.Filter.Eq("_id", new BsonObjectId(new ObjectId(objectId))); + var update = Builders.Update + .Set("values." + propertyName, new BsonDocument { { "age", BsonValue.Create(age) }, { "modification", date }, { "value", Compose(value) } }); - resourcesCollection.UpdateOne(filter, update); + resourcesCollection.UpdateOne(filter, update); - return true; + return true; + } + + [Public] + public bool Remove(IResource resource) + { + var objectId = resource.Instance.Variables["objectId"].ToString(); + var filter = Builders.Filter.Eq("_id", new BsonObjectId(new ObjectId(objectId))); + + this.database.DropCollection("record_" + objectId); + resourcesCollection.DeleteOne(filter); + + count--; + + ResourceRemoved?.Invoke(resource); + + + Instance.Modified("Count"); + + return true; + } + + async AsyncReply Fetch(string id) where T : IResource + { + + if (resources.ContainsKey(id) && resources[id].IsAlive) + { + if (resources[id].Target is T) + return (T)resources[id].Target;// new AsyncReply((T)resources[id].Target); + else + return default(T);// new AsyncReply(default(T)); ; } - [Public] - public bool Remove(IResource resource) + var filter = Builders.Filter.Eq("_id", new BsonObjectId(new ObjectId(id))); + var list = resourcesCollection.Find(filter).ToList(); + if (list.Count == 0) + return default(T);// new AsyncReply(default(T)); + var document = list[0]; + + var type = Type.GetType(document["classname"].AsString); + + if (type == null) + return default(T);// new AsyncReply(default(T)); + + IResource resource = (IResource)Activator.CreateInstance(ResourceProxy.GetProxy(type)); + + //var iid = document["_id"].AsObjectId.ToString(); + if (resources.ContainsKey(id)) + resources[id] = new WeakReference(resource); + else + resources.Add(id, new WeakReference(resource)); + + //@TODO this causes store.put to be invoked, need fix + await Warehouse.Put(document["name"].AsString, resource, this); + + + var parents = document["parents"].AsBsonArray; + var children = document["children"].AsBsonArray; + //var managers = document["managers"].AsBsonArray; + + var attributes = Parse(document["attributes"]).Then(x => { - var objectId = resource.Instance.Variables["objectId"].ToString(); - var filter = Builders.Filter.Eq("_id", new BsonObjectId(new ObjectId(objectId))); + resource.Instance.SetAttributes(x as Structure); + }); - this.database.DropCollection("record_" + objectId); - resourcesCollection.DeleteOne(filter); + // var bag = new AsyncBag(); - count--; + resource.Instance.Variables.Add("children", children.Select(x => x.AsString).ToArray()); + resource.Instance.Variables.Add("parents", parents.Select(x => x.AsString).ToArray()); - ResourceRemoved?.Invoke(resource); + // Apply store managers + foreach (var m in this.Instance.Managers) + resource.Instance.Managers.Add(m); + /* + // load managers + foreach(var m in managers) + { + IPermissionsManager pm = (IPermissionsManager)Activator.CreateInstance(Type.GetType(m["classname"].AsString)); + var sr = Parse(m["settings"]); + bag.Add(sr); + sr.Then((x) => + { + pm.Initialize((Structure)x, resource); + resource.Instance.Managers.Add(pm); + }); + } + */ + + // Load values + var values = document["values"].AsBsonDocument; + + + foreach (var v in values) + { + var valueInfo = v.Value as BsonDocument; + + var x = await Parse(valueInfo["value"]); + resource.Instance.LoadProperty(v.Name, + (ulong)valueInfo["age"].AsInt64, + valueInfo["modification"].ToUniversalTime(), + x); + + //bag.Add(av); + } + + if (resource is T) + return (T)resource; + else + return default(T); + } + + AsyncReply Parse(BsonValue value) + { + if (value.BsonType == BsonType.Document) + { + var doc = value.AsBsonDocument; + if (doc["type"] == 0) + { + return Warehouse.Get(doc["link"].AsString); + } // structure + else if (doc["type"] == 1) + { + var bag = new AsyncBag(); + var rt = new AsyncReply(); + + var bs = (BsonDocument)doc["values"].AsBsonDocument; + var s = new Structure(); + + foreach (var v in bs) + bag.Add(Parse(v.Value)); + + bag.Seal(); + bag.Then((x) => + { + for (var i = 0; i < x.Length; i++) + s[bs.GetElement(i).Name] = x[i]; + + rt.Trigger(s); + }); + + return rt; + } + else + return new AsyncReply(null); + } + else if (value.BsonType == BsonType.Array) + { + var array = value.AsBsonArray; + var bag = new AsyncBag(); + + foreach (var v in array) + bag.Add(Parse(v)); + + bag.Seal(); + + return bag; + } + else if (value.BsonType == BsonType.DateTime) + { + return new AsyncReply(value.ToUniversalTime()); + } + else + { + + return new AsyncReply(BsonTypeMapper.MapToDotNetValue(value)); + } + } + + public AsyncReply Get(string path) + { + var p = path.Split('/'); + if (p.Length == 2) + if (p[0] == "id") + { + // load from Id + return Fetch(p[1]); + + + /* + if (resources.ContainsKey(p[1])) + return new AsyncReply(resources[p[1]]); + else + return Fetch(p[1]); + */ + } + + return new AsyncReply(null); + } + + + + public string Link(IResource resource) + { + return this.Instance.Name + "/id/" + (string)resource.Instance.Variables["objectId"]; + } + + public async AsyncReply Put(IResource resource) + { + try + { + if (resource == this) + return true; + + var attrs = resource.Instance.GetAttributes(); + + foreach (var kv in resources) + if (kv.Value.Target == resource) + { + resource.Instance.Variables.Add("objectId", kv.Key); + return true; + } + + count++; Instance.Modified("Count"); - return true; - } + var type = ResourceProxy.GetBaseType(resource); - async AsyncReply Fetch(string id) where T : IResource - { - - if (resources.ContainsKey(id) && resources[id].IsAlive) - { - if (resources[id].Target is T) - return (T)resources[id].Target;// new AsyncReply((T)resources[id].Target); - else - return default(T);// new AsyncReply(default(T)); ; - } - - var filter = Builders.Filter.Eq("_id", new BsonObjectId(new ObjectId(id))); - var list = resourcesCollection.Find(filter).ToList(); - if (list.Count == 0) - return default(T);// new AsyncReply(default(T)); - var document = list[0]; - - var type = Type.GetType(document["classname"].AsString); - - if (type == null) - return default(T);// new AsyncReply(default(T)); - - IResource resource = (IResource)Activator.CreateInstance(ResourceProxy.GetProxy(type)); - - //var iid = document["_id"].AsObjectId.ToString(); - if (resources.ContainsKey(id)) - resources[id] = new WeakReference(resource); - else - resources.Add(id, new WeakReference(resource)); - - //@TODO this causes store.put to be invoked, need fix - await Warehouse.Put(document["name"].AsString, resource, this); - - - var parents = document["parents"].AsBsonArray; - var children = document["children"].AsBsonArray; - //var managers = document["managers"].AsBsonArray; - - var attributes = Parse(document["attributes"]).Then(x => - { - resource.Instance.SetAttributes(x as Structure); - }); - - // var bag = new AsyncBag(); - - resource.Instance.Variables.Add("children", children.Select(x => x.AsString).ToArray()); - resource.Instance.Variables.Add("parents", parents.Select(x => x.AsString).ToArray()); - - // Apply store managers - foreach (var m in this.Instance.Managers) - resource.Instance.Managers.Add(m); - - /* - // load managers - foreach(var m in managers) - { - IPermissionsManager pm = (IPermissionsManager)Activator.CreateInstance(Type.GetType(m["classname"].AsString)); - var sr = Parse(m["settings"]); - bag.Add(sr); - sr.Then((x) => - { - pm.Initialize((Structure)x, resource); - resource.Instance.Managers.Add(pm); - }); - } - */ - - // Load values - var values = document["values"].AsBsonDocument; - - - foreach (var v in values) - { - var valueInfo = v.Value as BsonDocument; - - var x = await Parse(valueInfo["value"]); - resource.Instance.LoadProperty(v.Name, - (ulong)valueInfo["age"].AsInt64, - valueInfo["modification"].ToUniversalTime(), - x); - - //bag.Add(av); - } - - if (resource is T) - return (T)resource; - else - return default(T); - } - - AsyncReply Parse(BsonValue value) - { - if (value.BsonType == BsonType.Document) - { - var doc = value.AsBsonDocument; - if (doc["type"] == 0) - { - return Warehouse.Get(doc["link"].AsString); - } // structure - else if (doc["type"] == 1) - { - var bag = new AsyncBag(); - var rt = new AsyncReply(); - - var bs = (BsonDocument)doc["values"].AsBsonDocument; - var s = new Structure(); - - foreach (var v in bs) - bag.Add(Parse(v.Value)); - - bag.Seal(); - bag.Then((x) => - { - for (var i = 0; i < x.Length; i++) - s[bs.GetElement(i).Name] = x[i]; - - rt.Trigger(s); - }); - - return rt; - } - else - return new AsyncReply(null); - } - else if (value.BsonType == BsonType.Array) - { - var array = value.AsBsonArray; - var bag = new AsyncBag(); - - foreach (var v in array) - bag.Add(Parse(v)); - - bag.Seal(); - - return bag; - } - else if (value.BsonType == BsonType.DateTime) - { - return new AsyncReply(value.ToUniversalTime()); - } - else - { - - return new AsyncReply(value.RawValue); - } - } - - public AsyncReply Get(string path) - { - var p = path.Split('/'); - if (p.Length == 2) - if (p[0] == "id") - { - // load from Id - return Fetch(p[1]); - - - /* - if (resources.ContainsKey(p[1])) - return new AsyncReply(resources[p[1]]); - else - return Fetch(p[1]); - */ - } - - return new AsyncReply(null); - } - - - - public string Link(IResource resource) - { - return this.Instance.Name + "/id/" + (string)resource.Instance.Variables["objectId"]; - } - - public async AsyncReply Put(IResource resource) - { - try - { - if (resource == this) - return true; - - var attrs = resource.Instance.GetAttributes(); - - foreach (var kv in resources) - if (kv.Value.Target == resource) - { - resource.Instance.Variables.Add("objectId", kv.Key); - return true; - } - - count++; - - Instance.Modified("Count"); - - var type = ResourceProxy.GetBaseType(resource); - - // insert the document - var document = new BsonDocument + // insert the document + var document = new BsonDocument { { "classname", type.FullName + "," + type.GetTypeInfo().Assembly.GetName().Name }, { "name", resource.Instance.Name }, }; - resourcesCollection.InsertOne(document); - resource.Instance.Variables["objectId"] = document["_id"].ToString(); + resourcesCollection.InsertOne(document); + resource.Instance.Variables["objectId"] = document["_id"].ToString(); - // now update the document - // * insert first to get the object id, update values, attributes, children and parents after in case the same resource has a property references self - - var parents = new BsonArray(); - var children = new BsonArray(); - - var template = resource.Instance.Template; - - // setup attributes - resource.Instance.Variables["children"] = new string[0]; - resource.Instance.Variables["parents"] = new string[] { this.Instance.Link }; - - // copy old children (in case we are moving a resource from a store to another. - if (resource.Instance.Store != this) - { - var resourceChildren = await resource.Instance.Children(); - - if (resourceChildren != null) - foreach (IResource c in resourceChildren) - children.Add(c.Instance.Link); - - var resourceParents = await resource.Instance.Parents(); - - if (resourceParents == null) - { - parents.Add(this.Instance.Link); - } - else - { - foreach (IResource p in resourceParents) - parents.Add(p.Instance.Link); - } - } - else - { - // just add self - parents.Add(this.Instance.Link); - } - - - var attrsDoc = ComposeStructure(attrs); - - - var values = new BsonDocument(); - - foreach (var pt in template.Properties) - { - var rt = pt.PropertyInfo.GetValue(resource, null); - - values.Add(pt.Name, - new BsonDocument { { "age", BsonValue.Create(resource.Instance.GetAge(pt.Index)) }, - { "modification", resource.Instance.GetModificationDate(pt.Index) }, - { "value", Compose(rt) } }); - } - - - var filter = Builders.Filter.Eq("_id", document["_id"]); - var update = Builders.Update - .Set("values", values).Set("parents", parents).Set("children", children).Set("attributes", attrsDoc); - resourcesCollection.UpdateOne(filter, update); - - - resources.Add(document["_id"].AsObjectId.ToString(), new WeakReference(resource)); - - //resource.Instance.Variables["objectId"] = document["_id"].ToString(); - - ResourceAdded?.Invoke(resource); - - return true; - - } - catch(Exception ex) - { - Console.WriteLine(ex); - return false; - } - } - - public BsonDocument ComposeStructure(Structure value) - { - var rt = new BsonDocument { { "type", 1 } }; - - var values = new BsonDocument(); - foreach (var i in value) - values.Add(i.Key, Compose(i.Value)); - - rt.Add("values", values); - return rt; - } - - public BsonArray ComposeVarArray(Array array) - { - var rt = new BsonArray(); - - for (var i = 0; i < array.Length; i++) - rt.Add(Compose(array.GetValue(i)));// [i])); - - return rt; - } - - BsonArray ComposeStructureArray(Structure[] structures) - { - var rt = new BsonArray(); - - if (structures == null || structures?.Length == 0) - return rt; - - foreach (var s in structures) - rt.Add(ComposeStructure(s)); - - return rt; - } - - BsonArray ComposeResourceArray(IResource[] array) - { - var rt = new BsonArray(); - foreach (var r in array) - { - rt.Add(new BsonDocument { { "type", 0 }, { "link", r.Instance.Link } }); - - //if (r.Instance.Variables.ContainsKey("objectId")) - - //rt.Add(new BsonObjectId(new ObjectId((string)r.Instance.Variables["objectId"]))); - } - - return rt; - } - - private BsonValue Compose(object valueObj) - { - var (type, value) = Codec.GetDataType(valueObj, null); - - switch (type) - { - case DataType.Void: - // nothing to do; - return BsonNull.Value; - - case DataType.String: - return new BsonString((string)value); - - case DataType.Resource: - case DataType.DistributedResource: - - return new BsonDocument { { "type", 0 }, { "link", (value as IResource).Instance.Link } }; - - //return new BsonObjectId(new ObjectId((string)(value as IResource).Instance.Variables["objectId"])); - - case DataType.Structure: - return ComposeStructure((Structure)value); - - case DataType.VarArray: - return ComposeVarArray((Array)value); - - case DataType.ResourceArray: - if (value is IResource[]) - return ComposeResourceArray((IResource[])value); - else - return ComposeResourceArray((IResource[])DC.CastConvert(value, typeof(IResource[]))); - - - case DataType.StructureArray: - return ComposeStructureArray((Structure[])value); - - - default: - return BsonValue.Create(value); - } - } - - public AsyncReply Retrieve(uint iid) - { - throw new NotImplementedException(); - } - - [Attribute] - public string Connection { get; set; } - [Attribute] - public string Collection { get; set; } - [Attribute] - public string Database { get; set; } - public AsyncReply Trigger(ResourceTrigger trigger) - { - - if (trigger == ResourceTrigger.Initialize) - { - - var collectionName = Collection ?? "resources"; - var dbName = Database ?? "Esiur"; - client = new MongoClient(Connection ?? "mongodb://localhost"); - database = client.GetDatabase(dbName); - - resourcesCollection = this.database.GetCollection(collectionName); - - - count = (int)resourcesCollection.CountDocuments(x => true); - - - // return new AsyncReply(true); - - - /* - var filter = new BsonDocument(); - - var list = resourcesCollection.Find(filter).ToList(); - - - // if (list.Count == 0) - // return new AsyncBag(new IResource[0]); - - var bag = new AsyncBag(); - - for(var i = 0; i < list.Count; i++) - { - Console.WriteLine("Loading {0}/{1}", i, list.Count); - bag.Add(Get("id/" + list[i]["_id"].AsObjectId.ToString())); - } - - bag.Seal(); - - var rt = new AsyncReply(); - - bag.Then((x) => { - - // storeChildren.AddRange(x); - rt.Trigger(true); - - }); - - return rt; - */ - - return new AsyncReply(true); - } - else if (trigger == ResourceTrigger.Terminate) - { - // save all resources - foreach (var resource in resources.Values) - if (resource.IsAlive) - SaveResource(resource.Target as IResource); - - return new AsyncReply(true); - } - else - return new AsyncReply(true); - } - - - public void SaveResource(IResource resource) - { - var attrs = resource.Instance.GetAttributes(); + // now update the document + // * insert first to get the object id, update values, attributes, children and parents after in case the same resource has a property references self var parents = new BsonArray(); var children = new BsonArray(); + var template = resource.Instance.Template; - //foreach (IResource c in resource.Instance.Children) - // children.Add(c.Instance.Link); + // setup attributes + resource.Instance.Variables["children"] = new string[0]; + resource.Instance.Variables["parents"] = new string[] { this.Instance.Link }; - var plist = resource.Instance.Variables["parents"] as string[]; + // copy old children (in case we are moving a resource from a store to another. + if (resource.Instance.Store != this) + { + var resourceChildren = await resource.Instance.Children(); - foreach (var link in plist)// Parents) - parents.Add(link); + if (resourceChildren != null) + foreach (IResource c in resourceChildren) + children.Add(c.Instance.Link); + + var resourceParents = await resource.Instance.Parents(); + + if (resourceParents == null) + { + parents.Add(this.Instance.Link); + } + else + { + foreach (IResource p in resourceParents) + parents.Add(p.Instance.Link); + } + } + else + { + // just add self + parents.Add(this.Instance.Link); + } + + + var attrsDoc = ComposeStructure(attrs); var values = new BsonDocument(); foreach (var pt in template.Properties) { - /* -#if NETSTANDARD1_5 - var pi = resource.GetType().GetTypeInfo().GetProperty(pt.Name); -#else - var pi = resource.GetType().GetProperty(pt.Name); -#endif -*/ var rt = pt.PropertyInfo.GetValue(resource, null); values.Add(pt.Name, - new BsonDocument { { "age", BsonValue.Create(resource.Instance.GetAge(pt.Index)) }, + new BsonDocument { { "age", BsonValue.Create(resource.Instance.GetAge(pt.Index)) }, + { "modification", resource.Instance.GetModificationDate(pt.Index) }, + { "value", Compose(rt) } }); + } + + + var filter = Builders.Filter.Eq("_id", document["_id"]); + var update = Builders.Update + .Set("values", values).Set("parents", parents).Set("children", children).Set("attributes", attrsDoc); + resourcesCollection.UpdateOne(filter, update); + + + resources.Add(document["_id"].AsObjectId.ToString(), new WeakReference(resource)); + + //resource.Instance.Variables["objectId"] = document["_id"].ToString(); + + ResourceAdded?.Invoke(resource); + + return true; + + } + catch (Exception ex) + { + Console.WriteLine(ex); + return false; + } + } + + public BsonDocument ComposeStructure(Structure value) + { + var rt = new BsonDocument { { "type", 1 } }; + + var values = new BsonDocument(); + foreach (var i in value) + values.Add(i.Key, Compose(i.Value)); + + rt.Add("values", values); + return rt; + } + + public BsonArray ComposeVarArray(Array array) + { + var rt = new BsonArray(); + + for (var i = 0; i < array.Length; i++) + rt.Add(Compose(array.GetValue(i)));// [i])); + + return rt; + } + + BsonArray ComposeStructureArray(Structure[] structures) + { + var rt = new BsonArray(); + + if (structures == null || structures?.Length == 0) + return rt; + + foreach (var s in structures) + rt.Add(ComposeStructure(s)); + + return rt; + } + + BsonArray ComposeResourceArray(IResource[] array) + { + var rt = new BsonArray(); + foreach (var r in array) + { + rt.Add(new BsonDocument { { "type", 0 }, { "link", r.Instance.Link } }); + + //if (r.Instance.Variables.ContainsKey("objectId")) + + //rt.Add(new BsonObjectId(new ObjectId((string)r.Instance.Variables["objectId"]))); + } + + return rt; + } + + private BsonValue Compose(object valueObj) + { + var (type, value) = Codec.GetDataType(valueObj, null); + + switch (type) + { + case DataType.Void: + // nothing to do; + return BsonNull.Value; + + case DataType.String: + return new BsonString((string)value); + + case DataType.Resource: + case DataType.DistributedResource: + + return new BsonDocument { { "type", 0 }, { "link", (value as IResource).Instance.Link } }; + + //return new BsonObjectId(new ObjectId((string)(value as IResource).Instance.Variables["objectId"])); + + case DataType.Structure: + return ComposeStructure((Structure)value); + + case DataType.VarArray: + return ComposeVarArray((Array)value); + + case DataType.ResourceArray: + if (value is IResource[]) + return ComposeResourceArray((IResource[])value); + else + return ComposeResourceArray((IResource[])DC.CastConvert(value, typeof(IResource[]))); + + + case DataType.StructureArray: + return ComposeStructureArray((Structure[])value); + + + default: + return BsonValue.Create(value); + } + } + + public AsyncReply Retrieve(uint iid) + { + throw new NotImplementedException(); + } + + [Attribute] + public string Connection { get; set; } + [Attribute] + public string Collection { get; set; } + [Attribute] + public string Database { get; set; } + public AsyncReply Trigger(ResourceTrigger trigger) + { + + if (trigger == ResourceTrigger.Initialize) + { + + var collectionName = Collection ?? "resources"; + var dbName = Database ?? "Esiur"; + client = new MongoClient(Connection ?? "mongodb://localhost"); + database = client.GetDatabase(dbName); + + resourcesCollection = this.database.GetCollection(collectionName); + + + count = (int)resourcesCollection.CountDocuments(x => true); + + + // return new AsyncReply(true); + + + /* + var filter = new BsonDocument(); + + var list = resourcesCollection.Find(filter).ToList(); + + + // if (list.Count == 0) + // return new AsyncBag(new IResource[0]); + + var bag = new AsyncBag(); + + for(var i = 0; i < list.Count; i++) + { + Console.WriteLine("Loading {0}/{1}", i, list.Count); + bag.Add(Get("id/" + list[i]["_id"].AsObjectId.ToString())); + } + + bag.Seal(); + + var rt = new AsyncReply(); + + bag.Then((x) => { + + // storeChildren.AddRange(x); + rt.Trigger(true); + + }); + + return rt; + */ + + return new AsyncReply(true); + } + else if (trigger == ResourceTrigger.Terminate) + { + // save all resources + foreach (var resource in resources.Values) + if (resource.IsAlive) + SaveResource(resource.Target as IResource); + + return new AsyncReply(true); + } + else + return new AsyncReply(true); + } + + + public void SaveResource(IResource resource) + { + var attrs = resource.Instance.GetAttributes(); + + var parents = new BsonArray(); + var children = new BsonArray(); + var template = resource.Instance.Template; + + //foreach (IResource c in resource.Instance.Children) + // children.Add(c.Instance.Link); + + var plist = resource.Instance.Variables["parents"] as string[]; + + foreach (var link in plist)// Parents) + parents.Add(link); + + + var values = new BsonDocument(); + + foreach (var pt in template.Properties) + { + /* +#if NETSTANDARD1_5 + var pi = resource.GetType().GetTypeInfo().GetProperty(pt.Name); +#else + var pi = resource.GetType().GetProperty(pt.Name); +#endif +*/ + var rt = pt.PropertyInfo.GetValue(resource, null); + + values.Add(pt.Name, + new BsonDocument { { "age", BsonValue.Create(resource.Instance.GetAge(pt.Index)) }, { "modification", resource.Instance.GetModificationDate(pt.Index) }, { "value", Compose(rt) } }); - } + } - var attrsDoc = ComposeStructure(attrs); + var attrsDoc = ComposeStructure(attrs); - var type = ResourceProxy.GetBaseType(resource); + var type = ResourceProxy.GetBaseType(resource); - var document = new BsonDocument + var document = new BsonDocument { { "parents", parents }, { "children", children }, @@ -638,283 +638,282 @@ namespace Esiur.Stores.MongoDB - var filter = Builders.Filter.Eq("_id", document["_id"]); + var filter = Builders.Filter.Eq("_id", document["_id"]); - /* - var update = Builders.Update - .Set("values", values); + /* + var update = Builders.Update + .Set("values", values); - var update = Builders.Update.Set("values", values).Set("parents", parents; - col.UpdateOne(filter, update); + var update = Builders.Update.Set("values", values).Set("parents", parents; + col.UpdateOne(filter, update); - */ + */ - resourcesCollection.ReplaceOne(filter, document); - } + resourcesCollection.ReplaceOne(filter, document); + } - public AsyncReply GetPropertyRecordByAge(IResource resource, string propertyName, ulong fromAge, ulong toAge) + public AsyncReply GetPropertyRecordByAge(IResource resource, string propertyName, ulong fromAge, ulong toAge) + { + var objectId = resource.Instance.Variables["objectId"].ToString(); + + var record = this.database.GetCollection("record_" + objectId); + var builder = Builders.Filter; + + var filter = builder.Gte("age", fromAge) & builder.Lte("age", toAge) & builder.Eq("property", propertyName); + + var reply = new AsyncReply(); + + record.FindAsync(filter).ContinueWith((x) => { - var objectId = resource.Instance.Variables["objectId"].ToString(); + var values = ((Task>)x).Result.ToList(); - var record = this.database.GetCollection("record_" + objectId); - var builder = Builders.Filter; + var bag = new AsyncBag(); - var filter = builder.Gte("age", fromAge) & builder.Lte("age", toAge) & builder.Eq("property", propertyName); - - var reply = new AsyncReply(); - - record.FindAsync(filter).ContinueWith((x) => - { - var values = ((Task>)x).Result.ToList(); - - var bag = new AsyncBag(); - - foreach (var v in values) - bag.Add(Parse(v["value"])); - - bag.Seal(); - - bag.Then((results) => - { - var list = new List(); - for (var i = 0; i < results.Length; i++) - list.Add(new PropertyValue(results[i], (ulong)values[i]["age"].AsInt64, values[i]["date"].ToUniversalTime())); - - reply.Trigger(list.ToArray()); - }); - - }); - - return reply; - } - - public AsyncReply GetPropertyRecordByDate(IResource resource, string propertyName, DateTime fromDate, DateTime toDate) - { - var objectId = resource.Instance.Variables["objectId"].ToString(); - - var record = this.database.GetCollection("record_" + objectId); - var builder = Builders.Filter; - - var filter = builder.Gte("date", fromDate) & builder.Lte("date", toDate) & builder.Eq("property", propertyName); - - var reply = new AsyncReply(); - - record.FindAsync(filter).ContinueWith((x) => - { - var values = ((Task>)x).Result.ToList(); - - var bag = new AsyncBag(); - - foreach (var v in values) - bag.Add(Parse(v["value"])); - - bag.Seal(); - - bag.Then((results) => - { - var list = new List(); - for (var i = 0; i < results.Length; i++) - list.Add(new PropertyValue(results[i], (ulong)values[i]["age"].AsInt64, values[i]["date"].ToUniversalTime())); - - reply.Trigger(list.ToArray()); - }); - - }); - - return reply; - } - - AsyncReply> GetRecordByAge(IResource resource, ulong fromAge, ulong toAge) - { - var properties = resource.Instance.Template.Properties.Where(x => x.Recordable).ToList(); - - var reply = new AsyncReply>(); - - AsyncBag bag = new AsyncBag(); - - foreach (var p in properties) - bag.Add(GetPropertyRecordByAge(resource, p.Name, fromAge, toAge)); + foreach (var v in values) + bag.Add(Parse(v["value"])); bag.Seal(); - bag.Then(x => + bag.Then((results) => { - var list = new KeyList(); + var list = new List(); + for (var i = 0; i < results.Length; i++) + list.Add(new PropertyValue(results[i], (ulong)values[i]["age"].AsInt64, values[i]["date"].ToUniversalTime())); - for (var i = 0; i < x.Length; i++) - list.Add(properties[i], x[i]); - - reply.Trigger(list); + reply.Trigger(list.ToArray()); }); - return reply; - } + }); - public AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate) + return reply; + } + + public AsyncReply GetPropertyRecordByDate(IResource resource, string propertyName, DateTime fromDate, DateTime toDate) + { + var objectId = resource.Instance.Variables["objectId"].ToString(); + + var record = this.database.GetCollection("record_" + objectId); + var builder = Builders.Filter; + + var filter = builder.Gte("date", fromDate) & builder.Lte("date", toDate) & builder.Eq("property", propertyName); + + var reply = new AsyncReply(); + + record.FindAsync(filter).ContinueWith((x) => { - var properties = resource.Instance.Template.Properties.Where(x => x.Recordable).ToList(); + var values = ((Task>)x).Result.ToList(); - var reply = new AsyncReply>(); + var bag = new AsyncBag(); - AsyncBag bag = new AsyncBag(); - - foreach (var p in properties) - bag.Add(GetPropertyRecordByDate(resource, p.Name, fromDate, toDate)); + foreach (var v in values) + bag.Add(Parse(v["value"])); bag.Seal(); - bag.Then(x => + bag.Then((results) => { - var list = new KeyList(); + var list = new List(); + for (var i = 0; i < results.Length; i++) + list.Add(new PropertyValue(results[i], (ulong)values[i]["age"].AsInt64, values[i]["date"].ToUniversalTime())); - for (var i = 0; i < x.Length; i++) - list.Add(properties[i], x[i]); - - reply.Trigger(list); + reply.Trigger(list.ToArray()); }); - return reply; - } + }); - public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + return reply; + } + + AsyncReply> GetRecordByAge(IResource resource, ulong fromAge, ulong toAge) + { + var properties = resource.Instance.Template.Properties.Where(x => x.Recordable).ToList(); + + var reply = new AsyncReply>(); + + AsyncBag bag = new AsyncBag(); + + foreach (var p in properties) + bag.Add(GetPropertyRecordByAge(resource, p.Name, fromAge, toAge)); + + bag.Seal(); + + bag.Then(x => { + var list = new KeyList(); - if (resource == this) - return true; + for (var i = 0; i < x.Length; i++) + list.Add(properties[i], x[i]); - var objectId = resource.Instance.Variables["objectId"].ToString(); + reply.Trigger(list); + }); - var filter = Builders.Filter.Eq("_id", new BsonObjectId(new ObjectId(objectId))); - var update = Builders.Update - .Set("values." + propertyName, new BsonDocument { { "age", BsonValue.Create(age) }, + return reply; + } + + public AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate) + { + var properties = resource.Instance.Template.Properties.Where(x => x.Recordable).ToList(); + + var reply = new AsyncReply>(); + + AsyncBag bag = new AsyncBag(); + + foreach (var p in properties) + bag.Add(GetPropertyRecordByDate(resource, p.Name, fromDate, toDate)); + + bag.Seal(); + + bag.Then(x => + { + var list = new KeyList(); + + for (var i = 0; i < x.Length; i++) + list.Add(properties[i], x[i]); + + reply.Trigger(list); + }); + + return reply; + } + + public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + { + + if (resource == this) + return true; + + var objectId = resource.Instance.Variables["objectId"].ToString(); + + var filter = Builders.Filter.Eq("_id", new BsonObjectId(new ObjectId(objectId))); + var update = Builders.Update + .Set("values." + propertyName, new BsonDocument { { "age", BsonValue.Create(age) }, { "modification", dateTime }, { "value", Compose(value) } }); - resourcesCollection.UpdateOne(filter, update); + resourcesCollection.UpdateOne(filter, update); - return true; + return true; - } + } - public AsyncBag Children(IResource resource, string name) where T : IResource + public AsyncBag Children(IResource resource, string name) where T : IResource + { + + if (resource == this) { + IFindFluent match; - if (resource == this) - { - IFindFluent match; - - if (name == null) - match = resourcesCollection.Find(x => (x["parents"] as BsonArray).Contains(this.Instance.Name)); - else - match = resourcesCollection.Find(x => (x["parents"] as BsonArray).Contains(this.Instance.Name) && x["name"] == name); - - - var st = match.ToList().Select(x => x["_id"].ToString()).ToArray(); - - - var bag = new AsyncBag(); - - foreach (var s in st) - { - var r = Fetch(s); - if (r.Ready && r.Result == null) - continue; - - bag.Add(r); - } - - bag.Seal(); - return bag; - } + if (name == null) + match = resourcesCollection.Find(x => (x["parents"] as BsonArray).Contains(this.Instance.Name)); else + match = resourcesCollection.Find(x => (x["parents"] as BsonArray).Contains(this.Instance.Name) && x["name"] == name); + + + var st = match.ToList().Select(x => x["_id"].ToString()).ToArray(); + + + var bag = new AsyncBag(); + + foreach (var s in st) { - var children = (string[])resource.Instance.Variables["children"]; + var r = Fetch(s); + if (r.Ready && r.Result == null) + continue; - if (children == null) - { - return new AsyncBag(null); - } - - var rt = new AsyncBag(); - - - foreach (var child in children) - { - var r = Warehouse.Get(child); - if (r is AsyncReply) - rt.Add(r);// (AsyncReply)r); - } - - rt.Seal(); - return rt; + bag.Add(r); } + + bag.Seal(); + return bag; } - - public AsyncBag Parents(IResource resource, string name) where T : IResource + else { + var children = (string[])resource.Instance.Variables["children"]; - if (resource == this) + if (children == null) { return new AsyncBag(null); } - else + + var rt = new AsyncBag(); + + + foreach (var child in children) { - var parents = (string[])resource.Instance.Variables["parents"]; - - if (parents == null) - { - return new AsyncBag(null); - } - - var rt = new AsyncBag(); - - - - foreach (var parent in parents) - { - var r = Warehouse.Get(parent); - if (r is AsyncReply) - rt.Add(r);// (AsyncReply)r); - } - - - rt.Seal(); - - - return rt; + var r = Warehouse.Get(child); + if (r is AsyncReply) + rt.Add(r);// (AsyncReply)r); } - } - - public AsyncReply AddChild(IResource resource, IResource child) - { - var list = (string[])resource.Instance.Variables["children"]; - resource.Instance.Variables["children"] = list.Concat(new string[] { child.Instance.Link }).ToArray(); - - SaveResource(resource); - - return new AsyncReply(true); - } - - public AsyncReply RemoveChild(IResource parent, IResource child) - { - throw new NotImplementedException(); - } - - public AsyncReply AddParent(IResource resource, IResource parent) - { - var list = (string[])resource.Instance.Variables["parents"]; - resource.Instance.Variables["parents"] = list.Concat(new string[] { parent.Instance.Link }).ToArray(); - - SaveResource(resource); - - return new AsyncReply(true); - } - - public AsyncReply RemoveParent(IResource child, IResource parent) - { - throw new NotImplementedException(); + rt.Seal(); + return rt; } } + + public AsyncBag Parents(IResource resource, string name) where T : IResource + { + + if (resource == this) + { + return new AsyncBag(null); + } + else + { + var parents = (string[])resource.Instance.Variables["parents"]; + + if (parents == null) + { + return new AsyncBag(null); + } + + var rt = new AsyncBag(); + + + + foreach (var parent in parents) + { + var r = Warehouse.Get(parent); + if (r is AsyncReply) + rt.Add(r);// (AsyncReply)r); + } + + + rt.Seal(); + + + return rt; + } + } + + + public AsyncReply AddChild(IResource resource, IResource child) + { + var list = (string[])resource.Instance.Variables["children"]; + resource.Instance.Variables["children"] = list.Concat(new string[] { child.Instance.Link }).ToArray(); + + SaveResource(resource); + + return new AsyncReply(true); + } + + public AsyncReply RemoveChild(IResource parent, IResource child) + { + throw new NotImplementedException(); + } + + public AsyncReply AddParent(IResource resource, IResource parent) + { + var list = (string[])resource.Instance.Variables["parents"]; + resource.Instance.Variables["parents"] = list.Concat(new string[] { parent.Instance.Link }).ToArray(); + + SaveResource(resource); + + return new AsyncReply(true); + } + + public AsyncReply RemoveParent(IResource child, IResource parent) + { + throw new NotImplementedException(); + } } diff --git a/Esiur/Core/AsyncAwaiter.cs b/Esiur/Core/AsyncAwaiter.cs index 424e872..618f399 100644 --- a/Esiur/Core/AsyncAwaiter.cs +++ b/Esiur/Core/AsyncAwaiter.cs @@ -4,50 +4,49 @@ using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; -namespace Esiur.Core +namespace Esiur.Core; + +public class AsyncAwaiter : INotifyCompletion { - public class AsyncAwaiter : INotifyCompletion + Action callback = null; + + AsyncException exception = null; + + object result; + + + public AsyncAwaiter(AsyncReply reply) { - Action callback = null; - - AsyncException exception = null; - - object result; - - - public AsyncAwaiter(AsyncReply reply) + reply.Then(x => { - reply.Then(x => - { - this.IsCompleted = true; - this.result = x; - this.callback?.Invoke(); - }).Error(x => - { - exception = x; - this.IsCompleted = true; - this.callback?.Invoke(); - }); - } - - public object GetResult() + this.IsCompleted = true; + this.result = x; + this.callback?.Invoke(); + }).Error(x => { - if (exception != null) - throw exception; - return result; - } - - public bool IsCompleted { get; private set; } - - public void OnCompleted(Action continuation) - { - if (IsCompleted) - continuation?.Invoke(); - else - // Continue.... - callback = continuation; - } - - + exception = x; + this.IsCompleted = true; + this.callback?.Invoke(); + }); } + + public object GetResult() + { + if (exception != null) + throw exception; + return result; + } + + public bool IsCompleted { get; private set; } + + public void OnCompleted(Action continuation) + { + if (IsCompleted) + continuation?.Invoke(); + else + // Continue.... + callback = continuation; + } + + } diff --git a/Esiur/Core/AsyncAwaiterGeneric.cs b/Esiur/Core/AsyncAwaiterGeneric.cs index f5e82e4..e0d5c2e 100644 --- a/Esiur/Core/AsyncAwaiterGeneric.cs +++ b/Esiur/Core/AsyncAwaiterGeneric.cs @@ -4,50 +4,48 @@ using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; -namespace Esiur.Core +namespace Esiur.Core; + +public class AsyncAwaiter : INotifyCompletion { - public class AsyncAwaiter : INotifyCompletion + Action callback = null; + + AsyncException exception = null; + + T result; + + public AsyncAwaiter(AsyncReply reply) { - Action callback = null; - - AsyncException exception = null; - - T result; - - public AsyncAwaiter(AsyncReply reply) + reply.Then(x => { - reply.Then(x => - { - this.IsCompleted = true; - this.result = (T)x; - this.callback?.Invoke(); - }).Error(x => - { - exception = x; - this.IsCompleted = true; - this.callback?.Invoke(); - }); - } - - public T GetResult() + this.IsCompleted = true; + this.result = (T)x; + this.callback?.Invoke(); + }).Error(x => { - if (exception != null) - throw exception; - return result; - } - - public bool IsCompleted { get; private set; } - - public void OnCompleted(Action continuation) - { - if (IsCompleted) - continuation?.Invoke(); - else - // Continue.... - callback = continuation; - } - - + exception = x; + this.IsCompleted = true; + this.callback?.Invoke(); + }); } -} + public T GetResult() + { + if (exception != null) + throw exception; + return result; + } + + public bool IsCompleted { get; private set; } + + public void OnCompleted(Action continuation) + { + if (IsCompleted) + continuation?.Invoke(); + else + // Continue.... + callback = continuation; + } + + +} diff --git a/Esiur/Core/AsyncBag.cs b/Esiur/Core/AsyncBag.cs index 008528e..add2c61 100644 --- a/Esiur/Core/AsyncBag.cs +++ b/Esiur/Core/AsyncBag.cs @@ -28,104 +28,103 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Core +namespace Esiur.Core; + +public class AsyncBag : AsyncReply { - public class AsyncBag: AsyncReply + + protected List replies = new List(); + List results = new List(); + + int count = 0; + bool sealedBag = false; + + + public Type ArrayType { get; set; } + + public AsyncBag Then(Action callback) + { + base.Then(new Action(o => callback((object[])o))); + return this; + } + + public new AsyncBagAwaiter GetAwaiter() + { + return new AsyncBagAwaiter(this); + } + + public new object[] Wait() + { + return (object[])base.Wait(); + } + + public new object[] Wait(int timeout) + { + return (object[])base.Wait(timeout); + } + + public void Seal() + { + if (sealedBag) + return; + + sealedBag = true; + + if (results.Count == 0) + Trigger(new object[0]); + + for (var i = 0; i < results.Count; i++) + //foreach(var reply in results.Keys) + { + var k = replies[i];// results.Keys.ElementAt(i); + var index = i; + + k.Then((r) => + { + results[index] = r; + count++; + if (count == results.Count) + { + if (ArrayType != null) + { + var ar = Array.CreateInstance(ArrayType, count); + for (var i = 0; i < count; i++) + ar.SetValue(results[i], i); + Trigger(ar); + } + else + Trigger(results.ToArray()); + } + }); + } + } + + public void Add(AsyncReply reply) + { + if (!sealedBag) + { + results.Add(null); + replies.Add(reply); + } + } + + public void AddBag(AsyncBag bag) + { + foreach (var r in bag.replies) + Add(r); + } + + + + public AsyncBag() { - protected List replies = new List(); - List results = new List(); + } - int count = 0; - bool sealedBag = false; - - - public Type ArrayType { get; set; } - - public AsyncBag Then(Action callback) - { - base.Then(new Action(o => callback((object[])o))); - return this; - } - - public new AsyncBagAwaiter GetAwaiter() - { - return new AsyncBagAwaiter(this); - } - - public new object[] Wait() - { - return (object[])base.Wait(); - } - - public new object[] Wait(int timeout) - { - return (object[])base.Wait(timeout); - } - - public void Seal() - { - if (sealedBag) - return; - - sealedBag = true; - - if (results.Count == 0) - Trigger(new object[0]); - - for (var i = 0; i < results.Count; i++) - //foreach(var reply in results.Keys) - { - var k = replies[i];// results.Keys.ElementAt(i); - var index = i; - - k.Then((r) => - { - results[index] = r; - count++; - if (count == results.Count) - { - if (ArrayType != null) - { - var ar = Array.CreateInstance(ArrayType, count); - for (var i = 0; i < count; i++) - ar.SetValue(results[i], i); - Trigger(ar); - } - else - Trigger(results.ToArray()); - } - }); - } - } - - public void Add(AsyncReply reply) - { - if (!sealedBag) - { - results.Add(null); - replies.Add(reply); - } - } - - public void AddBag(AsyncBag bag) - { - foreach (var r in bag.replies) - Add(r); - } - - - - public AsyncBag() - { - - } - - public AsyncBag(object[] results) - : base(results) - { - - } + public AsyncBag(object[] results) + : base(results) + { } + } diff --git a/Esiur/Core/AsyncBagAwaiter.cs b/Esiur/Core/AsyncBagAwaiter.cs index 577da5f..ec389c6 100644 --- a/Esiur/Core/AsyncBagAwaiter.cs +++ b/Esiur/Core/AsyncBagAwaiter.cs @@ -4,50 +4,48 @@ using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; -namespace Esiur.Core +namespace Esiur.Core; + +public class AsyncBagAwaiter : INotifyCompletion { - public class AsyncBagAwaiter : INotifyCompletion + Action callback = null; + + AsyncException exception = null; + + object[] result; + + public AsyncBagAwaiter(AsyncBag reply) { - Action callback = null; - - AsyncException exception = null; - - object[] result; - - public AsyncBagAwaiter(AsyncBag reply) + reply.Then(x => { - reply.Then(x => - { - this.IsCompleted = true; - this.result = x; - this.callback?.Invoke(); - }).Error(x => - { - exception = x; - this.IsCompleted = true; - this.callback?.Invoke(); - }); - } - - public object[] GetResult() + this.IsCompleted = true; + this.result = x; + this.callback?.Invoke(); + }).Error(x => { - if (exception != null) - throw exception; - return result; - } - - public bool IsCompleted { get; private set; } - - public void OnCompleted(Action continuation) - { - if (IsCompleted) - continuation?.Invoke(); - else - // Continue.... - callback = continuation; - } - - + exception = x; + this.IsCompleted = true; + this.callback?.Invoke(); + }); } -} + public object[] GetResult() + { + if (exception != null) + throw exception; + return result; + } + + public bool IsCompleted { get; private set; } + + public void OnCompleted(Action continuation) + { + if (IsCompleted) + continuation?.Invoke(); + else + // Continue.... + callback = continuation; + } + + +} diff --git a/Esiur/Core/AsyncBagAwaiterGeneric.cs b/Esiur/Core/AsyncBagAwaiterGeneric.cs index 562d4a7..c60d947 100644 --- a/Esiur/Core/AsyncBagAwaiterGeneric.cs +++ b/Esiur/Core/AsyncBagAwaiterGeneric.cs @@ -4,50 +4,48 @@ using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; -namespace Esiur.Core +namespace Esiur.Core; + +public class AsyncBagAwaiter : INotifyCompletion { - public class AsyncBagAwaiter : INotifyCompletion + Action callback = null; + + AsyncException exception = null; + + T[] result; + + public AsyncBagAwaiter(AsyncBag reply) { - Action callback = null; - - AsyncException exception = null; - - T[] result; - - public AsyncBagAwaiter(AsyncBag reply) + reply.Then(x => { - reply.Then(x => - { - this.IsCompleted = true; - this.result = x; - this.callback?.Invoke(); - }).Error(x => - { - exception = x; - this.IsCompleted = true; - this.callback?.Invoke(); - }); - } - - public T[] GetResult() + this.IsCompleted = true; + this.result = x; + this.callback?.Invoke(); + }).Error(x => { - if (exception != null) - throw exception; - return result; - } - - public bool IsCompleted { get; private set; } - - public void OnCompleted(Action continuation) - { - if (IsCompleted) - continuation?.Invoke(); - else - // Continue.... - callback = continuation; - } - - + exception = x; + this.IsCompleted = true; + this.callback?.Invoke(); + }); } -} + public T[] GetResult() + { + if (exception != null) + throw exception; + return result; + } + + public bool IsCompleted { get; private set; } + + public void OnCompleted(Action continuation) + { + if (IsCompleted) + continuation?.Invoke(); + else + // Continue.... + callback = continuation; + } + + +} diff --git a/Esiur/Core/AsyncBagGeneric.cs b/Esiur/Core/AsyncBagGeneric.cs index acbcdd5..240c1a5 100644 --- a/Esiur/Core/AsyncBagGeneric.cs +++ b/Esiur/Core/AsyncBagGeneric.cs @@ -28,48 +28,47 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Core +namespace Esiur.Core; + +public class AsyncBag : AsyncBag { - public class AsyncBag: AsyncBag - { - public AsyncBag Then(Action callback) - { - base.Then(new Action((o) => callback(((object[])o).Select(x=>(T)x).ToArray()))); - return this; - } - - - public void Add(AsyncReply reply) - { - base.Add(reply); - } - - public void AddBag(AsyncBag bag) - { - foreach (var r in bag.replies) - Add(r); - } - - - public new AsyncBagAwaiter GetAwaiter() - { - return new AsyncBagAwaiter(this); - } - - public new T[] Wait() - { - return base.Wait().Select(x => (T)x).ToArray(); - } - - public AsyncBag() - { - - } - - public AsyncBag(T[] results) - : base(results.Select(x=>(object)x).ToArray()) - { - - } + public AsyncBag Then(Action callback) + { + base.Then(new Action((o) => callback(((object[])o).Select(x => (T)x).ToArray()))); + return this; } -} + + + public void Add(AsyncReply reply) + { + base.Add(reply); + } + + public void AddBag(AsyncBag bag) + { + foreach (var r in bag.replies) + Add(r); + } + + + public new AsyncBagAwaiter GetAwaiter() + { + return new AsyncBagAwaiter(this); + } + + public new T[] Wait() + { + return base.Wait().Select(x => (T)x).ToArray(); + } + + public AsyncBag() + { + + } + + public AsyncBag(T[] results) + : base(results.Select(x => (object)x).ToArray()) + { + + } +} \ No newline at end of file diff --git a/Esiur/Core/AsyncException.cs b/Esiur/Core/AsyncException.cs index 69f6b68..c165bb7 100644 --- a/Esiur/Core/AsyncException.cs +++ b/Esiur/Core/AsyncException.cs @@ -26,32 +26,31 @@ using System; using System.Collections.Generic; using System.Text; -namespace Esiur.Core +namespace Esiur.Core; + +public class AsyncException : Exception { - public class AsyncException : Exception + public readonly ErrorType Type; + public readonly ExceptionCode Code; + + public AsyncException(Exception exception) : base(exception.Message, exception) { - public readonly ErrorType Type; - public readonly ExceptionCode Code; + Type = ErrorType.Exception; + Code = 0; + } - public AsyncException(Exception exception) :base(exception.Message, exception) - { - Type = ErrorType.Exception; - Code = 0; - } + public override string StackTrace => InnerException != null && Type == ErrorType.Exception ? InnerException.StackTrace : base.StackTrace; - public override string StackTrace => InnerException != null && Type == ErrorType.Exception ? InnerException.StackTrace : base.StackTrace; + public AsyncException(ErrorType type, ushort code, string message) + : base(type == ErrorType.Management ? ((ExceptionCode)code).ToString() : message) + { + this.Type = type; + this.Code = (ExceptionCode)code; - public AsyncException(ErrorType type, ushort code, string message) - : base(type == ErrorType.Management ? ((ExceptionCode)code).ToString() : message) - { - this.Type = type; - this.Code = (ExceptionCode)code; + } - } - - public override string ToString() - { - return Code.ToString() + ": " + Message; - } + public override string ToString() + { + return Code.ToString() + ": " + Message; } } diff --git a/Esiur/Core/AsyncQueue.cs b/Esiur/Core/AsyncQueue.cs index 1dc3c3c..c16dd0f 100644 --- a/Esiur/Core/AsyncQueue.cs +++ b/Esiur/Core/AsyncQueue.cs @@ -28,57 +28,56 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Core +namespace Esiur.Core; + +public class AsyncQueue : AsyncReply { - public class AsyncQueue : AsyncReply + List> list = new List>(); + //Action callback; + object queueLock = new object(); + + //public AsyncQueue Then(Action callback) + //{ + // base.Then(new Action(o => callback((T)o))); + + //return this; + //} + + public void Add(AsyncReply reply) { - List> list = new List>(); - //Action callback; - object queueLock = new object(); + lock (queueLock) + list.Add(reply); - //public AsyncQueue Then(Action callback) - //{ - // base.Then(new Action(o => callback((T)o))); + resultReady = false; + reply.Then(processQueue); + } - //return this; - //} + public void Remove(AsyncReply reply) + { + lock (queueLock) + list.Remove(reply); + processQueue(default(T)); + } - public void Add(AsyncReply reply) - { - lock (queueLock) - list.Add(reply); + void processQueue(T o) + { + lock (queueLock) + for (var i = 0; i < list.Count; i++) + if (list[i].Ready) + { + Trigger(list[i].Result); + resultReady = false; + list.RemoveAt(i); + i--; + } + else + break; - resultReady = false; - reply.Then(processQueue); - } + resultReady = (list.Count == 0); + } - public void Remove(AsyncReply reply) - { - lock (queueLock) - list.Remove(reply); - processQueue(default(T)); - } + public AsyncQueue() + { - void processQueue(T o) - { - lock (queueLock) - for (var i = 0; i < list.Count; i++) - if (list[i].Ready) - { - Trigger(list[i].Result); - resultReady = false; - list.RemoveAt(i); - i--; - } - else - break; - - resultReady = (list.Count == 0); - } - - public AsyncQueue() - { - - } } } diff --git a/Esiur/Core/AsyncReply.cs b/Esiur/Core/AsyncReply.cs index 3269d54..76a7812 100644 --- a/Esiur/Core/AsyncReply.cs +++ b/Esiur/Core/AsyncReply.cs @@ -33,328 +33,327 @@ using System.Threading; using System.Runtime.CompilerServices; using System.Diagnostics; -namespace Esiur.Core +namespace Esiur.Core; + +[AsyncMethodBuilder(typeof(AsyncReplyBuilder))] +public class AsyncReply { - [AsyncMethodBuilder(typeof(AsyncReplyBuilder))] - public class AsyncReply + public bool Debug = false; + + protected List> callbacks = new List>(); + protected object result; + + protected List> errorCallbacks = new List>(); + + protected List> progressCallbacks = new List>(); + + protected List> chunkCallbacks = new List>(); + + //List awaiters = new List(); + + object asyncLock = new object(); + + //public Timer timeout;// = new Timer() + protected bool resultReady = false; + AsyncException exception; + // StackTrace trace; + AutoResetEvent mutex = new AutoResetEvent(false); + + public static int MaxId; + + public int Id; + + public bool Ready { - public bool Debug = false; - - protected List> callbacks = new List>(); - protected object result; - - protected List> errorCallbacks = new List>(); - - protected List> progressCallbacks = new List>(); - - protected List> chunkCallbacks = new List>(); - - //List awaiters = new List(); - - object asyncLock = new object(); - - //public Timer timeout;// = new Timer() - protected bool resultReady = false; - AsyncException exception; - // StackTrace trace; - AutoResetEvent mutex = new AutoResetEvent(false); - - public static int MaxId; - - public int Id; - - public bool Ready - { - get { return resultReady; } - - } - - - public object Wait() - { - if (resultReady) - return result; - - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Wait"); - - //mutex = new AutoResetEvent(false); - mutex.WaitOne(); - - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Wait ended"); - - if (exception != null) - throw exception; - - return result; - } - - - public object Wait(int millisecondsTimeout) - { - if (resultReady) - return result; - - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Wait"); - - if (!mutex.WaitOne(millisecondsTimeout)) - { - var e = new Exception("AsyncReply timeout"); - TriggerError(e); - throw e; - } - - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Wait ended"); - - return result; - } - - public object Result - { - get { return result; } - } - - - public AsyncReply Then(Action callback) - { - //lock (callbacksLock) - //{ - lock (asyncLock) - { - // trace = new StackTrace(); - - if (resultReady) - { - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Then ready"); - - callback(result); - return this; - } - - - //timeout = new Timer(x => - //{ - // // Get calling method name - // Console.WriteLine(trace.GetFrame(1).GetMethod().Name); - - // var tr = String.Join("\r\n", trace.GetFrames().Select(f => f.GetMethod().Name)); - // timeout.Dispose(); - - // tr = trace.ToString(); - // throw new Exception("Request timeout " + Id); - //}, null, 15000, 0); - - - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Then pending"); - - - - callbacks.Add(callback); - - return this; - } - } - - - - public AsyncReply Error(Action callback) - { - // lock (callbacksLock) - // { - errorCallbacks.Add(callback); - - if (exception != null) - callback(exception); - - return this; - //} - } - - public AsyncReply Progress(Action callback) - { - //lock (callbacksLock) - //{ - progressCallbacks.Add(callback); - return this; - //} - } - - - public AsyncReply Chunk(Action callback) - { - // lock (callbacksLock) - // { - chunkCallbacks.Add(callback); - return this; - // } - } - - public AsyncReply Trigger(object result) - { - lock (asyncLock) - { - //timeout?.Dispose(); - - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Trigger"); - - if (resultReady) - return this; - - this.result = result; - - resultReady = true; - - //if (mutex != null) - mutex.Set(); - - foreach (var cb in callbacks) - cb(result); - - - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Trigger ended"); - - } - - return this; - } - - public AsyncReply TriggerError(Exception exception) - { - //timeout?.Dispose(); - - if (resultReady) - return this; - - if (exception is AsyncException) - this.exception = exception as AsyncException; - else - this.exception = new AsyncException(exception); - - - // lock (callbacksLock) - // { - foreach (var cb in errorCallbacks) - cb(this.exception); - // } - - mutex?.Set(); - - return this; - } - - public AsyncReply TriggerProgress(ProgressType type, int value, int max) - { - //timeout?.Dispose(); - - //lock (callbacksLock) - //{ - foreach (var cb in progressCallbacks) - cb(type, value, max); - - //} - - return this; - } - - - public AsyncReply TriggerChunk(object value) - { - - //timeout?.Dispose(); - - - //lock (callbacksLock) - //{ - foreach (var cb in chunkCallbacks) - cb(value); - - //} - - return this; - } - - public AsyncAwaiter GetAwaiter() - { - return new AsyncAwaiter(this); - } - - - - public AsyncReply() - { - // this.Debug = true; - Id = MaxId++; - } - - public AsyncReply(object result) - { - // this.Debug = true; - resultReady = true; - this.result = result; - - Id = MaxId++; - } - - /* - public AsyncReply Then(Action callback) - { - base.Then(new Action(o => callback((T)o))); - return this; - } - - public void Trigger(T result) - { - Trigger((object)result); - } - - public Task MoveNext(CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - - public void Dispose() - { - } - - public AsyncReply() - { - - } - - public new Task Task - { - get - { - return base.Task.ContinueWith((t) => - { - -#if NETSTANDARD - return (T)t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t); -#else - return (T)t.GetType().GetProperty("Result").GetValue(t); -#endif - }); - } - } - - public T Current => throw new NotImplementedException(); - - public AsyncReply(T result) - : base(result) - { - - } - - */ - - + get { return resultReady; } } + + + public object Wait() + { + if (resultReady) + return result; + + if (Debug) + Console.WriteLine($"AsyncReply: {Id} Wait"); + + //mutex = new AutoResetEvent(false); + mutex.WaitOne(); + + if (Debug) + Console.WriteLine($"AsyncReply: {Id} Wait ended"); + + if (exception != null) + throw exception; + + return result; + } + + + public object Wait(int millisecondsTimeout) + { + if (resultReady) + return result; + + if (Debug) + Console.WriteLine($"AsyncReply: {Id} Wait"); + + if (!mutex.WaitOne(millisecondsTimeout)) + { + var e = new Exception("AsyncReply timeout"); + TriggerError(e); + throw e; + } + + if (Debug) + Console.WriteLine($"AsyncReply: {Id} Wait ended"); + + return result; + } + + public object Result + { + get { return result; } + } + + + public AsyncReply Then(Action callback) + { + //lock (callbacksLock) + //{ + lock (asyncLock) + { + // trace = new StackTrace(); + + if (resultReady) + { + if (Debug) + Console.WriteLine($"AsyncReply: {Id} Then ready"); + + callback(result); + return this; + } + + + //timeout = new Timer(x => + //{ + // // Get calling method name + // Console.WriteLine(trace.GetFrame(1).GetMethod().Name); + + // var tr = String.Join("\r\n", trace.GetFrames().Select(f => f.GetMethod().Name)); + // timeout.Dispose(); + + // tr = trace.ToString(); + // throw new Exception("Request timeout " + Id); + //}, null, 15000, 0); + + + if (Debug) + Console.WriteLine($"AsyncReply: {Id} Then pending"); + + + + callbacks.Add(callback); + + return this; + } + } + + + + public AsyncReply Error(Action callback) + { + // lock (callbacksLock) + // { + errorCallbacks.Add(callback); + + if (exception != null) + callback(exception); + + return this; + //} + } + + public AsyncReply Progress(Action callback) + { + //lock (callbacksLock) + //{ + progressCallbacks.Add(callback); + return this; + //} + } + + + public AsyncReply Chunk(Action callback) + { + // lock (callbacksLock) + // { + chunkCallbacks.Add(callback); + return this; + // } + } + + public AsyncReply Trigger(object result) + { + lock (asyncLock) + { + //timeout?.Dispose(); + + if (Debug) + Console.WriteLine($"AsyncReply: {Id} Trigger"); + + if (resultReady) + return this; + + this.result = result; + + resultReady = true; + + //if (mutex != null) + mutex.Set(); + + foreach (var cb in callbacks) + cb(result); + + + if (Debug) + Console.WriteLine($"AsyncReply: {Id} Trigger ended"); + + } + + return this; + } + + public AsyncReply TriggerError(Exception exception) + { + //timeout?.Dispose(); + + if (resultReady) + return this; + + if (exception is AsyncException) + this.exception = exception as AsyncException; + else + this.exception = new AsyncException(exception); + + + // lock (callbacksLock) + // { + foreach (var cb in errorCallbacks) + cb(this.exception); + // } + + mutex?.Set(); + + return this; + } + + public AsyncReply TriggerProgress(ProgressType type, int value, int max) + { + //timeout?.Dispose(); + + //lock (callbacksLock) + //{ + foreach (var cb in progressCallbacks) + cb(type, value, max); + + //} + + return this; + } + + + public AsyncReply TriggerChunk(object value) + { + + //timeout?.Dispose(); + + + //lock (callbacksLock) + //{ + foreach (var cb in chunkCallbacks) + cb(value); + + //} + + return this; + } + + public AsyncAwaiter GetAwaiter() + { + return new AsyncAwaiter(this); + } + + + + public AsyncReply() + { + // this.Debug = true; + Id = MaxId++; + } + + public AsyncReply(object result) + { + // this.Debug = true; + resultReady = true; + this.result = result; + + Id = MaxId++; + } + + /* +public AsyncReply Then(Action callback) + { + base.Then(new Action(o => callback((T)o))); + return this; + } + + public void Trigger(T result) + { + Trigger((object)result); + } + + public Task MoveNext(CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public void Dispose() + { + } + + public AsyncReply() + { + + } + + public new Task Task + { + get + { + return base.Task.ContinueWith((t) => + { + +#if NETSTANDARD + return (T)t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t); +#else + return (T)t.GetType().GetProperty("Result").GetValue(t); +#endif + }); + } + } + + public T Current => throw new NotImplementedException(); + + public AsyncReply(T result) + : base(result) + { + + } + +*/ + + + } diff --git a/Esiur/Core/AsyncReplyBuilder.cs b/Esiur/Core/AsyncReplyBuilder.cs index 0c5f08e..114da18 100644 --- a/Esiur/Core/AsyncReplyBuilder.cs +++ b/Esiur/Core/AsyncReplyBuilder.cs @@ -3,66 +3,65 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Text; -namespace Esiur.Core +namespace Esiur.Core; + +public class AsyncReplyBuilder { - public class AsyncReplyBuilder + AsyncReply reply; + + AsyncReplyBuilder(AsyncReply reply) { - AsyncReply reply; - - AsyncReplyBuilder(AsyncReply reply) - { - this.reply = reply; - } - - public static AsyncReplyBuilder Create() - { - return new AsyncReplyBuilder(new AsyncReply()); - } - - public void Start(ref TStateMachine stateMachine) - where TStateMachine : IAsyncStateMachine - { - stateMachine.MoveNext(); - } - - public void SetStateMachine(IAsyncStateMachine stateMachine) - { - Console.WriteLine("SetStateMachine"); - } - - public void SetException(Exception exception) - { - reply.TriggerError(exception); - } - - public void SetResult() - { - reply.Trigger(null); - } - - public void AwaitOnCompleted( - ref TAwaiter awaiter, ref TStateMachine stateMachine) - where TAwaiter : INotifyCompletion - where TStateMachine : IAsyncStateMachine - { - awaiter.OnCompleted(stateMachine.MoveNext); - } - - public void AwaitUnsafeOnCompleted( - ref TAwaiter awaiter, ref TStateMachine stateMachine) - where TAwaiter : ICriticalNotifyCompletion - where TStateMachine : IAsyncStateMachine - { - awaiter.UnsafeOnCompleted(stateMachine.MoveNext); - } - - public AsyncReply Task - { - get - { - return reply; - } - } - + this.reply = reply; } + + public static AsyncReplyBuilder Create() + { + return new AsyncReplyBuilder(new AsyncReply()); + } + + public void Start(ref TStateMachine stateMachine) + where TStateMachine : IAsyncStateMachine + { + stateMachine.MoveNext(); + } + + public void SetStateMachine(IAsyncStateMachine stateMachine) + { + Console.WriteLine("SetStateMachine"); + } + + public void SetException(Exception exception) + { + reply.TriggerError(exception); + } + + public void SetResult() + { + reply.Trigger(null); + } + + public void AwaitOnCompleted( + ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : INotifyCompletion + where TStateMachine : IAsyncStateMachine + { + awaiter.OnCompleted(stateMachine.MoveNext); + } + + public void AwaitUnsafeOnCompleted( + ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : ICriticalNotifyCompletion + where TStateMachine : IAsyncStateMachine + { + awaiter.UnsafeOnCompleted(stateMachine.MoveNext); + } + + public AsyncReply Task + { + get + { + return reply; + } + } + } diff --git a/Esiur/Core/AsyncReplyBuilderGeneric.cs b/Esiur/Core/AsyncReplyBuilderGeneric.cs index 7992fc3..90be3e4 100644 --- a/Esiur/Core/AsyncReplyBuilderGeneric.cs +++ b/Esiur/Core/AsyncReplyBuilderGeneric.cs @@ -3,65 +3,65 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Text; -namespace Esiur.Core +namespace Esiur.Core; + +public class AsyncReplyBuilder { - public class AsyncReplyBuilder + AsyncReply reply; + + AsyncReplyBuilder(AsyncReply reply) { - AsyncReply reply; - - AsyncReplyBuilder(AsyncReply reply) - { - this.reply = reply; - } - - public static AsyncReplyBuilder Create() - { - return new AsyncReplyBuilder(new AsyncReply()); - } - - public void Start(ref TStateMachine stateMachine) - where TStateMachine : IAsyncStateMachine - { - stateMachine.MoveNext(); - } - - public void SetStateMachine(IAsyncStateMachine stateMachine) - { - Console.WriteLine("SetStateMachine"); - } - - public void SetException(Exception exception) - { - reply.TriggerError(exception); - } - - public void SetResult(T result) - { - reply.Trigger(result); - } - - public void AwaitOnCompleted( - ref TAwaiter awaiter, ref TStateMachine stateMachine) - where TAwaiter : INotifyCompletion - where TStateMachine : IAsyncStateMachine - { - awaiter.OnCompleted(stateMachine.MoveNext); - } - - public void AwaitUnsafeOnCompleted( - ref TAwaiter awaiter, ref TStateMachine stateMachine) - where TAwaiter : ICriticalNotifyCompletion - where TStateMachine : IAsyncStateMachine - { - awaiter.UnsafeOnCompleted(stateMachine.MoveNext); - } - - public AsyncReply Task - { - get { - return reply; - } - } - + this.reply = reply; } + + public static AsyncReplyBuilder Create() + { + return new AsyncReplyBuilder(new AsyncReply()); + } + + public void Start(ref TStateMachine stateMachine) + where TStateMachine : IAsyncStateMachine + { + stateMachine.MoveNext(); + } + + public void SetStateMachine(IAsyncStateMachine stateMachine) + { + Console.WriteLine("SetStateMachine"); + } + + public void SetException(Exception exception) + { + reply.TriggerError(exception); + } + + public void SetResult(T result) + { + reply.Trigger(result); + } + + public void AwaitOnCompleted( + ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : INotifyCompletion + where TStateMachine : IAsyncStateMachine + { + awaiter.OnCompleted(stateMachine.MoveNext); + } + + public void AwaitUnsafeOnCompleted( + ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : ICriticalNotifyCompletion + where TStateMachine : IAsyncStateMachine + { + awaiter.UnsafeOnCompleted(stateMachine.MoveNext); + } + + public AsyncReply Task + { + get + { + return reply; + } + } + } diff --git a/Esiur/Core/AsyncReplyGeneric.cs b/Esiur/Core/AsyncReplyGeneric.cs index 6f6a41a..042945d 100644 --- a/Esiur/Core/AsyncReplyGeneric.cs +++ b/Esiur/Core/AsyncReplyGeneric.cs @@ -33,347 +33,346 @@ using System.Threading; using System.Runtime.CompilerServices; using System.Diagnostics; -namespace Esiur.Core +namespace Esiur.Core; + +[AsyncMethodBuilder(typeof(AsyncReplyBuilder<>))] +public class AsyncReply : AsyncReply { - [AsyncMethodBuilder(typeof(AsyncReplyBuilder<>))] - public class AsyncReply : AsyncReply + + public AsyncReply Then(Action callback) + { + base.Then((x) => callback((T)x)); + return this; + } + + public new AsyncReply Progress(Action callback) + { + base.Progress(callback); + return this; + } + + + public AsyncReply Chunk(Action callback) + { + chunkCallbacks.Add((x) => callback((T)x)); + return this; + } + + public AsyncReply(T result) + : base(result) { - public AsyncReply Then(Action callback) - { - base.Then((x)=>callback((T)x)); - return this; - } - - public new AsyncReply Progress(Action callback) - { - base.Progress(callback); - return this; - } - - - public AsyncReply Chunk(Action callback) - { - chunkCallbacks.Add((x)=>callback((T)x)); - return this; - } - - public AsyncReply(T result) - : base(result) - { - - } - - public AsyncReply() - :base() - { - - } - - public new AsyncAwaiter GetAwaiter() - { - return new AsyncAwaiter(this); - } - - public new T Wait() - { - return (T)base.Wait(); - } - - public new T Wait(int millisecondsTimeout) - { - return (T)base.Wait(millisecondsTimeout); - } - - /* - protected new List callbacks = new List(); - protected new object result; - - protected new List> errorCallbacks = new List>(); - - protected new List> progressCallbacks = new List>(); - - protected new List chunkCallbacks = new List(); - - //List awaiters = new List(); - - object asyncLock = new object(); - - //public Timer timeout;// = new Timer() - - AsyncException exception; - // StackTrace trace; - AutoResetEvent mutex = new AutoResetEvent(false); - - public static int MaxId; - - public int Id; - - public bool Ready - { - get { return resultReady; } - - } - - - public T Wait() - { - - if (resultReady) - return result; - - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Wait"); - - //mutex = new AutoResetEvent(false); - mutex.WaitOne(); - - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Wait ended"); - - - return result; - } - - - public object Result - { - get { return result; } - } - - - public IAsyncReply Then(Action callback) - { - //lock (callbacksLock) - //{ - lock (asyncLock) - { - // trace = new StackTrace(); - - if (resultReady) - { - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Then ready"); - - callback(result); - return this; - } - - - //timeout = new Timer(x => - //{ - // // Get calling method name - // Console.WriteLine(trace.GetFrame(1).GetMethod().Name); - - // var tr = String.Join("\r\n", trace.GetFrames().Select(f => f.GetMethod().Name)); - // timeout.Dispose(); - - // tr = trace.ToString(); - // throw new Exception("Request timeout " + Id); - //}, null, 15000, 0); - - - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Then pending"); - - - - callbacks.Add(callback); - - return this; - } - } - - - - public IAsyncReply Error(Action callback) - { - // lock (callbacksLock) - // { - errorCallbacks.Add(callback); - - if (exception != null) - callback(exception); - - return this; - //} - } - - public IAsyncReply Progress(Action callback) - { - //lock (callbacksLock) - //{ - progressCallbacks.Add(callback); - return this; - //} - } - - - public IAsyncReply Chunk(Action callback) - { - // lock (callbacksLock) - // { - chunkCallbacks.Add(callback); - return this; - // } - } - - public void Trigger(object result) - { - lock (asyncLock) - { - //timeout?.Dispose(); - - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Trigger"); - - if (resultReady) - return; - - this.result = (T)result; - - resultReady = true; - - //if (mutex != null) - mutex.Set(); - - foreach (var cb in callbacks) - cb((T)result); - - - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Trigger ended"); - - } - } - - public void TriggerError(Exception exception) - { - //timeout?.Dispose(); - - if (resultReady) - return; - - if (exception is AsyncException) - this.exception = exception as AsyncException; - else - this.exception = new AsyncException(ErrorType.Management, 0, exception.Message); - - - // lock (callbacksLock) - // { - foreach (var cb in errorCallbacks) - cb(this.exception); - // } - - mutex?.Set(); - - } - - public void TriggerProgress(ProgressType type, int value, int max) - { - //timeout?.Dispose(); - - if (resultReady) - return; - - //lock (callbacksLock) - //{ - foreach (var cb in progressCallbacks) - cb(type, value, max); - - //} - } - - - public void TriggerChunk(object value) - { - - //timeout?.Dispose(); - - if (resultReady) - return; - - //lock (callbacksLock) - //{ - foreach (var cb in chunkCallbacks) - cb((T)value); - - //} - } - - public AsyncAwaiter GetAwaiter() - { - return new AsyncAwaiter(this); - } - - - - public AsyncReply() - { - // this.Debug = true; - Id = MaxId++; - } - - public AsyncReply(T result) - { - // this.Debug = true; - resultReady = true; - this.result = result; - - Id = MaxId++; - } - - /* - public AsyncReply Then(Action callback) - { - base.Then(new Action(o => callback((T)o))); - return this; - } - - public void Trigger(T result) - { - Trigger((object)result); - } - - public Task MoveNext(CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - - public void Dispose() - { - } - - public AsyncReply() - { - - } - - public new Task Task - { - get - { - return base.Task.ContinueWith((t) => - { - -#if NETSTANDARD - return (T)t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t); -#else - return (T)t.GetType().GetProperty("Result").GetValue(t); -#endif - }); - } - } - - public T Current => throw new NotImplementedException(); - - - - */ - - + } + public AsyncReply() + : base() + { } + + public new AsyncAwaiter GetAwaiter() + { + return new AsyncAwaiter(this); + } + + public new T Wait() + { + return (T)base.Wait(); + } + + public new T Wait(int millisecondsTimeout) + { + return (T)base.Wait(millisecondsTimeout); + } + + /* + protected new List callbacks = new List(); + protected new object result; + + protected new List> errorCallbacks = new List>(); + + protected new List> progressCallbacks = new List>(); + + protected new List chunkCallbacks = new List(); + + //List awaiters = new List(); + + object asyncLock = new object(); + + //public Timer timeout;// = new Timer() + + AsyncException exception; + // StackTrace trace; + AutoResetEvent mutex = new AutoResetEvent(false); + + public static int MaxId; + + public int Id; + + public bool Ready + { + get { return resultReady; } + + } + + + public T Wait() + { + + if (resultReady) + return result; + + if (Debug) + Console.WriteLine($"AsyncReply: {Id} Wait"); + + //mutex = new AutoResetEvent(false); + mutex.WaitOne(); + + if (Debug) + Console.WriteLine($"AsyncReply: {Id} Wait ended"); + + + return result; + } + + + public object Result + { + get { return result; } + } + + + public IAsyncReply Then(Action callback) + { + //lock (callbacksLock) + //{ + lock (asyncLock) + { + // trace = new StackTrace(); + + if (resultReady) + { + if (Debug) + Console.WriteLine($"AsyncReply: {Id} Then ready"); + + callback(result); + return this; + } + + + //timeout = new Timer(x => + //{ + // // Get calling method name + // Console.WriteLine(trace.GetFrame(1).GetMethod().Name); + + // var tr = String.Join("\r\n", trace.GetFrames().Select(f => f.GetMethod().Name)); + // timeout.Dispose(); + + // tr = trace.ToString(); + // throw new Exception("Request timeout " + Id); + //}, null, 15000, 0); + + + if (Debug) + Console.WriteLine($"AsyncReply: {Id} Then pending"); + + + + callbacks.Add(callback); + + return this; + } + } + + + + public IAsyncReply Error(Action callback) + { + // lock (callbacksLock) + // { + errorCallbacks.Add(callback); + + if (exception != null) + callback(exception); + + return this; + //} + } + + public IAsyncReply Progress(Action callback) + { + //lock (callbacksLock) + //{ + progressCallbacks.Add(callback); + return this; + //} + } + + + public IAsyncReply Chunk(Action callback) + { + // lock (callbacksLock) + // { + chunkCallbacks.Add(callback); + return this; + // } + } + + public void Trigger(object result) + { + lock (asyncLock) + { + //timeout?.Dispose(); + + if (Debug) + Console.WriteLine($"AsyncReply: {Id} Trigger"); + + if (resultReady) + return; + + this.result = (T)result; + + resultReady = true; + + //if (mutex != null) + mutex.Set(); + + foreach (var cb in callbacks) + cb((T)result); + + + if (Debug) + Console.WriteLine($"AsyncReply: {Id} Trigger ended"); + + } + } + + public void TriggerError(Exception exception) + { + //timeout?.Dispose(); + + if (resultReady) + return; + + if (exception is AsyncException) + this.exception = exception as AsyncException; + else + this.exception = new AsyncException(ErrorType.Management, 0, exception.Message); + + + // lock (callbacksLock) + // { + foreach (var cb in errorCallbacks) + cb(this.exception); + // } + + mutex?.Set(); + + } + + public void TriggerProgress(ProgressType type, int value, int max) + { + //timeout?.Dispose(); + + if (resultReady) + return; + + //lock (callbacksLock) + //{ + foreach (var cb in progressCallbacks) + cb(type, value, max); + + //} + } + + + public void TriggerChunk(object value) + { + + //timeout?.Dispose(); + + if (resultReady) + return; + + //lock (callbacksLock) + //{ + foreach (var cb in chunkCallbacks) + cb((T)value); + + //} + } + + public AsyncAwaiter GetAwaiter() + { + return new AsyncAwaiter(this); + } + + + + public AsyncReply() + { + // this.Debug = true; + Id = MaxId++; + } + + public AsyncReply(T result) + { + // this.Debug = true; + resultReady = true; + this.result = result; + + Id = MaxId++; + } + + /* +public AsyncReply Then(Action callback) + { + base.Then(new Action(o => callback((T)o))); + return this; + } + + public void Trigger(T result) + { + Trigger((object)result); + } + + public Task MoveNext(CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public void Dispose() + { + } + + public AsyncReply() + { + + } + + public new Task Task + { + get + { + return base.Task.ContinueWith((t) => + { + +#if NETSTANDARD + return (T)t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t); +#else + return (T)t.GetType().GetProperty("Result").GetValue(t); +#endif + }); + } + } + + public T Current => throw new NotImplementedException(); + + + +*/ + + + + } diff --git a/Esiur/Core/AsyncReplyNon.cs b/Esiur/Core/AsyncReplyNon.cs index 4bb5493..3efd09b 100644 --- a/Esiur/Core/AsyncReplyNon.cs +++ b/Esiur/Core/AsyncReplyNon.cs @@ -28,158 +28,157 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Core +namespace Esiur.Core; + +public class AsyncReply { - public class AsyncReply + + + + + protected List> callbacks = new List>(); + protected object result; + + protected List> errorCallbacks = new List>(); + + protected List> progressCallbacks = new List>(); + + protected List> chunkCallbacks = new List>(); + + object callbacksLock = new object(); + + protected bool resultReady = false; + AsyncException exception; + + TaskCompletionSource tcs = new TaskCompletionSource(); + + + public bool Ready { - + get { return resultReady; } + } + public object Result + { + get { return result; } + } + public AsyncReply Then(Action callback) + { + callbacks.Add(callback); - protected List> callbacks = new List>(); - protected object result; + if (resultReady) + callback(result); - protected List> errorCallbacks = new List>(); + return this; + } - protected List> progressCallbacks = new List>(); + public AsyncReply Error(Action callback) + { + errorCallbacks.Add(callback); - protected List> chunkCallbacks = new List>(); - - object callbacksLock = new object(); - - protected bool resultReady = false; - AsyncException exception; - - TaskCompletionSource tcs = new TaskCompletionSource(); - - - public bool Ready + if (exception != null) { - get { return resultReady; } + callback(exception); + tcs.SetException(exception); } - public object Result - { - get { return result; } - } + return this; + } - public AsyncReply Then(Action callback) - { - callbacks.Add(callback); + public AsyncReply Progress(Action callback) + { + progressCallbacks.Add(callback); + return this; + } - if (resultReady) - callback(result); + public AsyncReply Chunk(Action callback) + { + chunkCallbacks.Add(callback); + return this; + } - return this; - } + public void Trigger(object result) + { - public AsyncReply Error(Action callback) - { - errorCallbacks.Add(callback); - - if (exception != null) - { - callback(exception); - tcs.SetException(exception); - } - - return this; - } - - public AsyncReply Progress(Action callback) - { - progressCallbacks.Add(callback); - return this; - } - - public AsyncReply Chunk(Action callback) - { - chunkCallbacks.Add(callback); - return this; - } - - public void Trigger(object result) - { - - lock (callbacksLock) - { - if (resultReady) - return; - - this.result = result; - resultReady = true; - - foreach (var cb in callbacks) - cb(result); - - tcs.TrySetResult(result); - - } - - } - - public void TriggerError(AsyncException exception) + lock (callbacksLock) { if (resultReady) return; - this.exception = exception; - - - lock (callbacksLock) - { - foreach (var cb in errorCallbacks) - cb(exception); - } - - tcs.TrySetException(exception); - } - - public void TriggerProgress(ProgressType type, int value, int max) - { - if (resultReady) - return; - - lock (callbacksLock) - { - foreach (var cb in progressCallbacks) - cb(type, value, max); - - } - } - - public void TriggerChunk(object value) - { - if (resultReady) - return; - - lock (callbacksLock) - { - foreach (var cb in chunkCallbacks) - cb(value); - - } - } - - - public Task Task - { - get - { - return tcs.Task; - } - } - - public AsyncReply() - { - - } - - public AsyncReply(object result) - { - resultReady = true; - tcs.SetResult(result); this.result = result; + resultReady = true; + + foreach (var cb in callbacks) + cb(result); + + tcs.TrySetResult(result); + + } + + } + + public void TriggerError(AsyncException exception) + { + if (resultReady) + return; + + this.exception = exception; + + + lock (callbacksLock) + { + foreach (var cb in errorCallbacks) + cb(exception); + } + + tcs.TrySetException(exception); + } + + public void TriggerProgress(ProgressType type, int value, int max) + { + if (resultReady) + return; + + lock (callbacksLock) + { + foreach (var cb in progressCallbacks) + cb(type, value, max); + } } + + public void TriggerChunk(object value) + { + if (resultReady) + return; + + lock (callbacksLock) + { + foreach (var cb in chunkCallbacks) + cb(value); + + } + } + + + public Task Task + { + get + { + return tcs.Task; + } + } + + public AsyncReply() + { + + } + + public AsyncReply(object result) + { + resultReady = true; + tcs.SetResult(result); + this.result = result; + } } diff --git a/Esiur/Core/ErrorType.cs b/Esiur/Core/ErrorType.cs index 4ec2271..68227f7 100644 --- a/Esiur/Core/ErrorType.cs +++ b/Esiur/Core/ErrorType.cs @@ -2,11 +2,10 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Core +namespace Esiur.Core; + +public enum ErrorType { - public enum ErrorType - { - Management, - Exception - } + Management, + Exception } diff --git a/Esiur/Core/ExceptionCode.cs b/Esiur/Core/ExceptionCode.cs index c251bb7..79f81c2 100644 --- a/Esiur/Core/ExceptionCode.cs +++ b/Esiur/Core/ExceptionCode.cs @@ -2,44 +2,43 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Core +namespace Esiur.Core; + +public enum ExceptionCode : ushort { - public enum ExceptionCode : ushort - { - HostNotReachable, - AccessDenied, - UserOrTokenNotFound, - ChallengeFailed, - ResourceNotFound, - AttachDenied, - InvalidMethod, - InvokeDenied, - CreateDenied, - AddParentDenied, - AddChildDenied, - ViewAttributeDenied, - UpdateAttributeDenied, - StoreNotFound, - ParentNotFound, - ChildNotFound, - ResourceIsNotStore, - DeleteDenied, - DeleteFailed, - UpdateAttributeFailed, - GetAttributesFailed, - ClearAttributesFailed, - TemplateNotFound, - RenameDenied, - ClassNotFound, - MethodNotFound, - PropertyNotFound, - SetPropertyDenied, - ReadOnlyProperty, - GeneralFailure, - AddToStoreFailed, - NotAttached, - AlreadyListened, - AlreadyUnlistened, - NotListenable - } + HostNotReachable, + AccessDenied, + UserOrTokenNotFound, + ChallengeFailed, + ResourceNotFound, + AttachDenied, + InvalidMethod, + InvokeDenied, + CreateDenied, + AddParentDenied, + AddChildDenied, + ViewAttributeDenied, + UpdateAttributeDenied, + StoreNotFound, + ParentNotFound, + ChildNotFound, + ResourceIsNotStore, + DeleteDenied, + DeleteFailed, + UpdateAttributeFailed, + GetAttributesFailed, + ClearAttributesFailed, + TemplateNotFound, + RenameDenied, + ClassNotFound, + MethodNotFound, + PropertyNotFound, + SetPropertyDenied, + ReadOnlyProperty, + GeneralFailure, + AddToStoreFailed, + NotAttached, + AlreadyListened, + AlreadyUnlistened, + NotListenable } diff --git a/Esiur/Core/ExceptionLevel.cs b/Esiur/Core/ExceptionLevel.cs index 78117d8..eeffd15 100644 --- a/Esiur/Core/ExceptionLevel.cs +++ b/Esiur/Core/ExceptionLevel.cs @@ -2,13 +2,12 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Core +namespace Esiur.Core; + +public enum ExceptionLevel { - public enum ExceptionLevel - { - Code = 0x1, - Message = 0x2, - Source = 0x4, - Trace = 0x8 - } + Code = 0x1, + Message = 0x2, + Source = 0x4, + Trace = 0x8 } diff --git a/Esiur/Core/IAsyncReply.cs b/Esiur/Core/IAsyncReply.cs index 5c49389..5e0705d 100644 --- a/Esiur/Core/IAsyncReply.cs +++ b/Esiur/Core/IAsyncReply.cs @@ -3,19 +3,18 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Text; -namespace Esiur.Core -{ - public interface IAsyncReply//IAsyncEnumerator - { - IAsyncReply Then(Action callback); - IAsyncReply Error(Action callback); - IAsyncReply Progress(Action callback); - IAsyncReply Chunk(Action callback); - void Trigger(object result); - void TriggerError(Exception exception); - void TriggerProgress(ProgressType type, int value, int max); - void TriggerChunk(object value); +namespace Esiur.Core; - T Wait(); - } +public interface IAsyncReply//IAsyncEnumerator +{ + IAsyncReply Then(Action callback); + IAsyncReply Error(Action callback); + IAsyncReply Progress(Action callback); + IAsyncReply Chunk(Action callback); + void Trigger(object result); + void TriggerError(Exception exception); + void TriggerProgress(ProgressType type, int value, int max); + void TriggerChunk(object value); + + T Wait(); } diff --git a/Esiur/Core/IDestructible.cs b/Esiur/Core/IDestructible.cs index 26ef401..b16a33d 100644 --- a/Esiur/Core/IDestructible.cs +++ b/Esiur/Core/IDestructible.cs @@ -27,13 +27,12 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Core -{ - public delegate void DestroyedEvent(object sender); +namespace Esiur.Core; - public interface IDestructible - { - event DestroyedEvent OnDestroy; - void Destroy(); - } +public delegate void DestroyedEvent(object sender); + +public interface IDestructible +{ + event DestroyedEvent OnDestroy; + void Destroy(); } diff --git a/Esiur/Core/LogType.cs b/Esiur/Core/LogType.cs index eafb8c0..3b7d61f 100644 --- a/Esiur/Core/LogType.cs +++ b/Esiur/Core/LogType.cs @@ -29,12 +29,11 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Core +namespace Esiur.Core; + +public enum LogType { - public enum LogType - { - Debug, - Warning, - Error, - } + Debug, + Warning, + Error, } diff --git a/Esiur/Core/ProgressType.cs b/Esiur/Core/ProgressType.cs index 5ee724a..5470cf9 100644 --- a/Esiur/Core/ProgressType.cs +++ b/Esiur/Core/ProgressType.cs @@ -2,11 +2,10 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Core +namespace Esiur.Core; + +public enum ProgressType { - public enum ProgressType - { - Execution, - Network, - } + Execution, + Network, } diff --git a/Esiur/Data/AutoList.cs b/Esiur/Data/AutoList.cs index ac8c501..18a5ccc 100644 --- a/Esiur/Data/AutoList.cs +++ b/Esiur/Data/AutoList.cs @@ -30,285 +30,284 @@ using System.Collections; using Esiur.Core; using System.Reflection; -namespace Esiur.Data +namespace Esiur.Data; + +public class AutoList : IEnumerable, ICollection, ICollection { - public class AutoList : IEnumerable, ICollection, ICollection + + private readonly object syncRoot = new object(); + private List list = new List(); + + public delegate void Modified(ST sender, int index, T oldValue, T newValue); + public delegate void Added(ST sender, T value); + public delegate void Removed(ST sender, T value); + public delegate void Cleared(ST sender); + + + public event Modified OnModified; + public event Removed OnRemoved; + public event Cleared OnCleared; + public event Added OnAdd; + + bool removableList; + + + public ST State { get; set; } + /* + IOrderedEnumerable OrderBy(Func keySelector) { + return list.OrderBy(keySelector); + } + */ - private readonly object syncRoot = new object(); - private List list = new List(); - - public delegate void Modified(ST sender, int index, T oldValue, T newValue); - public delegate void Added(ST sender, T value); - public delegate void Removed(ST sender, T value); - public delegate void Cleared(ST sender); - - - public event Modified OnModified; - public event Removed OnRemoved; - public event Cleared OnCleared; - public event Added OnAdd; - - bool removableList; - - - public ST State { get; set; } - /* - IOrderedEnumerable OrderBy(Func keySelector) - { - return list.OrderBy(keySelector); - } - */ - - public void Sort() - { - lock(syncRoot) + public void Sort() + { + lock (syncRoot) list.Sort(); - } + } - public void Sort(IComparer comparer) - { - lock (syncRoot) - list.Sort(comparer); - } + public void Sort(IComparer comparer) + { + lock (syncRoot) + list.Sort(comparer); + } - public void Sort(Comparison comparison) - { - lock (syncRoot) - list.Sort(comparison); - } + public void Sort(Comparison comparison) + { + lock (syncRoot) + list.Sort(comparison); + } - public IEnumerable Where(Func predicate) - { - return list.Where(predicate); - } + public IEnumerable Where(Func predicate) + { + return list.Where(predicate); + } - /// - /// Convert AutoList to array - /// - /// Array - public T[] ToArray() - { - // list.OrderBy() - return list.ToArray(); - } + /// + /// Convert AutoList to array + /// + /// Array + public T[] ToArray() + { + // list.OrderBy() + return list.ToArray(); + } - /// - /// Create a new instance of AutoList - /// - /// State object to be included when an event is raised. - public AutoList(ST state) - { - State = state; + /// + /// Create a new instance of AutoList + /// + /// State object to be included when an event is raised. + public AutoList(ST state) + { + State = state; #if NETSTANDARD - removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())); + removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())); #else removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T))); #endif - } + } - /// - /// Create a new instance of AutoList - /// - /// Populate the list with items - /// - public AutoList(ST state, T[] values) - { - State = state; + /// + /// Create a new instance of AutoList + /// + /// Populate the list with items + /// + public AutoList(ST state, T[] values) + { + State = state; #if NETSTANDARD - removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())); + removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())); #else removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T))); #endif - AddRange(values); - } + AddRange(values); + } - /// - /// Synchronization lock of the list - /// - public object SyncRoot + /// + /// Synchronization lock of the list + /// + public object SyncRoot + { + get { - get - { - return syncRoot; - } + return syncRoot; } + } - /// - /// First item in the list - /// - public T First() + /// + /// First item in the list + /// + public T First() + { + return list.First(); + } + + /// + /// Get an item at a specified index + /// + public T this[int index] + { + get { - return list.First(); + return list[index]; } - - /// - /// Get an item at a specified index - /// - public T this[int index] + set { - get - { - return list[index]; - } - set - { - var oldValue = list[index]; + var oldValue = list[index]; - if (removableList) - { - if (oldValue != null) - ((IDestructible)oldValue).OnDestroy -= ItemDestroyed; - if (value != null) - ((IDestructible)value).OnDestroy += ItemDestroyed; - } - - lock (syncRoot) - list[index] = value; - - OnModified?.Invoke(State, index, oldValue, value); - } - } - - /// - /// Add item to the list - /// - public void Add(T value) - { if (removableList) + { + if (oldValue != null) + ((IDestructible)oldValue).OnDestroy -= ItemDestroyed; if (value != null) ((IDestructible)value).OnDestroy += ItemDestroyed; + } lock (syncRoot) - list.Add(value); + list[index] = value; - OnAdd?.Invoke(State, value); + OnModified?.Invoke(State, index, oldValue, value); } - - /// - /// Add an array of items to the list - /// - public void AddRange(T[] values) - { - foreach (var v in values) - Add(v); - } - - private void ItemDestroyed(object sender) - { - Remove((T)sender); - } - - /// - /// Clear the list - /// - public void Clear() - { - if (removableList) - foreach (IDestructible v in list) - if (v != null) - v.OnDestroy -= ItemDestroyed; - - lock (syncRoot) - list.Clear(); - - OnCleared?.Invoke(State); - } - - /// - /// Remove an item from the list - /// Item to remove - /// - public bool Remove(T value) - { - if (!list.Contains(value)) - return false; - - if (removableList) - if (value != null) - ((IDestructible)value).OnDestroy -= ItemDestroyed; - - lock (syncRoot) - list.Remove(value); - - OnRemoved?.Invoke(State, value); - - return true; - } - - /// - /// Number of items in the list - /// - public int Count - { - get { return list.Count; } - } - - public bool IsSynchronized => (list as ICollection).IsSynchronized; - - public bool IsReadOnly => false; - - - /// - /// Check if an item exists in the list - /// - /// Item to check if exists - public bool Contains(T value) - { - return list.Contains(value); - } - - /// - /// Check if any item of the given array is in the list - /// - /// Array of items - public bool ContainsAny(T[] values) - { - foreach (var v in values) - if (list.Contains(v)) - return true; - return false; - } - - /// - /// Check if any item of the given list is in the list - /// - /// List of items - public bool ContainsAny(AutoList values) - { - foreach (var v in values) - if (list.Contains((T)v)) - return true; - return false; - } - - public IEnumerator GetEnumerator() - { - return ((IEnumerable)list).GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IEnumerable)list).GetEnumerator(); - } - - public void CopyTo(Array array, int index) - { - lock (syncRoot) - (list as ICollection).CopyTo(array, index); - } - - public void CopyTo(T[] array, int arrayIndex) - { - lock (syncRoot) - list.CopyTo(array, arrayIndex); - } - - //bool ICollection.Remove(T item) - //{ - // lock(syncRoot) - // return Remove(item); - //} } + + /// + /// Add item to the list + /// + public void Add(T value) + { + if (removableList) + if (value != null) + ((IDestructible)value).OnDestroy += ItemDestroyed; + + lock (syncRoot) + list.Add(value); + + OnAdd?.Invoke(State, value); + } + + /// + /// Add an array of items to the list + /// + public void AddRange(T[] values) + { + foreach (var v in values) + Add(v); + } + + private void ItemDestroyed(object sender) + { + Remove((T)sender); + } + + /// + /// Clear the list + /// + public void Clear() + { + if (removableList) + foreach (IDestructible v in list) + if (v != null) + v.OnDestroy -= ItemDestroyed; + + lock (syncRoot) + list.Clear(); + + OnCleared?.Invoke(State); + } + + /// + /// Remove an item from the list + /// Item to remove + /// + public bool Remove(T value) + { + if (!list.Contains(value)) + return false; + + if (removableList) + if (value != null) + ((IDestructible)value).OnDestroy -= ItemDestroyed; + + lock (syncRoot) + list.Remove(value); + + OnRemoved?.Invoke(State, value); + + return true; + } + + /// + /// Number of items in the list + /// + public int Count + { + get { return list.Count; } + } + + public bool IsSynchronized => (list as ICollection).IsSynchronized; + + public bool IsReadOnly => false; + + + /// + /// Check if an item exists in the list + /// + /// Item to check if exists + public bool Contains(T value) + { + return list.Contains(value); + } + + /// + /// Check if any item of the given array is in the list + /// + /// Array of items + public bool ContainsAny(T[] values) + { + foreach (var v in values) + if (list.Contains(v)) + return true; + return false; + } + + /// + /// Check if any item of the given list is in the list + /// + /// List of items + public bool ContainsAny(AutoList values) + { + foreach (var v in values) + if (list.Contains((T)v)) + return true; + return false; + } + + public IEnumerator GetEnumerator() + { + return ((IEnumerable)list).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)list).GetEnumerator(); + } + + public void CopyTo(Array array, int index) + { + lock (syncRoot) + (list as ICollection).CopyTo(array, index); + } + + public void CopyTo(T[] array, int arrayIndex) + { + lock (syncRoot) + list.CopyTo(array, arrayIndex); + } + + //bool ICollection.Remove(T item) + //{ + // lock(syncRoot) + // return Remove(item); + //} } diff --git a/Esiur/Data/BinaryList.cs b/Esiur/Data/BinaryList.cs index 6d5ece2..f738841 100644 --- a/Esiur/Data/BinaryList.cs +++ b/Esiur/Data/BinaryList.cs @@ -30,685 +30,684 @@ using Esiur.Misc; using System.Reflection; using Esiur.Core; -namespace Esiur.Data +namespace Esiur.Data; + +/// +/// BinaryList holds a list of items to be converted to binary for storage and transmission +/// +public class BinaryList { + private List list = new List(); + /// - /// BinaryList holds a list of items to be converted to binary for storage and transmission + /// Create an instance of BinaryList /// - public class BinaryList + public BinaryList() { - private List list = new List(); - /// - /// Create an instance of BinaryList - /// - public BinaryList() + } + + /* + /// + /// Converts parameters to binary in same order + /// + /// Variables to convert + public static byte[] ToBytes(params object[] values) + { + var list = new List(); + + foreach (var i in values) { - - } - - /* - /// - /// Converts parameters to binary in same order - /// - /// Variables to convert - public static byte[] ToBytes(params object[] values) - { - var list = new List(); - - foreach (var i in values) + if (i is byte) + list.Add((byte)i); + else { - if (i is byte) - list.Add((byte)i); - else - { #if NETSTANDARD - MethodInfo mi = typeof(DC).GetTypeInfo().GetMethod("ToBytes", new Type[] { i.GetType() }); + MethodInfo mi = typeof(DC).GetTypeInfo().GetMethod("ToBytes", new Type[] { i.GetType() }); #else - MethodInfo mi = typeof(DC).GetMethod("ToBytes", new Type[] { i.GetType() }); + MethodInfo mi = typeof(DC).GetMethod("ToBytes", new Type[] { i.GetType() }); #endif - if (mi != null) - { - var b = (byte[])mi.Invoke(null, new object[] { i }); - list.AddRange(b); - } + if (mi != null) + { + var b = (byte[])mi.Invoke(null, new object[] { i }); + list.AddRange(b); } } - - return list.ToArray(); - } - - - /// - /// Create a new instance of BinaryList - /// - /// Populate the list items - public BinaryList(params object[] values) - { - AddRange(values); } - /// - /// Add an array of items at the end of the list - /// - /// Array of items - public void AddRange(object[] values) + return list.ToArray(); + } + + + /// + /// Create a new instance of BinaryList + /// + /// Populate the list items + public BinaryList(params object[] values) + { + AddRange(values); + } + + /// + /// Add an array of items at the end of the list + /// + /// Array of items + public void AddRange(object[] values) + { + foreach (var i in values) { - foreach (var i in values) + if (i is byte) + list.Add((byte)i); + else { - if (i is byte) - list.Add((byte)i); - else - { #if NETSTANDARD - MethodInfo mi = typeof(DC).GetTypeInfo().GetMethod("ToBytes", new Type[] { i.GetType() }); + MethodInfo mi = typeof(DC).GetTypeInfo().GetMethod("ToBytes", new Type[] { i.GetType() }); #else - MethodInfo mi = typeof(DC).GetMethod("ToBytes", new Type[] { i.GetType() }); + MethodInfo mi = typeof(DC).GetMethod("ToBytes", new Type[] { i.GetType() }); #endif - if (mi != null) - { - var b = (byte[])mi.Invoke(null, new object[] {i}); - list.AddRange(b); - } - } - } - } - - /// - /// Add multiple items at the end of the list - /// - /// Parameters of items - public void Append(params object[] values) - { - AddRange(values); - } - - /// - /// Insert new items to the list at a specified index - /// - /// Position in the list - /// Items to insert - public void Insert(int offset, params object[] values) - { - foreach (var i in values) - { - if (i is byte) + if (mi != null) { - list.Insert(offset++, (byte)i); - } - else - { -#if NETSTANDARD - MethodInfo mi = typeof(DC).GetTypeInfo().GetMethod("ToBytes", new Type[] { i.GetType() }); -#else - MethodInfo mi = typeof(DC).GetMethod("ToBytes", new Type[] { i.GetType() }); -#endif - if (mi != null) - { - var b = (byte[])mi.Invoke(null, new object[] { i }); - list.InsertRange(offset, b); - offset += b.Length; - } + var b = (byte[])mi.Invoke(null, new object[] {i}); + list.AddRange(b); } } } - - /// - /// Number of the items in the list - /// - public int Length - { - get - { - return list.Count; - } - } - - /* - public void Append(byte data) - { - list.Add(data); - } - - public void Append(byte[] data) - { - list.AddRange(data); - } - - public void Append(int data) - { - list.AddRange(DC.ToBytes(data)); - } - - public void Append(uint data) - { - list.AddRange(DC.ToBytes(data)); - } - - public void Append(float data) - { - list.AddRange(DC.ToBytes(data)); - } - - public void Append(short data) - { - list.AddRange(DC.ToBytes(data)); - } - - public void Append(ushort data) - { - list.AddRange(DC.ToBytes(data)); - } - - public void Append(double data) - { - list.AddRange(DC.ToBytes(data)); - } - - public void Append(sbyte data) - { - list.Add((byte)data); - } - */ - - - public int Length => list.Count; - - public BinaryList AddDateTime(DateTime value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertDateTime(int position, DateTime value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - - public BinaryList AddDateTimeArray(DateTime[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertDateTimeArray(int position, DateTime[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - public BinaryList AddGuid(Guid value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertGuid(int position, Guid value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - public BinaryList AddGuidArray(Guid[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertGuidArray(int position, Guid[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - - public BinaryList AddUInt8Array(byte[] value) - { - list.AddRange(value); - return this; - } - - - public BinaryList InsertUInt8Array(int position, byte[] value) - { - list.InsertRange(position, value); - return this; - } - - - public BinaryList AddHex(string value) - { - return this.AddUInt8Array(DC.FromHex(value, null)); - } - - public BinaryList InsertHex(int position, string value) - { - return this.InsertUInt8Array(position, DC.FromHex(value, null)); - } - - - - public BinaryList AddString(string value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertString(int position, string value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - public BinaryList AddStringArray(string[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertStringArray(int position, string[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - public BinaryList InsertUInt8(int position, byte value) - { - list.Insert(position, value); - return this; - } - - public BinaryList AddUInt8(byte value) - { - list.Add(value); - return this; - } - - public BinaryList AddInt8(sbyte value) - { - list.Add((byte)value); - return this; - } - - public BinaryList InsertInt8(int position, sbyte value) - { - list.Insert(position, (byte)value); - return this; - } - - public BinaryList AddInt8Array(sbyte[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertInt8Array(int position, sbyte[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - - public BinaryList AddChar(char value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertChar(int position, char value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - public BinaryList AddCharArray(char[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertCharArray(int position, char[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - - public BinaryList AddBoolean(bool value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertBoolean(int position, bool value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - public BinaryList AddBooleanArray(bool[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertBooleanArray(int position, bool[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - - public BinaryList AddUInt16(ushort value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - public BinaryList InsertUInt16(int position, ushort value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - public BinaryList AddUInt16Array(ushort[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertUInt16Array(int position, ushort[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - - public BinaryList AddInt16(short value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertInt16(int position, short value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - - public BinaryList AddInt16Array(short[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertInt16Array(int position, short[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - public BinaryList AddUInt32(uint value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - public BinaryList InsertUInt32(int position, uint value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - public BinaryList AddUInt32Array(uint[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - public BinaryList InsertUInt32Array(int position, uint[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - - public BinaryList AddInt32(int value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - public BinaryList InsertInt32(int position, int value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - public BinaryList AddInt32Array(int[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - public BinaryList InsertInt32Array(int position, int[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - - public BinaryList AddUInt64(ulong value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - public BinaryList InsertUInt64(int position, ulong value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - public BinaryList AddUInt64Array(ulong[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertUInt64Array(int position, ulong[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - - - - public BinaryList AddInt64(long value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertInt64(int position, long value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - public BinaryList AddInt64Array(long[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertInt64Array(int position, long[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - - public BinaryList AddFloat32(float value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertFloat32(int position, float value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - public BinaryList AddFloat32Array(float[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertFloat32Array(int position, float[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - - public BinaryList AddFloat64(double value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertFloat64(int position, double value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - public BinaryList AddFloat64Array(double[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertFloat64Array(int position, double[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - - - public BinaryList Add(DataType type, object value) - { - switch (type) - { - case DataType.Bool: - AddBoolean((bool)value); - return this; - case DataType.BoolArray: - AddBooleanArray((bool[])value); - return this; - case DataType.UInt8: - AddUInt8((byte)value); - return this; - case DataType.UInt8Array: - AddUInt8Array((byte[])value); - return this; - case DataType.Int8: - AddInt8((sbyte)value); - return this; - case DataType.Int8Array: - AddInt8Array((sbyte[])value); - return this; - case DataType.Char: - AddChar((char)value); - return this; - case DataType.CharArray: - AddCharArray((char[])value); - return this; - case DataType.UInt16: - AddUInt16((ushort)value); - return this; - case DataType.UInt16Array: - AddUInt16Array((ushort[])value); - return this; - case DataType.Int16: - AddInt16((short)value); - return this; - case DataType.Int16Array: - AddInt16Array((short[])value); - return this; - case DataType.UInt32: - AddUInt32((uint)value); - return this; - case DataType.UInt32Array: - AddUInt32Array((uint[])value); - return this; - case DataType.Int32: - AddInt32((int)value); - return this; - case DataType.Int32Array: - AddInt32Array((int[])value); - return this; - case DataType.UInt64: - AddUInt64((ulong)value); - return this; - case DataType.UInt64Array: - AddUInt64Array((ulong[])value); - return this; - case DataType.Int64: - AddInt64((long)value); - return this; - case DataType.Int64Array: - AddInt64Array((long[])value); - return this; - - case DataType.Float32: - AddFloat32((float)value); - return this; - case DataType.Float32Array: - AddFloat32Array((float[])value); - return this; - - case DataType.Float64: - AddFloat64((double)value); - return this; - case DataType.Float64Array: - AddFloat64Array((double[])value); - return this; - - case DataType.String: - AddString((string)value); - return this; - case DataType.StringArray: - AddStringArray((string[])value); - return this; - - case DataType.DateTime: - AddDateTime((DateTime)value); - return this; - case DataType.DateTimeArray: - AddDateTimeArray((DateTime[])value); - return this; - - default: - throw new Exception("Not Implemented " + type.ToString()); - //return this; - } - } - /// - /// Convert the list to an array of bytes - /// - /// Bytes array - public byte[] ToArray() - { - return list.ToArray(); - } - - public virtual AsyncReply Done() - { - return null; - // - } + } + + /// + /// Add multiple items at the end of the list + /// + /// Parameters of items + public void Append(params object[] values) + { + AddRange(values); + } + + /// + /// Insert new items to the list at a specified index + /// + /// Position in the list + /// Items to insert + public void Insert(int offset, params object[] values) + { + foreach (var i in values) + { + if (i is byte) + { + list.Insert(offset++, (byte)i); + } + else + { +#if NETSTANDARD + MethodInfo mi = typeof(DC).GetTypeInfo().GetMethod("ToBytes", new Type[] { i.GetType() }); +#else + MethodInfo mi = typeof(DC).GetMethod("ToBytes", new Type[] { i.GetType() }); +#endif + if (mi != null) + { + var b = (byte[])mi.Invoke(null, new object[] { i }); + list.InsertRange(offset, b); + offset += b.Length; + } + } + } + } + + /// + /// Number of the items in the list + /// + public int Length + { + get + { + return list.Count; + } + } + + /* + public void Append(byte data) + { + list.Add(data); + } + + public void Append(byte[] data) + { + list.AddRange(data); + } + + public void Append(int data) + { + list.AddRange(DC.ToBytes(data)); + } + + public void Append(uint data) + { + list.AddRange(DC.ToBytes(data)); + } + + public void Append(float data) + { + list.AddRange(DC.ToBytes(data)); + } + + public void Append(short data) + { + list.AddRange(DC.ToBytes(data)); + } + + public void Append(ushort data) + { + list.AddRange(DC.ToBytes(data)); + } + + public void Append(double data) + { + list.AddRange(DC.ToBytes(data)); + } + + public void Append(sbyte data) + { + list.Add((byte)data); + } + */ + + + public int Length => list.Count; + + public BinaryList AddDateTime(DateTime value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertDateTime(int position, DateTime value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + + public BinaryList AddDateTimeArray(DateTime[] value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertDateTimeArray(int position, DateTime[] value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + public BinaryList AddGuid(Guid value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertGuid(int position, Guid value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + public BinaryList AddGuidArray(Guid[] value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertGuidArray(int position, Guid[] value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + + public BinaryList AddUInt8Array(byte[] value) + { + list.AddRange(value); + return this; + } + + + public BinaryList InsertUInt8Array(int position, byte[] value) + { + list.InsertRange(position, value); + return this; + } + + + public BinaryList AddHex(string value) + { + return this.AddUInt8Array(DC.FromHex(value, null)); + } + + public BinaryList InsertHex(int position, string value) + { + return this.InsertUInt8Array(position, DC.FromHex(value, null)); + } + + + + public BinaryList AddString(string value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertString(int position, string value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + public BinaryList AddStringArray(string[] value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertStringArray(int position, string[] value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + public BinaryList InsertUInt8(int position, byte value) + { + list.Insert(position, value); + return this; + } + + public BinaryList AddUInt8(byte value) + { + list.Add(value); + return this; + } + + public BinaryList AddInt8(sbyte value) + { + list.Add((byte)value); + return this; + } + + public BinaryList InsertInt8(int position, sbyte value) + { + list.Insert(position, (byte)value); + return this; + } + + public BinaryList AddInt8Array(sbyte[] value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertInt8Array(int position, sbyte[] value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + + public BinaryList AddChar(char value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertChar(int position, char value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + public BinaryList AddCharArray(char[] value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertCharArray(int position, char[] value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + + public BinaryList AddBoolean(bool value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertBoolean(int position, bool value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + public BinaryList AddBooleanArray(bool[] value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertBooleanArray(int position, bool[] value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + + public BinaryList AddUInt16(ushort value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + public BinaryList InsertUInt16(int position, ushort value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + public BinaryList AddUInt16Array(ushort[] value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertUInt16Array(int position, ushort[] value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + + public BinaryList AddInt16(short value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertInt16(int position, short value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + + public BinaryList AddInt16Array(short[] value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertInt16Array(int position, short[] value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + public BinaryList AddUInt32(uint value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + public BinaryList InsertUInt32(int position, uint value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + public BinaryList AddUInt32Array(uint[] value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + public BinaryList InsertUInt32Array(int position, uint[] value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + + public BinaryList AddInt32(int value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + public BinaryList InsertInt32(int position, int value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + public BinaryList AddInt32Array(int[] value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + public BinaryList InsertInt32Array(int position, int[] value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + + public BinaryList AddUInt64(ulong value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + public BinaryList InsertUInt64(int position, ulong value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + public BinaryList AddUInt64Array(ulong[] value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertUInt64Array(int position, ulong[] value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + + + + public BinaryList AddInt64(long value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertInt64(int position, long value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + public BinaryList AddInt64Array(long[] value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertInt64Array(int position, long[] value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + + public BinaryList AddFloat32(float value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertFloat32(int position, float value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + public BinaryList AddFloat32Array(float[] value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertFloat32Array(int position, float[] value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + + public BinaryList AddFloat64(double value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertFloat64(int position, double value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + public BinaryList AddFloat64Array(double[] value) + { + list.AddRange(DC.ToBytes(value)); + return this; + } + + public BinaryList InsertFloat64Array(int position, double[] value) + { + list.InsertRange(position, DC.ToBytes(value)); + return this; + } + + + + public BinaryList Add(DataType type, object value) + { + switch (type) + { + case DataType.Bool: + AddBoolean((bool)value); + return this; + case DataType.BoolArray: + AddBooleanArray((bool[])value); + return this; + case DataType.UInt8: + AddUInt8((byte)value); + return this; + case DataType.UInt8Array: + AddUInt8Array((byte[])value); + return this; + case DataType.Int8: + AddInt8((sbyte)value); + return this; + case DataType.Int8Array: + AddInt8Array((sbyte[])value); + return this; + case DataType.Char: + AddChar((char)value); + return this; + case DataType.CharArray: + AddCharArray((char[])value); + return this; + case DataType.UInt16: + AddUInt16((ushort)value); + return this; + case DataType.UInt16Array: + AddUInt16Array((ushort[])value); + return this; + case DataType.Int16: + AddInt16((short)value); + return this; + case DataType.Int16Array: + AddInt16Array((short[])value); + return this; + case DataType.UInt32: + AddUInt32((uint)value); + return this; + case DataType.UInt32Array: + AddUInt32Array((uint[])value); + return this; + case DataType.Int32: + AddInt32((int)value); + return this; + case DataType.Int32Array: + AddInt32Array((int[])value); + return this; + case DataType.UInt64: + AddUInt64((ulong)value); + return this; + case DataType.UInt64Array: + AddUInt64Array((ulong[])value); + return this; + case DataType.Int64: + AddInt64((long)value); + return this; + case DataType.Int64Array: + AddInt64Array((long[])value); + return this; + + case DataType.Float32: + AddFloat32((float)value); + return this; + case DataType.Float32Array: + AddFloat32Array((float[])value); + return this; + + case DataType.Float64: + AddFloat64((double)value); + return this; + case DataType.Float64Array: + AddFloat64Array((double[])value); + return this; + + case DataType.String: + AddString((string)value); + return this; + case DataType.StringArray: + AddStringArray((string[])value); + return this; + + case DataType.DateTime: + AddDateTime((DateTime)value); + return this; + case DataType.DateTimeArray: + AddDateTimeArray((DateTime[])value); + return this; + + default: + throw new Exception("Not Implemented " + type.ToString()); + //return this; + } + } + /// + /// Convert the list to an array of bytes + /// + /// Bytes array + public byte[] ToArray() + { + return list.ToArray(); + } + + public virtual AsyncReply Done() + { + return null; + // } } diff --git a/Esiur/Data/Codec.cs b/Esiur/Data/Codec.cs index 14a271e..a3fbf27 100644 --- a/Esiur/Data/Codec.cs +++ b/Esiur/Data/Codec.cs @@ -38,173 +38,190 @@ using System.Runtime.CompilerServices; using System.Collections; using System.Dynamic; -namespace Esiur.Data +namespace Esiur.Data; + +public static class Codec { - public static class Codec + /// + /// Check if a DataType is an array + /// + /// DataType to check + /// True if DataType is an array, otherwise false + public static bool IsArray(this DataType type) { - /// - /// Check if a DataType is an array - /// - /// DataType to check - /// True if DataType is an array, otherwise false - public static bool IsArray(this DataType type) + return (((byte)type & 0x80) == 0x80) && (type != DataType.NotModified); + } + + /// + /// Get the element DataType + /// + /// + /// Passing UInt8Array will return UInt8 + /// + /// DataType to get its element DataType + public static DataType GetElementType(this DataType type) + { + return (DataType)((byte)type & 0x7F); + } + + /// + /// Get DataType array of a given Structure + /// + /// Structure to get its DataTypes + /// Distributed connection is required in case a type is at the other end + private static DataType[] GetStructureDateTypes(Structure structure, DistributedConnection connection) + { + var keys = structure.GetKeys(); + var types = new DataType[keys.Length]; + + for (var i = 0; i < keys.Length; i++) { - return (((byte)type & 0x80) == 0x80) && (type != DataType.NotModified); + types[i] = Codec.GetDataType(structure[keys[i]], connection).type; } + return types; + } - /// - /// Get the element DataType - /// - /// - /// Passing UInt8Array will return UInt8 - /// - /// DataType to get its element DataType - public static DataType GetElementType(this DataType type) - { - return (DataType)((byte)type & 0x7F); - } - - /// - /// Get DataType array of a given Structure - /// - /// Structure to get its DataTypes - /// Distributed connection is required in case a type is at the other end - private static DataType[] GetStructureDateTypes(Structure structure, DistributedConnection connection) - { - var keys = structure.GetKeys(); - var types = new DataType[keys.Length]; - - for (var i = 0; i < keys.Length; i++) - { - types[i] = Codec.GetDataType(structure[keys[i]], connection).type; - } - return types; - } - - /// - /// Compare two records - /// - /// Initial record to compare with - /// Next record to compare with the initial - /// DistributedConnection is required in case a structure holds items at the other end - public static RecordComparisonResult Compare(IRecord initial, IRecord next) - { - if (next == null) - return RecordComparisonResult.Null; - - if (initial == null) - return RecordComparisonResult.Record; - - if (next == initial) - return RecordComparisonResult.Same; - - if (next.GetType() == initial.GetType()) - return RecordComparisonResult.RecordSameType; + /// + /// Compare two records + /// + /// Initial record to compare with + /// Next record to compare with the initial + /// DistributedConnection is required in case a structure holds items at the other end + public static RecordComparisonResult Compare(IRecord initial, IRecord next) + { + if (next == null) + return RecordComparisonResult.Null; + if (initial == null) return RecordComparisonResult.Record; - } - /// - /// Compare two structures - /// - /// Initial structure to compare with - /// Next structure to compare with the initial - /// DistributedConnection is required in case a structure holds items at the other end - public static StructureComparisonResult Compare(Structure initial, Structure next, DistributedConnection connection) - { - if (next == null) - return StructureComparisonResult.Null; + if (next == initial) + return RecordComparisonResult.Same; - if (initial == null) + if (next.GetType() == initial.GetType()) + return RecordComparisonResult.RecordSameType; + + return RecordComparisonResult.Record; + } + + /// + /// Compare two structures + /// + /// Initial structure to compare with + /// Next structure to compare with the initial + /// DistributedConnection is required in case a structure holds items at the other end + public static StructureComparisonResult Compare(Structure initial, Structure next, DistributedConnection connection) + { + if (next == null) + return StructureComparisonResult.Null; + + if (initial == null) + return StructureComparisonResult.Structure; + + if (next == initial) + return StructureComparisonResult.Same; + + if (initial.Length != next.Length) + return StructureComparisonResult.Structure; + + var previousKeys = initial.GetKeys(); + var nextKeys = next.GetKeys(); + + for (var i = 0; i < previousKeys.Length; i++) + if (previousKeys[i] != nextKeys[i]) return StructureComparisonResult.Structure; - if (next == initial) - return StructureComparisonResult.Same; + var previousTypes = GetStructureDateTypes(initial, connection); + var nextTypes = GetStructureDateTypes(next, connection); - if (initial.Length != next.Length) - return StructureComparisonResult.Structure; + for (var i = 0; i < previousTypes.Length; i++) + if (previousTypes[i] != nextTypes[i]) + return StructureComparisonResult.StructureSameKeys; - var previousKeys = initial.GetKeys(); - var nextKeys = next.GetKeys(); + return StructureComparisonResult.StructureSameTypes; + } - for (var i = 0; i < previousKeys.Length; i++) - if (previousKeys[i] != nextKeys[i]) - return StructureComparisonResult.Structure; + /// + /// Compose an array of structures into an array of bytes + /// + /// Array of Structure to compose + /// DistributedConnection is required in case a structure in the array holds items at the other end + /// If true, prepend the length as UInt32 at the beginning of the returned bytes array + /// Array of bytes in the network byte order + public static byte[] ComposeStructureArray(Structure[] structures, DistributedConnection connection, bool prependLength = false) + { + if (structures == null || structures?.Length == 0) + return prependLength ? new byte[] { 0, 0, 0, 0 } : new byte[0]; - var previousTypes = GetStructureDateTypes(initial, connection); - var nextTypes = GetStructureDateTypes(next, connection); + var rt = new BinaryList(); + var comparsion = StructureComparisonResult.Structure; - for (var i = 0; i < previousTypes.Length; i++) - if (previousTypes[i] != nextTypes[i]) - return StructureComparisonResult.StructureSameKeys; + rt.AddUInt8((byte)comparsion) + .AddUInt8Array(ComposeStructure(structures[0], connection, true, true, true)); - return StructureComparisonResult.StructureSameTypes; + for (var i = 1; i < structures.Length; i++) + { + comparsion = Compare(structures[i - 1], structures[i], connection); + rt.AddUInt8((byte)comparsion); + + if (comparsion == StructureComparisonResult.Structure) + rt.AddUInt8Array(ComposeStructure(structures[i], connection, true, true, true)); + else if (comparsion == StructureComparisonResult.StructureSameKeys) + rt.AddUInt8Array(ComposeStructure(structures[i], connection, false, true, true)); + else if (comparsion == StructureComparisonResult.StructureSameTypes) + rt.AddUInt8Array(ComposeStructure(structures[i], connection, false, false, true)); } - /// - /// Compose an array of structures into an array of bytes - /// - /// Array of Structure to compose - /// DistributedConnection is required in case a structure in the array holds items at the other end - /// If true, prepend the length as UInt32 at the beginning of the returned bytes array - /// Array of bytes in the network byte order - public static byte[] ComposeStructureArray(Structure[] structures, DistributedConnection connection, bool prependLength = false) + if (prependLength) + rt.InsertInt32(0, rt.Length); + + return rt.ToArray(); + } + + /// + /// Parse an array of structures + /// + /// Bytes array + /// Zero-indexed offset + /// Number of bytes to parse + /// DistributedConnection is required in case a structure in the array holds items at the other end + /// Array of structures + public static AsyncBag ParseStructureArray(byte[] data, uint offset, uint length, DistributedConnection connection) + { + var reply = new AsyncBag(); + if (length == 0) { - if (structures == null || structures?.Length == 0) - return prependLength ? new byte[] { 0, 0, 0, 0 } : new byte[0]; - - var rt = new BinaryList(); - var comparsion = StructureComparisonResult.Structure; - - rt.AddUInt8((byte)comparsion) - .AddUInt8Array(ComposeStructure(structures[0], connection, true, true, true)); - - for (var i = 1; i < structures.Length; i++) - { - comparsion = Compare(structures[i - 1], structures[i], connection); - rt.AddUInt8((byte)comparsion); - - if (comparsion == StructureComparisonResult.Structure) - rt.AddUInt8Array(ComposeStructure(structures[i], connection, true, true, true)); - else if (comparsion == StructureComparisonResult.StructureSameKeys) - rt.AddUInt8Array(ComposeStructure(structures[i], connection, false, true, true)); - else if (comparsion == StructureComparisonResult.StructureSameTypes) - rt.AddUInt8Array(ComposeStructure(structures[i], connection, false, false, true)); - } - - if (prependLength) - rt.InsertInt32(0, rt.Length); - - return rt.ToArray(); + reply.Seal(); + return reply; } - /// - /// Parse an array of structures - /// - /// Bytes array - /// Zero-indexed offset - /// Number of bytes to parse - /// DistributedConnection is required in case a structure in the array holds items at the other end - /// Array of structures - public static AsyncBag ParseStructureArray(byte[] data, uint offset, uint length, DistributedConnection connection) + var end = offset + length; + + var result = (StructureComparisonResult)data[offset++]; + + AsyncReply previous = null; + // string[] previousKeys = null; + // DataType[] previousTypes = null; + + Structure.StructureMetadata metadata = new Structure.StructureMetadata(); + + + if (result == StructureComparisonResult.Null) + previous = new AsyncReply(null); + else if (result == StructureComparisonResult.Structure) { - var reply = new AsyncBag(); - if (length == 0) - { - reply.Seal(); - return reply; - } + uint cs = data.GetUInt32(offset); + offset += 4; + previous = ParseStructure(data, offset, cs, connection, out metadata); + offset += cs; + } - var end = offset + length; + reply.Add(previous); - var result = (StructureComparisonResult)data[offset++]; - - AsyncReply previous = null; - // string[] previousKeys = null; - // DataType[] previousTypes = null; - - Structure.StructureMetadata metadata = new Structure.StructureMetadata(); + while (offset < end) + { + result = (StructureComparisonResult)data[offset++]; if (result == StructureComparisonResult.Null) previous = new AsyncReply(null); @@ -212,116 +229,119 @@ namespace Esiur.Data { uint cs = data.GetUInt32(offset); offset += 4; - previous = ParseStructure(data, offset, cs, connection, out metadata); + previous = ParseStructure(data, offset, cs, connection, out metadata);// out previousKeys, out previousTypes); offset += cs; } + else if (result == StructureComparisonResult.StructureSameKeys) + { + uint cs = data.GetUInt32(offset); + offset += 4; + previous = ParseStructure(data, offset, cs, connection, out metadata, metadata.Keys); + offset += cs; + } + else if (result == StructureComparisonResult.StructureSameTypes) + { + uint cs = data.GetUInt32(offset); + offset += 4; + previous = ParseStructure(data, offset, cs, connection, out metadata, metadata.Keys, metadata.Types); + offset += cs; + } + + reply.Add(previous); + } + + reply.Seal(); + return reply; + } + + + public static AsyncBag ParseRecordArray(byte[] data, uint offset, uint length, DistributedConnection connection) + { + var reply = new AsyncBag(); + + if (length == 0) + { + reply.Seal(); + return reply; + } + + var end = offset + length; + + var isTyped = (data[offset] & 0x10) == 0x10; + + var result = (RecordComparisonResult)(data[offset++] & 0xF); + + if (isTyped) + { + var classId = data.GetGuid(offset); + offset += 16; + + var template = Warehouse.GetTemplateByClassId(classId, TemplateType.Record); + + reply.ArrayType = template?.DefinedType; + + AsyncReply previous = null; + + if (result == RecordComparisonResult.Null) + previous = new AsyncReply(null); + else if (result == RecordComparisonResult.Record + || result == RecordComparisonResult.RecordSameType) + { + uint cs = data.GetUInt32(offset); + uint recordLength = cs; + offset += 4; + previous = ParseRecord(data, offset, recordLength, connection, classId); + offset += recordLength; + } + + reply.Add(previous); + + while (offset < end) + { + result = (RecordComparisonResult)data[offset++]; + + if (result == RecordComparisonResult.Null) + previous = new AsyncReply(null); + else if (result == RecordComparisonResult.Record + || result == RecordComparisonResult.RecordSameType) + { + uint cs = data.GetUInt32(offset); + offset += 4; + previous = ParseRecord(data, offset, cs, connection, classId); + offset += cs; + } + else if (result == RecordComparisonResult.Same) + { + // do nothing + } + + reply.Add(previous); + } + } + else + { + AsyncReply previous = null; + Guid? classId = null; + + if (result == RecordComparisonResult.Null) + previous = new AsyncReply(null); + else if (result == RecordComparisonResult.Record) + { + uint cs = data.GetUInt32(offset); + uint recordLength = cs - 16; + offset += 4; + classId = data.GetGuid(offset); + offset += 16; + previous = ParseRecord(data, offset, recordLength, connection, classId); + offset += recordLength; + } reply.Add(previous); while (offset < end) { - result = (StructureComparisonResult)data[offset++]; - - if (result == StructureComparisonResult.Null) - previous = new AsyncReply(null); - else if (result == StructureComparisonResult.Structure) - { - uint cs = data.GetUInt32(offset); - offset += 4; - previous = ParseStructure(data, offset, cs, connection, out metadata);// out previousKeys, out previousTypes); - offset += cs; - } - else if (result == StructureComparisonResult.StructureSameKeys) - { - uint cs = data.GetUInt32(offset); - offset += 4; - previous = ParseStructure(data, offset, cs, connection, out metadata, metadata.Keys); - offset += cs; - } - else if (result == StructureComparisonResult.StructureSameTypes) - { - uint cs = data.GetUInt32(offset); - offset += 4; - previous = ParseStructure(data, offset, cs, connection, out metadata, metadata.Keys, metadata.Types); - offset += cs; - } - - reply.Add(previous); - } - - reply.Seal(); - return reply; - } - - - public static AsyncBag ParseRecordArray(byte[] data, uint offset, uint length, DistributedConnection connection) - { - var reply = new AsyncBag(); - - if (length == 0) - { - reply.Seal(); - return reply; - } - - var end = offset + length; - - var isTyped = (data[offset] & 0x10) == 0x10; - - var result = (RecordComparisonResult)(data[offset++] & 0xF); - - if (isTyped) - { - var classId = data.GetGuid(offset); - offset += 16; - - var template = Warehouse.GetTemplateByClassId(classId, TemplateType.Record); - - reply.ArrayType = template?.DefinedType; - - AsyncReply previous = null; - - if (result == RecordComparisonResult.Null) - previous = new AsyncReply(null); - else if (result == RecordComparisonResult.Record - || result == RecordComparisonResult.RecordSameType) - { - uint cs = data.GetUInt32(offset); - uint recordLength = cs; - offset += 4; - previous = ParseRecord(data, offset, recordLength, connection, classId); - offset += recordLength; - } - - reply.Add(previous); - - while (offset < end) - { - result = (RecordComparisonResult)data[offset++]; - - if (result == RecordComparisonResult.Null) - previous = new AsyncReply(null); - else if (result == RecordComparisonResult.Record - || result == RecordComparisonResult.RecordSameType) - { - uint cs = data.GetUInt32(offset); - offset += 4; - previous = ParseRecord(data, offset, cs, connection, classId); - offset += cs; - } - else if (result == RecordComparisonResult.Same) - { - // do nothing - } - - reply.Add(previous); - } - } - else - { - AsyncReply previous = null; - Guid? classId = null; + result = (RecordComparisonResult)data[offset++]; if (result == RecordComparisonResult.Null) previous = new AsyncReply(null); @@ -335,1279 +355,1259 @@ namespace Esiur.Data previous = ParseRecord(data, offset, recordLength, connection, classId); offset += recordLength; } - - reply.Add(previous); - - - while (offset < end) + else if (result == RecordComparisonResult.RecordSameType) { - result = (RecordComparisonResult)data[offset++]; - - if (result == RecordComparisonResult.Null) - previous = new AsyncReply(null); - else if (result == RecordComparisonResult.Record) - { - uint cs = data.GetUInt32(offset); - uint recordLength = cs - 16; - offset += 4; - classId = data.GetGuid(offset); - offset += 16; - previous = ParseRecord(data, offset, recordLength, connection, classId); - offset += recordLength; - } - else if (result == RecordComparisonResult.RecordSameType) - { - uint cs = data.GetUInt32(offset); - offset += 4; - previous = ParseRecord(data, offset, cs, connection, classId); - offset += cs; - } - else if (result == RecordComparisonResult.Same) - { - // do nothing - } - - reply.Add(previous); + uint cs = data.GetUInt32(offset); + offset += 4; + previous = ParseRecord(data, offset, cs, connection, classId); + offset += cs; + } + else if (result == RecordComparisonResult.Same) + { + // do nothing } + reply.Add(previous); } + } + + reply.Seal(); + return reply; + } + + public static AsyncReply ParseRecord(byte[] data, uint offset, uint length, DistributedConnection connection, Guid? classId = null) + { + var reply = new AsyncReply(); + + if (classId == null) + { + classId = data.GetGuid(offset); + + offset += 16; + length -= 16; + } + + var template = Warehouse.GetTemplateByClassId((Guid)classId, TemplateType.Record); + + if (template != null) + { + ParseVarArray(data, offset, length, connection).Then(ar => + { + if (template.DefinedType != null) + { + var record = Activator.CreateInstance(template.DefinedType) as IRecord; + for (var i = 0; i < template.Properties.Length; i++) + template.Properties[i].PropertyInfo.SetValue(record, ar[i]); + + reply.Trigger(record); + } + else + { + var record = new Record(); + + for (var i = 0; i < template.Properties.Length; i++) + record.Add(template.Properties[i].Name, ar[i]); + + reply.Trigger(record); + } + }); + } + else + { + connection.GetTemplate((Guid)classId).Then(tmp => + { + ParseVarArray(data, offset, length, connection).Then(ar => + { + var record = new Record(); + + for (var i = 0; i < tmp.Properties.Length; i++) + record.Add(tmp.Properties[i].Name, ar[i]); + + reply.Trigger(record); + }); + }).Error(x => reply.TriggerError(x)); + } + + return reply; + } + + public static byte[] ComposeRecord(IRecord record, DistributedConnection connection, bool includeClassId = true, bool prependLength = false) + { + var rt = new BinaryList(); + + var template = Warehouse.GetTemplateByType(record.GetType()); + + if (includeClassId) + rt.AddGuid(template.ClassId); + + foreach (var pt in template.Properties) + { + var value = pt.PropertyInfo.GetValue(record, null); + rt.AddUInt8Array(Compose(value, connection)); + } + + if (prependLength) + rt.InsertInt32(0, rt.Length); + + return rt.ToArray(); + } + + public static byte[] ComposeRecordArray(T[] records, DistributedConnection connection, bool prependLength = false) + where T : IRecord + { + + if (records == null || records?.Length == 0) + return prependLength ? new byte[] { 0, 0, 0, 0 } : new byte[0]; + + var rt = new BinaryList(); + var comparsion = Compare(null, records[0]); + + var type = records.GetType().GetElementType(); + var isTyped = type != typeof(IRecord); + + if (isTyped) + { + var template = Warehouse.GetTemplateByType(type); + + if (template != null) + { + // typed array ... no need to add class id , it will be included at the first entry + rt.AddUInt8((byte)(0x10 | (byte)comparsion)); + rt.AddGuid(template.ClassId); + } + else // something wrong + { + throw new Exception($"Template for type `{type.FullName}` not found."); + } + + if (comparsion == RecordComparisonResult.Record) + rt.AddUInt8Array(ComposeRecord(records[0], connection, false, true)); + + for (var i = 1; i < records.Length; i++) + { + comparsion = Compare(records[i - 1], records[i]); + + rt.AddUInt8((byte)comparsion); + + if (comparsion == RecordComparisonResult.RecordSameType + || comparsion == RecordComparisonResult.Record) + rt.AddUInt8Array(ComposeRecord(records[i], connection, false, true)); + } + } + else + { + rt.AddUInt8((byte)comparsion); + + if (comparsion == RecordComparisonResult.Record) + rt.AddUInt8Array(ComposeRecord(records[0], connection, true, true)); + + for (var i = 1; i < records.Length; i++) + { + comparsion = Compare(records[i - 1], records[i]); + + rt.AddUInt8((byte)comparsion); + + if (comparsion == RecordComparisonResult.Record) + rt.AddUInt8Array(ComposeRecord(records[i], connection, true, true)); + else if (comparsion == RecordComparisonResult.RecordSameType) + rt.AddUInt8Array(ComposeRecord(records[i], connection, false, true)); + } + } + + + if (prependLength) + rt.InsertInt32(0, rt.Length); + + + return rt.ToArray(); + } + + /// + /// Compose a structure into an array of bytes + /// + /// Structure to compose + /// DistributedConnection is required in case an item in the structure is at the other end + /// Whether to include the structure keys + /// Whether to include each item DataType + /// If true, prepend the length as UInt32 at the beginning of the returned bytes array + /// Array of bytes in the network byte order + public static byte[] ComposeStructure(Structure value, DistributedConnection connection, + bool includeKeys = true, bool includeTypes = true, bool prependLength = false) + { + var rt = new BinaryList(); + + if (includeKeys) + { + foreach (var i in value) + { + var key = DC.ToBytes(i.Key); + rt.AddUInt8((byte)key.Length) + .AddUInt8Array(key) + .AddUInt8Array(Compose(i.Value, connection)); + } + } + else + { + foreach (var i in value) + rt.AddUInt8Array(Compose(i.Value, connection, includeTypes)); + } + + if (prependLength) + rt.InsertInt32(0, rt.Length); + + return rt.ToArray(); + } + + /// + /// Parse a structure + /// + /// Bytes array + /// Zero-indexed offset. + /// Number of bytes to parse. + /// DistributedConnection is required in case a structure in the array holds items at the other end. + /// Value + public static AsyncReply ParseStructure(byte[] data, uint offset, uint contentLength, DistributedConnection connection) + { + Structure.StructureMetadata metadata; + return ParseStructure(data, offset, contentLength, connection, out metadata); + } + + /// + /// Parse a structure + /// + /// Bytes array + /// Zero-indexed offset. + /// Number of bytes to parse. + /// DistributedConnection is required in case a structure in the array holds items at the other end. + /// Array to store keys in. + /// Array to store DataTypes in. + /// Array of keys, in case the data doesn't include keys + /// Array of DataTypes, in case the data doesn't include DataTypes + /// Structure + public static AsyncReply ParseStructure(byte[] data, uint offset, uint length, DistributedConnection connection, out Structure.StructureMetadata metadata, string[] keys = null, DataType[] types = null)// out string[] parsedKeys, out DataType[] parsedTypes, string[] keys = null, DataType[] types = null) + { + var reply = new AsyncReply(); + var bag = new AsyncBag(); + var keylist = new List(); + var typelist = new List(); + + if (keys == null) + { + while (length > 0) + { + var len = data[offset++]; + keylist.Add(data.GetString(offset, len)); + offset += len; + + typelist.Add((DataType)data[offset]); + + uint rt; + bag.Add(Codec.Parse(data, offset, out rt, connection)); + length -= rt + len + 1; + offset += rt; + } + } + else if (types == null) + { + keylist.AddRange(keys); + + while (length > 0) + { + typelist.Add((DataType)data[offset]); + + uint rt; + bag.Add(Codec.Parse(data, offset, out rt, connection)); + length -= rt; + offset += rt; + } + } + else + { + keylist.AddRange(keys); + typelist.AddRange(types); + + var i = 0; + while (length > 0) + { + uint rt; + bag.Add(Codec.Parse(data, offset, out rt, connection, types[i])); + length -= rt; + offset += rt; + i++; + } + } + + bag.Seal(); + + bag.Then((res) => + { + // compose the list + var s = new Structure(); + for (var i = 0; i < keylist.Count; i++) + s[keylist[i]] = res[i]; + reply.Trigger(s); + }); + + metadata = new Structure.StructureMetadata() { Keys = keylist.ToArray(), Types = typelist.ToArray() }; + + return reply; + } + + /// + /// Parse a value + /// + /// Bytes array + /// Zero-indexed offset. + /// DistributedConnection is required in case a structure in the array holds items at the other end. + /// DataType, in case the data is not prepended with DataType + /// Structure + public static AsyncReply Parse(byte[] data, uint offset, DistributedConnection connection, DataType dataType = DataType.Unspecified) + { + uint size; + return Parse(data, offset, out size, connection); + } + + /// + /// Parse a value + /// + /// Bytes array + /// Zero-indexed offset. + /// Output the number of bytes parsed + /// DistributedConnection is required in case a structure in the array holds items at the other end. + /// DataType, in case the data is not prepended with DataType + /// Value + public static AsyncReply Parse(byte[] data, uint offset, out uint size, DistributedConnection connection, DataType dataType = DataType.Unspecified) + { + + bool isArray; + DataType t; + + if (dataType == DataType.Unspecified) + { + size = 1; + dataType = (DataType)data[offset++]; + } + else + size = 0; + + t = (DataType)((byte)dataType & 0x7F); + + isArray = ((byte)dataType & 0x80) == 0x80; + + var payloadSize = dataType.Size();// SizeOf(); + + + uint contentLength = 0; + + // check if we have the enough data + if (payloadSize == -1) + { + contentLength = data.GetUInt32(offset); + offset += 4; + size += 4 + contentLength; + } + else + size += (uint)payloadSize; + + if (isArray) + { + switch (t) + { + // VarArray ? + case DataType.Void: + return ParseVarArray(data, offset, contentLength, connection); + + case DataType.Bool: + return new AsyncReply(data.GetBooleanArray(offset, contentLength)); + + case DataType.UInt8: + return new AsyncReply(data.GetUInt8Array(offset, contentLength)); + + case DataType.Int8: + return new AsyncReply(data.GetInt8Array(offset, contentLength)); + + case DataType.Char: + return new AsyncReply(data.GetCharArray(offset, contentLength)); + + case DataType.Int16: + return new AsyncReply(data.GetInt16Array(offset, contentLength)); + + case DataType.UInt16: + return new AsyncReply(data.GetUInt16Array(offset, contentLength)); + + case DataType.Int32: + return new AsyncReply(data.GetInt32Array(offset, contentLength)); + + case DataType.UInt32: + return new AsyncReply(data.GetUInt32Array(offset, contentLength)); + + case DataType.Int64: + return new AsyncReply(data.GetInt64Array(offset, contentLength)); + + case DataType.UInt64: + return new AsyncReply(data.GetUInt64Array(offset, contentLength)); + + case DataType.Float32: + return new AsyncReply(data.GetFloat32Array(offset, contentLength)); + + case DataType.Float64: + return new AsyncReply(data.GetFloat64Array(offset, contentLength)); + + case DataType.String: + return new AsyncReply(data.GetStringArray(offset, contentLength)); + + case DataType.Resource: + case DataType.DistributedResource: + return ParseResourceArray(data, offset, contentLength, connection); + + case DataType.DateTime: + return new AsyncReply(data.GetDateTimeArray(offset, contentLength)); + + case DataType.Structure: + return ParseStructureArray(data, offset, contentLength, connection); + + case DataType.Record: + return ParseRecordArray(data, offset, contentLength, connection); + } + } + else + { + switch (t) + { + case DataType.NotModified: + return new AsyncReply(new NotModified()); + + case DataType.Void: + return new AsyncReply(null); + + case DataType.Bool: + return new AsyncReply(data.GetBoolean(offset)); + + case DataType.UInt8: + return new AsyncReply(data[offset]); + + case DataType.Int8: + return new AsyncReply((sbyte)data[offset]); + + case DataType.Char: + return new AsyncReply(data.GetChar(offset)); + + case DataType.Int16: + return new AsyncReply(data.GetInt16(offset)); + + case DataType.UInt16: + return new AsyncReply(data.GetUInt16(offset)); + + case DataType.Int32: + return new AsyncReply(data.GetInt32(offset)); + + case DataType.UInt32: + return new AsyncReply(data.GetUInt32(offset)); + + case DataType.Int64: + return new AsyncReply(data.GetInt64(offset)); + + case DataType.UInt64: + return new AsyncReply(data.GetUInt64(offset)); + + case DataType.Float32: + return new AsyncReply(data.GetFloat32(offset)); + + case DataType.Float64: + return new AsyncReply(data.GetFloat64(offset)); + + case DataType.String: + return new AsyncReply(data.GetString(offset, contentLength)); + + case DataType.Resource: + return ParseResource(data, offset); + + case DataType.DistributedResource: + return ParseDistributedResource(data, offset, connection); + + case DataType.DateTime: + return new AsyncReply(data.GetDateTime(offset)); + + case DataType.Structure: + return ParseStructure(data, offset, contentLength, connection); + + case DataType.Record: + return ParseRecord(data, offset, contentLength, connection); + } + } + + + return null; + } + + /// + /// Parse a resource + /// + /// Bytes array + /// Zero-indexed offset. + /// Resource + public static AsyncReply ParseResource(byte[] data, uint offset) + { + return Warehouse.GetById(data.GetUInt32(offset)); + } + + /// + /// Parse a DistributedResource + /// + /// Bytes array + /// Zero-indexed offset. + /// DistributedConnection is required. + /// DistributedResource + public static AsyncReply ParseDistributedResource(byte[] data, uint offset, DistributedConnection connection) + { + //var g = data.GetGuid(offset); + //offset += 16; + + // find the object + var iid = data.GetUInt32(offset); + + return connection.Fetch(iid);// Warehouse.Get(iid); + } + + + /// + /// Check if a resource is local to a given connection. + /// + /// Resource to check. + /// DistributedConnection to check if the resource is local to it. + /// True, if the resource owner is the given connection, otherwise False. + public static bool IsLocalResource(IResource resource, DistributedConnection connection) + { + if (resource is DistributedResource) + if ((resource as DistributedResource).Connection == connection) + return true; + + return false; + } + + /// + /// Compare two resources + /// + /// Initial resource to make comparison with. + /// Next resource to compare with the initial. + /// DistributedConnection is required to check locality. + /// Null, same, local, distributed or same class distributed. + + public static ResourceComparisonResult Compare(IResource initial, IResource next, DistributedConnection connection) + { + if (next == null) + return ResourceComparisonResult.Null; + else if (next == initial) + return ResourceComparisonResult.Same; + else if (IsLocalResource(next, connection)) + return ResourceComparisonResult.Local; + else + return ResourceComparisonResult.Distributed; + } + + /// + /// Compose a resource + /// + /// Resource to compose. + /// DistributedConnection is required to check locality. + /// Array of bytes in the network byte order. + public static byte[] ComposeResource(IResource resource, DistributedConnection connection) + { + if (IsLocalResource(resource, connection)) + return DC.ToBytes((resource as DistributedResource).Id); + else + { + return new BinaryList().AddGuid(resource.Instance.Template.ClassId).AddUInt32(resource.Instance.Id).ToArray(); + //return BinaryList.ToBytes(resource.Instance.Template.ClassId, resource.Instance.Id); + } + } + + /// + /// Compose an array of resources + /// + /// Array of resources. + /// DistributedConnection is required to check locality. + /// If True, prepend the length of the output at the beginning. + /// Array of bytes in the network byte order. + public static byte[] ComposeResourceArray(T[] resources, DistributedConnection connection, bool prependLength = false) + where T : IResource + { + + if (resources == null || resources?.Length == 0) + return prependLength ? new byte[] { 0, 0, 0, 0 } : new byte[0]; + + + foreach (var r in resources) + connection.cache.Add(r, DateTime.UtcNow); + + var rt = new BinaryList(); + var comparsion = Compare(null, resources[0], connection); + + var type = resources.GetType().GetElementType(); + + + if (type != typeof(IResource)) + { + // get template + var tmp = Warehouse.GetTemplateByType(type); + + if (tmp == null) // something wrong + rt.AddUInt8((byte)comparsion); + else + { + // typed array + rt.AddUInt8((byte)((byte)(tmp.Type == TemplateType.Resource ? ResourceArrayType.Static : ResourceArrayType.Wrapper) + | (byte)comparsion)); + // add type + rt.AddGuid(tmp.ClassId); + } + } + else + { + rt.AddUInt8((byte)comparsion); + } + + + if (comparsion == ResourceComparisonResult.Local) + rt.AddUInt32((resources[0] as DistributedResource).Id); + else if (comparsion == ResourceComparisonResult.Distributed) + rt.AddUInt32(resources[0].Instance.Id); + + for (var i = 1; i < resources.Length; i++) + { + comparsion = Compare(resources[i - 1], resources[i], connection); + rt.AddUInt8((byte)comparsion); + if (comparsion == ResourceComparisonResult.Local) + rt.AddUInt32((resources[i] as DistributedResource).Id); + else if (comparsion == ResourceComparisonResult.Distributed) + rt.AddUInt32(resources[i].Instance.Id); + } + + if (prependLength) + rt.InsertInt32(0, rt.Length); + + return rt.ToArray(); + } + + /// + /// Parse an array of bytes into array of resources + /// + /// Array of bytes. + /// Number of bytes to parse. + /// Zero-indexed offset. + /// DistributedConnection is required to fetch resources. + /// Array of resources. + public static AsyncBag ParseResourceArray(byte[] data, uint offset, uint length, DistributedConnection connection) + { + var reply = new AsyncBag(); + if (length == 0) + { reply.Seal(); return reply; } - public static AsyncReply ParseRecord(byte[] data, uint offset, uint length, DistributedConnection connection, Guid? classId = null) + var end = offset + length; + + // Is typed array ? + var type = (ResourceArrayType)(data[offset] & 0xF0); + + var result = (ResourceComparisonResult)(data[offset++] & 0xF); + + + if (type == ResourceArrayType.Wrapper) { - var reply = new AsyncReply(); - - if (classId == null) - { - classId = data.GetGuid(offset); - - offset += 16; - length -= 16; - } - - var template = Warehouse.GetTemplateByClassId((Guid)classId, TemplateType.Record); - - if (template != null) - { - ParseVarArray(data, offset, length, connection).Then(ar => - { - if (template.DefinedType != null) - { - var record = Activator.CreateInstance(template.DefinedType) as IRecord; - for (var i = 0; i < template.Properties.Length; i++) - template.Properties[i].PropertyInfo.SetValue(record, ar[i]); - - reply.Trigger(record); - } - else - { - var record = new Record(); - - for (var i = 0; i < template.Properties.Length; i++) - record.Add(template.Properties[i].Name, ar[i]); - - reply.Trigger(record); - } - }); - } - else - { - connection.GetTemplate((Guid)classId).Then(tmp => { - ParseVarArray(data, offset, length, connection).Then(ar => - { - var record = new Record(); - - for (var i = 0; i < tmp.Properties.Length; i++) - record.Add(tmp.Properties[i].Name, ar[i]); - - reply.Trigger(record); - }); - }).Error(x=>reply.TriggerError(x)); - } - - return reply; + var classId = data.GetGuid(offset); + offset += 16; + var tmp = Warehouse.GetTemplateByClassId(classId, TemplateType.Resource); + // not mine, look if the type is elsewhere + if (tmp == null) + Warehouse.GetTemplateByClassId(classId, TemplateType.Wrapper); + reply.ArrayType = tmp?.DefinedType; + } + else if (type == ResourceArrayType.Static) + { + var classId = data.GetGuid(offset); + offset += 16; + var tmp = Warehouse.GetTemplateByClassId(classId, TemplateType.Wrapper); + reply.ArrayType = tmp?.DefinedType; } - public static byte[] ComposeRecord(IRecord record, DistributedConnection connection, bool includeClassId = true, bool prependLength = false) + AsyncReply previous = null; + + if (result == ResourceComparisonResult.Null) + previous = new AsyncReply(null); + else if (result == ResourceComparisonResult.Local) { - var rt = new BinaryList(); - - var template = Warehouse.GetTemplateByType(record.GetType()); - - if (includeClassId) - rt.AddGuid(template.ClassId); - - foreach (var pt in template.Properties) - { - var value = pt.PropertyInfo.GetValue(record, null); - rt.AddUInt8Array(Compose(value, connection)); - } - - if (prependLength) - rt.InsertInt32(0, rt.Length); - - return rt.ToArray(); + previous = Warehouse.GetById(data.GetUInt32(offset)); + offset += 4; + } + else if (result == ResourceComparisonResult.Distributed) + { + previous = connection.Fetch(data.GetUInt32(offset)); + offset += 4; } - public static byte[] ComposeRecordArray(T[] records, DistributedConnection connection, bool prependLength = false) - where T : IRecord + reply.Add(previous); + + + while (offset < end) { - - if (records == null || records?.Length == 0) - return prependLength ? new byte[] { 0, 0, 0, 0 } : new byte[0]; + result = (ResourceComparisonResult)data[offset++]; - var rt = new BinaryList(); - var comparsion = Compare(null, records[0]); - - var type = records.GetType().GetElementType(); - var isTyped = type != typeof(IRecord); - - if (isTyped) - { - var template = Warehouse.GetTemplateByType(type); - - if (template != null) - { - // typed array ... no need to add class id , it will be included at the first entry - rt.AddUInt8((byte)(0x10 | (byte)comparsion)); - rt.AddGuid(template.ClassId); - } - else // something wrong - { - throw new Exception($"Template for type `{type.FullName}` not found."); - } - - if (comparsion == RecordComparisonResult.Record) - rt.AddUInt8Array(ComposeRecord(records[0], connection, false, true)); - - for (var i = 1; i < records.Length; i++) - { - comparsion = Compare(records[i - 1], records[i]); - - rt.AddUInt8((byte)comparsion); - - if (comparsion == RecordComparisonResult.RecordSameType - || comparsion == RecordComparisonResult.Record) - rt.AddUInt8Array(ComposeRecord(records[i], connection, false, true)); - } - } - else - { - rt.AddUInt8((byte)comparsion); - - if (comparsion == RecordComparisonResult.Record) - rt.AddUInt8Array(ComposeRecord(records[0], connection, true, true)); - - for (var i = 1; i < records.Length; i++) - { - comparsion = Compare(records[i - 1], records[i]); - - rt.AddUInt8((byte)comparsion); - - if (comparsion == RecordComparisonResult.Record) - rt.AddUInt8Array(ComposeRecord(records[i], connection, true, true)); - else if (comparsion == RecordComparisonResult.RecordSameType) - rt.AddUInt8Array(ComposeRecord(records[i], connection, false, true)); - } - } - - - if (prependLength) - rt.InsertInt32(0, rt.Length); - - - return rt.ToArray(); - } - - /// - /// Compose a structure into an array of bytes - /// - /// Structure to compose - /// DistributedConnection is required in case an item in the structure is at the other end - /// Whether to include the structure keys - /// Whether to include each item DataType - /// If true, prepend the length as UInt32 at the beginning of the returned bytes array - /// Array of bytes in the network byte order - public static byte[] ComposeStructure(Structure value, DistributedConnection connection, - bool includeKeys = true, bool includeTypes = true, bool prependLength = false) - { - var rt = new BinaryList(); - - if (includeKeys) - { - foreach (var i in value) - { - var key = DC.ToBytes(i.Key); - rt.AddUInt8((byte)key.Length) - .AddUInt8Array(key) - .AddUInt8Array(Compose(i.Value, connection)); - } - } - else - { - foreach (var i in value) - rt.AddUInt8Array(Compose(i.Value, connection, includeTypes)); - } - - if (prependLength) - rt.InsertInt32(0, rt.Length); - - return rt.ToArray(); - } - - /// - /// Parse a structure - /// - /// Bytes array - /// Zero-indexed offset. - /// Number of bytes to parse. - /// DistributedConnection is required in case a structure in the array holds items at the other end. - /// Value - public static AsyncReply ParseStructure(byte[] data, uint offset, uint contentLength, DistributedConnection connection) - { - Structure.StructureMetadata metadata; - return ParseStructure(data, offset, contentLength, connection, out metadata); - } - - /// - /// Parse a structure - /// - /// Bytes array - /// Zero-indexed offset. - /// Number of bytes to parse. - /// DistributedConnection is required in case a structure in the array holds items at the other end. - /// Array to store keys in. - /// Array to store DataTypes in. - /// Array of keys, in case the data doesn't include keys - /// Array of DataTypes, in case the data doesn't include DataTypes - /// Structure - public static AsyncReply ParseStructure(byte[] data, uint offset, uint length, DistributedConnection connection, out Structure.StructureMetadata metadata, string[] keys = null, DataType[] types = null)// out string[] parsedKeys, out DataType[] parsedTypes, string[] keys = null, DataType[] types = null) - { - var reply = new AsyncReply(); - var bag = new AsyncBag(); - var keylist = new List(); - var typelist = new List(); - - if (keys == null) - { - while (length > 0) - { - var len = data[offset++]; - keylist.Add(data.GetString(offset, len)); - offset += len; - - typelist.Add((DataType)data[offset]); - - uint rt; - bag.Add(Codec.Parse(data, offset, out rt, connection)); - length -= rt + len + 1; - offset += rt; - } - } - else if (types == null) - { - keylist.AddRange(keys); - - while (length > 0) - { - typelist.Add((DataType)data[offset]); - - uint rt; - bag.Add(Codec.Parse(data, offset, out rt, connection)); - length -= rt; - offset += rt; - } - } - else - { - keylist.AddRange(keys); - typelist.AddRange(types); - - var i = 0; - while (length > 0) - { - uint rt; - bag.Add(Codec.Parse(data, offset, out rt, connection, types[i])); - length -= rt; - offset += rt; - i++; - } - } - - bag.Seal(); - - bag.Then((res) => - { - // compose the list - var s = new Structure(); - for (var i = 0; i < keylist.Count; i++) - s[keylist[i]] = res[i]; - reply.Trigger(s); - }); - - metadata = new Structure.StructureMetadata() { Keys = keylist.ToArray(), Types = typelist.ToArray() }; - - return reply; - } - - /// - /// Parse a value - /// - /// Bytes array - /// Zero-indexed offset. - /// DistributedConnection is required in case a structure in the array holds items at the other end. - /// DataType, in case the data is not prepended with DataType - /// Structure - public static AsyncReply Parse(byte[] data, uint offset, DistributedConnection connection, DataType dataType = DataType.Unspecified) - { - uint size; - return Parse(data, offset, out size, connection); - } - - /// - /// Parse a value - /// - /// Bytes array - /// Zero-indexed offset. - /// Output the number of bytes parsed - /// DistributedConnection is required in case a structure in the array holds items at the other end. - /// DataType, in case the data is not prepended with DataType - /// Value - public static AsyncReply Parse(byte[] data, uint offset, out uint size, DistributedConnection connection, DataType dataType = DataType.Unspecified) - { - - bool isArray; - DataType t; - - if (dataType == DataType.Unspecified) - { - size = 1; - dataType = (DataType)data[offset++]; - } - else - size = 0; - - t = (DataType)((byte)dataType & 0x7F); - - isArray = ((byte)dataType & 0x80) == 0x80; - - var payloadSize = dataType.Size();// SizeOf(); - - - uint contentLength = 0; - - // check if we have the enough data - if (payloadSize == -1) - { - contentLength = data.GetUInt32(offset); - offset += 4; - size += 4 + contentLength; - } - else - size += (uint)payloadSize; - - if (isArray) - { - switch (t) - { - // VarArray ? - case DataType.Void: - return ParseVarArray(data, offset, contentLength, connection); - - case DataType.Bool: - return new AsyncReply(data.GetBooleanArray(offset, contentLength)); - - case DataType.UInt8: - return new AsyncReply(data.GetUInt8Array(offset, contentLength)); - - case DataType.Int8: - return new AsyncReply(data.GetInt8Array(offset, contentLength)); - - case DataType.Char: - return new AsyncReply(data.GetCharArray(offset, contentLength)); - - case DataType.Int16: - return new AsyncReply(data.GetInt16Array(offset, contentLength)); - - case DataType.UInt16: - return new AsyncReply(data.GetUInt16Array(offset, contentLength)); - - case DataType.Int32: - return new AsyncReply(data.GetInt32Array(offset, contentLength)); - - case DataType.UInt32: - return new AsyncReply(data.GetUInt32Array(offset, contentLength)); - - case DataType.Int64: - return new AsyncReply(data.GetInt64Array(offset, contentLength)); - - case DataType.UInt64: - return new AsyncReply(data.GetUInt64Array(offset, contentLength)); - - case DataType.Float32: - return new AsyncReply(data.GetFloat32Array(offset, contentLength)); - - case DataType.Float64: - return new AsyncReply(data.GetFloat64Array(offset, contentLength)); - - case DataType.String: - return new AsyncReply(data.GetStringArray(offset, contentLength)); - - case DataType.Resource: - case DataType.DistributedResource: - return ParseResourceArray(data, offset, contentLength, connection); - - case DataType.DateTime: - return new AsyncReply(data.GetDateTimeArray(offset, contentLength)); - - case DataType.Structure: - return ParseStructureArray(data, offset, contentLength, connection); - - case DataType.Record: - return ParseRecordArray(data, offset, contentLength, connection); - } - } - else - { - switch (t) - { - case DataType.NotModified: - return new AsyncReply(new NotModified()); - - case DataType.Void: - return new AsyncReply(null); - - case DataType.Bool: - return new AsyncReply(data.GetBoolean(offset)); - - case DataType.UInt8: - return new AsyncReply(data[offset]); - - case DataType.Int8: - return new AsyncReply((sbyte)data[offset]); - - case DataType.Char: - return new AsyncReply(data.GetChar(offset)); - - case DataType.Int16: - return new AsyncReply(data.GetInt16(offset)); - - case DataType.UInt16: - return new AsyncReply(data.GetUInt16(offset)); - - case DataType.Int32: - return new AsyncReply(data.GetInt32(offset)); - - case DataType.UInt32: - return new AsyncReply(data.GetUInt32(offset)); - - case DataType.Int64: - return new AsyncReply(data.GetInt64(offset)); - - case DataType.UInt64: - return new AsyncReply(data.GetUInt64(offset)); - - case DataType.Float32: - return new AsyncReply(data.GetFloat32(offset)); - - case DataType.Float64: - return new AsyncReply(data.GetFloat64(offset)); - - case DataType.String: - return new AsyncReply(data.GetString(offset, contentLength)); - - case DataType.Resource: - return ParseResource(data, offset); - - case DataType.DistributedResource: - return ParseDistributedResource(data, offset, connection); - - case DataType.DateTime: - return new AsyncReply(data.GetDateTime(offset)); - - case DataType.Structure: - return ParseStructure(data, offset, contentLength, connection); - - case DataType.Record: - return ParseRecord(data, offset, contentLength, connection); - } - } - - - return null; - } - - /// - /// Parse a resource - /// - /// Bytes array - /// Zero-indexed offset. - /// Resource - public static AsyncReply ParseResource(byte[] data, uint offset) - { - return Warehouse.GetById(data.GetUInt32(offset)); - } - - /// - /// Parse a DistributedResource - /// - /// Bytes array - /// Zero-indexed offset. - /// DistributedConnection is required. - /// DistributedResource - public static AsyncReply ParseDistributedResource(byte[] data, uint offset, DistributedConnection connection) - { - //var g = data.GetGuid(offset); - //offset += 16; - - // find the object - var iid = data.GetUInt32(offset); - - return connection.Fetch(iid);// Warehouse.Get(iid); - } - - - /// - /// Check if a resource is local to a given connection. - /// - /// Resource to check. - /// DistributedConnection to check if the resource is local to it. - /// True, if the resource owner is the given connection, otherwise False. - public static bool IsLocalResource(IResource resource, DistributedConnection connection) - { - if (resource is DistributedResource) - if ((resource as DistributedResource).Connection == connection) - return true; - - return false; - } - - /// - /// Compare two resources - /// - /// Initial resource to make comparison with. - /// Next resource to compare with the initial. - /// DistributedConnection is required to check locality. - /// Null, same, local, distributed or same class distributed. - - public static ResourceComparisonResult Compare(IResource initial, IResource next, DistributedConnection connection) - { - if (next == null) - return ResourceComparisonResult.Null; - else if (next == initial) - return ResourceComparisonResult.Same; - else if (IsLocalResource(next, connection)) - return ResourceComparisonResult.Local; - else - return ResourceComparisonResult.Distributed; - } - - /// - /// Compose a resource - /// - /// Resource to compose. - /// DistributedConnection is required to check locality. - /// Array of bytes in the network byte order. - public static byte[] ComposeResource(IResource resource, DistributedConnection connection) - { - if (IsLocalResource(resource, connection)) - return DC.ToBytes((resource as DistributedResource).Id); - else - { - return new BinaryList().AddGuid(resource.Instance.Template.ClassId).AddUInt32(resource.Instance.Id).ToArray(); - //return BinaryList.ToBytes(resource.Instance.Template.ClassId, resource.Instance.Id); - } - } - - /// - /// Compose an array of resources - /// - /// Array of resources. - /// DistributedConnection is required to check locality. - /// If True, prepend the length of the output at the beginning. - /// Array of bytes in the network byte order. - public static byte[] ComposeResourceArray(T[] resources, DistributedConnection connection, bool prependLength = false) - where T : IResource - { - - if (resources == null || resources?.Length == 0) - return prependLength ? new byte[] { 0, 0, 0, 0 } : new byte[0]; - - - foreach(var r in resources) - connection.cache.Add(r, DateTime.UtcNow); - - var rt = new BinaryList(); - var comparsion = Compare(null, resources[0], connection); - - var type = resources.GetType().GetElementType(); - - - if (type != typeof(IResource)) - { - // get template - var tmp = Warehouse.GetTemplateByType(type); - - if (tmp == null) // something wrong - rt.AddUInt8((byte)comparsion); - else - { - // typed array - rt.AddUInt8((byte)((byte)( tmp.Type == TemplateType.Resource ? ResourceArrayType.Static : ResourceArrayType.Wrapper) - | (byte)comparsion)); - // add type - rt.AddGuid(tmp.ClassId); - } - } - else - { - rt.AddUInt8((byte)comparsion); - } - - - if (comparsion == ResourceComparisonResult.Local) - rt.AddUInt32((resources[0] as DistributedResource).Id); - else if (comparsion == ResourceComparisonResult.Distributed) - rt.AddUInt32(resources[0].Instance.Id); - - for (var i = 1; i < resources.Length; i++) - { - comparsion = Compare(resources[i - 1], resources[i], connection); - rt.AddUInt8((byte)comparsion); - if (comparsion == ResourceComparisonResult.Local) - rt.AddUInt32((resources[i] as DistributedResource).Id); - else if (comparsion == ResourceComparisonResult.Distributed) - rt.AddUInt32(resources[i].Instance.Id); - } - - if (prependLength) - rt.InsertInt32(0, rt.Length); - - return rt.ToArray(); - } - - /// - /// Parse an array of bytes into array of resources - /// - /// Array of bytes. - /// Number of bytes to parse. - /// Zero-indexed offset. - /// DistributedConnection is required to fetch resources. - /// Array of resources. - public static AsyncBag ParseResourceArray(byte[] data, uint offset, uint length, DistributedConnection connection) - { - var reply = new AsyncBag(); - if (length == 0) - { - reply.Seal(); - return reply; - } - - var end = offset + length; - - // Is typed array ? - var type = (ResourceArrayType) (data[offset] & 0xF0); - - var result = (ResourceComparisonResult)(data[offset++] & 0xF); - - - if (type == ResourceArrayType.Wrapper) - { - var classId = data.GetGuid(offset); - offset += 16; - var tmp = Warehouse.GetTemplateByClassId(classId, TemplateType.Resource); - // not mine, look if the type is elsewhere - if (tmp == null) - Warehouse.GetTemplateByClassId(classId, TemplateType.Wrapper); - reply.ArrayType = tmp?.DefinedType; - } - else if (type == ResourceArrayType.Static) - { - var classId = data.GetGuid(offset); - offset += 16; - var tmp = Warehouse.GetTemplateByClassId(classId, TemplateType.Wrapper); - reply.ArrayType = tmp?.DefinedType; - } - - AsyncReply previous = null; + AsyncReply current = null; if (result == ResourceComparisonResult.Null) - previous = new AsyncReply(null); + { + current = new AsyncReply(null); + } + else if (result == ResourceComparisonResult.Same) + { + current = previous; + } else if (result == ResourceComparisonResult.Local) { - previous = Warehouse.GetById(data.GetUInt32(offset)); + current = Warehouse.GetById(data.GetUInt32(offset)); offset += 4; } else if (result == ResourceComparisonResult.Distributed) { - previous = connection.Fetch(data.GetUInt32(offset)); + current = connection.Fetch(data.GetUInt32(offset)); offset += 4; } - reply.Add(previous); + reply.Add(current); + previous = current; + } - while (offset < end) + reply.Seal(); + return reply; + } + + /// + /// Compose an array of variables + /// + /// Variables. + /// DistributedConnection is required to check locality. + /// If True, prepend the length as UInt32 at the beginning of the output. + /// Array of bytes in the network byte order. + public static byte[] ComposeVarArray(Array array, DistributedConnection connection, bool prependLength = false) + { + var rt = new List(); + + for (var i = 0; i < array.Length; i++) + rt.AddRange(Compose(array.GetValue(i), connection)); + if (prependLength) + rt.InsertRange(0, DC.ToBytes(rt.Count)); + return rt.ToArray(); + } + /// + /// Parse an array of variables. + /// + /// Array of bytes. + /// DistributedConnection is required to fetch resources. + /// Array of variables. + public static AsyncBag ParseVarArray(byte[] data, DistributedConnection connection) + { + return ParseVarArray(data, 0, (uint)data.Length, connection); + } + + /// + /// Parse an array of bytes into an array of varialbes. + /// + /// Array of bytes. + /// Zero-indexed offset. + /// Number of bytes to parse. + /// DistributedConnection is required to fetch resources. + /// Array of variables. + public static AsyncBag ParseVarArray(byte[] data, uint offset, uint length, DistributedConnection connection) + { + var rt = new AsyncBag(); + + while (length > 0) + { + uint cs; + + rt.Add(Parse(data, offset, out cs, connection)); + + if (cs > 0) { - result = (ResourceComparisonResult)data[offset++]; - - AsyncReply current = null; - - if (result == ResourceComparisonResult.Null) - { - current = new AsyncReply(null); - } - else if (result == ResourceComparisonResult.Same) - { - current = previous; - } - else if (result == ResourceComparisonResult.Local) - { - current = Warehouse.GetById(data.GetUInt32(offset)); - offset += 4; - } - else if (result == ResourceComparisonResult.Distributed) - { - current = connection.Fetch(data.GetUInt32(offset)); - offset += 4; - } - - reply.Add(current); - - previous = current; + offset += (uint)cs; + length -= (uint)cs; } + else + throw new Exception("Error while parsing structured data"); - reply.Seal(); - return reply; } - /// - /// Compose an array of variables - /// - /// Variables. - /// DistributedConnection is required to check locality. - /// If True, prepend the length as UInt32 at the beginning of the output. - /// Array of bytes in the network byte order. - public static byte[] ComposeVarArray(Array array, DistributedConnection connection, bool prependLength = false) - { - var rt = new List(); + rt.Seal(); + return rt; + } - for (var i = 0; i < array.Length; i++) - rt.AddRange(Compose(array.GetValue(i), connection)); - if (prependLength) - rt.InsertRange(0, DC.ToBytes(rt.Count)); - return rt.ToArray(); - } - /// - /// Parse an array of variables. - /// - /// Array of bytes. - /// DistributedConnection is required to fetch resources. - /// Array of variables. - public static AsyncBag ParseVarArray(byte[] data, DistributedConnection connection) + /// + /// Compose an array of property values. + /// + /// PropertyValue array. + /// DistributedConnection is required to check locality. + /// If True, prepend the length as UInt32 at the beginning of the output. + /// Array of bytes in the network byte order. + /// //, bool includeAge = true + public static byte[] ComposePropertyValueArray(PropertyValue[] array, DistributedConnection connection, bool prependLength = false) + { + var rt = new List(); + for (var i = 0; i < array.Length; i++) + rt.AddRange(ComposePropertyValue(array[i], connection)); + if (prependLength) + rt.InsertRange(0, DC.ToBytes(rt.Count)); + return rt.ToArray(); + } + + /// + /// Compose a property value. + /// + /// Property value + /// DistributedConnection is required to check locality. + /// Array of bytes in the network byte order. + public static byte[] ComposePropertyValue(PropertyValue propertyValue, DistributedConnection connection)//, bool includeAge = true) + { + + return new BinaryList() + .AddUInt64(propertyValue.Age) + .AddDateTime(propertyValue.Date) + .AddUInt8Array(Compose(propertyValue.Value, connection)) + .ToArray(); + + // age, date, value + //if (includeAge) + // return BinaryList.ToBytes(propertyValue.Age, propertyValue.Date, Compose(propertyValue.Value, connection)); + //else + // return BinaryList.ToBytes(propertyValue.Date, Compose(propertyValue.Value, connection)); + + } + + + /// + /// Parse property value. + /// + /// Array of bytes. + /// Zero-indexed offset. + /// DistributedConnection is required to fetch resources. + /// Output content size. + /// PropertyValue. + public static AsyncReply ParsePropertyValue(byte[] data, uint offset, out uint cs, DistributedConnection connection)//, bool ageIncluded = true) + { + var reply = new AsyncReply(); + + var age = data.GetUInt64(offset); + offset += 8; + + DateTime date = data.GetDateTime(offset); + offset += 8; + + uint valueSize; + + Parse(data, offset, out valueSize, connection).Then(value => { - return ParseVarArray(data, 0, (uint)data.Length, connection); + reply.Trigger(new PropertyValue(value, age, date)); + }); + + cs = 16 + valueSize; + return reply; + } + + /// + /// Parse an array of PropertyValue. + /// + /// Array of bytes. + /// DistributedConnection is required to fetch resources. + /// Array of variables. + public static AsyncBag ParsePropertyValueArray(byte[] data, DistributedConnection connection) + { + return ParsePropertyValueArray(data, 0, (uint)data.Length, connection); + } + + /// + /// Parse resource history + /// + /// Array of bytes. + /// Zero-indexed offset. + /// Number of bytes to parse. + /// Resource + /// Starting age. + /// Ending age. + /// DistributedConnection is required to fetch resources. + /// + public static AsyncReply> ParseHistory(byte[] data, uint offset, uint length, IResource resource, DistributedConnection connection) + { + //var count = (int)toAge - (int)fromAge; + + var list = new KeyList(); + + var reply = new AsyncReply>(); + + var bagOfBags = new AsyncBag(); + + var ends = offset + length; + while (offset < ends) + { + var index = data[offset++]; + var pt = resource.Instance.Template.GetPropertyTemplateByIndex(index); + list.Add(pt, null); + var cs = data.GetUInt32(offset); + offset += 4; + bagOfBags.Add(ParsePropertyValueArray(data, offset, cs, connection)); + offset += cs; } - /// - /// Parse an array of bytes into an array of varialbes. - /// - /// Array of bytes. - /// Zero-indexed offset. - /// Number of bytes to parse. - /// DistributedConnection is required to fetch resources. - /// Array of variables. - public static AsyncBag ParseVarArray(byte[] data, uint offset, uint length, DistributedConnection connection) - { - var rt = new AsyncBag(); + bagOfBags.Seal(); - while (length > 0) + bagOfBags.Then(x => + { + for (var i = 0; i < list.Count; i++) + list[list.Keys.ElementAt(i)] = x[i]; + + reply.Trigger(list); + }); + + return reply; + + } + + /// + /// Compose resource history + /// + /// History + /// DistributedConnection is required to fetch resources. + /// + public static byte[] ComposeHistory(KeyList history, + DistributedConnection connection, bool prependLength = false) + { + var rt = new BinaryList(); + + for (var i = 0; i < history.Count; i++) + rt.AddUInt8(history.Keys.ElementAt(i).Index) + .AddUInt8Array(ComposePropertyValueArray(history.Values.ElementAt(i), connection, true)); + + // rt.Append((byte)history.Keys.ElementAt(i).Index, + // ComposePropertyValueArray(history.Values.ElementAt(i), connection, true)); + + if (prependLength) + rt.InsertInt32(0, rt.Length); + + return rt.ToArray(); + } + + /// + /// Parse an array of PropertyValue. + /// + /// Array of bytes. + /// Zero-indexed offset. + /// Number of bytes to parse. + /// DistributedConnection is required to fetch resources. + /// Whether property age is represented in the data. + /// + public static AsyncBag ParsePropertyValueArray(byte[] data, uint offset, uint length, DistributedConnection connection)//, bool ageIncluded = true) + { + var rt = new AsyncBag(); + + while (length > 0) + { + uint cs; + + rt.Add(ParsePropertyValue(data, offset, out cs, connection));//, ageIncluded)); + + if (cs > 0) { - uint cs; - - rt.Add(Parse(data, offset, out cs, connection)); - - if (cs > 0) - { - offset += (uint)cs; - length -= (uint)cs; - } - else - throw new Exception("Error while parsing structured data"); - + offset += (uint)cs; + length -= (uint)cs; } - - rt.Seal(); - return rt; + else + throw new Exception("Error while parsing ValueInfo structured data"); } - /// - /// Compose an array of property values. - /// - /// PropertyValue array. - /// DistributedConnection is required to check locality. - /// If True, prepend the length as UInt32 at the beginning of the output. - /// Array of bytes in the network byte order. - /// //, bool includeAge = true - public static byte[] ComposePropertyValueArray(PropertyValue[] array, DistributedConnection connection, bool prependLength = false) + rt.Seal(); + return rt; + } + + /// + /// Compose a variable + /// + /// Value to compose. + /// DistributedConnection is required to check locality. + /// If True, prepend the DataType at the beginning of the output. + /// Array of bytes in the network byte order. + public static byte[] Compose(object valueOrSource, DistributedConnection connection, bool prependType = true) + { + + var (type, value) = GetDataType(valueOrSource, connection); + var rt = new BinaryList(); + + switch (type) { - var rt = new List(); - for (var i = 0; i < array.Length; i++) - rt.AddRange(ComposePropertyValue(array[i], connection)); - if (prependLength) - rt.InsertRange(0, DC.ToBytes(rt.Count)); - return rt.ToArray(); - } + case DataType.Void: + // nothing to do; + break; - /// - /// Compose a property value. - /// - /// Property value - /// DistributedConnection is required to check locality. - /// Array of bytes in the network byte order. - public static byte[] ComposePropertyValue(PropertyValue propertyValue, DistributedConnection connection)//, bool includeAge = true) - { + case DataType.String: + var st = DC.ToBytes((string)value); + rt.AddInt32(st.Length).AddUInt8Array(st); + break; - return new BinaryList() - .AddUInt64(propertyValue.Age) - .AddDateTime(propertyValue.Date) - .AddUInt8Array(Compose(propertyValue.Value, connection)) - .ToArray(); + case DataType.Resource: + rt.AddUInt32((value as DistributedResource).Id); + break; - // age, date, value - //if (includeAge) - // return BinaryList.ToBytes(propertyValue.Age, propertyValue.Date, Compose(propertyValue.Value, connection)); + case DataType.DistributedResource: + //rt.Append((value as IResource).Instance.Template.ClassId, (value as IResource).Instance.Id); + connection.cache.Add(value as IResource, DateTime.UtcNow); + rt.AddUInt32((value as IResource).Instance.Id); + + break; + + case DataType.Structure: + rt.AddUInt8Array(ComposeStructure((Structure)value, connection, true, true, true)); + break; + + case DataType.VarArray: + rt.AddUInt8Array(ComposeVarArray((Array)value, connection, true)); + break; + + case DataType.Record: + rt.AddUInt8Array(ComposeRecord((IRecord)value, connection, true, true)); + break; + + case DataType.ResourceArray: + + rt.AddUInt8Array(ComposeResourceArray((IResource[])value, connection, true)); + break; + //if (value is IResource[]) + // rt.AddUInt8Array(ComposeResourceArray((IResource[])value, connection, true)); //else - // return BinaryList.ToBytes(propertyValue.Date, Compose(propertyValue.Value, connection)); + // rt.AddUInt8Array(ComposeResourceArray((IResource[])DC.CastConvert(value, typeof(IResource[])), connection, true)); + //break; + case DataType.StructureArray: + rt.AddUInt8Array(ComposeStructureArray((Structure[])value, connection, true)); + break; + + case DataType.RecordArray: + rt.AddUInt8Array(ComposeRecordArray((IRecord[])value, connection, true)); + break; + + default: + rt.Add(type, value); + if (type.IsArray()) + rt.InsertInt32(0, rt.Length); + break; } + if (prependType) + rt.InsertUInt8(0, (byte)type); - /// - /// Parse property value. - /// - /// Array of bytes. - /// Zero-indexed offset. - /// DistributedConnection is required to fetch resources. - /// Output content size. - /// PropertyValue. - public static AsyncReply ParsePropertyValue(byte[] data, uint offset, out uint cs, DistributedConnection connection)//, bool ageIncluded = true) + return rt.ToArray(); + } + + + public static bool IsAnonymous(Type type) + { + // Detect anonymous types + var info = type.GetTypeInfo(); + var hasCompilerGeneratedAttribute = info.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Count() > 0; + var nameContainsAnonymousType = type.FullName.Contains("AnonymousType"); + return hasCompilerGeneratedAttribute && nameContainsAnonymousType; + } + + /// + /// Check if a type implements an interface + /// + /// Sub-class type. + /// Super-interface type. + /// True, if implements . + public static bool ImplementsInterface(Type type, Type iface) + { + while (type != null) { - var reply = new AsyncReply(); - - var age = data.GetUInt64(offset); - offset += 8; - - DateTime date = data.GetDateTime(offset); - offset += 8; - - uint valueSize; - - Parse(data, offset, out valueSize, connection).Then(value => - { - reply.Trigger(new PropertyValue(value, age, date)); - }); - - cs = 16 + valueSize; - return reply; - } - - /// - /// Parse an array of PropertyValue. - /// - /// Array of bytes. - /// DistributedConnection is required to fetch resources. - /// Array of variables. - public static AsyncBag ParsePropertyValueArray(byte[] data, DistributedConnection connection) - { - return ParsePropertyValueArray(data, 0, (uint)data.Length, connection); - } - - /// - /// Parse resource history - /// - /// Array of bytes. - /// Zero-indexed offset. - /// Number of bytes to parse. - /// Resource - /// Starting age. - /// Ending age. - /// DistributedConnection is required to fetch resources. - /// - public static AsyncReply> ParseHistory(byte[] data, uint offset, uint length, IResource resource, DistributedConnection connection) - { - //var count = (int)toAge - (int)fromAge; - - var list = new KeyList(); - - var reply = new AsyncReply>(); - - var bagOfBags = new AsyncBag(); - - var ends = offset + length; - while (offset < ends) - { - var index = data[offset++]; - var pt = resource.Instance.Template.GetPropertyTemplateByIndex(index); - list.Add(pt, null); - var cs = data.GetUInt32(offset); - offset += 4; - bagOfBags.Add(ParsePropertyValueArray(data, offset, cs, connection)); - offset += cs; - } - - bagOfBags.Seal(); - - bagOfBags.Then(x => - { - for (var i = 0; i < list.Count; i++) - list[list.Keys.ElementAt(i)] = x[i]; - - reply.Trigger(list); - }); - - return reply; - - } - - /// - /// Compose resource history - /// - /// History - /// DistributedConnection is required to fetch resources. - /// - public static byte[] ComposeHistory(KeyList history, - DistributedConnection connection, bool prependLength = false) - { - var rt = new BinaryList(); - - for (var i = 0; i < history.Count; i++) - rt.AddUInt8(history.Keys.ElementAt(i).Index) - .AddUInt8Array(ComposePropertyValueArray(history.Values.ElementAt(i), connection, true)); - - // rt.Append((byte)history.Keys.ElementAt(i).Index, - // ComposePropertyValueArray(history.Values.ElementAt(i), connection, true)); - - if (prependLength) - rt.InsertInt32(0, rt.Length); - - return rt.ToArray(); - } - - /// - /// Parse an array of PropertyValue. - /// - /// Array of bytes. - /// Zero-indexed offset. - /// Number of bytes to parse. - /// DistributedConnection is required to fetch resources. - /// Whether property age is represented in the data. - /// - public static AsyncBag ParsePropertyValueArray(byte[] data, uint offset, uint length, DistributedConnection connection)//, bool ageIncluded = true) - { - var rt = new AsyncBag(); - - while (length > 0) - { - uint cs; - - rt.Add(ParsePropertyValue(data, offset, out cs, connection));//, ageIncluded)); - - if (cs > 0) - { - offset += (uint)cs; - length -= (uint)cs; - } - else - throw new Exception("Error while parsing ValueInfo structured data"); - } - - rt.Seal(); - return rt; - } - - /// - /// Compose a variable - /// - /// Value to compose. - /// DistributedConnection is required to check locality. - /// If True, prepend the DataType at the beginning of the output. - /// Array of bytes in the network byte order. - public static byte[] Compose(object valueOrSource, DistributedConnection connection, bool prependType = true) - { - - var (type, value) = GetDataType(valueOrSource, connection); - var rt = new BinaryList(); - - switch (type) - { - case DataType.Void: - // nothing to do; - break; - - case DataType.String: - var st = DC.ToBytes((string)value); - rt.AddInt32(st.Length).AddUInt8Array(st); - break; - - case DataType.Resource: - rt.AddUInt32((value as DistributedResource).Id); - break; - - case DataType.DistributedResource: - //rt.Append((value as IResource).Instance.Template.ClassId, (value as IResource).Instance.Id); - connection.cache.Add(value as IResource, DateTime.UtcNow); - rt.AddUInt32((value as IResource).Instance.Id); - - break; - - case DataType.Structure: - rt.AddUInt8Array(ComposeStructure((Structure)value, connection, true, true, true)); - break; - - case DataType.VarArray: - rt.AddUInt8Array(ComposeVarArray((Array)value, connection, true)); - break; - - case DataType.Record: - rt.AddUInt8Array(ComposeRecord((IRecord)value, connection, true, true)); - break; - - case DataType.ResourceArray: - - rt.AddUInt8Array(ComposeResourceArray((IResource[])value, connection, true)); - break; - //if (value is IResource[]) - // rt.AddUInt8Array(ComposeResourceArray((IResource[])value, connection, true)); - //else - // rt.AddUInt8Array(ComposeResourceArray((IResource[])DC.CastConvert(value, typeof(IResource[])), connection, true)); - //break; - - case DataType.StructureArray: - rt.AddUInt8Array(ComposeStructureArray((Structure[])value, connection, true)); - break; - - case DataType.RecordArray: - rt.AddUInt8Array(ComposeRecordArray((IRecord[])value, connection, true)); - break; - - default: - rt.Add(type, value); - if (type.IsArray()) - rt.InsertInt32(0, rt.Length); - break; - } - - if (prependType) - rt.InsertUInt8(0, (byte)type); - - return rt.ToArray(); - } - - - public static bool IsAnonymous(Type type) - { - // Detect anonymous types - var info = type.GetTypeInfo(); - var hasCompilerGeneratedAttribute = info.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Count() > 0; - var nameContainsAnonymousType = type.FullName.Contains("AnonymousType"); - return hasCompilerGeneratedAttribute && nameContainsAnonymousType; - } - - /// - /// Check if a type implements an interface - /// - /// Sub-class type. - /// Super-interface type. - /// True, if implements . - public static bool ImplementsInterface(Type type, Type iface) - { - while (type != null) - { - if (type == iface) - return true; + if (type == iface) + return true; #if NETSTANDARD - if (type.GetTypeInfo().GetInterfaces().Contains(iface)) - return true; + if (type.GetTypeInfo().GetInterfaces().Contains(iface)) + return true; - type = type.GetTypeInfo().BaseType; + type = type.GetTypeInfo().BaseType; #else if (type.GetInterfaces().Contains(iface)) return true; type = type.BaseType; #endif - } - - return false; } - public static bool InheritsClass(Type type, Type parent) - => type.IsSubclassOf(parent); + return false; + } - /// - /// Check if a type inherits another type. - /// - /// Child type. - /// Parent type. - /// True, if inherits . - private static bool HasParentType(Type childType, Type parentType) + public static bool InheritsClass(Type type, Type parent) + => type.IsSubclassOf(parent); + + /// + /// Check if a type inherits another type. + /// + /// Child type. + /// Parent type. + /// True, if inherits . + private static bool HasParentType(Type childType, Type parentType) + { + while (childType != null) { - while (childType != null) - { - if (childType == parentType) - return true; + if (childType == parentType) + return true; #if NETSTANDARD - childType = childType.GetTypeInfo().BaseType; + childType = childType.GetTypeInfo().BaseType; #else childType = childType.BaseType; #endif - } - - return false; } - /// - /// Get the DataType of a given value. - /// This function is needed to compose a value. - /// - /// Value to find its DataType. - /// DistributedConnection is required to check locality of resources. - /// DataType. - public static (DataType type, object value) GetDataType(object value, DistributedConnection connection) + return false; + } + + /// + /// Get the DataType of a given value. + /// This function is needed to compose a value. + /// + /// Value to find its DataType. + /// DistributedConnection is required to check locality of resources. + /// DataType. + public static (DataType type, object value) GetDataType(object value, DistributedConnection connection) + { + + if (value == null) + return (DataType.Void, null); + + if (value is IUserType) + value = (value as IUserType).Get(); + + + // value = (List<>)value.ToArray(); + + if (value is Func) + //if (connection != null) + value = (value as Func)(connection); + //else + // return (DataType.Void, null); + else if (value is DistributedPropertyContext) { - - if (value == null) - return (DataType.Void, null); - - if (value is IUserType) - value = (value as IUserType).Get(); - - - // value = (List<>)value.ToArray(); - - if (value is Func) + try + { //if (connection != null) - value = (value as Func)(connection); - //else - // return (DataType.Void, null); - else if (value is DistributedPropertyContext) - { - try - { - //if (connection != null) - value = (value as DistributedPropertyContext).Method(connection); - //else - } - catch(Exception ex) - { - Global.Log(ex); - return (DataType.Void, null); - } - // return (DataType.Void, null); + value = (value as DistributedPropertyContext).Method(connection); + //else } - - if (value == null) + catch (Exception ex) + { + Global.Log(ex); + return (DataType.Void, null); + } + // return (DataType.Void, null); + } + + if (value == null) + return (DataType.Void, null); + + + var t = value.GetType(); + + // Convert ICollection to Array + if (!t.IsArray && typeof(ICollection).IsAssignableFrom(t)) + { + var col = t.GetInterfaces().Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ICollection<>)); + if (col.Count() == 0) return (DataType.Void, null); + var elementType = col.First().GetGenericArguments()[0]; - var t = value.GetType(); - - // Convert ICollection to Array - if (!t.IsArray && typeof(ICollection).IsAssignableFrom(t)) - { - var col = t.GetInterfaces().Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ICollection<>)); - if (col.Count() == 0) - return (DataType.Void, null); - - var elementType = col.First().GetGenericArguments()[0]; - - value = new ArrayList((ICollection)value).ToArray(elementType); - t = value.GetType(); - } - - var isArray = t.IsArray; - - if (isArray) - { - t = t.GetElementType(); - if (t.IsEnum) - { - var src = value as Array; - t = t.GetEnumUnderlyingType(); - var dst = Array.CreateInstance(t, src.Length); - src.CopyTo(dst, 0); - value = dst; - } - } - else if (t.IsEnum) - { - t = t.GetEnumUnderlyingType(); - value = Convert.ChangeType(value, t); - } - - DataType type; - - - - if (t == typeof(bool)) - type = DataType.Bool; - else if (t == typeof(char)) - type = DataType.Char; - else if (t == typeof(byte)) - type = DataType.UInt8; - else if (t == typeof(sbyte)) - type = DataType.Int8; - else if (t == typeof(short)) - type = DataType.Int16; - else if (t == typeof(ushort)) - type = DataType.UInt16; - else if (t == typeof(int)) - type = DataType.Int32; - else if (t == typeof(uint)) - type = DataType.UInt32; - else if (t == typeof(long)) - type = DataType.Int64; - else if (t == typeof(ulong)) - type = DataType.UInt64; - else if (t == typeof(float)) - type = DataType.Float32; - else if (t == typeof(double)) - type = DataType.Float64; - else if (t == typeof(decimal)) - type = DataType.Decimal; - else if (t == typeof(string)) - type = DataType.String; - else if (t == typeof(DateTime)) - type = DataType.DateTime; - else if (typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject)) - type = DataType.Structure; - //else if (t == typeof(DistributedResource)) - // type = DataType.DistributedResource; - else if (ImplementsInterface(t, typeof(IResource))) - { - if (isArray) - return (DataType.ResourceArray, value); - else - { - return (IsLocalResource((IResource)value, connection) ? DataType.Resource : DataType.DistributedResource, value); - } - } - else if (ImplementsInterface(t, typeof(IRecord))) - type = DataType.Record; - else - type = DataType.Void; - - - if (isArray) - return ((DataType)((byte)type | 0x80), value); - else - return (type, value); - + value = new ArrayList((ICollection)value).ToArray(elementType); + t = value.GetType(); } + var isArray = t.IsArray; + + if (isArray) + { + t = t.GetElementType(); + if (t.IsEnum) + { + var src = value as Array; + t = t.GetEnumUnderlyingType(); + var dst = Array.CreateInstance(t, src.Length); + src.CopyTo(dst, 0); + value = dst; + } + } + else if (t.IsEnum) + { + t = t.GetEnumUnderlyingType(); + value = Convert.ChangeType(value, t); + } + + DataType type; + + + + if (t == typeof(bool)) + type = DataType.Bool; + else if (t == typeof(char)) + type = DataType.Char; + else if (t == typeof(byte)) + type = DataType.UInt8; + else if (t == typeof(sbyte)) + type = DataType.Int8; + else if (t == typeof(short)) + type = DataType.Int16; + else if (t == typeof(ushort)) + type = DataType.UInt16; + else if (t == typeof(int)) + type = DataType.Int32; + else if (t == typeof(uint)) + type = DataType.UInt32; + else if (t == typeof(long)) + type = DataType.Int64; + else if (t == typeof(ulong)) + type = DataType.UInt64; + else if (t == typeof(float)) + type = DataType.Float32; + else if (t == typeof(double)) + type = DataType.Float64; + else if (t == typeof(decimal)) + type = DataType.Decimal; + else if (t == typeof(string)) + type = DataType.String; + else if (t == typeof(DateTime)) + type = DataType.DateTime; + else if (typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject)) + type = DataType.Structure; + //else if (t == typeof(DistributedResource)) + // type = DataType.DistributedResource; + else if (ImplementsInterface(t, typeof(IResource))) + { + if (isArray) + return (DataType.ResourceArray, value); + else + { + return (IsLocalResource((IResource)value, connection) ? DataType.Resource : DataType.DistributedResource, value); + } + } + else if (ImplementsInterface(t, typeof(IRecord))) + type = DataType.Record; + else + type = DataType.Void; + + + if (isArray) + return ((DataType)((byte)type | 0x80), value); + else + return (type, value); + } + } diff --git a/Esiur/Data/DataConverter.cs b/Esiur/Data/DataConverter.cs index 79d9d9e..33d6d33 100644 --- a/Esiur/Data/DataConverter.cs +++ b/Esiur/Data/DataConverter.cs @@ -37,569 +37,569 @@ using Esiur.Data; using Esiur.Core; using Esiur.Resource; -namespace Esiur.Data +namespace Esiur.Data; + +public static class DC // Data Converter { - public static class DC // Data Converter + public static object CastConvert(object value, Type destinationType) { - public static object CastConvert(object value, Type destinationType) - { - if (value == null) - return null; + if (value == null) + return null; - var sourceType = value.GetType(); + var sourceType = value.GetType(); - if (destinationType == sourceType) - { - return value; - } - else - { - if (sourceType.IsArray && (destinationType.IsArray || destinationType == typeof(object))) - { - destinationType = destinationType.GetElementType(); - - var v = value as Array; - - var rt = Array.CreateInstance(destinationType, v.Length); - - for (var i = 0; i < rt.Length; i++) - { - rt.SetValue(CastConvert(v.GetValue(i), destinationType), i); - } - - return rt; - - } - else - { - try - { - var underType = Nullable.GetUnderlyingType(destinationType); - if (underType != null) - { - if (value == null) - return null; - else - destinationType = underType; - } - - if (destinationType.IsInstanceOfType(value)) - { - return value; - } - else if (typeof(IUserType).IsAssignableFrom(destinationType)) - { - var rt = Activator.CreateInstance(destinationType) as IUserType; - rt.Set(value); - return rt; - } - else if (sourceType == typeof(Structure) && sourceType.IsAssignableFrom(destinationType)) - { - return Structure.FromStructure((Structure)value, destinationType); - } - else if (destinationType.IsEnum) - { - return Enum.ToObject(destinationType, value); - } - else - { - return Convert.ChangeType(value, destinationType); - } - } - catch - { - return null; - } - } - } - } - - - public static byte[] ToBytes(sbyte value) - { - return new byte[1] { (byte)value }; - } - - public static byte[] ToBytes(byte value) - { - return new byte[1] { value }; - } - - public static byte[] ToBytes(IPAddress ip) - { - return ip.GetAddressBytes(); - } - - public static byte[] ToBytes(PhysicalAddress mac) - { - return mac.GetAddressBytes(); - } - - public static byte[] ToBytes(bool value) - { - return new byte[1] { value ? (byte)1 : (byte)0 }; - } - - public static byte ToByte(bool value) - { - return value ? (byte)1 : (byte)0; - } - - public static byte ToByte(sbyte value) - { - return (byte)value; - } - - public static byte[] ToBytes(byte[] value) + if (destinationType == sourceType) { return value; } - - - public static byte[] ToBytes(bool[] value) + else { - - byte[] ba = new byte[value.Length]; - - for (int i = 0; i < ba.Length; i++) - ba[i] = DC.ToByte(value[i]); - - return ba; - } - - public static byte[] ToBytes(sbyte[] value) - { - - byte[] ba = new byte[value.Length]; - - for (int i = 0; i < ba.Length; i++) - ba[i] = DC.ToByte(value[i]); - - return ba; - } - - public static byte[] ToBytes(char value) - { - byte[] ret = BitConverter.GetBytes(value); - Array.Reverse(ret); - return ret; - } - - public static byte[] ToBytes(Guid value) - { - return value.ToByteArray(); - } - - public static byte[] ToBytes(Guid[] value) - { - var rt = new List(); - foreach (var g in value) - rt.AddRange(g.ToByteArray()); - return rt.ToArray(); - } - - public static byte[] ToBytes(char[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - - public static byte[] ToBytes(short[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - - - - public static byte[] ToBytes(ushort[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - - public static void Append(ref byte[] dst, byte[] src) - { - Append(ref dst, src, (uint)0, (uint)src.Length); - } - - public static void Append(ref byte[] dst, byte[] src, uint srcOffset, uint length) - { - var dstOffset = dst.Length; - Array.Resize(ref dst, dstOffset + (int)length); - Buffer.BlockCopy(src, (int)srcOffset, dst, dstOffset, (int)length); - } - - public static byte[] Combine(byte[] src1, uint src1Offset, uint src1Length, byte[] src2, uint src2Offset, uint src2Length) - { - var rt = new byte[src1Length + src2Length]; - Buffer.BlockCopy(src1, (int)src1Offset, rt, 0, (int)src1Length); - Buffer.BlockCopy(src2, (int)src2Offset, rt, (int)src1Length, (int)src2Length); - return rt; - } - - public static byte[] Merge(params byte[][] arrays) - { - var s = arrays.Sum(x => x.Length); - var r = new byte[s]; - var offset = 0; - foreach (var array in arrays) + if (sourceType.IsArray && (destinationType.IsArray || destinationType == typeof(object))) { - Buffer.BlockCopy(array, 0, r, offset, array.Length); - offset += array.Length; - } + destinationType = destinationType.GetElementType(); - return r; - } + var v = value as Array; + var rt = Array.CreateInstance(destinationType, v.Length); - public static byte[] ToBytes(this int[] value) - { - List rt = new List(); + for (var i = 0; i < rt.Length; i++) + { + rt.SetValue(CastConvert(v.GetValue(i), destinationType), i); + } - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); + return rt; - return rt.ToArray(); - } - - public static byte[] ToBytes(this uint[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - - public static byte[] ToBytes(this long[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - - public static byte[] ToBytes(this ulong[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - - public static byte[] ToBytes(this float[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - - public static byte[] ToBytes(this double[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - - - public static byte[] ToBytes(this decimal[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - - - public static byte[] ToBytes(this DateTime[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - - - public static byte[] ToBytes(this string[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - { - byte[] ba = ToBytes(value[i]); - // add string length - rt.AddRange(ToBytes(ba.Length)); - // add encoded string - rt.AddRange(ba); - } - - return rt.ToArray(); - } - - public static unsafe byte[] ToBytes(this int value) - { - var rt = new byte[4]; - byte* p = (byte*)&value; - - rt[0] = *(p + 3); - rt[1] = *(p + 2); - rt[2] = *(p + 1); - rt[3] = *(p + 0); - - return rt; - } - - public static unsafe byte[] ToBytes(this short value) - { - var rt = new byte[2]; - byte* p = (byte*)&value; - - rt[0] = *(p + 1); - rt[1] = *(p + 0); - - return rt; - } - - public static unsafe byte[] ToBytes(this float value) - - { - var rt = new byte[4]; - - //float rt = 0; - byte* p = (byte*)&value; - rt[0] = *(p + 3); - rt[1] = *(p + 2); - rt[2] = *(p + 1); - rt[3] = *(p); - - return rt; - } - - - - - public static byte[] ToBytes(this string value) - { - return Encoding.UTF8.GetBytes(value); - } - - public unsafe static byte[] ToBytes(this double value) - { - var rt = new byte[8]; - - byte* p = (byte*)&value; - - rt[0] = *(p + 7); - rt[1] = *(p + 6); - rt[2] = *(p + 5); - rt[3] = *(p + 4); - rt[4] = *(p + 3); - rt[5] = *(p + 2); - rt[6] = *(p + 1); - rt[7] = *(p + 0); - - return rt; - } - - public static unsafe byte[] ToBytes(this long value) - { - var rt = new byte[8]; - - byte* p = (byte*)&value; - - rt[0] = *(p + 7); - rt[1] = *(p + 6); - rt[2] = *(p + 5); - rt[3] = *(p + 4); - rt[4] = *(p + 3); - rt[5] = *(p + 2); - rt[6] = *(p + 1); - rt[7] = *(p + 0); - - return rt; - - } - - public static unsafe byte[] ToBytes(this DateTime value) - { - - var rt = new byte[8]; - var v = value.ToUniversalTime().Ticks; - - byte* p = (byte*)&v; - - rt[0] = *(p + 7); - rt[1] = *(p + 6); - rt[2] = *(p + 5); - rt[3] = *(p + 4); - rt[4] = *(p + 3); - rt[5] = *(p + 2); - rt[6] = *(p + 1); - rt[7] = *(p + 0); - - return rt; - - } - - - public static unsafe byte[] ToBytes(this ulong value) - { - var rt = new byte[8]; - - byte* p = (byte*)&value; - - rt[0] = *(p + 7); - rt[1] = *(p + 6); - rt[2] = *(p + 5); - rt[3] = *(p + 4); - rt[4] = *(p + 3); - rt[5] = *(p + 2); - rt[6] = *(p + 1); - rt[7] = *(p + 0); - - return rt; - } - - public static unsafe byte[] ToBytes(this uint value) - { - - var rt = new byte[4]; - - byte* p = (byte*)&value; - - rt[0] = *(p + 3); - rt[1] = *(p + 2); - rt[2] = *(p + 1); - rt[3] = *(p + 0); - - return rt; - } - - public static unsafe byte[] ToBytes(this ushort value) - { - var rt = new byte[2]; - - byte* p = (byte*)&value; - - rt[0] = *(p + 1); - rt[1] = *(p); - - return rt; - } - - public static byte[] ToBytes(this decimal value) - { - byte[] ret = new byte[0];// BitConverter.GetBytes(value); - - Array.Reverse(ret); - - return ret; - } - - public static string ToHex(this byte[] ba) - { - if (ba == null) - return "NULL"; - return ToHex(ba, 0, (uint)ba.Length); - } - - public static string ToHex(this byte[] ba, uint offset, uint length, string separator = " ") - { - - if (separator == null) - separator = ""; - - return string.Join(separator, ba.Skip((int)offset).Take((int)length).Select(x => x.ToString("x2")).ToArray()); - - //StringBuilder hex = new StringBuilder((int)length * 2); - - //for (var i = offset; i < offset + length; i++) - //{ - // hex.AppendFormat("{0:x2}", ba[i]); - // if (separator != null) - // hex.Append(separator); - //} - - //return hex.ToString(); - } - - public static byte[] FromHex(string hexString, string separator = " ") - { - var rt = new List(); - - if (separator == null) - { - for (var i = 0; i < hexString.Length; i += 2) - rt.Add(Convert.ToByte(hexString.Substring(i, 2), 16)); } else { - var hexes = hexString.Split(new string[] { separator }, StringSplitOptions.RemoveEmptyEntries); - foreach (var h in hexes) - rt.Add(Convert.ToByte(h, 16)); - } - - return rt.ToArray(); - } - - public static string FlagsEnumToString(ulong value) - { - - string rt = typeof(T).Name + ":"; - - for (int i = 0; i < 64; i++) - { - ulong bit = (ulong)(Convert.ToUInt64(Math.Pow(2, i)) & value); - if (bit != 0) + try { - rt += " " + Enum.GetName(typeof(T), bit); + var underType = Nullable.GetUnderlyingType(destinationType); + if (underType != null) + { + if (value == null) + return null; + else + destinationType = underType; + } + + if (destinationType.IsInstanceOfType(value)) + { + return value; + } + else if (typeof(IUserType).IsAssignableFrom(destinationType)) + { + var rt = Activator.CreateInstance(destinationType) as IUserType; + rt.Set(value); + return rt; + } + else if (sourceType == typeof(Structure) && sourceType.IsAssignableFrom(destinationType)) + { + return Structure.FromStructure((Structure)value, destinationType); + } + else if (destinationType.IsEnum) + { + return Enum.ToObject(destinationType, value); + } + else + { + return Convert.ChangeType(value, destinationType); + } + } + catch + { + return null; } } + } + } - return rt; + + public static byte[] ToBytes(sbyte value) + { + return new byte[1] { (byte)value }; + } + + public static byte[] ToBytes(byte value) + { + return new byte[1] { value }; + } + + public static byte[] ToBytes(IPAddress ip) + { + return ip.GetAddressBytes(); + } + + public static byte[] ToBytes(PhysicalAddress mac) + { + return mac.GetAddressBytes(); + } + + public static byte[] ToBytes(bool value) + { + return new byte[1] { value ? (byte)1 : (byte)0 }; + } + + public static byte ToByte(bool value) + { + return value ? (byte)1 : (byte)0; + } + + public static byte ToByte(sbyte value) + { + return (byte)value; + } + + public static byte[] ToBytes(byte[] value) + { + return value; + } + + + public static byte[] ToBytes(bool[] value) + { + + byte[] ba = new byte[value.Length]; + + for (int i = 0; i < ba.Length; i++) + ba[i] = DC.ToByte(value[i]); + + return ba; + } + + public static byte[] ToBytes(sbyte[] value) + { + + byte[] ba = new byte[value.Length]; + + for (int i = 0; i < ba.Length; i++) + ba[i] = DC.ToByte(value[i]); + + return ba; + } + + public static byte[] ToBytes(char value) + { + byte[] ret = BitConverter.GetBytes(value); + Array.Reverse(ret); + return ret; + } + + public static byte[] ToBytes(Guid value) + { + return value.ToByteArray(); + } + + public static byte[] ToBytes(Guid[] value) + { + var rt = new List(); + foreach (var g in value) + rt.AddRange(g.ToByteArray()); + return rt.ToArray(); + } + + public static byte[] ToBytes(char[] value) + { + List rt = new List(); + + for (int i = 0; i < value.Length; i++) + rt.AddRange(ToBytes(value[i])); + + return rt.ToArray(); + } + + public static byte[] ToBytes(short[] value) + { + List rt = new List(); + + for (int i = 0; i < value.Length; i++) + rt.AddRange(ToBytes(value[i])); + + return rt.ToArray(); + } + + + + public static byte[] ToBytes(ushort[] value) + { + List rt = new List(); + + for (int i = 0; i < value.Length; i++) + rt.AddRange(ToBytes(value[i])); + + return rt.ToArray(); + } + + public static void Append(ref byte[] dst, byte[] src) + { + Append(ref dst, src, (uint)0, (uint)src.Length); + } + + public static void Append(ref byte[] dst, byte[] src, uint srcOffset, uint length) + { + var dstOffset = dst.Length; + Array.Resize(ref dst, dstOffset + (int)length); + Buffer.BlockCopy(src, (int)srcOffset, dst, dstOffset, (int)length); + } + + public static byte[] Combine(byte[] src1, uint src1Offset, uint src1Length, byte[] src2, uint src2Offset, uint src2Length) + { + var rt = new byte[src1Length + src2Length]; + Buffer.BlockCopy(src1, (int)src1Offset, rt, 0, (int)src1Length); + Buffer.BlockCopy(src2, (int)src2Offset, rt, (int)src1Length, (int)src2Length); + return rt; + } + + public static byte[] Merge(params byte[][] arrays) + { + var s = arrays.Sum(x => x.Length); + var r = new byte[s]; + var offset = 0; + foreach (var array in arrays) + { + Buffer.BlockCopy(array, 0, r, offset, array.Length); + offset += array.Length; } - public static bool TryParse(object Input, out T Results) + return r; + } + + + public static byte[] ToBytes(this int[] value) + { + List rt = new List(); + + for (int i = 0; i < value.Length; i++) + rt.AddRange(ToBytes(value[i])); + + return rt.ToArray(); + } + + public static byte[] ToBytes(this uint[] value) + { + List rt = new List(); + + for (int i = 0; i < value.Length; i++) + rt.AddRange(ToBytes(value[i])); + + return rt.ToArray(); + } + + public static byte[] ToBytes(this long[] value) + { + List rt = new List(); + + for (int i = 0; i < value.Length; i++) + rt.AddRange(ToBytes(value[i])); + + return rt.ToArray(); + } + + public static byte[] ToBytes(this ulong[] value) + { + List rt = new List(); + + for (int i = 0; i < value.Length; i++) + rt.AddRange(ToBytes(value[i])); + + return rt.ToArray(); + } + + public static byte[] ToBytes(this float[] value) + { + List rt = new List(); + + for (int i = 0; i < value.Length; i++) + rt.AddRange(ToBytes(value[i])); + + return rt.ToArray(); + } + + public static byte[] ToBytes(this double[] value) + { + List rt = new List(); + + for (int i = 0; i < value.Length; i++) + rt.AddRange(ToBytes(value[i])); + + return rt.ToArray(); + } + + + public static byte[] ToBytes(this decimal[] value) + { + List rt = new List(); + + for (int i = 0; i < value.Length; i++) + rt.AddRange(ToBytes(value[i])); + + return rt.ToArray(); + } + + + public static byte[] ToBytes(this DateTime[] value) + { + List rt = new List(); + + for (int i = 0; i < value.Length; i++) + rt.AddRange(ToBytes(value[i])); + + return rt.ToArray(); + } + + + public static byte[] ToBytes(this string[] value) + { + List rt = new List(); + + for (int i = 0; i < value.Length; i++) { - try + byte[] ba = ToBytes(value[i]); + // add string length + rt.AddRange(ToBytes(ba.Length)); + // add encoded string + rt.AddRange(ba); + } + + return rt.ToArray(); + } + + public static unsafe byte[] ToBytes(this int value) + { + var rt = new byte[4]; + byte* p = (byte*)&value; + + rt[0] = *(p + 3); + rt[1] = *(p + 2); + rt[2] = *(p + 1); + rt[3] = *(p + 0); + + return rt; + } + + public static unsafe byte[] ToBytes(this short value) + { + var rt = new byte[2]; + byte* p = (byte*)&value; + + rt[0] = *(p + 1); + rt[1] = *(p + 0); + + return rt; + } + + public static unsafe byte[] ToBytes(this float value) + + { + var rt = new byte[4]; + + //float rt = 0; + byte* p = (byte*)&value; + rt[0] = *(p + 3); + rt[1] = *(p + 2); + rt[2] = *(p + 1); + rt[3] = *(p); + + return rt; + } + + + + + public static byte[] ToBytes(this string value) + { + return Encoding.UTF8.GetBytes(value); + } + + public unsafe static byte[] ToBytes(this double value) + { + var rt = new byte[8]; + + byte* p = (byte*)&value; + + rt[0] = *(p + 7); + rt[1] = *(p + 6); + rt[2] = *(p + 5); + rt[3] = *(p + 4); + rt[4] = *(p + 3); + rt[5] = *(p + 2); + rt[6] = *(p + 1); + rt[7] = *(p + 0); + + return rt; + } + + public static unsafe byte[] ToBytes(this long value) + { + var rt = new byte[8]; + + byte* p = (byte*)&value; + + rt[0] = *(p + 7); + rt[1] = *(p + 6); + rt[2] = *(p + 5); + rt[3] = *(p + 4); + rt[4] = *(p + 3); + rt[5] = *(p + 2); + rt[6] = *(p + 1); + rt[7] = *(p + 0); + + return rt; + + } + + public static unsafe byte[] ToBytes(this DateTime value) + { + + var rt = new byte[8]; + var v = value.ToUniversalTime().Ticks; + + byte* p = (byte*)&v; + + rt[0] = *(p + 7); + rt[1] = *(p + 6); + rt[2] = *(p + 5); + rt[3] = *(p + 4); + rt[4] = *(p + 3); + rt[5] = *(p + 2); + rt[6] = *(p + 1); + rt[7] = *(p + 0); + + return rt; + + } + + + public static unsafe byte[] ToBytes(this ulong value) + { + var rt = new byte[8]; + + byte* p = (byte*)&value; + + rt[0] = *(p + 7); + rt[1] = *(p + 6); + rt[2] = *(p + 5); + rt[3] = *(p + 4); + rt[4] = *(p + 3); + rt[5] = *(p + 2); + rt[6] = *(p + 1); + rt[7] = *(p + 0); + + return rt; + } + + public static unsafe byte[] ToBytes(this uint value) + { + + var rt = new byte[4]; + + byte* p = (byte*)&value; + + rt[0] = *(p + 3); + rt[1] = *(p + 2); + rt[2] = *(p + 1); + rt[3] = *(p + 0); + + return rt; + } + + public static unsafe byte[] ToBytes(this ushort value) + { + var rt = new byte[2]; + + byte* p = (byte*)&value; + + rt[0] = *(p + 1); + rt[1] = *(p); + + return rt; + } + + public static byte[] ToBytes(this decimal value) + { + byte[] ret = new byte[0];// BitConverter.GetBytes(value); + + Array.Reverse(ret); + + return ret; + } + + public static string ToHex(this byte[] ba) + { + if (ba == null) + return "NULL"; + return ToHex(ba, 0, (uint)ba.Length); + } + + public static string ToHex(this byte[] ba, uint offset, uint length, string separator = " ") + { + + if (separator == null) + separator = ""; + + return string.Join(separator, ba.Skip((int)offset).Take((int)length).Select(x => x.ToString("x2")).ToArray()); + + //StringBuilder hex = new StringBuilder((int)length * 2); + + //for (var i = offset; i < offset + length; i++) + //{ + // hex.AppendFormat("{0:x2}", ba[i]); + // if (separator != null) + // hex.Append(separator); + //} + + //return hex.ToString(); + } + + public static byte[] FromHex(string hexString, string separator = " ") + { + var rt = new List(); + + if (separator == null) + { + for (var i = 0; i < hexString.Length; i += 2) + rt.Add(Convert.ToByte(hexString.Substring(i, 2), 16)); + } + else + { + var hexes = hexString.Split(new string[] { separator }, StringSplitOptions.RemoveEmptyEntries); + foreach (var h in hexes) + rt.Add(Convert.ToByte(h, 16)); + } + + return rt.ToArray(); + } + + public static string FlagsEnumToString(ulong value) + { + + string rt = typeof(T).Name + ":"; + + for (int i = 0; i < 64; i++) + { + ulong bit = (ulong)(Convert.ToUInt64(Math.Pow(2, i)) & value); + if (bit != 0) { + rt += " " + Enum.GetName(typeof(T), bit); + } + } + + return rt; + } + + public static bool TryParse(object Input, out T Results) + { + try + { #if NETSTANDARD - var tryParse = typeof(T).GetTypeInfo().GetDeclaredMethod("TryParse"); - if ((bool)tryParse.Invoke(null, new object[] { Input, null })) - { - var parse = typeof(T).GetTypeInfo().GetDeclaredMethod("Parse"); + var tryParse = typeof(T).GetTypeInfo().GetDeclaredMethod("TryParse"); + if ((bool)tryParse.Invoke(null, new object[] { Input, null })) + { + var parse = typeof(T).GetTypeInfo().GetDeclaredMethod("Parse"); - Results = (T)parse.Invoke(null, new object[] { Input }); - return true; - } + Results = (T)parse.Invoke(null, new object[] { Input }); + return true; + } #else if ((bool)typeof(T).InvokeMember("TryParse", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[] { Input, null })) { @@ -608,384 +608,383 @@ namespace Esiur.Data } #endif - else - { - Results = default(T); - return false; - } - } - catch //Exception ex) + else { Results = default(T); return false; } } - - - - public static DateTime FromUnixTime(uint seconds) + catch //Exception ex) { - return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds((double)seconds); - } - - public static DateTime FromUnixTime(ulong milliseconds) - { - return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds((double)milliseconds); - } - - - public static sbyte GetInt8(this byte[] data, uint offset) - { - return (sbyte)data[offset]; - } - - public static sbyte[] GetInt8Array(this byte[] data, uint offset, uint length) - { - var rt = new sbyte[length]; - Buffer.BlockCopy(data, (int)offset, rt, 0, (int)length); - return rt; - } - - public static byte GetUInt8(this byte[] data, uint offset) - { - return data[offset]; - } - - public static byte[] GetUInt8Array(this byte[] data, uint offset, uint length) - { - var rt = new byte[length]; - Buffer.BlockCopy(data, (int)offset, rt, 0, (int)length); - return rt; - } - - public static Int16 GetInt16(this byte[] data, uint offset) - { - return (Int16)((data[offset] << 8) | data[offset + 1]); - } - - public static Int16[] GetInt16Array(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - - var rt = new Int16[length / 2]; - for (var i = offset; i < end; i += 2) - rt[j++] = GetInt16(data, i); - - return rt; - } - - public static UInt16 GetUInt16(this byte[] data, uint offset) - { - return (UInt16)((data[offset] << 8) | data[offset + 1]); - } - - public static UInt16[] GetUInt16Array(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - var rt = new UInt16[length / 2]; - - for (var i = offset; i < end; i += 2) - rt[j++] = GetUInt16(data, i); - - return rt; - - } - - public static Int32 GetInt32(this byte[] data, uint offset) - { - return (Int32)((data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]); - } - - public static Int32[] GetInt32Array(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - - var rt = new Int32[length / 4]; - for (var i = offset; i < end; i += 4) - rt[j++] = GetInt32(data, i); - - return rt; - } - - public static UInt32 GetUInt32(this byte[] data, uint offset) - { - return (UInt32)((data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]); - } - - public static UInt32[] GetUInt32Array(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - var rt = new UInt32[length / 4]; - - for (var i = offset; i < end; i += 4) - rt[j++] = GetUInt16(data, i); - - return rt; - } - - - public static unsafe UInt64 GetUInt64(this byte[] data, uint offset) - { - UInt64 rt = 0; - byte* p = (byte*)&rt; - - *(p + 7) = data[offset++]; - *(p + 6) = data[offset++]; - *(p + 5) = data[offset++]; - *(p + 4) = data[offset++]; - *(p + 3) = data[offset++]; - *(p + 2) = data[offset++]; - *(p + 1) = data[offset++]; - *(p) = data[offset++]; - - return rt; - - } - - public static Int64[] GetInt64Array(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - var rt = new Int64[length / 8]; - - for (var i = offset; i < end; i += 8) - rt[j++] = GetInt64(data, i); - - return rt; - } - - public static unsafe Int64 GetInt64(this byte[] data, uint offset) - { - Int64 rt = 0; - byte* p = (byte*)&rt; - - *(p + 7) = data[offset++]; - *(p + 6) = data[offset++]; - *(p + 5) = data[offset++]; - *(p + 4) = data[offset++]; - *(p + 3) = data[offset++]; - *(p + 2) = data[offset++]; - *(p + 1) = data[offset++]; - *(p) = data[offset++]; - - return rt; - - /* Or - return (Int64)( - (data[offset] << 56) - | (data[offset + 1] << 48) - | (data[offset + 2] << 40) - | (data[offset + 3] << 32) - | (data[offset + 4] << 24) - | (data[offset + 5] << 16) - | (data[offset + 6] << 8) - | (data[offset + 7]) - ); - */ - } - - public static UInt64[] GetUInt64Array(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - var rt = new UInt64[length / 8]; - - for (var i = offset; i < end; i += 8) - rt[j++] = GetUInt64(data, i); - - return rt; - } - - public static unsafe float GetFloat32(this byte[] data, uint offset) - { - float rt = 0; - byte* p = (byte*)&rt; - *p = data[offset + 3]; - *(p + 1) = data[offset + 2]; - *(p + 2) = data[offset + 1]; - *(p + 3) = data[offset]; - return rt; - } - - public static float[] GetFloat32Array(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - var rt = new float[length / 4]; - - for (var i = offset; i < end; i += 4) - rt[j++] = GetFloat32(data, i); - - return rt; - } - - public static unsafe double GetFloat64(this byte[] data, uint offset) - { - double rt = 0; - byte* p = (byte*)&rt; - - *(p + 7) = data[offset++]; - *(p + 6) = data[offset++]; - *(p + 5) = data[offset++]; - *(p + 4) = data[offset++]; - *(p + 3) = data[offset++]; - *(p + 2) = data[offset++]; - *(p + 1) = data[offset++]; - *(p) = data[offset++]; - - return rt; - } - - public static double[] GetFloat64Array(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - var rt = new double[length / 8]; - - for (var i = offset; i < end; i += 8) - rt[j++] = GetFloat64(data, i); - - return rt; - } - - public static bool GetBoolean(this byte[] data, uint offset) - { - return data[offset] > 0; - } - - public static bool[] GetBooleanArray(this byte[] data, uint offset, uint length) - { - var rt = new bool[length]; - for (var i = 0; i < length; i++) - rt[i] = data[offset + i] > 0; - return rt; - } - - public static char GetChar(this byte[] data, uint offset) - { - return Convert.ToChar(((data[offset] << 8) | data[offset + 1])); - } - - public static char[] GetCharArray(this byte[] data, uint offset, uint length) - { - - var j = 0; var end = offset + length; - var rt = new char[length / 2]; - - for (var i = offset; i < end; i += 2) - rt[j++] = GetChar(data, i); - - return rt; - } - - public static string GetString(this byte[] data, uint offset, uint length) - { - return Encoding.UTF8.GetString(data, (int)offset, (int)length); - } - - public static string[] GetStringArray(this byte[] data, uint offset, uint length) - { - List ar = new List(); - - uint i = 0; - - while (i < length) - { - var cl = GetUInt32(data, offset + i); - i += 4; - ar.Add(Encoding.UTF8.GetString(data, (int)(offset + i), (int)cl)); - i += cl; - } - - return ar.ToArray(); - } - - public static Guid GetGuid(this byte[] data, uint offset) - { - return new Guid(Clip(data, offset, 16)); - } - - public static Guid[] GetGuidArray(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - var rt = new Guid[length / 16]; - - for (var i = offset; i < end; i += 16) - rt[j++] = GetGuid(data, i); - - return rt; - } - - public static DateTime GetDateTime(this byte[] data, uint offset) - { - var ticks = GetInt64(data, offset); - return new DateTime(ticks, DateTimeKind.Utc); - } - - public static DateTime[] GetDateTimeArray(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - var rt = new DateTime[length / 8]; - - for (var i = offset; i < end; i += 8) - rt[j++] = GetDateTime(data, i); - - return rt; - } - - public static IPAddress GetIPv4Address(this byte[] data, uint offset) - { - return new IPAddress((long)GetUInt32(data, offset)); - } - - public static IPAddress[] GetIPv4AddressArray(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - var rt = new IPAddress[length / 4]; - - for (var i = offset; i < end; i += 4) - rt[j++] = GetIPv6Address(data, i); - - return rt; - } - - public static IPAddress GetIPv6Address(this byte[] data, uint offset) - { - return new IPAddress(Clip(data, offset, 16)); - } - - public static IPAddress[] GetIPv6AddressArray(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - var rt = new IPAddress[length / 16]; - - for (var i = offset; i < end; i += 16) - rt[j++] = GetIPv6Address(data, i); - - return rt; - - } - - - - public static byte[] Clip(this byte[] data, uint offset, uint length) - { - if (data.Length < offset + length) - return null; - - // if (length == data.Length && offset == 0) - // return data.ToArray(); - - var b = new byte[length]; - Buffer.BlockCopy(data, (int)offset, b, 0, (int)length); - return b; - } - - public static string ToISODateTime(this DateTime date) - { - return date.ToString("yyyy-MM-dd HH:mm:ss"); - } - public static uint ToUnixTime(this DateTime date) - { - return (uint)(date - new DateTime(1970, 1, 1)).TotalSeconds; + Results = default(T); + return false; } } + + public static DateTime FromUnixTime(uint seconds) + { + return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds((double)seconds); + } + + public static DateTime FromUnixTime(ulong milliseconds) + { + return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds((double)milliseconds); + } + + + public static sbyte GetInt8(this byte[] data, uint offset) + { + return (sbyte)data[offset]; + } + + public static sbyte[] GetInt8Array(this byte[] data, uint offset, uint length) + { + var rt = new sbyte[length]; + Buffer.BlockCopy(data, (int)offset, rt, 0, (int)length); + return rt; + } + + public static byte GetUInt8(this byte[] data, uint offset) + { + return data[offset]; + } + + public static byte[] GetUInt8Array(this byte[] data, uint offset, uint length) + { + var rt = new byte[length]; + Buffer.BlockCopy(data, (int)offset, rt, 0, (int)length); + return rt; + } + + public static Int16 GetInt16(this byte[] data, uint offset) + { + return (Int16)((data[offset] << 8) | data[offset + 1]); + } + + public static Int16[] GetInt16Array(this byte[] data, uint offset, uint length) + { + var j = 0; var end = offset + length; + + var rt = new Int16[length / 2]; + for (var i = offset; i < end; i += 2) + rt[j++] = GetInt16(data, i); + + return rt; + } + + public static UInt16 GetUInt16(this byte[] data, uint offset) + { + return (UInt16)((data[offset] << 8) | data[offset + 1]); + } + + public static UInt16[] GetUInt16Array(this byte[] data, uint offset, uint length) + { + var j = 0; var end = offset + length; + var rt = new UInt16[length / 2]; + + for (var i = offset; i < end; i += 2) + rt[j++] = GetUInt16(data, i); + + return rt; + + } + + public static Int32 GetInt32(this byte[] data, uint offset) + { + return (Int32)((data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]); + } + + public static Int32[] GetInt32Array(this byte[] data, uint offset, uint length) + { + var j = 0; var end = offset + length; + + var rt = new Int32[length / 4]; + for (var i = offset; i < end; i += 4) + rt[j++] = GetInt32(data, i); + + return rt; + } + + public static UInt32 GetUInt32(this byte[] data, uint offset) + { + return (UInt32)((data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]); + } + + public static UInt32[] GetUInt32Array(this byte[] data, uint offset, uint length) + { + var j = 0; var end = offset + length; + var rt = new UInt32[length / 4]; + + for (var i = offset; i < end; i += 4) + rt[j++] = GetUInt16(data, i); + + return rt; + } + + + public static unsafe UInt64 GetUInt64(this byte[] data, uint offset) + { + UInt64 rt = 0; + byte* p = (byte*)&rt; + + *(p + 7) = data[offset++]; + *(p + 6) = data[offset++]; + *(p + 5) = data[offset++]; + *(p + 4) = data[offset++]; + *(p + 3) = data[offset++]; + *(p + 2) = data[offset++]; + *(p + 1) = data[offset++]; + *(p) = data[offset++]; + + return rt; + + } + + public static Int64[] GetInt64Array(this byte[] data, uint offset, uint length) + { + var j = 0; var end = offset + length; + var rt = new Int64[length / 8]; + + for (var i = offset; i < end; i += 8) + rt[j++] = GetInt64(data, i); + + return rt; + } + + public static unsafe Int64 GetInt64(this byte[] data, uint offset) + { + Int64 rt = 0; + byte* p = (byte*)&rt; + + *(p + 7) = data[offset++]; + *(p + 6) = data[offset++]; + *(p + 5) = data[offset++]; + *(p + 4) = data[offset++]; + *(p + 3) = data[offset++]; + *(p + 2) = data[offset++]; + *(p + 1) = data[offset++]; + *(p) = data[offset++]; + + return rt; + + /* Or + return (Int64)( + (data[offset] << 56) + | (data[offset + 1] << 48) + | (data[offset + 2] << 40) + | (data[offset + 3] << 32) + | (data[offset + 4] << 24) + | (data[offset + 5] << 16) + | (data[offset + 6] << 8) + | (data[offset + 7]) + ); + */ + } + + public static UInt64[] GetUInt64Array(this byte[] data, uint offset, uint length) + { + var j = 0; var end = offset + length; + var rt = new UInt64[length / 8]; + + for (var i = offset; i < end; i += 8) + rt[j++] = GetUInt64(data, i); + + return rt; + } + + public static unsafe float GetFloat32(this byte[] data, uint offset) + { + float rt = 0; + byte* p = (byte*)&rt; + *p = data[offset + 3]; + *(p + 1) = data[offset + 2]; + *(p + 2) = data[offset + 1]; + *(p + 3) = data[offset]; + return rt; + } + + public static float[] GetFloat32Array(this byte[] data, uint offset, uint length) + { + var j = 0; var end = offset + length; + var rt = new float[length / 4]; + + for (var i = offset; i < end; i += 4) + rt[j++] = GetFloat32(data, i); + + return rt; + } + + public static unsafe double GetFloat64(this byte[] data, uint offset) + { + double rt = 0; + byte* p = (byte*)&rt; + + *(p + 7) = data[offset++]; + *(p + 6) = data[offset++]; + *(p + 5) = data[offset++]; + *(p + 4) = data[offset++]; + *(p + 3) = data[offset++]; + *(p + 2) = data[offset++]; + *(p + 1) = data[offset++]; + *(p) = data[offset++]; + + return rt; + } + + public static double[] GetFloat64Array(this byte[] data, uint offset, uint length) + { + var j = 0; var end = offset + length; + var rt = new double[length / 8]; + + for (var i = offset; i < end; i += 8) + rt[j++] = GetFloat64(data, i); + + return rt; + } + + public static bool GetBoolean(this byte[] data, uint offset) + { + return data[offset] > 0; + } + + public static bool[] GetBooleanArray(this byte[] data, uint offset, uint length) + { + var rt = new bool[length]; + for (var i = 0; i < length; i++) + rt[i] = data[offset + i] > 0; + return rt; + } + + public static char GetChar(this byte[] data, uint offset) + { + return Convert.ToChar(((data[offset] << 8) | data[offset + 1])); + } + + public static char[] GetCharArray(this byte[] data, uint offset, uint length) + { + + var j = 0; var end = offset + length; + var rt = new char[length / 2]; + + for (var i = offset; i < end; i += 2) + rt[j++] = GetChar(data, i); + + return rt; + } + + public static string GetString(this byte[] data, uint offset, uint length) + { + return Encoding.UTF8.GetString(data, (int)offset, (int)length); + } + + public static string[] GetStringArray(this byte[] data, uint offset, uint length) + { + List ar = new List(); + + uint i = 0; + + while (i < length) + { + var cl = GetUInt32(data, offset + i); + i += 4; + ar.Add(Encoding.UTF8.GetString(data, (int)(offset + i), (int)cl)); + i += cl; + } + + return ar.ToArray(); + } + + public static Guid GetGuid(this byte[] data, uint offset) + { + return new Guid(Clip(data, offset, 16)); + } + + public static Guid[] GetGuidArray(this byte[] data, uint offset, uint length) + { + var j = 0; var end = offset + length; + var rt = new Guid[length / 16]; + + for (var i = offset; i < end; i += 16) + rt[j++] = GetGuid(data, i); + + return rt; + } + + public static DateTime GetDateTime(this byte[] data, uint offset) + { + var ticks = GetInt64(data, offset); + return new DateTime(ticks, DateTimeKind.Utc); + } + + public static DateTime[] GetDateTimeArray(this byte[] data, uint offset, uint length) + { + var j = 0; var end = offset + length; + var rt = new DateTime[length / 8]; + + for (var i = offset; i < end; i += 8) + rt[j++] = GetDateTime(data, i); + + return rt; + } + + public static IPAddress GetIPv4Address(this byte[] data, uint offset) + { + return new IPAddress((long)GetUInt32(data, offset)); + } + + public static IPAddress[] GetIPv4AddressArray(this byte[] data, uint offset, uint length) + { + var j = 0; var end = offset + length; + var rt = new IPAddress[length / 4]; + + for (var i = offset; i < end; i += 4) + rt[j++] = GetIPv6Address(data, i); + + return rt; + } + + public static IPAddress GetIPv6Address(this byte[] data, uint offset) + { + return new IPAddress(Clip(data, offset, 16)); + } + + public static IPAddress[] GetIPv6AddressArray(this byte[] data, uint offset, uint length) + { + var j = 0; var end = offset + length; + var rt = new IPAddress[length / 16]; + + for (var i = offset; i < end; i += 16) + rt[j++] = GetIPv6Address(data, i); + + return rt; + + } + + + + public static byte[] Clip(this byte[] data, uint offset, uint length) + { + if (data.Length < offset + length) + return null; + + // if (length == data.Length && offset == 0) + // return data.ToArray(); + + var b = new byte[length]; + Buffer.BlockCopy(data, (int)offset, b, 0, (int)length); + return b; + } + + public static string ToISODateTime(this DateTime date) + { + return date.ToString("yyyy-MM-dd HH:mm:ss"); + } + public static uint ToUnixTime(this DateTime date) + { + return (uint)(date - new DateTime(1970, 1, 1)).TotalSeconds; + } } + + diff --git a/Esiur/Data/DataType.cs b/Esiur/Data/DataType.cs index e3dc564..912b21c 100644 --- a/Esiur/Data/DataType.cs +++ b/Esiur/Data/DataType.cs @@ -28,92 +28,90 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Data +namespace Esiur.Data; +public enum DataType : byte { - public enum DataType : byte - { - Void = 0x0, - //Variant, - Bool, - Int8, - UInt8, - Char, - Int16, - UInt16, - Int32, - UInt32, - Int64, - UInt64, - Float32, - Float64, - Decimal, - DateTime, - Resource, - DistributedResource, - ResourceLink, - String, - Structure, - Record, - //Stream, - //Array = 0x80, - VarArray = 0x80, - BoolArray, - Int8Array, - UInt8Array, - CharArray, - Int16Array, - UInt16Array, - Int32Array, - UInt32Array, - Int64Array, - UInt64Array, - Float32Array, - Float64Array, - DecimalArray, - DateTimeArray, - ResourceArray, - DistributedResourceArray, - ResourceLinkArray, - StringArray, - StructureArray, - RecordArray, - NotModified = 0x7f, - Unspecified = 0xff, - } + Void = 0x0, + //Variant, + Bool, + Int8, + UInt8, + Char, + Int16, + UInt16, + Int32, + UInt32, + Int64, + UInt64, + Float32, + Float64, + Decimal, + DateTime, + Resource, + DistributedResource, + ResourceLink, + String, + Structure, + Record, + //Stream, + //Array = 0x80, + VarArray = 0x80, + BoolArray, + Int8Array, + UInt8Array, + CharArray, + Int16Array, + UInt16Array, + Int32Array, + UInt32Array, + Int64Array, + UInt64Array, + Float32Array, + Float64Array, + DecimalArray, + DateTimeArray, + ResourceArray, + DistributedResourceArray, + ResourceLinkArray, + StringArray, + StructureArray, + RecordArray, + NotModified = 0x7f, + Unspecified = 0xff, +} - public static class DataTypeExpansions +public static class DataTypeExpansions +{ + public static int Size(this DataType t) { - public static int Size(this DataType t) + switch (t) { - switch (t) - { - case DataType.Void: - case DataType.NotModified: - return 0; - case DataType.Bool: - case DataType.UInt8: - case DataType.Int8: - return 1; - case DataType.Char: - case DataType.UInt16: - case DataType.Int16: - return 2; - case DataType.Int32: - case DataType.UInt32: - case DataType.Float32: - case DataType.Resource: - return 4; - case DataType.Int64: - case DataType.UInt64: - case DataType.Float64: - case DataType.DateTime: - return 8; - case DataType.DistributedResource: - return 4; + case DataType.Void: + case DataType.NotModified: + return 0; + case DataType.Bool: + case DataType.UInt8: + case DataType.Int8: + return 1; + case DataType.Char: + case DataType.UInt16: + case DataType.Int16: + return 2; + case DataType.Int32: + case DataType.UInt32: + case DataType.Float32: + case DataType.Resource: + return 4; + case DataType.Int64: + case DataType.UInt64: + case DataType.Float64: + case DataType.DateTime: + return 8; + case DataType.DistributedResource: + return 4; - default: - return -1; - } + default: + return -1; } } } diff --git a/Esiur/Data/IRecord.cs b/Esiur/Data/IRecord.cs index dfba44a..7953491 100644 --- a/Esiur/Data/IRecord.cs +++ b/Esiur/Data/IRecord.cs @@ -2,10 +2,9 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Data -{ - public interface IRecord - { +namespace Esiur.Data; + +public interface IRecord +{ - } } diff --git a/Esiur/Data/IUserType.cs b/Esiur/Data/IUserType.cs index 14dd77f..6485b33 100644 --- a/Esiur/Data/IUserType.cs +++ b/Esiur/Data/IUserType.cs @@ -2,11 +2,10 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Data +namespace Esiur.Data; +public interface IUserType { - public interface IUserType - { - object Get(); - void Set(object value); - } + object Get(); + void Set(object value); } + diff --git a/Esiur/Data/KeyList.cs b/Esiur/Data/KeyList.cs index ce39cbb..c88903d 100644 --- a/Esiur/Data/KeyList.cs +++ b/Esiur/Data/KeyList.cs @@ -33,212 +33,210 @@ using System.Linq; using System.Linq.Expressions; using Esiur.Core; -namespace Esiur.Data +namespace Esiur.Data; + +public class KeyList : IEnumerable> { + private readonly object syncRoot = new object(); + private Dictionary dic; - public class KeyList : IEnumerable> + public delegate void Modified(KT key, T oldValue, T newValue, KeyList sender); + public delegate void Added(T value, KeyList sender); + public delegate void Removed(KT key, T value, KeyList sender); + public delegate void Cleared(KeyList sender); + + public event Modified OnModified; + public event Removed OnRemoved; + public event Cleared OnCleared; + public event Added OnAdd; + + bool removableList; + + public object SyncRoot { - private readonly object syncRoot = new object(); - private Dictionary dic; - - public delegate void Modified(KT key, T oldValue, T newValue, KeyList sender); - public delegate void Added(T value, KeyList sender); - public delegate void Removed(KT key, T value, KeyList sender); - public delegate void Cleared(KeyList sender); - - public event Modified OnModified; - public event Removed OnRemoved; - public event Cleared OnCleared; - public event Added OnAdd; - - bool removableList; - - public object SyncRoot + get { - get - { - return syncRoot; - } + return syncRoot; } + } - public T Take(KT key) + public T Take(KT key) + { + if (dic.ContainsKey(key)) { + var v = dic[key]; + Remove(key); + return v; + } + else + return default(T); + } + + public void Sort(Func, object> keySelector) + { + dic = dic.OrderBy(keySelector).ToDictionary(x => x.Key, x => x.Value); + } + + public T[] ToArray() + { + var a = new T[Count]; + dic.Values.CopyTo(a, 0); + return a; + } + + public void Add(KT key, T value) + { + lock (syncRoot) + { + if (removableList) + if (value != null) + ((IDestructible)value).OnDestroy += ItemDestroyed; + if (dic.ContainsKey(key)) { - var v = dic[key]; - Remove(key); - return v; + var oldValue = dic[key]; + if (removableList) + if (oldValue != null) + ((IDestructible)oldValue).OnDestroy -= ItemDestroyed; + dic[key] = value; + if (OnModified != null) + OnModified(key, oldValue, value, this); } + else + { + dic.Add(key, value); + + if (OnAdd != null) + OnAdd(value, this); + } + } + } + + private void ItemDestroyed(object sender) + { + RemoveValue((T)sender); + } + + public void RemoveValue(T value) + { + var toRemove = new List(); + foreach (var kv in dic) + if (kv.Value.Equals(value)) + toRemove.Add(kv.Key); + + foreach (var k in toRemove) + Remove(k); + } + + public T this[KT key] + { + get + { + if (dic.ContainsKey(key)) + return dic[key]; else return default(T); } - - public void Sort(Func, object> keySelector) + set { - dic = dic.OrderBy(keySelector).ToDictionary(x => x.Key, x => x.Value); + Add(key, value); } + } - public T[] ToArray() + + public IEnumerator> GetEnumerator() + { + return dic.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return dic.GetEnumerator(); + } + + + public void Clear() + { + if (removableList) + foreach (IDestructible v in dic.Values) + if (v != null) + v.OnDestroy -= ItemDestroyed; + + lock (syncRoot) + dic.Clear(); + + if (OnCleared != null) + OnCleared(this); + } + + public Dictionary.KeyCollection Keys + { + get { return dic.Keys; } + } + + public Dictionary.ValueCollection Values + { + get { - var a = new T[Count]; - dic.Values.CopyTo(a, 0); - return a; + return dic.Values; } + } - public void Add(KT key, T value) - { - lock (syncRoot) - { - if (removableList) - if (value != null) - ((IDestructible)value).OnDestroy += ItemDestroyed; + public void Remove(KT key) + { + if (!dic.ContainsKey(key)) + return; - if (dic.ContainsKey(key)) - { - var oldValue = dic[key]; - if (removableList) - if (oldValue != null) - ((IDestructible)oldValue).OnDestroy -= ItemDestroyed; - dic[key] = value; - if (OnModified != null) - OnModified(key, oldValue, value, this); - } - else - { - dic.Add(key, value); + var value = dic[key]; - if (OnAdd != null) - OnAdd(value, this); - } - } - } + if (removableList) + if (value != null) + ((IDestructible)value).OnDestroy -= ItemDestroyed; - private void ItemDestroyed(object sender) - { - RemoveValue((T)sender); - } + lock (syncRoot) + dic.Remove(key); - public void RemoveValue(T value) - { - var toRemove = new List(); - foreach (var kv in dic) - if (kv.Value.Equals(value)) - toRemove.Add(kv.Key); + if (OnRemoved != null) + OnRemoved(key, value, this); + } - foreach (var k in toRemove) - Remove(k); - } + public object Owner + { + get; + set; + } - public T this[KT key] - { - get - { - if (dic.ContainsKey(key)) - return dic[key]; - else - return default(T); - } - set - { - Add(key, value); - } - } - - - public IEnumerator> GetEnumerator() - { - return dic.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return dic.GetEnumerator(); - } + public int Count + { + get { return dic.Count; } + } + public bool Contains(KT Key) + { + return dic.ContainsKey(Key); + } + public bool ContainsKey(KT Key) + { + return dic.ContainsKey(Key); + } + public bool ContainsValue(T Value) + { + return dic.ContainsValue(Value); + } - public void Clear() - { - if (removableList) - foreach (IDestructible v in dic.Values) - if (v != null) - v.OnDestroy -= ItemDestroyed; - - lock (syncRoot) - dic.Clear(); - - if (OnCleared != null) - OnCleared(this); - } - - public Dictionary.KeyCollection Keys - { - get { return dic.Keys; } - } - - public Dictionary.ValueCollection Values - { - get - { - return dic.Values; - } - } - - public void Remove(KT key) - { - if (!dic.ContainsKey(key)) - return; - - var value = dic[key]; - - if (removableList) - if (value != null) - ((IDestructible)value).OnDestroy -= ItemDestroyed; - - lock (syncRoot) - dic.Remove(key); - - if (OnRemoved != null) - OnRemoved(key, value, this); - } - - public object Owner - { - get; - set; - } - - public int Count - { - get { return dic.Count; } - } - public bool Contains(KT Key) - { - return dic.ContainsKey(Key); - } - public bool ContainsKey(KT Key) - { - return dic.ContainsKey(Key); - } - public bool ContainsValue(T Value) - { - return dic.ContainsValue(Value); - } - - - public KeyList(object owner = null) - { - #if NETSTANDARD - removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())); + public KeyList(object owner = null) + { +#if NETSTANDARD + removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())); #else removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T))); #endif - this.Owner = owner; + this.Owner = owner; - if (typeof(KT) == typeof(string)) - dic = (Dictionary)(object)new Dictionary(StringComparer.OrdinalIgnoreCase); - else - dic = new Dictionary(); - } + if (typeof(KT) == typeof(string)) + dic = (Dictionary)(object)new Dictionary(StringComparer.OrdinalIgnoreCase); + else + dic = new Dictionary(); } -} \ No newline at end of file +} diff --git a/Esiur/Data/NotModified.cs b/Esiur/Data/NotModified.cs index 0ae002c..2dfed3d 100644 --- a/Esiur/Data/NotModified.cs +++ b/Esiur/Data/NotModified.cs @@ -28,10 +28,8 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Data +namespace Esiur.Data; +public class NotModified { - public class NotModified - { - } } diff --git a/Esiur/Data/PropertyValue.cs b/Esiur/Data/PropertyValue.cs index 8a52c57..d91d219 100644 --- a/Esiur/Data/PropertyValue.cs +++ b/Esiur/Data/PropertyValue.cs @@ -2,34 +2,33 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Data -{ - public class PropertyValue - { - /// - /// Get or set the value. - /// - public object Value { get; set; } - /// - /// Get or set date of modification or occurrence. - /// - public DateTime Date { get; set; } - /// - /// Get or set property age. - /// - public ulong Age { get; set; } +namespace Esiur.Data; - /// - /// Create an instance of PropertyValue. - /// - /// Value. - /// Age. - /// Date. - public PropertyValue(object value, ulong age, DateTime date) - { - Value = value; - Age = age; - Date = date; - } +public class PropertyValue +{ + /// + /// Get or set the value. + /// + public object Value { get; set; } + /// + /// Get or set date of modification or occurrence. + /// + public DateTime Date { get; set; } + /// + /// Get or set property age. + /// + public ulong Age { get; set; } + + /// + /// Create an instance of PropertyValue. + /// + /// Value. + /// Age. + /// Date. + public PropertyValue(object value, ulong age, DateTime date) + { + Value = value; + Age = age; + Date = date; } } diff --git a/Esiur/Data/Record.cs b/Esiur/Data/Record.cs index aec3495..df6e462 100644 --- a/Esiur/Data/Record.cs +++ b/Esiur/Data/Record.cs @@ -2,10 +2,8 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Data +namespace Esiur.Data; +public class Record : KeyList, IRecord { - public class Record: KeyList, IRecord - { - - } + } diff --git a/Esiur/Data/RecordComparisonResult.cs b/Esiur/Data/RecordComparisonResult.cs index 7318c33..9e78b1b 100644 --- a/Esiur/Data/RecordComparisonResult.cs +++ b/Esiur/Data/RecordComparisonResult.cs @@ -2,13 +2,12 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Data +namespace Esiur.Data; + +public enum RecordComparisonResult : byte { - public enum RecordComparisonResult : byte - { - Null, - Record, - RecordSameType, - Same - } + Null, + Record, + RecordSameType, + Same } diff --git a/Esiur/Data/ResourceArrayType.cs b/Esiur/Data/ResourceArrayType.cs index 3f110d5..7f93b36 100644 --- a/Esiur/Data/ResourceArrayType.cs +++ b/Esiur/Data/ResourceArrayType.cs @@ -2,12 +2,11 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Data +namespace Esiur.Data; + +public enum ResourceArrayType { - public enum ResourceArrayType - { - Dynamic = 0x0, - Static = 0x10, - Wrapper = 0x20, - } + Dynamic = 0x0, + Static = 0x10, + Wrapper = 0x20, } diff --git a/Esiur/Data/ResourceComparisonResult.cs b/Esiur/Data/ResourceComparisonResult.cs index 741a9b5..c173f8c 100644 --- a/Esiur/Data/ResourceComparisonResult.cs +++ b/Esiur/Data/ResourceComparisonResult.cs @@ -2,13 +2,12 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Data +namespace Esiur.Data; + +public enum ResourceComparisonResult { - public enum ResourceComparisonResult - { - Null, // null - Distributed, // resource is distributed - Local, // resource is local - Same, // Same as previous - } + Null, // null + Distributed, // resource is distributed + Local, // resource is local + Same, // Same as previous } diff --git a/Esiur/Data/ResourceJsonConverter.cs b/Esiur/Data/ResourceJsonConverter.cs index c8798cd..d13b132 100644 --- a/Esiur/Data/ResourceJsonConverter.cs +++ b/Esiur/Data/ResourceJsonConverter.cs @@ -1,5 +1,4 @@ -using Esiur.Net.IIP; -using Esiur.Resource; + /* Copyright (c) 2017-2021 Ahmed Kh. Zamil @@ -24,76 +23,77 @@ SOFTWARE. */ +using Esiur.Net.IIP; +using Esiur.Resource; using System; using System.Collections.Generic; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; -namespace Esiur.Data +namespace Esiur.Data; + +class ResourceJsonConverter : JsonConverter { - class ResourceJsonConverter : JsonConverter + public override IResource Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options) { - public override IResource Read( - ref Utf8JsonReader reader, - Type typeToConvert, - JsonSerializerOptions options) - { - return (IResource)JsonSerializer.Deserialize(ref reader,typeof(IResource), options); - } - - - public override void Write( - Utf8JsonWriter writer, - IResource resource, - JsonSerializerOptions options) - { - - writer.WriteStartObject(); - - foreach (var pt in resource.Instance.Template.Properties) - { - var rt = pt.PropertyInfo.GetValue(resource, null); - if (rt is DistributedPropertyContext) - continue; - - writer.WritePropertyName(options.PropertyNamingPolicy?.ConvertName(pt.Name) ?? pt.Name); - - if (rt is IResource) - JsonSerializer.Serialize(writer, (IResource) rt, options); - else - JsonSerializer.Serialize(writer, rt, options); - } - - writer.WriteEndObject(); - - } + return (IResource)JsonSerializer.Deserialize(ref reader, typeof(IResource), options); } - public class DoubleJsonConverter : JsonConverter + public override void Write( + Utf8JsonWriter writer, + IResource resource, + JsonSerializerOptions options) { - public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType == JsonTokenType.String && reader.GetString() == "NaN") - { - return double.NaN; - } - return reader.GetDouble(); // JsonException thrown if reader.TokenType != JsonTokenType.Number - } + writer.WriteStartObject(); - public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOptions options) + foreach (var pt in resource.Instance.Template.Properties) { - if (double.IsNaN(value)) - { - writer.WriteStringValue("NaN"); - } + var rt = pt.PropertyInfo.GetValue(resource, null); + if (rt is DistributedPropertyContext) + continue; + + writer.WritePropertyName(options.PropertyNamingPolicy?.ConvertName(pt.Name) ?? pt.Name); + + if (rt is IResource) + JsonSerializer.Serialize(writer, (IResource)rt, options); else - { - writer.WriteNumberValue(value); - } + JsonSerializer.Serialize(writer, rt, options); } + + writer.WriteEndObject(); + + } +} + + +public class DoubleJsonConverter : JsonConverter +{ + public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String && reader.GetString() == "NaN") + { + return double.NaN; + } + + return reader.GetDouble(); // JsonException thrown if reader.TokenType != JsonTokenType.Number } + public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOptions options) + { + if (double.IsNaN(value)) + { + writer.WriteStringValue("NaN"); + } + else + { + writer.WriteNumberValue(value); + } + } } + diff --git a/Esiur/Data/ResourceList.cs b/Esiur/Data/ResourceList.cs index cb8e5f2..c5bb77c 100644 --- a/Esiur/Data/ResourceList.cs +++ b/Esiur/Data/ResourceList.cs @@ -30,245 +30,244 @@ using System.Collections; using Esiur.Core; using System.Reflection; -namespace Esiur.Data +namespace Esiur.Data; + +public class ResourceList : IEnumerable, ICollection, ICollection { - public class ResourceList : IEnumerable, ICollection, ICollection + + private readonly object syncRoot = new object(); + private List list = new List(); + + public delegate void Modified(ST sender, int index, T oldValue, T newValue); + public delegate void Added(ST sender, T value); + public delegate void Removed(ST sender, int index, T value); + public delegate void Cleared(ST sender); + + + public event Modified OnModified; + public event Removed OnRemoved; + public event Cleared OnCleared; + public event Added OnAdd; + + ST state; + + public void Sort() { + list.Sort(); + } - private readonly object syncRoot = new object(); - private List list = new List(); + public void Sort(IComparer comparer) + { + list.Sort(comparer); + } - public delegate void Modified(ST sender, int index, T oldValue, T newValue); - public delegate void Added(ST sender, T value); - public delegate void Removed(ST sender, int index, T value); - public delegate void Cleared(ST sender); + public void Sort(Comparison comparison) + { + list.Sort(comparison); + } + public IEnumerable Where(Func predicate) + { + return list.Where(predicate); + } - public event Modified OnModified; - public event Removed OnRemoved; - public event Cleared OnCleared; - public event Added OnAdd; + /// + /// Convert AutoList to array + /// + /// Array + public T[] ToArray() + { + // list.OrderBy() + return list.ToArray(); + } - ST state; + /// + /// Create a new instance of AutoList + /// + /// State object to be included when an event is raised. + public ResourceList(ST state) + { + this.state = state; + } - public void Sort() + /// + /// Create a new instance of AutoList + /// + /// Populate the list with items + /// + public ResourceList(ST state, T[] values) + { + this.state = state; + AddRange(values); + } + + /// + /// Synchronization lock of the list + /// + public object SyncRoot + { + get { - list.Sort(); - } - - public void Sort(IComparer comparer) - { - list.Sort(comparer); - } - - public void Sort(Comparison comparison) - { - list.Sort(comparison); - } - - public IEnumerable Where(Func predicate) - { - return list.Where(predicate); - } - - /// - /// Convert AutoList to array - /// - /// Array - public T[] ToArray() - { - // list.OrderBy() - return list.ToArray(); - } - - /// - /// Create a new instance of AutoList - /// - /// State object to be included when an event is raised. - public ResourceList(ST state) - { - this.state = state; - } - - /// - /// Create a new instance of AutoList - /// - /// Populate the list with items - /// - public ResourceList(ST state, T[] values) - { - this.state = state; - AddRange(values); - } - - /// - /// Synchronization lock of the list - /// - public object SyncRoot - { - get - { - return syncRoot; - } - } - - /// - /// First item in the list - /// - public T First() - { - return list.First(); - } - - /// - /// Get an item at a specified index - /// - public T this[int index] - { - get - { - return list[index]; - } - set - { - var oldValue = list[index]; - - lock (syncRoot) - list[index] = value; - - OnModified?.Invoke(state, index, oldValue, value); - } - } - - /// - /// Add item to the list - /// - public void Add(T value) - { - lock (syncRoot) - list.Add(value); - - OnAdd?.Invoke(state, value); - } - - /// - /// Add an array of items to the list - /// - public void AddRange(T[] values) - { - foreach (var v in values) - Add(v); - } - - private void ItemDestroyed(object sender) - { - Remove((T)sender); - } - - /// - /// Clear the list - /// - public void Clear() - { - - lock (syncRoot) - list.Clear(); - - OnCleared?.Invoke(state); - } - - /// - /// Remove an item from the list - /// Item to remove - /// - public void Remove(T value) - { - var index = 0; - - lock (syncRoot) - { - index = list.IndexOf(value); - - if (index == -1) - return; - - list.RemoveAt(index); - - - } - - OnRemoved?.Invoke(state, index, value); - } - - /// - /// Number of items in the list - /// - public int Count - { - get { return list.Count; } - } - - public bool IsSynchronized => (list as ICollection).IsSynchronized; - - public bool IsReadOnly => throw new NotImplementedException(); - - - /// - /// Check if an item exists in the list - /// - /// Item to check if exists - public bool Contains(T value) - { - return list.Contains(value); - } - - /// - /// Check if any item of the given array is in the list - /// - /// Array of items - public bool ContainsAny(T[] values) - { - foreach (var v in values) - if (list.Contains(v)) - return true; - return false; - } - - /// - /// Check if any item of the given list is in the list - /// - /// List of items - public bool ContainsAny(AutoList values) - { - foreach (var v in values) - if (list.Contains((T)v)) - return true; - return false; - } - - public IEnumerator GetEnumerator() - { - return ((IEnumerable)list).GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IEnumerable)list).GetEnumerator(); - } - - public void CopyTo(Array array, int index) - { - (list as ICollection).CopyTo(array, index); - } - - public void CopyTo(T[] array, int arrayIndex) - { - list.CopyTo(array, arrayIndex); - } - - bool ICollection.Remove(T item) - { - return list.Remove(item); + return syncRoot; } } + + /// + /// First item in the list + /// + public T First() + { + return list.First(); + } + + /// + /// Get an item at a specified index + /// + public T this[int index] + { + get + { + return list[index]; + } + set + { + var oldValue = list[index]; + + lock (syncRoot) + list[index] = value; + + OnModified?.Invoke(state, index, oldValue, value); + } + } + + /// + /// Add item to the list + /// + public void Add(T value) + { + lock (syncRoot) + list.Add(value); + + OnAdd?.Invoke(state, value); + } + + /// + /// Add an array of items to the list + /// + public void AddRange(T[] values) + { + foreach (var v in values) + Add(v); + } + + private void ItemDestroyed(object sender) + { + Remove((T)sender); + } + + /// + /// Clear the list + /// + public void Clear() + { + + lock (syncRoot) + list.Clear(); + + OnCleared?.Invoke(state); + } + + /// + /// Remove an item from the list + /// Item to remove + /// + public void Remove(T value) + { + var index = 0; + + lock (syncRoot) + { + index = list.IndexOf(value); + + if (index == -1) + return; + + list.RemoveAt(index); + + + } + + OnRemoved?.Invoke(state, index, value); + } + + /// + /// Number of items in the list + /// + public int Count + { + get { return list.Count; } + } + + public bool IsSynchronized => (list as ICollection).IsSynchronized; + + public bool IsReadOnly => throw new NotImplementedException(); + + + /// + /// Check if an item exists in the list + /// + /// Item to check if exists + public bool Contains(T value) + { + return list.Contains(value); + } + + /// + /// Check if any item of the given array is in the list + /// + /// Array of items + public bool ContainsAny(T[] values) + { + foreach (var v in values) + if (list.Contains(v)) + return true; + return false; + } + + /// + /// Check if any item of the given list is in the list + /// + /// List of items + public bool ContainsAny(AutoList values) + { + foreach (var v in values) + if (list.Contains((T)v)) + return true; + return false; + } + + public IEnumerator GetEnumerator() + { + return ((IEnumerable)list).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)list).GetEnumerator(); + } + + public void CopyTo(Array array, int index) + { + (list as ICollection).CopyTo(array, index); + } + + public void CopyTo(T[] array, int arrayIndex) + { + list.CopyTo(array, arrayIndex); + } + + bool ICollection.Remove(T item) + { + return list.Remove(item); + } } diff --git a/Esiur/Data/StringKeyList.cs b/Esiur/Data/StringKeyList.cs index 9e76af8..6d5f0f1 100644 --- a/Esiur/Data/StringKeyList.cs +++ b/Esiur/Data/StringKeyList.cs @@ -31,190 +31,189 @@ using System.Text; using System.Reflection; using System.Linq; -namespace Esiur.Data +namespace Esiur.Data; + + +public class StringKeyList : IEnumerable> { - public class StringKeyList : IEnumerable> + //private List m_keys = new List(); + //private List m_values = new List(); + + private List> m_Variables = new List>(); + + private bool allowMultiple; + + public delegate void Modified(string Key, string NewValue); + public event Modified OnModified; + + public StringKeyList(bool AllowMultipleValues = false) { - - //private List m_keys = new List(); - //private List m_values = new List(); + allowMultiple = AllowMultipleValues; + } - private List> m_Variables = new List>(); + public void Add(string Key, string Value) + { + if (OnModified != null) + OnModified(Key, Value); - private bool allowMultiple; + var key = Key.ToLower(); - public delegate void Modified(string Key, string NewValue); - public event Modified OnModified; - - public StringKeyList(bool AllowMultipleValues = false) + if (!allowMultiple) { - allowMultiple = AllowMultipleValues; - } - - public void Add(string Key, string Value) - { - if (OnModified != null) - OnModified(Key, Value); - - var key = Key.ToLower(); - - if (!allowMultiple) - { - foreach(var kv in m_Variables) - { - if (kv.Key.ToLower() == key) - { - m_Variables.Remove(kv); - break; - } - } - } - - m_Variables.Add(new KeyValuePair(Key, Value)); - } - - public string this[string Key] - { - get - { - var key = Key.ToLower(); - foreach (var kv in m_Variables) - if (kv.Key.ToLower() == key) - return kv.Value; - - return null; - } - set - { - var key = Key.ToLower(); - - var toRemove = m_Variables.Where(x => x.Key.ToLower() == key).ToArray(); - - foreach (var item in toRemove) - m_Variables.Remove(item); - - - m_Variables.Add(new KeyValuePair(Key, value)); - - OnModified?.Invoke(Key, value); - - } - } - - IEnumerator> IEnumerable>.GetEnumerator() - { - //return m_keys.GetEnumerator(); - return m_Variables.GetEnumerator(); - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return m_Variables.GetEnumerator(); - } - - public void Clear() - { - if (OnModified != null) - OnModified(null, null); - - m_Variables.Clear(); - - } - - /* - public string[] Keys - { - get - { - return m_keys.ToArray(); - } - } - - - //public Dictionary.ValueCollection Values - public string[] Values - { - get - { - //return m_Variables.Values; - return m_values.ToArray(); - } - } - */ - - public List GetValues(string Key) - { - var key = Key.ToLower(); - - List values = new List(); - foreach (var kv in m_Variables) - if (kv.Key.ToLower() == key) - values.Add(kv.Value); - - return values; - } - - public void RemoveAll(string Key) - { - while (Remove(Key)){} - } - - public bool Remove(string Key) - { - var key = Key.ToLower(); - - foreach(var kv in m_Variables) { if (kv.Key.ToLower() == key) { - if (OnModified != null) - OnModified(Key, null); m_Variables.Remove(kv); - return true; + break; } } - - return false; } - public int Count - { - get { return m_Variables.Count; } - } - - public bool ContainsKey(string Key) + m_Variables.Add(new KeyValuePair(Key, Value)); + } + + public string this[string Key] + { + get { var key = Key.ToLower(); foreach (var kv in m_Variables) if (kv.Key.ToLower() == key) - return true; - return false; - } + return kv.Value; - /* - public bool ContainsKey(string Key) + return null; + } + set { - //return m_Variables.ContainsKey(Key); - return m_keys.Contains(Key.ToLower()); - } - */ + var key = Key.ToLower(); - public bool ContainsValue(string Value) - { - var value = Value.ToLower(); - foreach (var kv in m_Variables) - if (kv.Value.ToLower() == value) - return true; - return false; - } + var toRemove = m_Variables.Where(x => x.Key.ToLower() == key).ToArray(); - //internal KeyList() - //{ - // m_Session = Session; - // m_Server = Server; - //} + foreach (var item in toRemove) + m_Variables.Remove(item); + + + m_Variables.Add(new KeyValuePair(Key, value)); + + OnModified?.Invoke(Key, value); + + } + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + //return m_keys.GetEnumerator(); + return m_Variables.GetEnumerator(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return m_Variables.GetEnumerator(); + } + + public void Clear() + { + if (OnModified != null) + OnModified(null, null); + + m_Variables.Clear(); } + + /* + public string[] Keys + { + get + { + return m_keys.ToArray(); + } + } + + + //public Dictionary.ValueCollection Values + public string[] Values + { + get + { + //return m_Variables.Values; + return m_values.ToArray(); + } + } + */ + + public List GetValues(string Key) + { + var key = Key.ToLower(); + + List values = new List(); + + foreach (var kv in m_Variables) + if (kv.Key.ToLower() == key) + values.Add(kv.Value); + + return values; + } + + public void RemoveAll(string Key) + { + while (Remove(Key)) { } + } + + public bool Remove(string Key) + { + var key = Key.ToLower(); + + foreach (var kv in m_Variables) + { + if (kv.Key.ToLower() == key) + { + if (OnModified != null) + OnModified(Key, null); + m_Variables.Remove(kv); + return true; + } + } + + return false; + } + + public int Count + { + get { return m_Variables.Count; } + } + + public bool ContainsKey(string Key) + { + var key = Key.ToLower(); + foreach (var kv in m_Variables) + if (kv.Key.ToLower() == key) + return true; + return false; + } + + /* + public bool ContainsKey(string Key) + { + //return m_Variables.ContainsKey(Key); + return m_keys.Contains(Key.ToLower()); + } + */ + + public bool ContainsValue(string Value) + { + var value = Value.ToLower(); + foreach (var kv in m_Variables) + if (kv.Value.ToLower() == value) + return true; + return false; + } + + //internal KeyList() + //{ + // m_Session = Session; + // m_Server = Server; + //} + } \ No newline at end of file diff --git a/Esiur/Data/Structure.cs b/Esiur/Data/Structure.cs index bf677d1..72729c4 100644 --- a/Esiur/Data/Structure.cs +++ b/Esiur/Data/Structure.cs @@ -34,148 +34,147 @@ using Esiur.Core; using System.Reflection; using System.Dynamic; -namespace Esiur.Data +namespace Esiur.Data; + +public class Structure : IEnumerable> { - public class Structure : IEnumerable> + + public struct StructureMetadata + { + public string[] Keys; + public DataType[] Types; + } + + private Dictionary dic = new Dictionary(StringComparer.OrdinalIgnoreCase); + private object syncRoot = new object(); + + + public bool ContainsKey(string key) + { + return dic.ContainsKey(key); + } + + public override string ToString() + { + var rt = ""; + foreach (var kv in dic) + rt += kv.Key + ": " + kv.Value.ToString() + " \r\n"; + + return rt.TrimEnd('\r', '\n'); + } + + public Structure(Structure source) + { + dic = source.dic; + } + public Structure() { - public struct StructureMetadata - { - public string[] Keys; - public DataType[] Types; - } - - private Dictionary dic = new Dictionary(StringComparer.OrdinalIgnoreCase); - private object syncRoot = new object(); - - - public bool ContainsKey(string key) - { - return dic.ContainsKey(key); - } - - public override string ToString() - { - var rt = ""; - foreach (var kv in dic) - rt += kv.Key + ": " + kv.Value.ToString() + " \r\n"; - - return rt.TrimEnd('\r', '\n'); - } - - public Structure(Structure source) - { - dic = source.dic; - } - public Structure() - { - - } - - public static Structure FromStructure(Structure source, Type destinationType) - { - var rt = Activator.CreateInstance(destinationType) as Structure; - rt.dic = source.dic; - return rt; - } - - public static T FromStructure(Structure source) where T : Structure - { - var rt = Activator.CreateInstance(); - rt.dic = source.dic; - return rt; - } - - public static explicit operator Structure(ExpandoObject obj) => FromDynamic(obj); - - public static Structure FromDynamic(ExpandoObject obj) - { - var rt = new Structure(); - foreach (var kv in obj) - rt[kv.Key] = kv.Value; - return rt; - } - - public static Structure FromObject(object obj) - { - var type = obj.GetType(); - - if (obj is Structure) - return obj as Structure; - else //if (Codec.IsAnonymous(type)) - { - var st = new Structure(); - - var pi = type.GetTypeInfo().GetProperties().Where(x=>x.CanRead); - foreach (var p in pi) - st[p.Name] = p.GetValue(obj); - - var fi = type.GetTypeInfo().GetFields().Where(x => x.IsPublic); - foreach (var f in fi) - st[f.Name] = f.GetValue(obj); - - return st; - } - //else - // return null; - } - public IEnumerator> GetEnumerator() - { - return dic.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return dic.GetEnumerator(); - } - - public int Length - { - get { return dic.Count; } - } - - public KeyValuePair At(int index) - { - return dic.ElementAt(index); - } - - public object SyncRoot - { - get { return syncRoot; } - } - - public string[] GetKeys() => dic.Keys.ToArray();//GetKeys() - //{ - // return dic.Keys.ToArray(); - //} - - public Structure Add(string key, object value) - { - if (dic.ContainsKey(key)) - dic[key] = value; - else - dic.Add(key, value); - - return this; - } - - public object this[string index] - { - get - { - if (dic.ContainsKey(index)) - return dic[index]; - else - return null; - } - set - { - if (dic.ContainsKey(index)) - dic[index] = value; - else - dic.Add(index, value); - } - } - } + + public static Structure FromStructure(Structure source, Type destinationType) + { + var rt = Activator.CreateInstance(destinationType) as Structure; + rt.dic = source.dic; + return rt; + } + + public static T FromStructure(Structure source) where T : Structure + { + var rt = Activator.CreateInstance(); + rt.dic = source.dic; + return rt; + } + + public static explicit operator Structure(ExpandoObject obj) => FromDynamic(obj); + + public static Structure FromDynamic(ExpandoObject obj) + { + var rt = new Structure(); + foreach (var kv in obj) + rt[kv.Key] = kv.Value; + return rt; + } + + public static Structure FromObject(object obj) + { + var type = obj.GetType(); + + if (obj is Structure) + return obj as Structure; + else //if (Codec.IsAnonymous(type)) + { + var st = new Structure(); + + var pi = type.GetTypeInfo().GetProperties().Where(x => x.CanRead); + foreach (var p in pi) + st[p.Name] = p.GetValue(obj); + + var fi = type.GetTypeInfo().GetFields().Where(x => x.IsPublic); + foreach (var f in fi) + st[f.Name] = f.GetValue(obj); + + return st; + } + //else + // return null; + } + public IEnumerator> GetEnumerator() + { + return dic.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return dic.GetEnumerator(); + } + + public int Length + { + get { return dic.Count; } + } + + public KeyValuePair At(int index) + { + return dic.ElementAt(index); + } + + public object SyncRoot + { + get { return syncRoot; } + } + + public string[] GetKeys() => dic.Keys.ToArray();//GetKeys() + //{ + // return dic.Keys.ToArray(); + //} + + public Structure Add(string key, object value) + { + if (dic.ContainsKey(key)) + dic[key] = value; + else + dic.Add(key, value); + + return this; + } + + public object this[string index] + { + get + { + if (dic.ContainsKey(index)) + return dic[index]; + else + return null; + } + set + { + if (dic.ContainsKey(index)) + dic[index] = value; + else + dic.Add(index, value); + } + } + } diff --git a/Esiur/Data/StructureComparisonResult.cs b/Esiur/Data/StructureComparisonResult.cs index c76d973..6d150ad 100644 --- a/Esiur/Data/StructureComparisonResult.cs +++ b/Esiur/Data/StructureComparisonResult.cs @@ -2,14 +2,13 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Data +namespace Esiur.Data; + +public enum StructureComparisonResult : byte { - public enum StructureComparisonResult : byte - { - Null, - Structure, - StructureSameKeys, - StructureSameTypes, - Same - } + Null, + Structure, + StructureSameKeys, + StructureSameTypes, + Same } diff --git a/Esiur/Esiur.csproj b/Esiur/Esiur.csproj index f3223ef..0ca824f 100644 --- a/Esiur/Esiur.csproj +++ b/Esiur/Esiur.csproj @@ -4,20 +4,20 @@ netstandard2.0 Distributed Resources Platform Ahmed Kh. Zamil - https://github.com/Esiur/Esiur-dotnet/blob/master/LICENSE - http://www.esiur.com + http://www.esiur.com true - 1.8.8 + 2.0.0-alpha https://github.com/esiur/esiur-dotnet Ahmed Kh. Zamil - 1.8.8.0 + 2.0.0.0 Esiur Foundation - 1.8.8.0 + 2.0.0.0 Esiur Esiur Esiur Esiur - 9.0 + latest + LICENSE @@ -79,10 +79,13 @@ - - + + + + + \ No newline at end of file diff --git a/Esiur/LICENSE b/Esiur/LICENSE new file mode 100644 index 0000000..5018e9d --- /dev/null +++ b/Esiur/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017-2021 Esiur Foundation, Ahmed Kh. Zamil. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Esiur/Misc/Global.cs b/Esiur/Misc/Global.cs index bc5a7b7..ba3cd54 100644 --- a/Esiur/Misc/Global.cs +++ b/Esiur/Misc/Global.cs @@ -42,449 +42,448 @@ using System.Text.Json; using Esiur.Resource; using System.Text.Json.Serialization; -namespace Esiur.Misc +namespace Esiur.Misc; +public static class Global { - public static class Global + private static KeyList variables = new KeyList(); + // private static Hashtable m_Cached = new Hashtable(); + //internal static bool SystemIsWorking = false; + + private static Random rand = new Random(System.Environment.TickCount); + + //public static Encoding DefaultEncoding = Encoding.GetEncoding(1252);// .GetEncoding("windows-1252"); + + public static KeyList Counters = new KeyList(); + + public delegate void LogEvent(string service, LogType type, string message); + + public static event LogEvent SystemLog; + + + public static string ToJson(this IResource resource) { - private static KeyList variables = new KeyList(); - // private static Hashtable m_Cached = new Hashtable(); - //internal static bool SystemIsWorking = false; - - private static Random rand = new Random(System.Environment.TickCount); - - //public static Encoding DefaultEncoding = Encoding.GetEncoding(1252);// .GetEncoding("windows-1252"); - - public static KeyList Counters = new KeyList(); - - public delegate void LogEvent(string service, LogType type, string message); - - public static event LogEvent SystemLog; - - - public static string ToJson(this IResource resource) + try { - try - { - return JsonSerializer.Serialize(resource, Global.SerializeOptions); - }catch (Exception ex) - { - Console.WriteLine(ex.ToString()); - return "{}"; - } + return JsonSerializer.Serialize(resource, Global.SerializeOptions); } - - public static JsonSerializerOptions SerializeOptions = new JsonSerializerOptions + catch (Exception ex) { - ReferenceHandler = ReferenceHandler.Preserve, - WriteIndented = true, - Converters = + Console.WriteLine(ex.ToString()); + return "{}"; + } + } + + public static JsonSerializerOptions SerializeOptions = new JsonSerializerOptions + { + ReferenceHandler = ReferenceHandler.Preserve, + WriteIndented = true, + Converters = { new ResourceJsonConverter(), new DoubleJsonConverter() } - }; + }; - public static string Version { get; }= FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion; + public static string Version { get; } = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion; - //FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location); - // string version = fvi.FileVersion; + //FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location); + // string version = fvi.FileVersion; - /* - public static char GetDirectorySeparator() - { - return System.IO.Path.DirectorySeparatorChar; - } - */ - - public static void Log(Exception ex, params object[] arguments) - { - try - { - - - var stack = new StackTrace(ex, true); - var frame = stack.GetFrames().First(); - var method = frame.GetMethod(); - var parameters = method.GetParameters(); - var service = method.DeclaringType.Name; - var message = ""; - - if (arguments.Length > 0 && parameters.Length > 0) - { - message = "Arguments ( "; - - for (int i = 0; i < parameters.Length && i < arguments.Length; i++) - { - message += parameters[i].Name + ": " + arguments[i].ToString() + " "; - } - - message += ")" + Environment.NewLine + "------------------------------------------------"; - } - - message += ex.ToString(); - - Log(service, LogType.Error, message); - - - - Log(service, LogType.Error, ex.ToString()); - - } - catch - { - - } - } - - public static void Log(string service, LogType type, string message, bool appendHeader = true) - { - //if (type != LogType.Debug) - Console.WriteLine(service + " " + message); - - SystemLog?.Invoke(service, type, message); - } - - /* - public static string GetTempPath() - { - return System.IO.Path.GetTempPath(); - } - */ - - public static string RemoveControlCharacters(string inString) - { - if (inString == null) return null; - - StringBuilder newString = new StringBuilder(); - char ch; - - for (int i = 0; i < inString.Length; i++) - { - - ch = inString[i]; - - if (!char.IsControl(ch)) - { - newString.Append(ch); - } - } - return newString.ToString(); - } - - public static void PrintCounters() - { - string[] keys = new string[Counters.Keys.Count]; - Counters.Keys.CopyTo(keys, 0); - - foreach (string k in keys) - { - Console.WriteLine(k + ":" + Counters[k]); - } - } -// Encoding ANSI = Encoding.GetEncoding(1252); - - /* - public static Hashtable Cached - { - get - { - return m_Cached; - } - }*/ - - /* - public static string ByteArrayToMAC(byte[] array) - { - string rt=""; - - if (array == null) - return "00:00:00:00:00:00"; - else - { - //for (int i = 0; i < array.Length - 1; i++) - // rt += Convert.ToString(array[i], 16) + ":"; - - //rt += Convert.ToString(array[array.Length - 1], 16); - - rt = BitConverter.ToString(array); - rt = rt.Replace('-', ':'); - return rt; - } - - } - */ - - - - /* - public static string IPAddressFromInt32(UInt32 IP) - { - //var dIP = DC.ToBytes(IP); - - return (IP >> 24) + "." + ((IP >> 16) & 0xFF) + "." + ((IP >> 8) & 0xFF) + "." + (IP & 0xFF); - } - */ - - public static KeyList Variables - { - get - { - return variables; - } - } - - - public static uint CurrentUnixTime() - { - return (uint)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; - } - - public static void SetConsoleColors(ConsoleColor ForegroundColor, ConsoleColor BackgroundColor) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - switch (ForegroundColor) - { - case ConsoleColor.Black: - Console.Write("\u001B[30m"); - break; - case ConsoleColor.Blue: - Console.Write("\u001B[1;34m"); - break; - case ConsoleColor.Cyan: - Console.Write("\u001B[1;36m"); - break; - case ConsoleColor.Gray: - case ConsoleColor.DarkGray: - Console.Write("\u001B[1;30m"); - break; - case ConsoleColor.Green: - Console.Write("\u001B[1;32m"); - break; - case ConsoleColor.Magenta: - Console.Write("\u001B[1;35m"); - break; - case ConsoleColor.Red: - Console.Write("\u001B[1;31m"); - break; - case ConsoleColor.White: - Console.Write("\u001B[1;37m"); - break; - case ConsoleColor.Yellow: - Console.Write("\u001B[1;33m"); - break; - - case ConsoleColor.DarkBlue: - Console.Write("\u001B[34m"); - break; - case ConsoleColor.DarkCyan: - Console.Write("\u001B[36m"); - break; - case ConsoleColor.DarkGreen: - Console.Write("\u001B[32m"); - break; - case ConsoleColor.DarkMagenta: - Console.Write("\u001B[35m"); - break; - case ConsoleColor.DarkRed: - Console.Write("\u001B[31m"); - break; - case ConsoleColor.DarkYellow: - Console.Write("\u001B[33m"); - break; - } - - - switch (BackgroundColor) - { - case ConsoleColor.Black: - Console.Write("\u001B[40m"); - break; - case ConsoleColor.Blue: - Console.Write("\u001B[1;44m"); - break; - case ConsoleColor.Cyan: - Console.Write("\u001B[1;46m"); - break; - case ConsoleColor.Gray: - case ConsoleColor.DarkGray: - Console.Write("\u001B[1;40m"); - break; - case ConsoleColor.Green: - Console.Write("\u001B[1;42m"); - break; - case ConsoleColor.Magenta: - Console.Write("\u001B[1;45m"); - break; - case ConsoleColor.Red: - Console.Write("\u001B[1;41m"); - break; - case ConsoleColor.White: - Console.Write("\u001B[1;47m"); - break; - case ConsoleColor.Yellow: - Console.Write("\u001B[1;43m"); - break; - - case ConsoleColor.DarkBlue: - Console.Write("\u001B[44m"); - break; - case ConsoleColor.DarkCyan: - Console.Write("\u001B[46m"); - break; - case ConsoleColor.DarkGreen: - Console.Write("\u001B[42m"); - break; - case ConsoleColor.DarkMagenta: - Console.Write("\u001B[45m"); - break; - case ConsoleColor.DarkRed: - Console.Write("\u001B[41m"); - break; - case ConsoleColor.DarkYellow: - Console.Write("\u001B[43m"); - break; - } - } - else - { - Console.ForegroundColor = ForegroundColor; - Console.BackgroundColor = BackgroundColor; - } - } - - public static string GetUserPart(string strAddress) - { - return strAddress.Substring(0, strAddress.IndexOf("@", 0)); - } - - public static byte[][] GetBytesFromChunk(byte[] Data, int ChunkSize) - { - if (ChunkSize == 1) - { - byte[][] ar = new byte[0][]; - int ptr = 0; - while (ptr < Data.Length) - { - Array.Resize(ref ar, ar.Length + 1); - ar[ar.Length - 1] = new byte[Data[ptr]]; - Buffer.BlockCopy(Data, ++ptr, ar[ar.Length - 1], 0, Data[ptr]); - ptr += Data[ptr] + 1; - } - return ar; - } - return null; - } - - - - - - public static string GetFileTitle(string Filename) - { - string[] s = Filename.Split(Path.DirectorySeparatorChar); - return s[s.Length - 1]; - } - - public static string GetNewFileName(string FileDir) - { - string tempGetNewFileName = null; - short i = 0; - string NewFile = null; - NewFile = FileDir; - Begin: - FileInfo FF = new FileInfo(NewFile); - if (FF.Exists) - { - //If FSO.FileExists(NewFile) Then - i++; //= i + 1; - NewFile = FileDir.Substring(0, FileDir.Length - 4) + "_" + i + "." + FileDir.Substring(FileDir.Length - 3); - goto Begin; - } - else - { - tempGetNewFileName = NewFile; - } - return tempGetNewFileName; - } - - ///////////////////////////////////// - public static string TrimEx(string strIn) - { - return strIn.Replace("\r", "").Replace("\n", ""); - } - - /* - public static bool IsUnix() - { - // Linux OSs under Mono 1.2 uses unknown integer numbers so this should identify all non windows as unix - return (Environment.OSVersion.Platform != PlatformID.Win32NT - && Environment.OSVersion.Platform != PlatformID.Win32Windows); // || Environment.OSVersion.Platform == PlatformID.Linux; - } - */ - - public static string GenerateCode() - { - return GenerateCode(16); - } - - - - public static byte[] GenerateBytes(int length) - { - var b = new byte[length]; - rand.NextBytes(b); - return b; - } - - public static string GenerateCode(int length) - { - return GenerateCode(length, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");// ~!@#$%^&*()_-+=\\?/"); - } - - public static string GenerateCode(int length, string chars) - //public static string GenerateCode(int Length) - { - //var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~!@#$%^&*()_-+=\\?/"; - var result = new string( - Enumerable.Repeat(chars, length) - .Select(s => s[rand.Next(s.Length)]) - .ToArray()); - //if (result.Length < length) - // Console.WriteLine(); - return result; - /* - int len = 0; - string code = ""; - - while(len < Length) - { - var c = Convert.ToChar((byte)(rand.NextDouble() * 255)); - if (Char.IsLetterOrDigit(c)) - { - code += c; - len++; - } - } - - return code; - */ - } - - public static string ReplaceOnce(string Expression, string Find, string Replacement) - { - int pos = Expression.IndexOf(Find); - if (pos != -1) - return Expression.Substring(0, pos) + Replacement + Expression.Substring(pos + Find.Length); - else - return Expression; - } - //public void Replace(string Expression, string Find, string Replacement, int Start, int Count) - //{ - // Expression.IndexOf( - //} + /* + public static char GetDirectorySeparator() + { + return System.IO.Path.DirectorySeparatorChar; } -} \ No newline at end of file + */ + + public static void Log(Exception ex, params object[] arguments) + { + try + { + + + var stack = new StackTrace(ex, true); + var frame = stack.GetFrames().First(); + var method = frame.GetMethod(); + var parameters = method.GetParameters(); + var service = method.DeclaringType.Name; + var message = ""; + + if (arguments.Length > 0 && parameters.Length > 0) + { + message = "Arguments ( "; + + for (int i = 0; i < parameters.Length && i < arguments.Length; i++) + { + message += parameters[i].Name + ": " + arguments[i].ToString() + " "; + } + + message += ")" + Environment.NewLine + "------------------------------------------------"; + } + + message += ex.ToString(); + + Log(service, LogType.Error, message); + + + + Log(service, LogType.Error, ex.ToString()); + + } + catch + { + + } + } + + public static void Log(string service, LogType type, string message, bool appendHeader = true) + { + //if (type != LogType.Debug) + Console.WriteLine(service + " " + message); + + SystemLog?.Invoke(service, type, message); + } + + /* + public static string GetTempPath() + { + return System.IO.Path.GetTempPath(); + } + */ + + public static string RemoveControlCharacters(string inString) + { + if (inString == null) return null; + + StringBuilder newString = new StringBuilder(); + char ch; + + for (int i = 0; i < inString.Length; i++) + { + + ch = inString[i]; + + if (!char.IsControl(ch)) + { + newString.Append(ch); + } + } + return newString.ToString(); + } + + public static void PrintCounters() + { + string[] keys = new string[Counters.Keys.Count]; + Counters.Keys.CopyTo(keys, 0); + + foreach (string k in keys) + { + Console.WriteLine(k + ":" + Counters[k]); + } + } + // Encoding ANSI = Encoding.GetEncoding(1252); + + /* +public static Hashtable Cached +{ + get + { + return m_Cached; + } +}*/ + + /* + public static string ByteArrayToMAC(byte[] array) + { + string rt=""; + + if (array == null) + return "00:00:00:00:00:00"; + else + { + //for (int i = 0; i < array.Length - 1; i++) + // rt += Convert.ToString(array[i], 16) + ":"; + + //rt += Convert.ToString(array[array.Length - 1], 16); + + rt = BitConverter.ToString(array); + rt = rt.Replace('-', ':'); + return rt; + } + + } + */ + + + + /* + public static string IPAddressFromInt32(UInt32 IP) + { + //var dIP = DC.ToBytes(IP); + + return (IP >> 24) + "." + ((IP >> 16) & 0xFF) + "." + ((IP >> 8) & 0xFF) + "." + (IP & 0xFF); + } + */ + + public static KeyList Variables + { + get + { + return variables; + } + } + + + public static uint CurrentUnixTime() + { + return (uint)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; + } + + public static void SetConsoleColors(ConsoleColor ForegroundColor, ConsoleColor BackgroundColor) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + switch (ForegroundColor) + { + case ConsoleColor.Black: + Console.Write("\u001B[30m"); + break; + case ConsoleColor.Blue: + Console.Write("\u001B[1;34m"); + break; + case ConsoleColor.Cyan: + Console.Write("\u001B[1;36m"); + break; + case ConsoleColor.Gray: + case ConsoleColor.DarkGray: + Console.Write("\u001B[1;30m"); + break; + case ConsoleColor.Green: + Console.Write("\u001B[1;32m"); + break; + case ConsoleColor.Magenta: + Console.Write("\u001B[1;35m"); + break; + case ConsoleColor.Red: + Console.Write("\u001B[1;31m"); + break; + case ConsoleColor.White: + Console.Write("\u001B[1;37m"); + break; + case ConsoleColor.Yellow: + Console.Write("\u001B[1;33m"); + break; + + case ConsoleColor.DarkBlue: + Console.Write("\u001B[34m"); + break; + case ConsoleColor.DarkCyan: + Console.Write("\u001B[36m"); + break; + case ConsoleColor.DarkGreen: + Console.Write("\u001B[32m"); + break; + case ConsoleColor.DarkMagenta: + Console.Write("\u001B[35m"); + break; + case ConsoleColor.DarkRed: + Console.Write("\u001B[31m"); + break; + case ConsoleColor.DarkYellow: + Console.Write("\u001B[33m"); + break; + } + + + switch (BackgroundColor) + { + case ConsoleColor.Black: + Console.Write("\u001B[40m"); + break; + case ConsoleColor.Blue: + Console.Write("\u001B[1;44m"); + break; + case ConsoleColor.Cyan: + Console.Write("\u001B[1;46m"); + break; + case ConsoleColor.Gray: + case ConsoleColor.DarkGray: + Console.Write("\u001B[1;40m"); + break; + case ConsoleColor.Green: + Console.Write("\u001B[1;42m"); + break; + case ConsoleColor.Magenta: + Console.Write("\u001B[1;45m"); + break; + case ConsoleColor.Red: + Console.Write("\u001B[1;41m"); + break; + case ConsoleColor.White: + Console.Write("\u001B[1;47m"); + break; + case ConsoleColor.Yellow: + Console.Write("\u001B[1;43m"); + break; + + case ConsoleColor.DarkBlue: + Console.Write("\u001B[44m"); + break; + case ConsoleColor.DarkCyan: + Console.Write("\u001B[46m"); + break; + case ConsoleColor.DarkGreen: + Console.Write("\u001B[42m"); + break; + case ConsoleColor.DarkMagenta: + Console.Write("\u001B[45m"); + break; + case ConsoleColor.DarkRed: + Console.Write("\u001B[41m"); + break; + case ConsoleColor.DarkYellow: + Console.Write("\u001B[43m"); + break; + } + } + else + { + Console.ForegroundColor = ForegroundColor; + Console.BackgroundColor = BackgroundColor; + } + } + + public static string GetUserPart(string strAddress) + { + return strAddress.Substring(0, strAddress.IndexOf("@", 0)); + } + + public static byte[][] GetBytesFromChunk(byte[] Data, int ChunkSize) + { + if (ChunkSize == 1) + { + byte[][] ar = new byte[0][]; + int ptr = 0; + while (ptr < Data.Length) + { + Array.Resize(ref ar, ar.Length + 1); + ar[ar.Length - 1] = new byte[Data[ptr]]; + Buffer.BlockCopy(Data, ++ptr, ar[ar.Length - 1], 0, Data[ptr]); + ptr += Data[ptr] + 1; + } + return ar; + } + return null; + } + + + + + + public static string GetFileTitle(string Filename) + { + string[] s = Filename.Split(Path.DirectorySeparatorChar); + return s[s.Length - 1]; + } + + public static string GetNewFileName(string FileDir) + { + string tempGetNewFileName = null; + short i = 0; + string NewFile = null; + NewFile = FileDir; + Begin: + FileInfo FF = new FileInfo(NewFile); + if (FF.Exists) + { + //If FSO.FileExists(NewFile) Then + i++; //= i + 1; + NewFile = FileDir.Substring(0, FileDir.Length - 4) + "_" + i + "." + FileDir.Substring(FileDir.Length - 3); + goto Begin; + } + else + { + tempGetNewFileName = NewFile; + } + return tempGetNewFileName; + } + + ///////////////////////////////////// + public static string TrimEx(string strIn) + { + return strIn.Replace("\r", "").Replace("\n", ""); + } + + /* + public static bool IsUnix() + { + // Linux OSs under Mono 1.2 uses unknown integer numbers so this should identify all non windows as unix + return (Environment.OSVersion.Platform != PlatformID.Win32NT + && Environment.OSVersion.Platform != PlatformID.Win32Windows); // || Environment.OSVersion.Platform == PlatformID.Linux; + } + */ + + public static string GenerateCode() + { + return GenerateCode(16); + } + + + + public static byte[] GenerateBytes(int length) + { + var b = new byte[length]; + rand.NextBytes(b); + return b; + } + + public static string GenerateCode(int length) + { + return GenerateCode(length, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");// ~!@#$%^&*()_-+=\\?/"); + } + + public static string GenerateCode(int length, string chars) + //public static string GenerateCode(int Length) + { + //var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~!@#$%^&*()_-+=\\?/"; + var result = new string( + Enumerable.Repeat(chars, length) + .Select(s => s[rand.Next(s.Length)]) + .ToArray()); + //if (result.Length < length) + // Console.WriteLine(); + return result; + /* + int len = 0; + string code = ""; + + while(len < Length) + { + var c = Convert.ToChar((byte)(rand.NextDouble() * 255)); + if (Char.IsLetterOrDigit(c)) + { + code += c; + len++; + } + } + + return code; + */ + } + + public static string ReplaceOnce(string Expression, string Find, string Replacement) + { + int pos = Expression.IndexOf(Find); + if (pos != -1) + return Expression.Substring(0, pos) + Replacement + Expression.Substring(pos + Find.Length); + else + return Expression; + } + //public void Replace(string Expression, string Find, string Replacement, int Start, int Count) + //{ + // Expression.IndexOf( + //} +} diff --git a/Esiur/Net/DataLink/PacketFilter.cs b/Esiur/Net/DataLink/PacketFilter.cs index e9c574e..dad670e 100644 --- a/Esiur/Net/DataLink/PacketFilter.cs +++ b/Esiur/Net/DataLink/PacketFilter.cs @@ -31,26 +31,24 @@ using Esiur.Data; using Esiur.Net.Packets; using Esiur.Resource; -namespace Esiur.Net.DataLink +namespace Esiur.Net.DataLink; +public abstract class PacketFilter : IResource { - public abstract class PacketFilter : IResource + + public Instance Instance { + get; + set; + } - public Instance Instance - { - get; - set; - } + public event DestroyedEvent OnDestroy; - public event DestroyedEvent OnDestroy; + public abstract AsyncReply Trigger(ResourceTrigger trigger); - public abstract AsyncReply Trigger(ResourceTrigger trigger); + public abstract bool Execute(Packet packet); - public abstract bool Execute(Packet packet); - - public void Destroy() - { - OnDestroy?.Invoke(this); - } + public void Destroy() + { + OnDestroy?.Invoke(this); } } diff --git a/Esiur/Net/DataLink/PacketServer.cs b/Esiur/Net/DataLink/PacketServer.cs index e1de446..aff14fb 100644 --- a/Esiur/Net/DataLink/PacketServer.cs +++ b/Esiur/Net/DataLink/PacketServer.cs @@ -32,91 +32,89 @@ using System.Runtime.InteropServices; using Esiur.Net.Packets; using Esiur.Resource; -namespace Esiur.Net.DataLink +namespace Esiur.Net.DataLink; +public class PacketServer : IResource { - public class PacketServer:IResource + List sources = new List(); + List filters = new List(); + + + [Storable] + public string Mode { - List sources = new List(); - List filters = new List(); + get; + set; + } - - [Storable] - public string Mode + public Instance Instance + { + get; + set; + } + + public List Sources + { + get { - get; - set; + return sources; } + } - public Instance Instance - { - get; - set; - } + public event DestroyedEvent OnDestroy; - public List Sources + public void Destroy() + { + OnDestroy?.Invoke(this); + } + + public AsyncReply Trigger(ResourceTrigger trigger) + { + if (trigger == ResourceTrigger.Initialize) { - get + /* + foreach (var resource in Instance.Children()) { - return sources; + + if (resource is PacketFilter) + { + filters.Add(resource as PacketFilter); + } + else if (resource is PacketSource) + { + sources.Add(resource as PacketSource); + } + } + */ + foreach (var src in sources) + { + src.OnNewPacket += PacketReceived; + src.Open(); + } + } + else if (trigger == ResourceTrigger.Terminate) + { + // foreach (var src in sources) + // src.Close(); + } + else if (trigger == ResourceTrigger.SystemReload) + { + foreach (var src in sources) + { + src.Close(); + src.Open(); } } - public event DestroyedEvent OnDestroy; + return new AsyncReply(true); + } - public void Destroy() + void PacketReceived(Packet Packet) + { + foreach (var f in filters) { - OnDestroy?.Invoke(this); - } - - public AsyncReply Trigger(ResourceTrigger trigger) - { - if (trigger == ResourceTrigger.Initialize) + if (f.Execute(Packet)) { - /* - foreach (var resource in Instance.Children()) - { - - if (resource is PacketFilter) - { - filters.Add(resource as PacketFilter); - } - else if (resource is PacketSource) - { - sources.Add(resource as PacketSource); - } - } - */ - foreach (var src in sources) - { - src.OnNewPacket += PacketReceived; - src.Open(); - } - } - else if (trigger == ResourceTrigger.Terminate) - { - // foreach (var src in sources) - // src.Close(); - } - else if (trigger == ResourceTrigger.SystemReload) - { - foreach (var src in sources) - { - src.Close(); - src.Open(); - } - } - - return new AsyncReply( true); - } - - void PacketReceived(Packet Packet) - { - foreach (var f in filters) - { - if (f.Execute(Packet)) - { - break; - } + break; } } } diff --git a/Esiur/Net/DataLink/PacketSource.cs b/Esiur/Net/DataLink/PacketSource.cs index 4b79cb2..a7c3d06 100644 --- a/Esiur/Net/DataLink/PacketSource.cs +++ b/Esiur/Net/DataLink/PacketSource.cs @@ -30,66 +30,64 @@ using System.Text; using Esiur.Core; using Esiur.Resource; -namespace Esiur.Net.DataLink +namespace Esiur.Net.DataLink; +public abstract class PacketSource : IResource { - public abstract class PacketSource: IResource + public delegate void NewPacket(Packet Packet); + public abstract event NewPacket OnNewPacket; + public event DestroyedEvent OnDestroy; + + public Instance Instance { - public delegate void NewPacket(Packet Packet); - public abstract event NewPacket OnNewPacket; - public event DestroyedEvent OnDestroy; + get; + set; + } - public Instance Instance + + public abstract AsyncReply Trigger(ResourceTrigger trigger); + + + public abstract bool RawMode + { + set; + get; + } + + //public PacketSource(PacketServer Server, bool RawMode) + //{ + // this.RawMode = RawMode; + //} + + + public abstract bool Open(); + + public abstract bool Close(); + + + public abstract bool Write(Packet packet); + + public void Destroy() + { + OnDestroy?.Invoke(this); + } + + /* + public virtual string TypeName + { + get { - get; - set; - } - - - public abstract AsyncReply Trigger(ResourceTrigger trigger); - - - public abstract bool RawMode - { - set; - get; - } - - //public PacketSource(PacketServer Server, bool RawMode) - //{ - // this.RawMode = RawMode; - //} - - - public abstract bool Open(); - - public abstract bool Close(); - - - public abstract bool Write(Packet packet); - - public void Destroy() - { - OnDestroy?.Invoke(this); - } - - /* - public virtual string TypeName - { - get - { - return "Raw"; - } - } - */ - - public abstract byte[] Address - { - get; - } - - public abstract string DeviceId - { - get; + return "Raw"; } } + */ + + public abstract byte[] Address + { + get; + } + + public abstract string DeviceId + { + get; + } } diff --git a/Esiur/Net/HTTP/HTTPConnection.cs b/Esiur/Net/HTTP/HTTPConnection.cs index 2c3f6e8..4e104d7 100644 --- a/Esiur/Net/HTTP/HTTPConnection.cs +++ b/Esiur/Net/HTTP/HTTPConnection.cs @@ -38,400 +38,399 @@ using Esiur.Misc; using System.Security.Cryptography; using Esiur.Core; -namespace Esiur.Net.HTTP +namespace Esiur.Net.HTTP; +public class HTTPConnection : NetworkConnection { - public class HTTPConnection : NetworkConnection + + + + public bool WSMode { get; internal set; } + public HTTPServer Server { get; internal set; } + + public WebsocketPacket WSRequest { get; set; } + public HTTPRequestPacket Request { get; set; } + public HTTPResponsePacket Response { get; } = new HTTPResponsePacket(); + + HTTPSession session; + + public KeyList Variables { get; } = new KeyList(); + + + + internal long Parse(byte[] data) { - - - - public bool WSMode { get; internal set; } - public HTTPServer Server { get; internal set; } - - public WebsocketPacket WSRequest { get; set; } - public HTTPRequestPacket Request { get; set; } - public HTTPResponsePacket Response { get; } = new HTTPResponsePacket(); - - HTTPSession session; - - public KeyList Variables { get; } = new KeyList(); - - - - internal long Parse(byte[] data) + if (WSMode) { - if (WSMode) + // now parse WS protocol + WebsocketPacket ws = new WebsocketPacket(); + + var pSize = ws.Parse(data, 0, (uint)data.Length); + + + if (pSize > 0) { - // now parse WS protocol - WebsocketPacket ws = new WebsocketPacket(); - - var pSize = ws.Parse(data, 0, (uint)data.Length); - - - if (pSize > 0) - { - WSRequest = ws; - return 0; - } - else - { - return pSize; - } + WSRequest = ws; + return 0; } else { - var rp = new HTTPRequestPacket(); - var pSize = rp.Parse(data, 0, (uint)data.Length); - if (pSize > 0) - { - Request = rp; - return 0; - } - else - { - return pSize; - } + return pSize; } } - - - public void Flush() + else { - // close the connection - if (Request.Headers["connection"].ToLower() != "keep-alive" & IsConnected) - Close(); + var rp = new HTTPRequestPacket(); + var pSize = rp.Parse(data, 0, (uint)data.Length); + if (pSize > 0) + { + Request = rp; + return 0; + } + else + { + return pSize; + } + } + } + + + public void Flush() + { + // close the connection + if (Request.Headers["connection"].ToLower() != "keep-alive" & IsConnected) + Close(); + } + + public bool Upgrade() + { + if (IsWebsocketRequest()) + { + string magicString = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + string ret = Request.Headers["Sec-WebSocket-Key"] + magicString; + // Compute the SHA1 hash + SHA1 sha = SHA1.Create(); + byte[] sha1Hash = sha.ComputeHash(Encoding.UTF8.GetBytes(ret)); + Response.Headers["Upgrade"] = Request.Headers["Upgrade"]; + Response.Headers["Connection"] = Request.Headers["Connection"];// "Upgrade"; + Response.Headers["Sec-WebSocket-Accept"] = Convert.ToBase64String(sha1Hash); + + if (Request.Headers.ContainsKey("Sec-WebSocket-Protocol")) + Response.Headers["Sec-WebSocket-Protocol"] = Request.Headers["Sec-WebSocket-Protocol"]; + + + Response.Number = HTTPResponsePacket.ResponseCode.Switching; + Response.Text = "Switching Protocols"; + WSMode = true; + + Send(); + + return true; } - public bool Upgrade() + return false; + } + + public HTTPServer Parent + { + get { - if (IsWebsocketRequest()) + return Server; + } + } + + public void Send(WebsocketPacket packet) + { + if (packet.Data != null) + base.Send(packet.Data); + } + + public override void Send(string data) + { + Response.Message = Encoding.UTF8.GetBytes(data); + Send(); + } + + public override void Send(byte[] msg, int offset, int length) + { + Response.Message = DC.Clip(msg, (uint)offset, (uint)length); + Send(); + } + + public override void Send(byte[] message) + { + Response.Message = message; + Send(); + } + + public void Send(HTTPResponsePacket.ComposeOptions Options = HTTPResponsePacket.ComposeOptions.AllCalculateLength) + { + if (Response.Handled) + return; + + + try + { + Response.Compose(Options); + base.Send(Response.Data); + + // Refresh the current session + if (session != null) + session.Refresh(); + + } + catch + { + try { - string magicString = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - string ret = Request.Headers["Sec-WebSocket-Key"] + magicString; - // Compute the SHA1 hash - SHA1 sha = SHA1.Create(); - byte[] sha1Hash = sha.ComputeHash(Encoding.UTF8.GetBytes(ret)); - Response.Headers["Upgrade"] = Request.Headers["Upgrade"]; - Response.Headers["Connection"] = Request.Headers["Connection"];// "Upgrade"; - Response.Headers["Sec-WebSocket-Accept"] = Convert.ToBase64String(sha1Hash); + Close(); + } + finally { } + } + finally + { - if (Request.Headers.ContainsKey("Sec-WebSocket-Protocol")) - Response.Headers["Sec-WebSocket-Protocol"] = Request.Headers["Sec-WebSocket-Protocol"]; + } + } - Response.Number = HTTPResponsePacket.ResponseCode.Switching; - Response.Text = "Switching Protocols"; - WSMode = true; + public void CreateNewSession() + { + if (session == null) + { + // Create a new one + session = Server.CreateSession(Global.GenerateCode(12), 60 * 20); - Send(); + HTTPResponsePacket.HTTPCookie cookie = new HTTPResponsePacket.HTTPCookie("SID", session.Id); + cookie.Expires = DateTime.MaxValue; + cookie.Path = "/"; + cookie.HttpOnly = true; + Response.Cookies.Add(cookie); + } + } + + + public bool IsWebsocketRequest() + { + if (Request.Headers.ContainsKey("connection") + && Request.Headers["connection"].ToLower().Contains("upgrade") + && Request.Headers.ContainsKey("upgrade") + && Request.Headers["upgrade"].ToLower() == "websocket" + && Request.Headers.ContainsKey("Sec-WebSocket-Version") + && Request.Headers["Sec-WebSocket-Version"] == "13" + && Request.Headers.ContainsKey("Sec-WebSocket-Key")) + //&& Request.Headers.ContainsKey("Sec-WebSocket-Protocol")) + { + return true; + } + else + { + return false; + } + } + + protected override void DataReceived(NetworkBuffer data) + { + + byte[] msg = data.Read(); + + var BL = Parse(msg); + + if (BL == 0) + { + if (Request.Method == HTTPRequestPacket.HTTPMethod.UNKNOWN) + { + Close(); + return; + } + if (Request.URL == "") + { + Close(); + return; + } + } + else if (BL == -1) + { + data.HoldForNextWrite(msg); + return; + } + else if (BL < 0) + { + data.HoldFor(msg, (uint)(msg.Length - BL)); + return; + } + else if (BL > 0) + { + if (BL > Server.MaxPost) + { + Send( + "POST method content is larger than " + + Server.MaxPost + + " bytes."); + + Close(); + } + else + { + data.HoldFor(msg, (uint)(msg.Length + BL)); + } + return; + } + else if (BL < 0) // for security + { + Close(); + return; + } + + + + if (IsWebsocketRequest() & !WSMode) + { + Upgrade(); + //return; + } + + + //return; + + try + { + if (!Server.Execute(this)) + { + Response.Number = HTTPResponsePacket.ResponseCode.InternalServerError; + Send("Bad Request"); + Close(); + } + } + catch (Exception ex) + { + if (ex.Message != "Thread was being aborted.") + { + + Global.Log("HTTPServer", LogType.Error, ex.ToString()); + + //Console.WriteLine(ex.ToString()); + //EventLog.WriteEntry("HttpServer", ex.ToString(), EventLogEntryType.Error); + Send(Error500(ex.Message)); + } + + } + } + + private string Error500(string msg) + { + return "500 Internal Server Error
\r\n" + + "
\r\n" + + "500 Internal Server Error
" + msg + "\r\n" + + "
\r\n" + + "
\r\n"; + } + + public async AsyncReply SendFile(string filename) + { + if (Response.Handled == true) + return false; + + + try + { + + //HTTP/1.1 200 OK + //Server: Microsoft-IIS/5.0 + //Content-Location: http://127.0.0.1/index.html + //Date: Wed, 10 Dec 2003 19:10:25 GMT + //Content-Type: text/html + //Accept-Ranges: bytes + //Last-Modified: Mon, 22 Sep 2003 22:36:56 GMT + //Content-Length: 1957 + + if (!File.Exists(filename)) + { + Response.Number = HTTPResponsePacket.ResponseCode.NotFound; + Send("File Not Found"); return true; } - return false; - } - public HTTPServer Parent - { - get - { - return Server; - } - } - - public void Send(WebsocketPacket packet) - { - if (packet.Data != null) - base.Send(packet.Data); - } - - public override void Send(string data) - { - Response.Message = Encoding.UTF8.GetBytes(data); - Send(); - } - - public override void Send(byte[] msg, int offset, int length) - { - Response.Message = DC.Clip(msg, (uint)offset, (uint)length); - Send(); - } - - public override void Send(byte[] message) - { - Response.Message = message; - Send(); - } - - public void Send(HTTPResponsePacket.ComposeOptions Options = HTTPResponsePacket.ComposeOptions.AllCalculateLength) - { - if (Response.Handled) - return; - - - try - { - Response.Compose(Options); - base.Send(Response.Data); - - // Refresh the current session - if (session != null) - session.Refresh(); - - } - catch + var fileEditTime = File.GetLastWriteTime(filename).ToUniversalTime(); + if (Request.Headers.ContainsKey("if-modified-since")) { try { - Close(); + var ims = DateTime.Parse(Request.Headers["if-modified-since"]); + if ((fileEditTime - ims).TotalSeconds < 2) + { + Response.Number = HTTPResponsePacket.ResponseCode.NotModified; + Response.Headers.Clear(); + //Response.Text = "Not Modified"; + Send(HTTPResponsePacket.ComposeOptions.SpecifiedHeadersOnly); + return true; + } } - finally { } + catch + { + return false; + } + } + + + + Response.Number = HTTPResponsePacket.ResponseCode.OK; + // Fri, 30 Oct 2007 14:19:41 GMT + Response.Headers["Last-Modified"] = fileEditTime.ToString("ddd, dd MMM yyyy HH:mm:ss"); + FileInfo fi = new FileInfo(filename); + Response.Headers["Content-Length"] = fi.Length.ToString(); + Send(HTTPResponsePacket.ComposeOptions.SpecifiedHeadersOnly); + + //var fd = File.ReadAllBytes(filename); + + //base.Send(fd); + + + using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + + var buffer = new byte[60000]; + + + while (true) + { + var n = fs.Read(buffer, 0, 60000); + + if (n <= 0) + break; + + //Thread.Sleep(50); + await base.SendAsync(buffer, 0, n); + + } + } + + return true; + + } + catch + { + try + { + Close(); } finally { } - } - - public void CreateNewSession() - { - if (session == null) - { - // Create a new one - session = Server.CreateSession(Global.GenerateCode(12), 60 * 20); - - HTTPResponsePacket.HTTPCookie cookie = new HTTPResponsePacket.HTTPCookie("SID", session.Id); - cookie.Expires = DateTime.MaxValue; - cookie.Path = "/"; - cookie.HttpOnly = true; - - Response.Cookies.Add(cookie); - } - } - - - public bool IsWebsocketRequest() - { - if (Request.Headers.ContainsKey("connection") - && Request.Headers["connection"].ToLower().Contains("upgrade") - && Request.Headers.ContainsKey("upgrade") - && Request.Headers["upgrade"].ToLower() == "websocket" - && Request.Headers.ContainsKey("Sec-WebSocket-Version") - && Request.Headers["Sec-WebSocket-Version"] == "13" - && Request.Headers.ContainsKey("Sec-WebSocket-Key")) - //&& Request.Headers.ContainsKey("Sec-WebSocket-Protocol")) - { - return true; - } - else - { - return false; - } - } - - protected override void DataReceived(NetworkBuffer data) - { - - byte[] msg = data.Read(); - - var BL = Parse(msg); - - if (BL == 0) - { - if (Request.Method == HTTPRequestPacket.HTTPMethod.UNKNOWN) - { - Close(); - return; - } - if (Request.URL == "") - { - Close(); - return; - } - } - else if (BL == -1) - { - data.HoldForNextWrite(msg); - return; - } - else if (BL < 0) - { - data.HoldFor(msg, (uint)(msg.Length - BL)); - return; - } - else if (BL > 0) - { - if (BL > Server.MaxPost) - { - Send( - "POST method content is larger than " - + Server.MaxPost - + " bytes."); - - Close(); - } - else - { - data.HoldFor(msg, (uint)(msg.Length + BL)); - } - return; - } - else if (BL < 0) // for security - { - Close(); - return; - } - - - - if (IsWebsocketRequest() & !WSMode) - { - Upgrade(); - //return; - } - - - //return; - - try - { - if (!Server.Execute(this)) - { - Response.Number = HTTPResponsePacket.ResponseCode.InternalServerError; - Send("Bad Request"); - Close(); - } - } - catch (Exception ex) - { - if (ex.Message != "Thread was being aborted.") - { - - Global.Log("HTTPServer", LogType.Error, ex.ToString()); - - //Console.WriteLine(ex.ToString()); - //EventLog.WriteEntry("HttpServer", ex.ToString(), EventLogEntryType.Error); - Send(Error500(ex.Message)); - } - - } - } - - private string Error500(string msg) - { - return "500 Internal Server Error
\r\n" - + "
\r\n" - + "500 Internal Server Error
" + msg + "\r\n" - + "
\r\n" - + "
\r\n"; - } - - public async AsyncReply SendFile(string filename) - { - if (Response.Handled == true) - return false; - - - try - { - - //HTTP/1.1 200 OK - //Server: Microsoft-IIS/5.0 - //Content-Location: http://127.0.0.1/index.html - //Date: Wed, 10 Dec 2003 19:10:25 GMT - //Content-Type: text/html - //Accept-Ranges: bytes - //Last-Modified: Mon, 22 Sep 2003 22:36:56 GMT - //Content-Length: 1957 - - if (!File.Exists(filename)) - { - Response.Number = HTTPResponsePacket.ResponseCode.NotFound; - Send("File Not Found"); - return true; - } - - - var fileEditTime = File.GetLastWriteTime(filename).ToUniversalTime(); - if (Request.Headers.ContainsKey("if-modified-since")) - { - try - { - var ims = DateTime.Parse(Request.Headers["if-modified-since"]); - if ((fileEditTime - ims).TotalSeconds < 2) - { - Response.Number = HTTPResponsePacket.ResponseCode.NotModified; - Response.Headers.Clear(); - //Response.Text = "Not Modified"; - Send(HTTPResponsePacket.ComposeOptions.SpecifiedHeadersOnly); - return true; - } - } - catch - { - return false; - } - } - - - - Response.Number = HTTPResponsePacket.ResponseCode.OK; - // Fri, 30 Oct 2007 14:19:41 GMT - Response.Headers["Last-Modified"] = fileEditTime.ToString("ddd, dd MMM yyyy HH:mm:ss"); - FileInfo fi = new FileInfo(filename); - Response.Headers["Content-Length"] = fi.Length.ToString(); - Send(HTTPResponsePacket.ComposeOptions.SpecifiedHeadersOnly); - - //var fd = File.ReadAllBytes(filename); - - //base.Send(fd); - - - using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - - var buffer = new byte[60000]; - - - while (true) - { - var n = fs.Read(buffer, 0, 60000); - - if (n <= 0) - break; - - //Thread.Sleep(50); - await base.SendAsync(buffer, 0, n); - - } - } - - return true; - - } - catch - { - try - { - Close(); - } - finally { - - } - - return false; - } - } - - protected override void Connected() - { - // do nothing - } - - protected override void Disconencted() - { - // do nothing + return false; } } -} \ No newline at end of file + + protected override void Connected() + { + // do nothing + } + + protected override void Disconencted() + { + // do nothing + } +} diff --git a/Esiur/Net/HTTP/HTTPFilter.cs b/Esiur/Net/HTTP/HTTPFilter.cs index d2ef40c..8819eb6 100644 --- a/Esiur/Net/HTTP/HTTPFilter.cs +++ b/Esiur/Net/HTTP/HTTPFilter.cs @@ -35,48 +35,46 @@ using Esiur.Data; using Esiur.Core; using Esiur.Resource; -namespace Esiur.Net.HTTP +namespace Esiur.Net.HTTP; + +public abstract class HTTPFilter : IResource { - - public abstract class HTTPFilter : IResource + public Instance Instance { - public Instance Instance - { - get; - set; - } - - public event DestroyedEvent OnDestroy; - - public abstract AsyncReply Trigger(ResourceTrigger trigger); - - /* - public virtual void SessionModified(HTTPSession session, string key, object oldValue, object newValue) - { - - } - - public virtual void SessionExpired(HTTPSession session) - { - - } - */ - - public abstract AsyncReply Execute(HTTPConnection sender); - - public virtual void ClientConnected(HTTPConnection HTTP) - { - //return false; - } - - public virtual void ClientDisconnected(HTTPConnection HTTP) - { - //return false; - } - - public void Destroy() - { - OnDestroy?.Invoke(this); - } + get; + set; } -} \ No newline at end of file + + public event DestroyedEvent OnDestroy; + + public abstract AsyncReply Trigger(ResourceTrigger trigger); + + /* + public virtual void SessionModified(HTTPSession session, string key, object oldValue, object newValue) + { + + } + + public virtual void SessionExpired(HTTPSession session) + { + + } + */ + + public abstract AsyncReply Execute(HTTPConnection sender); + + public virtual void ClientConnected(HTTPConnection HTTP) + { + //return false; + } + + public virtual void ClientDisconnected(HTTPConnection HTTP) + { + //return false; + } + + public void Destroy() + { + OnDestroy?.Invoke(this); + } +} diff --git a/Esiur/Net/HTTP/HTTPServer.cs b/Esiur/Net/HTTP/HTTPServer.cs index 6fc8a02..31fb944 100644 --- a/Esiur/Net/HTTP/HTTPServer.cs +++ b/Esiur/Net/HTTP/HTTPServer.cs @@ -39,262 +39,260 @@ using Esiur.Net.Packets; using System.Security.Cryptography.X509Certificates; using Esiur.Resource; -namespace Esiur.Net.HTTP +namespace Esiur.Net.HTTP; +public class HTTPServer : NetworkServer, IResource { - public class HTTPServer : NetworkServer, IResource + Dictionary sessions = new Dictionary(); + HTTPFilter[] filters = new HTTPFilter[0]; + + public Instance Instance { - Dictionary sessions= new Dictionary(); - HTTPFilter[] filters = new HTTPFilter[0]; + get; + set; + } - public Instance Instance + [Attribute] + public virtual string IP + { + get; + set; + } + + [Attribute] + public virtual ushort Port + { + get; + set; + } + + //[Attribute] + //public virtual uint Timeout + //{ + // get; + // set; + //} + + //[Attribute] + //public virtual uint Clock + //{ + // get; + // set; + //} + + [Attribute] + public virtual uint MaxPost + { + get; + set; + } + + [Attribute] + public virtual bool SSL + { + get; + set; + } + + [Attribute] + public virtual string Certificate + { + get; + set; + } + + + public HTTPSession CreateSession(string id, int timeout) + { + var s = new HTTPSession(); + + s.Set(id, timeout); + + + sessions.Add(id, s); + + return s; + } + + public static string MakeCookie(string Item, string Value, DateTime Expires, string Domain, string Path, bool HttpOnly) + { + + //Set-Cookie: ckGeneric=CookieBody; expires=Sun, 30-Dec-2001 21:00:00 GMT; domain=.com.au; path=/ + //Set-Cookie: SessionID=another; expires=Fri, 29 Jun 2006 20:47:11 UTC; path=/ + string Cookie = Item + "=" + Value; + + if (Expires.Ticks != 0) { - get; - set; + Cookie += "; expires=" + Expires.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss") + " GMT"; } - - [Attribute] - public virtual string IP + if (Domain != null) { - get; - set; + Cookie += "; domain=" + Domain; } - - [Attribute] - public virtual ushort Port + if (Path != null) { - get; - set; + Cookie += "; path=" + Path; } - - //[Attribute] - //public virtual uint Timeout - //{ - // get; - // set; - //} - - //[Attribute] - //public virtual uint Clock - //{ - // get; - // set; - //} - - [Attribute] - public virtual uint MaxPost + if (HttpOnly) { - get; - set; + Cookie += "; HttpOnly"; } + return Cookie; + } - [Attribute] - public virtual bool SSL + protected override void ClientDisconnected(HTTPConnection connection) + { + foreach (var filter in filters) + filter.ClientDisconnected(connection); + } + + + + internal bool Execute(HTTPConnection sender) + { + foreach (var resource in filters) + if (resource.Execute(sender).Wait(30000)) + return true; + return false; + } + + + + + /* + protected override void SessionEnded(NetworkSession session) + { + // verify wether there are no active connections related to the session + + foreach (HTTPConnection c in Connections)//.Values) { - get; - set; - } - - [Attribute] - public virtual string Certificate - { - get; - set; - } - - - public HTTPSession CreateSession(string id, int timeout) - { - var s = new HTTPSession(); - - s.Set(id, timeout); - - - sessions.Add(id, s); - - return s; - } - - public static string MakeCookie(string Item, string Value, DateTime Expires, string Domain, string Path, bool HttpOnly) - { - - //Set-Cookie: ckGeneric=CookieBody; expires=Sun, 30-Dec-2001 21:00:00 GMT; domain=.com.au; path=/ - //Set-Cookie: SessionID=another; expires=Fri, 29 Jun 2006 20:47:11 UTC; path=/ - string Cookie = Item + "=" + Value; - - if (Expires.Ticks != 0) + if (c.Session == session) { - Cookie += "; expires=" + Expires.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss") + " GMT"; - } - if (Domain != null) - { - Cookie += "; domain=" + Domain; - } - if (Path != null) - { - Cookie += "; path=" + Path; - } - if (HttpOnly) - { - Cookie += "; HttpOnly"; - } - return Cookie; - } - - protected override void ClientDisconnected(HTTPConnection connection) - { - foreach (var filter in filters) - filter.ClientDisconnected(connection); - } - - - - internal bool Execute(HTTPConnection sender) - { - foreach (var resource in filters) - if (resource.Execute(sender).Wait(30000)) - return true; - return false; - } - - - - - /* - protected override void SessionEnded(NetworkSession session) - { - // verify wether there are no active connections related to the session - - foreach (HTTPConnection c in Connections)//.Values) - { - if (c.Session == session) - { - session.Refresh(); - return; - } - } - - foreach (Instance instance in Instance.Children) - { - var f = (HTTPFilter)instance.Resource; - f.SessionExpired((HTTPSession)session); - } - - base.SessionEnded((HTTPSession)session); - //Sessions.Remove(Session.ID); - //Session.Dispose(); - } - */ - - /* - public int TTL - { - get - { - return Timeout;// mTimeout; - } - } - */ - - - public async AsyncReply Trigger(ResourceTrigger trigger) - { - - if (trigger == ResourceTrigger.Initialize) - { - //var ip = (IPAddress)Instance.Attributes["ip"]; - //var port = (int)Instance.Attributes["port"]; - //var ssl = (bool)Instance.Attributes["ssl"]; - //var cert = (string)Instance.Attributes["certificate"]; - - //if (ip == null) ip = IPAddress.Any; - - Sockets.ISocket listener; - IPAddress ipAdd; - - if (IP == null) - ipAdd = IPAddress.Any; - else - ipAdd = IPAddress.Parse(IP); - - if (SSL) - listener = new SSLSocket(new IPEndPoint(ipAdd, Port), new X509Certificate2(Certificate)); - else - listener = new TCPSocket(new IPEndPoint(ipAdd, Port)); - - Start(listener); - } - else if (trigger == ResourceTrigger.Terminate) - { - Stop(); - } - else if (trigger == ResourceTrigger.SystemReload) - { - await Trigger(ResourceTrigger.Terminate); - await Trigger(ResourceTrigger.Initialize); - } - else if (trigger == ResourceTrigger.SystemInitialized) - { - filters = await Instance.Children(); - } - - return true; - - } - - - public override void Add(HTTPConnection connection) - { - connection.Server = this; - base.Add(connection); - } - - public override void Remove(HTTPConnection connection) - { - connection.Server = null; - base.Remove(connection); - } - - protected override void ClientConnected(HTTPConnection connection) - { - if (filters.Length == 0) - { - connection.Close(); + session.Refresh(); return; } - - foreach (var resource in filters) - { - resource.ClientConnected(connection); - } } - - /* - public int LocalPort - { - get - { - return cServer.LocalPort; - } - } - */ - - /* - public HTTPServer(int Port) + foreach (Instance instance in Instance.Children) { - cServer = new TServer(); - cServer.LocalPort = Port; - cServer.StartServer(); - cServer.ClientConnected += new TServer.eClientConnected(ClientConnected); - cServer.ClientDisConnected += new TServer.eClientDisConnected(ClientDisConnected); - cServer.ClientIsSwitching += new TServer.eClientIsSwitching(ClientIsSwitching); - cServer.DataReceived += new TServer.eDataReceived(DataReceived); + var f = (HTTPFilter)instance.Resource; + f.SessionExpired((HTTPSession)session); + } - }*/ - - //~HTTPServer() - //{ - // cServer.StopServer(); - //} + base.SessionEnded((HTTPSession)session); + //Sessions.Remove(Session.ID); + //Session.Dispose(); } -} \ No newline at end of file + */ + + /* + public int TTL + { + get + { + return Timeout;// mTimeout; + } + } + */ + + + public async AsyncReply Trigger(ResourceTrigger trigger) + { + + if (trigger == ResourceTrigger.Initialize) + { + //var ip = (IPAddress)Instance.Attributes["ip"]; + //var port = (int)Instance.Attributes["port"]; + //var ssl = (bool)Instance.Attributes["ssl"]; + //var cert = (string)Instance.Attributes["certificate"]; + + //if (ip == null) ip = IPAddress.Any; + + Sockets.ISocket listener; + IPAddress ipAdd; + + if (IP == null) + ipAdd = IPAddress.Any; + else + ipAdd = IPAddress.Parse(IP); + + if (SSL) + listener = new SSLSocket(new IPEndPoint(ipAdd, Port), new X509Certificate2(Certificate)); + else + listener = new TCPSocket(new IPEndPoint(ipAdd, Port)); + + Start(listener); + } + else if (trigger == ResourceTrigger.Terminate) + { + Stop(); + } + else if (trigger == ResourceTrigger.SystemReload) + { + await Trigger(ResourceTrigger.Terminate); + await Trigger(ResourceTrigger.Initialize); + } + else if (trigger == ResourceTrigger.SystemInitialized) + { + filters = await Instance.Children(); + } + + return true; + + } + + + public override void Add(HTTPConnection connection) + { + connection.Server = this; + base.Add(connection); + } + + public override void Remove(HTTPConnection connection) + { + connection.Server = null; + base.Remove(connection); + } + + protected override void ClientConnected(HTTPConnection connection) + { + if (filters.Length == 0) + { + connection.Close(); + return; + } + + foreach (var resource in filters) + { + resource.ClientConnected(connection); + } + } + + + /* + public int LocalPort + { + get + { + return cServer.LocalPort; + } + } + */ + + /* + public HTTPServer(int Port) + { + cServer = new TServer(); + cServer.LocalPort = Port; + cServer.StartServer(); + cServer.ClientConnected += new TServer.eClientConnected(ClientConnected); + cServer.ClientDisConnected += new TServer.eClientDisConnected(ClientDisConnected); + cServer.ClientIsSwitching += new TServer.eClientIsSwitching(ClientIsSwitching); + cServer.DataReceived += new TServer.eDataReceived(DataReceived); + + }*/ + + //~HTTPServer() + //{ + // cServer.StopServer(); + //} +} diff --git a/Esiur/Net/HTTP/HTTPSession.cs b/Esiur/Net/HTTP/HTTPSession.cs index c2ea05a..d97166f 100644 --- a/Esiur/Net/HTTP/HTTPSession.cs +++ b/Esiur/Net/HTTP/HTTPSession.cs @@ -35,96 +35,94 @@ using Esiur.Data; using Esiur.Misc; using Esiur.Core; -namespace Esiur.Net.HTTP +namespace Esiur.Net.HTTP; +public class HTTPSession : IDestructible // where T : TClient { - public class HTTPSession : IDestructible // where T : TClient + public delegate void SessionModifiedEvent(HTTPSession session, string key, object oldValue, object newValue); + public delegate void SessionEndedEvent(HTTPSession session); + + private string id; + private Timer timer; + private int timeout; + DateTime creation; + DateTime lastAction; + + private KeyList variables; + + public event SessionEndedEvent OnEnd; + public event SessionModifiedEvent OnModify; + public event DestroyedEvent OnDestroy; + + public KeyList Variables { - public delegate void SessionModifiedEvent(HTTPSession session, string key, object oldValue, object newValue); - public delegate void SessionEndedEvent(HTTPSession session); + get { return variables; } + } - private string id; - private Timer timer; - private int timeout; - DateTime creation; - DateTime lastAction; + public HTTPSession() + { + variables = new KeyList(); + variables.OnModified += new KeyList.Modified(VariablesModified); + creation = DateTime.Now; + } - private KeyList variables; + internal void Set(string id, int timeout) + { + //modified = sessionModifiedEvent; + //ended = sessionEndEvent; + this.id = id; - public event SessionEndedEvent OnEnd; - public event SessionModifiedEvent OnModify; - public event DestroyedEvent OnDestroy; - - public KeyList Variables + if (this.timeout != 0) { - get { return variables; } - } - - public HTTPSession() - { - variables = new KeyList(); - variables.OnModified += new KeyList.Modified(VariablesModified); + this.timeout = timeout; + timer = new Timer(OnSessionEndTimerCallback, null, TimeSpan.FromSeconds(timeout), TimeSpan.FromSeconds(0)); creation = DateTime.Now; } - - internal void Set(string id, int timeout) - { - //modified = sessionModifiedEvent; - //ended = sessionEndEvent; - this.id = id; - - if (this.timeout != 0) - { - this.timeout = timeout; - timer = new Timer(OnSessionEndTimerCallback, null, TimeSpan.FromSeconds(timeout), TimeSpan.FromSeconds(0)); - creation = DateTime.Now; - } - } - - private void OnSessionEndTimerCallback(object o) - { - OnEnd?.Invoke(this); - } - - void VariablesModified(string key, object oldValue, object newValue, KeyList sender) - { - OnModify?.Invoke(this, key, oldValue, newValue); - } - - public void Destroy() - { - OnDestroy?.Invoke(this); - timer.Dispose(); - timer = null; - } - - internal void Refresh() - { - lastAction = DateTime.Now; - timer.Change(TimeSpan.FromSeconds(timeout), TimeSpan.FromSeconds(0)); - } - - public int Timeout // Seconds - { - get - { - return timeout; - } - set - { - timeout = value; - Refresh(); - } - } - - public string Id - { - get { return id; } - } - - public DateTime LastAction - { - get { return lastAction; } - } } -} \ No newline at end of file + private void OnSessionEndTimerCallback(object o) + { + OnEnd?.Invoke(this); + } + + void VariablesModified(string key, object oldValue, object newValue, KeyList sender) + { + OnModify?.Invoke(this, key, oldValue, newValue); + } + + public void Destroy() + { + OnDestroy?.Invoke(this); + timer.Dispose(); + timer = null; + } + + internal void Refresh() + { + lastAction = DateTime.Now; + timer.Change(TimeSpan.FromSeconds(timeout), TimeSpan.FromSeconds(0)); + } + + public int Timeout // Seconds + { + get + { + return timeout; + } + set + { + timeout = value; + Refresh(); + } + } + + public string Id + { + get { return id; } + } + + public DateTime LastAction + { + get { return lastAction; } + } +} + diff --git a/Esiur/Net/HTTP/IIPoHTTP.cs b/Esiur/Net/HTTP/IIPoHTTP.cs index 2ee4a5a..6ee669b 100644 --- a/Esiur/Net/HTTP/IIPoHTTP.cs +++ b/Esiur/Net/HTTP/IIPoHTTP.cs @@ -6,34 +6,32 @@ using System; using System.Collections.Generic; using System.Text; -namespace Esiur.Net.HTTP +namespace Esiur.Net.HTTP; +public class IIPoHTTP : HTTPFilter { - public class IIPoHTTP : HTTPFilter + [Attribute] + EntryPoint EntryPoint { get; set; } + + public override AsyncReply Execute(HTTPConnection sender) { - [Attribute] - EntryPoint EntryPoint { get; set; } + if (sender.Request.URL != "iip") + return new AsyncReply(false); - public override AsyncReply Execute(HTTPConnection sender) + IIPPacket.IIPPacketAction action = (IIPPacket.IIPPacketAction)Convert.ToByte(sender.Request.Query["a"]); + + if (action == IIPPacket.IIPPacketAction.QueryLink) { - if (sender.Request.URL != "iip") - return new AsyncReply(false); - - IIPPacket.IIPPacketAction action = (IIPPacket.IIPPacketAction)Convert.ToByte(sender.Request.Query["a"]); - - if (action == IIPPacket.IIPPacketAction.QueryLink) + EntryPoint.Query(sender.Request.Query["l"], null).Then(x => { - EntryPoint.Query(sender.Request.Query["l"], null).Then(x => - { - }); - } - - return new AsyncReply(true); + }); } - public override AsyncReply Trigger(ResourceTrigger trigger) - { - return new AsyncReply(true); - } + return new AsyncReply(true); + } + + public override AsyncReply Trigger(ResourceTrigger trigger) + { + return new AsyncReply(true); } } diff --git a/Esiur/Net/HTTP/IIPoWS.cs b/Esiur/Net/HTTP/IIPoWS.cs index 60dba37..9779fc8 100644 --- a/Esiur/Net/HTTP/IIPoWS.cs +++ b/Esiur/Net/HTTP/IIPoWS.cs @@ -32,94 +32,91 @@ using Esiur.Net.IIP; using Esiur.Net.Sockets; using Esiur.Core; -namespace Esiur.Net.HTTP +namespace Esiur.Net.HTTP; +public class IIPoWS : HTTPFilter { - public class IIPoWS: HTTPFilter + [Attribute] + public DistributedServer Server { - [Attribute] - public DistributedServer Server + get; + set; + } + + public override AsyncReply Execute(HTTPConnection sender) + { + + if (sender.IsWebsocketRequest()) { - get; - set; - } + if (Server == null) + return new AsyncReply(false); - public override AsyncReply Execute(HTTPConnection sender) - { + var tcpSocket = sender.Unassign(); - if (sender.IsWebsocketRequest()) - { - if (Server == null) - return new AsyncReply(false); + if (tcpSocket == null) + return new AsyncReply(false); - var tcpSocket = sender.Unassign(); + var httpServer = sender.Parent; + var wsSocket = new WSocket(tcpSocket); + httpServer.Remove(sender); - if (tcpSocket == null) - return new AsyncReply(false); + var iipConnection = new DistributedConnection(); - var httpServer = sender.Parent; - var wsSocket = new WSocket(tcpSocket); - httpServer.Remove(sender); + Server.Add(iipConnection); + iipConnection.Assign(wsSocket); + wsSocket.Begin(); - var iipConnection = new DistributedConnection(); - - Server.Add(iipConnection); - iipConnection.Assign(wsSocket); - wsSocket.Begin(); - - return new AsyncReply(true); - } - - return new AsyncReply( false); - - /* - if (sender.Request.Filename.StartsWith("/iip/")) - { - // find the service - var path = sender.Request.Filename.Substring(5);// sender.Request.Query["path"]; - - - Warehouse.Get(path).Then((r) => - { - if (r is DistributedServer) - { - var httpServer = sender.Parent; - var iipServer = r as DistributedServer; - var tcpSocket = sender.Unassign(); - if (tcpSocket == null) - return; - - var wsSocket = new WSSocket(tcpSocket); - httpServer.RemoveConnection(sender); - - //httpServer.Connections.Remove(sender); - var iipConnection = new DistributedConnection(); - // iipConnection.OnReady += IipConnection_OnReady; -// iipConnection.Server = iipServer; - // iipConnection.Assign(wsSocket); - - iipServer.AddConnection(iipConnection); - iipConnection.Assign(wsSocket); - wsSocket.Begin(); - } - }); - - return true; - } - - return false; - */ - } - - private void IipConnection_OnReady(DistributedConnection sender) - { - Warehouse.Put(sender.RemoteUsername, sender, null, sender.Server).Wait(); - } - - public override AsyncReply Trigger(ResourceTrigger trigger) - { return new AsyncReply(true); } + + return new AsyncReply(false); + + /* + if (sender.Request.Filename.StartsWith("/iip/")) + { + // find the service + var path = sender.Request.Filename.Substring(5);// sender.Request.Query["path"]; + + + Warehouse.Get(path).Then((r) => + { + if (r is DistributedServer) + { + var httpServer = sender.Parent; + var iipServer = r as DistributedServer; + var tcpSocket = sender.Unassign(); + if (tcpSocket == null) + return; + + var wsSocket = new WSSocket(tcpSocket); + httpServer.RemoveConnection(sender); + + //httpServer.Connections.Remove(sender); + var iipConnection = new DistributedConnection(); +// iipConnection.OnReady += IipConnection_OnReady; +// iipConnection.Server = iipServer; +// iipConnection.Assign(wsSocket); + + iipServer.AddConnection(iipConnection); + iipConnection.Assign(wsSocket); + wsSocket.Begin(); + } + }); + + return true; + } + + return false; + */ + } + + private void IipConnection_OnReady(DistributedConnection sender) + { + Warehouse.Put(sender.RemoteUsername, sender, null, sender.Server).Wait(); + } + + public override AsyncReply Trigger(ResourceTrigger trigger) + { + return new AsyncReply(true); } - } - + diff --git a/Esiur/Net/IIP/DistributedConnection.cs b/Esiur/Net/IIP/DistributedConnection.cs index ac7f8c5..c6815bb 100644 --- a/Esiur/Net/IIP/DistributedConnection.cs +++ b/Esiur/Net/IIP/DistributedConnection.cs @@ -40,1242 +40,1240 @@ using System.Linq; using System.Diagnostics; using static Esiur.Net.Packets.IIPPacket; -namespace Esiur.Net.IIP +namespace Esiur.Net.IIP; +public partial class DistributedConnection : NetworkConnection, IStore { - public partial class DistributedConnection : NetworkConnection, IStore + public delegate void ReadyEvent(DistributedConnection sender); + public delegate void ErrorEvent(DistributedConnection sender, byte errorCode, string errorMessage); + + /// + /// Ready event is raised when the connection is fully established. + /// + public event ReadyEvent OnReady; + + /// + /// Error event + /// + public event ErrorEvent OnError; + + IIPPacket packet = new IIPPacket(); + IIPAuthPacket authPacket = new IIPAuthPacket(); + + Session session; + + AsyncReply openReply; + + byte[] localPasswordOrToken; + byte[] localNonce, remoteNonce; + + bool ready, readyToEstablish; + + string _hostname; + ushort _port; + + DateTime loginDate; + + /// + /// Local username to authenticate ourselves. + /// + public string LocalUsername => session.LocalAuthentication.Username;// { get; set; } + + /// + /// Peer's username. + /// + public string RemoteUsername => session.RemoteAuthentication.Username;// { get; set; } + + /// + /// Working domain. + /// + //public string Domain { get { return domain; } } + + + /// + /// The session related to this connection. + /// + public Session Session => session; + + /// + /// Distributed server responsible for this connection, usually for incoming connections. + /// + public DistributedServer Server { get; internal set; } + + public bool Remove(IResource resource) { - public delegate void ReadyEvent(DistributedConnection sender); - public delegate void ErrorEvent(DistributedConnection sender, byte errorCode, string errorMessage); + // nothing to do + return true; + } - /// - /// Ready event is raised when the connection is fully established. - /// - public event ReadyEvent OnReady; + /// + /// Send data to the other end as parameters + /// + /// Values will be converted to bytes then sent. + internal SendList SendParams(AsyncReply reply = null)//params object[] values) + { + return new SendList(this, reply); - /// - /// Error event - /// - public event ErrorEvent OnError; + /* + var data = BinaryList.ToBytes(values); - IIPPacket packet = new IIPPacket(); - IIPAuthPacket authPacket = new IIPAuthPacket(); - - Session session; - - AsyncReply openReply; - - byte[] localPasswordOrToken; - byte[] localNonce, remoteNonce; - - bool ready, readyToEstablish; - - string _hostname; - ushort _port; - - DateTime loginDate; - - /// - /// Local username to authenticate ourselves. - /// - public string LocalUsername => session.LocalAuthentication.Username;// { get; set; } - - /// - /// Peer's username. - /// - public string RemoteUsername => session.RemoteAuthentication.Username;// { get; set; } - - /// - /// Working domain. - /// - //public string Domain { get { return domain; } } - - - /// - /// The session related to this connection. - /// - public Session Session => session; - - /// - /// Distributed server responsible for this connection, usually for incoming connections. - /// - public DistributedServer Server { get; internal set; } - - public bool Remove(IResource resource) + if (ready) { - // nothing to do - return true; - } + var cmd = (IIPPacketCommand)(data[0] >> 6); - /// - /// Send data to the other end as parameters - /// - /// Values will be converted to bytes then sent. - internal SendList SendParams(AsyncReply reply = null)//params object[] values) - { - return new SendList(this, reply); - - /* - var data = BinaryList.ToBytes(values); - - if (ready) + if (cmd == IIPPacketCommand.Event) { - var cmd = (IIPPacketCommand)(data[0] >> 6); - - if (cmd == IIPPacketCommand.Event) - { - var evt = (IIPPacketEvent)(data[0] & 0x3f); - //Console.Write("Sent: " + cmd.ToString() + " " + evt.ToString()); - } - else if (cmd == IIPPacketCommand.Report) - { - var r = (IIPPacketReport)(data[0] & 0x3f); - //Console.Write("Sent: " + cmd.ToString() + " " + r.ToString()); - - } - else - { - var act = (IIPPacketAction)(data[0] & 0x3f); - //Console.Write("Sent: " + cmd.ToString() + " " + act.ToString()); - - } - - //foreach (var param in values) - // Console.Write(", " + param); - - //Console.WriteLine(); + var evt = (IIPPacketEvent)(data[0] & 0x3f); + //Console.Write("Sent: " + cmd.ToString() + " " + evt.ToString()); } - - - Send(data); - - //StackTrace stackTrace = new StackTrace(; - - // Get calling method name - - //Console.WriteLine("TX " + hostType + " " + ar.Length + " " + stackTrace.GetFrame(1).GetMethod().ToString()); - */ - } - - /// - /// Send raw data through the connection. - /// - /// Data to send. - public override void Send(byte[] data) - { - //Console.WriteLine("Client: {0}", Data.Length); - - Global.Counters["IIP Sent Packets"]++; - base.Send(data); - } - - /// - /// KeyList to store user variables related to this connection. - /// - public KeyList Variables { get; } = new KeyList(); - - /// - /// IResource interface. - /// - public Instance Instance - { - get; - set; - } - - /// - /// Assign a socket to the connection. - /// - /// Any socket that implements ISocket. - public override void Assign(Sockets.ISocket socket) - { - base.Assign(socket); - - session.RemoteAuthentication.Source.Attributes[SourceAttributeType.IPv4] = socket.RemoteEndPoint.Address; - session.RemoteAuthentication.Source.Attributes[SourceAttributeType.Port] = socket.RemoteEndPoint.Port; - session.LocalAuthentication.Source.Attributes[SourceAttributeType.IPv4] = socket.LocalEndPoint.Address; - session.LocalAuthentication.Source.Attributes[SourceAttributeType.Port] = socket.LocalEndPoint.Port; - - if (socket.State == SocketState.Established && - session.LocalAuthentication.Type == AuthenticationType.Client) + else if (cmd == IIPPacketCommand.Report) { - Declare(); - } - } - - private void Declare() - { - var dmn = DC.ToBytes(session.LocalAuthentication.Domain);// domain); - - if (session.LocalAuthentication.Method == AuthenticationMethod.Credentials) - { - // declare (Credentials -> No Auth, No Enctypt) - - var un = DC.ToBytes(session.LocalAuthentication.Username); - - SendParams() - .AddUInt8(0x60) - .AddUInt8((byte)dmn.Length) - .AddUInt8Array(dmn) - .AddUInt8Array(localNonce) - .AddUInt8((byte)un.Length) - .AddUInt8Array(un) - .Done();//, dmn, localNonce, (byte)un.Length, un); - } - else if (session.LocalAuthentication.Method == AuthenticationMethod.Token) - { - - SendParams() - .AddUInt8(0x70) - .AddUInt8((byte)dmn.Length) - .AddUInt8Array(dmn) - .AddUInt8Array(localNonce) - .AddUInt64(session.LocalAuthentication.TokenIndex) - .Done();//, dmn, localNonce, token + var r = (IIPPacketReport)(data[0] & 0x3f); + //Console.Write("Sent: " + cmd.ToString() + " " + r.ToString()); } - else if (session.LocalAuthentication.Method == AuthenticationMethod.None) - { - SendParams() - .AddUInt8(0x40) - .AddUInt8((byte)dmn.Length) - .AddUInt8Array(dmn) - .Done();//, dmn, localNonce, token - } - } - - /// - /// Create a new distributed connection. - /// - /// Socket to transfer data through. - /// Working domain. - /// Username. - /// Password. - public DistributedConnection(Sockets.ISocket socket, string domain, string username, string password) - { - this.session = new Session(new ClientAuthentication() - , new HostAuthentication()); - //Instance.Name = Global.GenerateCode(12); - //this.hostType = AuthenticationType.Client; - //this.domain = domain; - //this.localUsername = username; - session.LocalAuthentication.Domain = domain; - session.LocalAuthentication.Username = username; - session.LocalAuthentication.Method = AuthenticationMethod.Credentials; - this.localPasswordOrToken = DC.ToBytes(password); - - init(); - - Assign(socket); - } - - public DistributedConnection(Sockets.ISocket socket, string domain, ulong tokenIndex, string token) - { - this.session = new Session(new ClientAuthentication() - , new HostAuthentication()); - //Instance.Name = Global.GenerateCode(12); - //this.hostType = AuthenticationType.Client; - //this.domain = domain; - //this.localUsername = username; - session.LocalAuthentication.Domain = domain; - session.LocalAuthentication.TokenIndex = tokenIndex; - session.LocalAuthentication.Method = AuthenticationMethod.Token; - - this.localPasswordOrToken = DC.ToBytes(token); - - init(); - - Assign(socket); - } - - - /// - /// Create a new instance of a distributed connection - /// - public DistributedConnection() - { - //myId = Global.GenerateCode(12); - // localParams.Host = DistributedParameters.HostType.Host; - session = new Session(new HostAuthentication(), new ClientAuthentication()); - init(); - } - - - - public string Link(IResource resource) - { - if (resource is DistributedResource) - { - var r = resource as DistributedResource; - if (r.Instance.Store == this) - return this.Instance.Name + "/" + r.Id; - } - - return null; - } - - - void init() - { - //var q = queue; - queue.Then((x) => - { - if (x.Type == DistributedResourceQueueItem.DistributedResourceQueueItemType.Event) - x.Resource._EmitEventByIndex(x.Index, x.Value); - else - x.Resource._UpdatePropertyByIndex(x.Index, x.Value); - }); - //q.timeout?.Dispose(); - - var r = new Random(); - localNonce = new byte[32]; - r.NextBytes(localNonce); - } - - public override void Destroy() - { - UnsubscribeAll(); - this.OnReady = null; - this.OnError = null; - base.Destroy(); - } - - - private uint processPacket(byte[] msg, uint offset, uint ends, NetworkBuffer data, int chunkId) - { - //var packet = new IIPPacket(); - - - - // packets++; - - if (ready) - { - var rt = packet.Parse(msg, offset, ends); - //Console.WriteLine("Rec: " + chunkId + " " + packet.ToString()); - - /* - if (packet.Command == IIPPacketCommand.Event) - Console.WriteLine("Rec: " + packet.Command.ToString() + " " + packet.Event.ToString()); - else if (packet.Command == IIPPacketCommand.Report) - Console.WriteLine("Rec: " + packet.Command.ToString() + " " + packet.Report.ToString()); - else - Console.WriteLine("Rec: " + packet.Command.ToString() + " " + packet.Action.ToString() + " " + packet.ResourceId + " " + offset + "/" + ends); - */ - - - //packs.Add(packet.Command.ToString() + " " + packet.Action.ToString() + " " + packet.Event.ToString()); - - //if (packs.Count > 1) - // Console.WriteLine("P2"); - - //Console.WriteLine(""); - - if (rt <= 0) - { - //Console.WriteLine("Hold"); - var size = ends - offset; - data.HoldFor(msg, offset, size, size + (uint)(-rt)); - return ends; - } - else - { - - //Console.WriteLine($"CMD {packet.Command} {offset} {ends}"); - - offset += (uint)rt; - - if (packet.Command == IIPPacket.IIPPacketCommand.Event) - { - switch (packet.Event) - { - case IIPPacket.IIPPacketEvent.ResourceReassigned: - IIPEventResourceReassigned(packet.ResourceId, packet.NewResourceId); - break; - case IIPPacket.IIPPacketEvent.ResourceDestroyed: - IIPEventResourceDestroyed(packet.ResourceId); - break; - case IIPPacket.IIPPacketEvent.PropertyUpdated: - IIPEventPropertyUpdated(packet.ResourceId, packet.MethodIndex, packet.Content); - break; - case IIPPacket.IIPPacketEvent.EventOccurred: - IIPEventEventOccurred(packet.ResourceId, packet.MethodIndex, packet.Content); - break; - - case IIPPacketEvent.ChildAdded: - IIPEventChildAdded(packet.ResourceId, packet.ChildId); - break; - case IIPPacketEvent.ChildRemoved: - IIPEventChildRemoved(packet.ResourceId, packet.ChildId); - break; - case IIPPacketEvent.Renamed: - IIPEventRenamed(packet.ResourceId, packet.Content); - break; - case IIPPacketEvent.AttributesUpdated: - IIPEventAttributesUpdated(packet.ResourceId, packet.Content); - break; - } - } - else if (packet.Command == IIPPacket.IIPPacketCommand.Request) - { - switch (packet.Action) - { - // Manage - case IIPPacket.IIPPacketAction.AttachResource: - IIPRequestAttachResource(packet.CallbackId, packet.ResourceId); - break; - case IIPPacket.IIPPacketAction.ReattachResource: - IIPRequestReattachResource(packet.CallbackId, packet.ResourceId, packet.ResourceAge); - break; - case IIPPacket.IIPPacketAction.DetachResource: - IIPRequestDetachResource(packet.CallbackId, packet.ResourceId); - break; - case IIPPacket.IIPPacketAction.CreateResource: - IIPRequestCreateResource(packet.CallbackId, packet.StoreId, packet.ResourceId, packet.Content); - break; - case IIPPacket.IIPPacketAction.DeleteResource: - IIPRequestDeleteResource(packet.CallbackId, packet.ResourceId); - break; - case IIPPacketAction.AddChild: - IIPRequestAddChild(packet.CallbackId, packet.ResourceId, packet.ChildId); - break; - case IIPPacketAction.RemoveChild: - IIPRequestRemoveChild(packet.CallbackId, packet.ResourceId, packet.ChildId); - break; - case IIPPacketAction.RenameResource: - IIPRequestRenameResource(packet.CallbackId, packet.ResourceId, packet.Content); - break; - - // Inquire - case IIPPacket.IIPPacketAction.TemplateFromClassName: - IIPRequestTemplateFromClassName(packet.CallbackId, packet.ClassName); - break; - case IIPPacket.IIPPacketAction.TemplateFromClassId: - IIPRequestTemplateFromClassId(packet.CallbackId, packet.ClassId); - break; - case IIPPacket.IIPPacketAction.TemplateFromResourceId: - IIPRequestTemplateFromResourceId(packet.CallbackId, packet.ResourceId); - break; - case IIPPacketAction.QueryLink: - IIPRequestQueryResources(packet.CallbackId, packet.ResourceLink); - break; - - case IIPPacketAction.ResourceChildren: - IIPRequestResourceChildren(packet.CallbackId, packet.ResourceId); - break; - case IIPPacketAction.ResourceParents: - IIPRequestResourceParents(packet.CallbackId, packet.ResourceId); - break; - - case IIPPacket.IIPPacketAction.ResourceHistory: - IIPRequestInquireResourceHistory(packet.CallbackId, packet.ResourceId, packet.FromDate, packet.ToDate); - break; - - case IIPPacketAction.LinkTemplates: - IIPRequestLinkTemplates(packet.CallbackId, packet.ResourceLink); - break; - - // Invoke - case IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments: - IIPRequestInvokeFunctionArrayArguments(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content); - break; - - case IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments: - IIPRequestInvokeFunctionNamedArguments(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content); - break; - - //case IIPPacket.IIPPacketAction.GetProperty: - // IIPRequestGetProperty(packet.CallbackId, packet.ResourceId, packet.MethodIndex); - // break; - //case IIPPacket.IIPPacketAction.GetPropertyIfModified: - // IIPRequestGetPropertyIfModifiedSince(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.ResourceAge); - // break; - - case IIPPacket.IIPPacketAction.Listen: - IIPRequestListen(packet.CallbackId, packet.ResourceId, packet.MethodIndex); - break; - - case IIPPacket.IIPPacketAction.Unlisten: - IIPRequestUnlisten(packet.CallbackId, packet.ResourceId, packet.MethodIndex); - break; - - case IIPPacket.IIPPacketAction.SetProperty: - IIPRequestSetProperty(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content); - break; - - // Attribute - case IIPPacketAction.GetAllAttributes: - IIPRequestGetAttributes(packet.CallbackId, packet.ResourceId, packet.Content, true); - break; - case IIPPacketAction.UpdateAllAttributes: - IIPRequestUpdateAttributes(packet.CallbackId, packet.ResourceId, packet.Content, true); - break; - case IIPPacketAction.ClearAllAttributes: - IIPRequestClearAttributes(packet.CallbackId, packet.ResourceId, packet.Content, true); - break; - case IIPPacketAction.GetAttributes: - IIPRequestGetAttributes(packet.CallbackId, packet.ResourceId, packet.Content, false); - break; - case IIPPacketAction.UpdateAttributes: - IIPRequestUpdateAttributes(packet.CallbackId, packet.ResourceId, packet.Content, false); - break; - case IIPPacketAction.ClearAttributes: - IIPRequestClearAttributes(packet.CallbackId, packet.ResourceId, packet.Content, false); - break; - } - } - else if (packet.Command == IIPPacket.IIPPacketCommand.Reply) - { - switch (packet.Action) - { - // Manage - case IIPPacket.IIPPacketAction.AttachResource: - IIPReply(packet.CallbackId, packet.ClassId, packet.ResourceAge, packet.ResourceLink, packet.Content); - break; - - case IIPPacket.IIPPacketAction.ReattachResource: - IIPReply(packet.CallbackId, packet.ResourceAge, packet.Content); - - break; - case IIPPacket.IIPPacketAction.DetachResource: - IIPReply(packet.CallbackId); - break; - - case IIPPacket.IIPPacketAction.CreateResource: - IIPReply(packet.CallbackId, packet.ResourceId); - break; - - case IIPPacket.IIPPacketAction.DeleteResource: - case IIPPacketAction.AddChild: - case IIPPacketAction.RemoveChild: - case IIPPacketAction.RenameResource: - IIPReply(packet.CallbackId); - break; - - // Inquire - - case IIPPacket.IIPPacketAction.TemplateFromClassName: - case IIPPacket.IIPPacketAction.TemplateFromClassId: - case IIPPacket.IIPPacketAction.TemplateFromResourceId: - IIPReply(packet.CallbackId, TypeTemplate.Parse(packet.Content)); - break; - - case IIPPacketAction.QueryLink: - case IIPPacketAction.ResourceChildren: - case IIPPacketAction.ResourceParents: - case IIPPacketAction.ResourceHistory: - case IIPPacketAction.LinkTemplates: - IIPReply(packet.CallbackId, packet.Content); - break; - - // Invoke - case IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments: - case IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments: - IIPReplyInvoke(packet.CallbackId, packet.Content); - break; - - //case IIPPacket.IIPPacketAction.GetProperty: - // IIPReply(packet.CallbackId, packet.Content); - // break; - - //case IIPPacket.IIPPacketAction.GetPropertyIfModified: - // IIPReply(packet.CallbackId, packet.Content); - // break; - - case IIPPacketAction.Listen: - case IIPPacketAction.Unlisten: - case IIPPacketAction.SetProperty: - IIPReply(packet.CallbackId); - break; - - // Attribute - case IIPPacketAction.GetAllAttributes: - case IIPPacketAction.GetAttributes: - IIPReply(packet.CallbackId, packet.Content); - break; - - case IIPPacketAction.UpdateAllAttributes: - case IIPPacketAction.UpdateAttributes: - case IIPPacketAction.ClearAllAttributes: - case IIPPacketAction.ClearAttributes: - IIPReply(packet.CallbackId); - break; - - } - - } - else if (packet.Command == IIPPacketCommand.Report) - { - switch (packet.Report) - { - case IIPPacketReport.ManagementError: - IIPReportError(packet.CallbackId, ErrorType.Management, packet.ErrorCode, null); - break; - case IIPPacketReport.ExecutionError: - IIPReportError(packet.CallbackId, ErrorType.Exception, packet.ErrorCode, packet.ErrorMessage); - break; - case IIPPacketReport.ProgressReport: - IIPReportProgress(packet.CallbackId, ProgressType.Execution, packet.ProgressValue, packet.ProgressMax); - break; - case IIPPacketReport.ChunkStream: - IIPReportChunk(packet.CallbackId, packet.Content); - - break; - } - } - } - } - else { - var rt = authPacket.Parse(msg, offset, ends); + var act = (IIPPacketAction)(data[0] & 0x3f); + //Console.Write("Sent: " + cmd.ToString() + " " + act.ToString()); - //Console.WriteLine(session.LocalAuthentication.Type.ToString() + " " + offset + " " + ends + " " + rt + " " + authPacket.ToString()); + } - if (rt <= 0) + //foreach (var param in values) + // Console.Write(", " + param); + + //Console.WriteLine(); + } + + + Send(data); + + //StackTrace stackTrace = new StackTrace(; + + // Get calling method name + + //Console.WriteLine("TX " + hostType + " " + ar.Length + " " + stackTrace.GetFrame(1).GetMethod().ToString()); + */ + } + + /// + /// Send raw data through the connection. + /// + /// Data to send. + public override void Send(byte[] data) + { + //Console.WriteLine("Client: {0}", Data.Length); + + Global.Counters["IIP Sent Packets"]++; + base.Send(data); + } + + /// + /// KeyList to store user variables related to this connection. + /// + public KeyList Variables { get; } = new KeyList(); + + /// + /// IResource interface. + /// + public Instance Instance + { + get; + set; + } + + /// + /// Assign a socket to the connection. + /// + /// Any socket that implements ISocket. + public override void Assign(Sockets.ISocket socket) + { + base.Assign(socket); + + session.RemoteAuthentication.Source.Attributes[SourceAttributeType.IPv4] = socket.RemoteEndPoint.Address; + session.RemoteAuthentication.Source.Attributes[SourceAttributeType.Port] = socket.RemoteEndPoint.Port; + session.LocalAuthentication.Source.Attributes[SourceAttributeType.IPv4] = socket.LocalEndPoint.Address; + session.LocalAuthentication.Source.Attributes[SourceAttributeType.Port] = socket.LocalEndPoint.Port; + + if (socket.State == SocketState.Established && + session.LocalAuthentication.Type == AuthenticationType.Client) + { + Declare(); + } + } + + private void Declare() + { + var dmn = DC.ToBytes(session.LocalAuthentication.Domain);// domain); + + if (session.LocalAuthentication.Method == AuthenticationMethod.Credentials) + { + // declare (Credentials -> No Auth, No Enctypt) + + var un = DC.ToBytes(session.LocalAuthentication.Username); + + SendParams() + .AddUInt8(0x60) + .AddUInt8((byte)dmn.Length) + .AddUInt8Array(dmn) + .AddUInt8Array(localNonce) + .AddUInt8((byte)un.Length) + .AddUInt8Array(un) + .Done();//, dmn, localNonce, (byte)un.Length, un); + } + else if (session.LocalAuthentication.Method == AuthenticationMethod.Token) + { + + SendParams() + .AddUInt8(0x70) + .AddUInt8((byte)dmn.Length) + .AddUInt8Array(dmn) + .AddUInt8Array(localNonce) + .AddUInt64(session.LocalAuthentication.TokenIndex) + .Done();//, dmn, localNonce, token + + } + else if (session.LocalAuthentication.Method == AuthenticationMethod.None) + { + SendParams() + .AddUInt8(0x40) + .AddUInt8((byte)dmn.Length) + .AddUInt8Array(dmn) + .Done();//, dmn, localNonce, token + } + } + + /// + /// Create a new distributed connection. + /// + /// Socket to transfer data through. + /// Working domain. + /// Username. + /// Password. + public DistributedConnection(Sockets.ISocket socket, string domain, string username, string password) + { + this.session = new Session(new ClientAuthentication() + , new HostAuthentication()); + //Instance.Name = Global.GenerateCode(12); + //this.hostType = AuthenticationType.Client; + //this.domain = domain; + //this.localUsername = username; + session.LocalAuthentication.Domain = domain; + session.LocalAuthentication.Username = username; + session.LocalAuthentication.Method = AuthenticationMethod.Credentials; + this.localPasswordOrToken = DC.ToBytes(password); + + init(); + + Assign(socket); + } + + public DistributedConnection(Sockets.ISocket socket, string domain, ulong tokenIndex, string token) + { + this.session = new Session(new ClientAuthentication() + , new HostAuthentication()); + //Instance.Name = Global.GenerateCode(12); + //this.hostType = AuthenticationType.Client; + //this.domain = domain; + //this.localUsername = username; + session.LocalAuthentication.Domain = domain; + session.LocalAuthentication.TokenIndex = tokenIndex; + session.LocalAuthentication.Method = AuthenticationMethod.Token; + + this.localPasswordOrToken = DC.ToBytes(token); + + init(); + + Assign(socket); + } + + + /// + /// Create a new instance of a distributed connection + /// + public DistributedConnection() + { + //myId = Global.GenerateCode(12); + // localParams.Host = DistributedParameters.HostType.Host; + session = new Session(new HostAuthentication(), new ClientAuthentication()); + init(); + } + + + + public string Link(IResource resource) + { + if (resource is DistributedResource) + { + var r = resource as DistributedResource; + if (r.Instance.Store == this) + return this.Instance.Name + "/" + r.Id; + } + + return null; + } + + + void init() + { + //var q = queue; + queue.Then((x) => + { + if (x.Type == DistributedResourceQueueItem.DistributedResourceQueueItemType.Event) + x.Resource._EmitEventByIndex(x.Index, x.Value); + else + x.Resource._UpdatePropertyByIndex(x.Index, x.Value); + }); + //q.timeout?.Dispose(); + + var r = new Random(); + localNonce = new byte[32]; + r.NextBytes(localNonce); + } + + public override void Destroy() + { + UnsubscribeAll(); + this.OnReady = null; + this.OnError = null; + base.Destroy(); + } + + + private uint processPacket(byte[] msg, uint offset, uint ends, NetworkBuffer data, int chunkId) + { + //var packet = new IIPPacket(); + + + + // packets++; + + if (ready) + { + var rt = packet.Parse(msg, offset, ends); + //Console.WriteLine("Rec: " + chunkId + " " + packet.ToString()); + + /* + if (packet.Command == IIPPacketCommand.Event) + Console.WriteLine("Rec: " + packet.Command.ToString() + " " + packet.Event.ToString()); + else if (packet.Command == IIPPacketCommand.Report) + Console.WriteLine("Rec: " + packet.Command.ToString() + " " + packet.Report.ToString()); + else + Console.WriteLine("Rec: " + packet.Command.ToString() + " " + packet.Action.ToString() + " " + packet.ResourceId + " " + offset + "/" + ends); + */ + + + //packs.Add(packet.Command.ToString() + " " + packet.Action.ToString() + " " + packet.Event.ToString()); + + //if (packs.Count > 1) + // Console.WriteLine("P2"); + + //Console.WriteLine(""); + + if (rt <= 0) + { + //Console.WriteLine("Hold"); + var size = ends - offset; + data.HoldFor(msg, offset, size, size + (uint)(-rt)); + return ends; + } + else + { + + //Console.WriteLine($"CMD {packet.Command} {offset} {ends}"); + + offset += (uint)rt; + + if (packet.Command == IIPPacket.IIPPacketCommand.Event) { - data.HoldFor(msg, ends + (uint)(-rt)); - return ends; - } - else - { - offset += (uint)rt; - - if (session.LocalAuthentication.Type == AuthenticationType.Host) + switch (packet.Event) { - if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Declare) - { - session.RemoteAuthentication.Method = authPacket.RemoteMethod; + case IIPPacket.IIPPacketEvent.ResourceReassigned: + IIPEventResourceReassigned(packet.ResourceId, packet.NewResourceId); + break; + case IIPPacket.IIPPacketEvent.ResourceDestroyed: + IIPEventResourceDestroyed(packet.ResourceId); + break; + case IIPPacket.IIPPacketEvent.PropertyUpdated: + IIPEventPropertyUpdated(packet.ResourceId, packet.MethodIndex, packet.Content); + break; + case IIPPacket.IIPPacketEvent.EventOccurred: + IIPEventEventOccurred(packet.ResourceId, packet.MethodIndex, packet.Content); + break; - if (authPacket.RemoteMethod == AuthenticationMethod.Credentials && authPacket.LocalMethod == AuthenticationMethod.None) + case IIPPacketEvent.ChildAdded: + IIPEventChildAdded(packet.ResourceId, packet.ChildId); + break; + case IIPPacketEvent.ChildRemoved: + IIPEventChildRemoved(packet.ResourceId, packet.ChildId); + break; + case IIPPacketEvent.Renamed: + IIPEventRenamed(packet.ResourceId, packet.Content); + break; + case IIPPacketEvent.AttributesUpdated: + IIPEventAttributesUpdated(packet.ResourceId, packet.Content); + break; + } + } + else if (packet.Command == IIPPacket.IIPPacketCommand.Request) + { + switch (packet.Action) + { + // Manage + case IIPPacket.IIPPacketAction.AttachResource: + IIPRequestAttachResource(packet.CallbackId, packet.ResourceId); + break; + case IIPPacket.IIPPacketAction.ReattachResource: + IIPRequestReattachResource(packet.CallbackId, packet.ResourceId, packet.ResourceAge); + break; + case IIPPacket.IIPPacketAction.DetachResource: + IIPRequestDetachResource(packet.CallbackId, packet.ResourceId); + break; + case IIPPacket.IIPPacketAction.CreateResource: + IIPRequestCreateResource(packet.CallbackId, packet.StoreId, packet.ResourceId, packet.Content); + break; + case IIPPacket.IIPPacketAction.DeleteResource: + IIPRequestDeleteResource(packet.CallbackId, packet.ResourceId); + break; + case IIPPacketAction.AddChild: + IIPRequestAddChild(packet.CallbackId, packet.ResourceId, packet.ChildId); + break; + case IIPPacketAction.RemoveChild: + IIPRequestRemoveChild(packet.CallbackId, packet.ResourceId, packet.ChildId); + break; + case IIPPacketAction.RenameResource: + IIPRequestRenameResource(packet.CallbackId, packet.ResourceId, packet.Content); + break; + + // Inquire + case IIPPacket.IIPPacketAction.TemplateFromClassName: + IIPRequestTemplateFromClassName(packet.CallbackId, packet.ClassName); + break; + case IIPPacket.IIPPacketAction.TemplateFromClassId: + IIPRequestTemplateFromClassId(packet.CallbackId, packet.ClassId); + break; + case IIPPacket.IIPPacketAction.TemplateFromResourceId: + IIPRequestTemplateFromResourceId(packet.CallbackId, packet.ResourceId); + break; + case IIPPacketAction.QueryLink: + IIPRequestQueryResources(packet.CallbackId, packet.ResourceLink); + break; + + case IIPPacketAction.ResourceChildren: + IIPRequestResourceChildren(packet.CallbackId, packet.ResourceId); + break; + case IIPPacketAction.ResourceParents: + IIPRequestResourceParents(packet.CallbackId, packet.ResourceId); + break; + + case IIPPacket.IIPPacketAction.ResourceHistory: + IIPRequestInquireResourceHistory(packet.CallbackId, packet.ResourceId, packet.FromDate, packet.ToDate); + break; + + case IIPPacketAction.LinkTemplates: + IIPRequestLinkTemplates(packet.CallbackId, packet.ResourceLink); + break; + + // Invoke + case IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments: + IIPRequestInvokeFunctionArrayArguments(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content); + break; + + case IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments: + IIPRequestInvokeFunctionNamedArguments(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content); + break; + + //case IIPPacket.IIPPacketAction.GetProperty: + // IIPRequestGetProperty(packet.CallbackId, packet.ResourceId, packet.MethodIndex); + // break; + //case IIPPacket.IIPPacketAction.GetPropertyIfModified: + // IIPRequestGetPropertyIfModifiedSince(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.ResourceAge); + // break; + + case IIPPacket.IIPPacketAction.Listen: + IIPRequestListen(packet.CallbackId, packet.ResourceId, packet.MethodIndex); + break; + + case IIPPacket.IIPPacketAction.Unlisten: + IIPRequestUnlisten(packet.CallbackId, packet.ResourceId, packet.MethodIndex); + break; + + case IIPPacket.IIPPacketAction.SetProperty: + IIPRequestSetProperty(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content); + break; + + // Attribute + case IIPPacketAction.GetAllAttributes: + IIPRequestGetAttributes(packet.CallbackId, packet.ResourceId, packet.Content, true); + break; + case IIPPacketAction.UpdateAllAttributes: + IIPRequestUpdateAttributes(packet.CallbackId, packet.ResourceId, packet.Content, true); + break; + case IIPPacketAction.ClearAllAttributes: + IIPRequestClearAttributes(packet.CallbackId, packet.ResourceId, packet.Content, true); + break; + case IIPPacketAction.GetAttributes: + IIPRequestGetAttributes(packet.CallbackId, packet.ResourceId, packet.Content, false); + break; + case IIPPacketAction.UpdateAttributes: + IIPRequestUpdateAttributes(packet.CallbackId, packet.ResourceId, packet.Content, false); + break; + case IIPPacketAction.ClearAttributes: + IIPRequestClearAttributes(packet.CallbackId, packet.ResourceId, packet.Content, false); + break; + } + } + else if (packet.Command == IIPPacket.IIPPacketCommand.Reply) + { + switch (packet.Action) + { + // Manage + case IIPPacket.IIPPacketAction.AttachResource: + IIPReply(packet.CallbackId, packet.ClassId, packet.ResourceAge, packet.ResourceLink, packet.Content); + break; + + case IIPPacket.IIPPacketAction.ReattachResource: + IIPReply(packet.CallbackId, packet.ResourceAge, packet.Content); + + break; + case IIPPacket.IIPPacketAction.DetachResource: + IIPReply(packet.CallbackId); + break; + + case IIPPacket.IIPPacketAction.CreateResource: + IIPReply(packet.CallbackId, packet.ResourceId); + break; + + case IIPPacket.IIPPacketAction.DeleteResource: + case IIPPacketAction.AddChild: + case IIPPacketAction.RemoveChild: + case IIPPacketAction.RenameResource: + IIPReply(packet.CallbackId); + break; + + // Inquire + + case IIPPacket.IIPPacketAction.TemplateFromClassName: + case IIPPacket.IIPPacketAction.TemplateFromClassId: + case IIPPacket.IIPPacketAction.TemplateFromResourceId: + IIPReply(packet.CallbackId, TypeTemplate.Parse(packet.Content)); + break; + + case IIPPacketAction.QueryLink: + case IIPPacketAction.ResourceChildren: + case IIPPacketAction.ResourceParents: + case IIPPacketAction.ResourceHistory: + case IIPPacketAction.LinkTemplates: + IIPReply(packet.CallbackId, packet.Content); + break; + + // Invoke + case IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments: + case IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments: + IIPReplyInvoke(packet.CallbackId, packet.Content); + break; + + //case IIPPacket.IIPPacketAction.GetProperty: + // IIPReply(packet.CallbackId, packet.Content); + // break; + + //case IIPPacket.IIPPacketAction.GetPropertyIfModified: + // IIPReply(packet.CallbackId, packet.Content); + // break; + + case IIPPacketAction.Listen: + case IIPPacketAction.Unlisten: + case IIPPacketAction.SetProperty: + IIPReply(packet.CallbackId); + break; + + // Attribute + case IIPPacketAction.GetAllAttributes: + case IIPPacketAction.GetAttributes: + IIPReply(packet.CallbackId, packet.Content); + break; + + case IIPPacketAction.UpdateAllAttributes: + case IIPPacketAction.UpdateAttributes: + case IIPPacketAction.ClearAllAttributes: + case IIPPacketAction.ClearAttributes: + IIPReply(packet.CallbackId); + break; + + } + + } + else if (packet.Command == IIPPacketCommand.Report) + { + switch (packet.Report) + { + case IIPPacketReport.ManagementError: + IIPReportError(packet.CallbackId, ErrorType.Management, packet.ErrorCode, null); + break; + case IIPPacketReport.ExecutionError: + IIPReportError(packet.CallbackId, ErrorType.Exception, packet.ErrorCode, packet.ErrorMessage); + break; + case IIPPacketReport.ProgressReport: + IIPReportProgress(packet.CallbackId, ProgressType.Execution, packet.ProgressValue, packet.ProgressMax); + break; + case IIPPacketReport.ChunkStream: + IIPReportChunk(packet.CallbackId, packet.Content); + + break; + } + } + } + } + + else + { + var rt = authPacket.Parse(msg, offset, ends); + + //Console.WriteLine(session.LocalAuthentication.Type.ToString() + " " + offset + " " + ends + " " + rt + " " + authPacket.ToString()); + + if (rt <= 0) + { + data.HoldFor(msg, ends + (uint)(-rt)); + return ends; + } + else + { + offset += (uint)rt; + + if (session.LocalAuthentication.Type == AuthenticationType.Host) + { + if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Declare) + { + session.RemoteAuthentication.Method = authPacket.RemoteMethod; + + if (authPacket.RemoteMethod == AuthenticationMethod.Credentials && authPacket.LocalMethod == AuthenticationMethod.None) + { + try { - try + Server.Membership.UserExists(authPacket.RemoteUsername, authPacket.Domain).Then(x => { - Server.Membership.UserExists(authPacket.RemoteUsername, authPacket.Domain).Then(x => + if (x) { - if (x) - { - session.RemoteAuthentication.Username = authPacket.RemoteUsername; - remoteNonce = authPacket.RemoteNonce; - session.RemoteAuthentication.Domain = authPacket.Domain; - SendParams() - .AddUInt8(0xa0) - .AddUInt8Array(localNonce) - .Done(); + session.RemoteAuthentication.Username = authPacket.RemoteUsername; + remoteNonce = authPacket.RemoteNonce; + session.RemoteAuthentication.Domain = authPacket.Domain; + SendParams() + .AddUInt8(0xa0) + .AddUInt8Array(localNonce) + .Done(); //SendParams((byte)0xa0, localNonce); } - else - { + else + { //Console.WriteLine("User not found"); SendParams().AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.UserOrTokenNotFound) - .AddUInt16(14) - .AddString("User not found").Done(); - } - }); - } - catch (Exception ex) - { - var errMsg = DC.ToBytes(ex.Message); - - SendParams().AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.GeneralFailure) - .AddUInt16((ushort)errMsg.Length) - .AddUInt8Array(errMsg).Done(); - } + .AddUInt8((byte)ExceptionCode.UserOrTokenNotFound) + .AddUInt16(14) + .AddString("User not found").Done(); + } + }); } - else if (authPacket.RemoteMethod == AuthenticationMethod.Token && authPacket.LocalMethod == AuthenticationMethod.None) + catch (Exception ex) { - try + var errMsg = DC.ToBytes(ex.Message); + + SendParams().AddUInt8(0xc0) + .AddUInt8((byte)ExceptionCode.GeneralFailure) + .AddUInt16((ushort)errMsg.Length) + .AddUInt8Array(errMsg).Done(); + } + } + else if (authPacket.RemoteMethod == AuthenticationMethod.Token && authPacket.LocalMethod == AuthenticationMethod.None) + { + try + { + // Check if user and token exists + Server.Membership.TokenExists(authPacket.RemoteTokenIndex, authPacket.Domain).Then(x => { - // Check if user and token exists - Server.Membership.TokenExists(authPacket.RemoteTokenIndex, authPacket.Domain).Then(x => + if (x != null) + { + session.RemoteAuthentication.Username = x; + session.RemoteAuthentication.TokenIndex = authPacket.RemoteTokenIndex; + remoteNonce = authPacket.RemoteNonce; + session.RemoteAuthentication.Domain = authPacket.Domain; + SendParams() + .AddUInt8(0xa0) + .AddUInt8Array(localNonce) + .Done(); + } + else { - if (x != null) - { - session.RemoteAuthentication.Username = x; - session.RemoteAuthentication.TokenIndex = authPacket.RemoteTokenIndex; - remoteNonce = authPacket.RemoteNonce; - session.RemoteAuthentication.Domain = authPacket.Domain; - SendParams() - .AddUInt8(0xa0) - .AddUInt8Array(localNonce) - .Done(); - } - else - { //Console.WriteLine("User not found"); SendParams() - .AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.UserOrTokenNotFound) - .AddUInt16(15) - .AddString("Token not found") - .Done(); - } - }); - } - catch (Exception ex) - { - var errMsg = DC.ToBytes(ex.Message); - - SendParams() - .AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.GeneralFailure) - .AddUInt16((ushort)errMsg.Length) - .AddUInt8Array(errMsg) - .Done(); - } + .AddUInt8(0xc0) + .AddUInt8((byte)ExceptionCode.UserOrTokenNotFound) + .AddUInt16(15) + .AddString("Token not found") + .Done(); + } + }); } - else if (authPacket.RemoteMethod == AuthenticationMethod.None && authPacket.LocalMethod == AuthenticationMethod.None) + catch (Exception ex) { - try - { - // Check if guests are allowed - if (Server.Membership.GuestsAllowed) - { - session.RemoteAuthentication.Username = "g-" + Global.GenerateCode(); - session.RemoteAuthentication.Domain = authPacket.Domain; - readyToEstablish = true; - SendParams() - .AddUInt8(0x80) - .Done(); - } - else - { - SendParams() - .AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.AccessDenied) - .AddUInt16(18) - .AddString("Guests not allowed") - .Done(); - } - } - catch (Exception ex) - { - var errMsg = DC.ToBytes(ex.Message); - - SendParams().AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.GeneralFailure) - .AddUInt16((ushort)errMsg.Length) - .AddUInt8Array(errMsg).Done(); - } - } - - } - else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Action) - { - if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.AuthenticateHash) - { - var remoteHash = authPacket.Hash; - AsyncReply reply = null; - - try - { - if (session.RemoteAuthentication.Method == AuthenticationMethod.Credentials) - { - reply = Server.Membership.GetPassword(session.RemoteAuthentication.Username, - session.RemoteAuthentication.Domain); - } - else if (session.RemoteAuthentication.Method == AuthenticationMethod.Token) - { - reply = Server.Membership.GetToken(session.RemoteAuthentication.TokenIndex, - session.RemoteAuthentication.Domain); - } - else - { - // Error - } - - reply.Then((pw) => - { - if (pw != null) - { - var hashFunc = SHA256.Create(); - //var hash = hashFunc.ComputeHash(BinaryList.ToBytes(pw, remoteNonce, localNonce)); - var hash = hashFunc.ComputeHash((new BinaryList()) - .AddUInt8Array(pw) - .AddUInt8Array(remoteNonce) - .AddUInt8Array(localNonce) - .ToArray()); - if (hash.SequenceEqual(remoteHash)) - { - // send our hash - //var localHash = hashFunc.ComputeHash(BinaryList.ToBytes(localNonce, remoteNonce, pw)); - //SendParams((byte)0, localHash); - - var localHash = hashFunc.ComputeHash((new BinaryList()).AddUInt8Array(localNonce).AddUInt8Array(remoteNonce).AddUInt8Array(pw).ToArray()); - SendParams().AddUInt8(0).AddUInt8Array(localHash).Done(); - - readyToEstablish = true; - } - else - { - //Global.Log("auth", LogType.Warning, "U:" + RemoteUsername + " IP:" + Socket.RemoteEndPoint.Address.ToString() + " S:DENIED"); - SendParams().AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.AccessDenied) - .AddUInt16(13) - .AddString("Access Denied") - .Done(); - } - } - }); - } - catch (Exception ex) - { - var errMsg = DC.ToBytes(ex.Message); - - SendParams().AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.GeneralFailure) - .AddUInt16((ushort)errMsg.Length) - .AddUInt8Array(errMsg).Done(); - } - } - else if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.NewConnection) - { - if (readyToEstablish) - { - var r = new Random(); - session.Id = new byte[32]; - r.NextBytes(session.Id); - //SendParams((byte)0x28, session.Id); - SendParams().AddUInt8(0x28) - .AddUInt8Array(session.Id) - .Done(); - - if (this.Instance == null) - { - Warehouse.Put(this.RemoteUsername, this, null, Server).Then(x => - { - - ready = true; - openReply?.Trigger(true); - OnReady?.Invoke(this); - - Server?.Membership.Login(session); - loginDate = DateTime.Now; - - }).Error(x => - { - openReply?.TriggerError(x); - }); - } - else - { - ready = true; - openReply?.Trigger(true); - OnReady?.Invoke(this); - Server?.Membership.Login(session); - } - - //Global.Log("auth", LogType.Warning, "U:" + RemoteUsername + " IP:" + Socket.RemoteEndPoint.Address.ToString() + " S:AUTH"); - - } - else - { - SendParams() - .AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.GeneralFailure) - .AddUInt16(9) - .AddString("Not ready") - .Done(); - } - } - } - } - else if (session.LocalAuthentication.Type == AuthenticationType.Client) - { - if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Acknowledge) - { - if (authPacket.RemoteMethod == AuthenticationMethod.None) - { - // send establish - SendParams() - .AddUInt8(0x20) - .AddUInt16(0) - .Done(); - } - else if (authPacket.RemoteMethod == AuthenticationMethod.Credentials - || authPacket.RemoteMethod == AuthenticationMethod.Token) - { - remoteNonce = authPacket.RemoteNonce; - - // send our hash - var hashFunc = SHA256.Create(); - //var localHash = hashFunc.ComputeHash(BinaryList.ToBytes(localPassword, localNonce, remoteNonce)); - var localHash = hashFunc.ComputeHash(new BinaryList() - .AddUInt8Array(localPasswordOrToken) - .AddUInt8Array(localNonce) - .AddUInt8Array(remoteNonce) - .ToArray()); + var errMsg = DC.ToBytes(ex.Message); SendParams() - .AddUInt8(0) - .AddUInt8Array(localHash) + .AddUInt8(0xc0) + .AddUInt8((byte)ExceptionCode.GeneralFailure) + .AddUInt16((ushort)errMsg.Length) + .AddUInt8Array(errMsg) .Done(); } - //SendParams((byte)0, localHash); } - else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Action) + else if (authPacket.RemoteMethod == AuthenticationMethod.None && authPacket.LocalMethod == AuthenticationMethod.None) { - if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.AuthenticateHash) + try { - // check if the server knows my password - var hashFunc = SHA256.Create(); - //var remoteHash = hashFunc.ComputeHash(BinaryList.ToBytes(remoteNonce, localNonce, localPassword)); - var remoteHash = hashFunc.ComputeHash(new BinaryList() - .AddUInt8Array(remoteNonce) - .AddUInt8Array(localNonce) - .AddUInt8Array(localPasswordOrToken) - .ToArray()); - - - if (remoteHash.SequenceEqual(authPacket.Hash)) + // Check if guests are allowed + if (Server.Membership.GuestsAllowed) { - // send establish request + session.RemoteAuthentication.Username = "g-" + Global.GenerateCode(); + session.RemoteAuthentication.Domain = authPacket.Domain; + readyToEstablish = true; SendParams() - .AddUInt8(0x20) - .AddUInt16(0) + .AddUInt8(0x80) .Done(); } else { SendParams() .AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.ChallengeFailed) - .AddUInt16(16) - .AddString("Challenge Failed") + .AddUInt8((byte)ExceptionCode.AccessDenied) + .AddUInt16(18) + .AddString("Guests not allowed") .Done(); - - //SendParams((byte)0xc0, 1, (ushort)5, DC.ToBytes("Error")); } } - else if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.ConnectionEstablished) + catch (Exception ex) { - session.Id = authPacket.SessionId; + var errMsg = DC.ToBytes(ex.Message); - ready = true; - // put it in the warehouse + SendParams().AddUInt8(0xc0) + .AddUInt8((byte)ExceptionCode.GeneralFailure) + .AddUInt16((ushort)errMsg.Length) + .AddUInt8Array(errMsg).Done(); + } + } - if (this.Instance == null) + } + else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Action) + { + if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.AuthenticateHash) + { + var remoteHash = authPacket.Hash; + AsyncReply reply = null; + + try + { + if (session.RemoteAuthentication.Method == AuthenticationMethod.Credentials) { - Warehouse.Put(this.LocalUsername, this, null, Server).Then(x => - { - openReply?.Trigger(true); - OnReady?.Invoke(this); - - }).Error(x => openReply?.TriggerError(x)); + reply = Server.Membership.GetPassword(session.RemoteAuthentication.Username, + session.RemoteAuthentication.Domain); + } + else if (session.RemoteAuthentication.Method == AuthenticationMethod.Token) + { + reply = Server.Membership.GetToken(session.RemoteAuthentication.TokenIndex, + session.RemoteAuthentication.Domain); } else { - openReply?.Trigger(true); - OnReady?.Invoke(this); + // Error } + + reply.Then((pw) => + { + if (pw != null) + { + var hashFunc = SHA256.Create(); + //var hash = hashFunc.ComputeHash(BinaryList.ToBytes(pw, remoteNonce, localNonce)); + var hash = hashFunc.ComputeHash((new BinaryList()) + .AddUInt8Array(pw) + .AddUInt8Array(remoteNonce) + .AddUInt8Array(localNonce) + .ToArray()); + if (hash.SequenceEqual(remoteHash)) + { + // send our hash + //var localHash = hashFunc.ComputeHash(BinaryList.ToBytes(localNonce, remoteNonce, pw)); + //SendParams((byte)0, localHash); + + var localHash = hashFunc.ComputeHash((new BinaryList()).AddUInt8Array(localNonce).AddUInt8Array(remoteNonce).AddUInt8Array(pw).ToArray()); + SendParams().AddUInt8(0).AddUInt8Array(localHash).Done(); + + readyToEstablish = true; + } + else + { + //Global.Log("auth", LogType.Warning, "U:" + RemoteUsername + " IP:" + Socket.RemoteEndPoint.Address.ToString() + " S:DENIED"); + SendParams().AddUInt8(0xc0) + .AddUInt8((byte)ExceptionCode.AccessDenied) + .AddUInt16(13) + .AddString("Access Denied") + .Done(); + } + } + }); + } + catch (Exception ex) + { + var errMsg = DC.ToBytes(ex.Message); + + SendParams().AddUInt8(0xc0) + .AddUInt8((byte)ExceptionCode.GeneralFailure) + .AddUInt16((ushort)errMsg.Length) + .AddUInt8Array(errMsg).Done(); } } - else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Error) + else if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.NewConnection) { - openReply?.TriggerError(new AsyncException(ErrorType.Management, authPacket.ErrorCode, authPacket.ErrorMessage)); - OnError?.Invoke(this, authPacket.ErrorCode, authPacket.ErrorMessage); - Close(); + if (readyToEstablish) + { + var r = new Random(); + session.Id = new byte[32]; + r.NextBytes(session.Id); + //SendParams((byte)0x28, session.Id); + SendParams().AddUInt8(0x28) + .AddUInt8Array(session.Id) + .Done(); + + if (this.Instance == null) + { + Warehouse.Put(this.RemoteUsername, this, null, Server).Then(x => + { + + ready = true; + openReply?.Trigger(true); + OnReady?.Invoke(this); + + Server?.Membership.Login(session); + loginDate = DateTime.Now; + + }).Error(x => + { + openReply?.TriggerError(x); + }); + } + else + { + ready = true; + openReply?.Trigger(true); + OnReady?.Invoke(this); + Server?.Membership.Login(session); + } + + //Global.Log("auth", LogType.Warning, "U:" + RemoteUsername + " IP:" + Socket.RemoteEndPoint.Address.ToString() + " S:AUTH"); + + } + else + { + SendParams() + .AddUInt8(0xc0) + .AddUInt8((byte)ExceptionCode.GeneralFailure) + .AddUInt16(9) + .AddString("Not ready") + .Done(); + } } } } - } - - return offset; - - //if (offset < ends) - // processPacket(msg, offset, ends, data, chunkId); - } - - protected override void DataReceived(NetworkBuffer data) - { - // Console.WriteLine("DR " + hostType + " " + data.Available + " " + RemoteEndPoint.ToString()); - var msg = data.Read(); - uint offset = 0; - uint ends = (uint)msg.Length; - - var packs = new List(); - - var chunkId = (new Random()).Next(1000, 1000000); - - var list = new List();// double, IIPPacketCommand>(); - - - this.Socket.Hold(); - - try - { - while (offset < ends) + else if (session.LocalAuthentication.Type == AuthenticationType.Client) { - offset = processPacket(msg, offset, ends, data, chunkId); - } - } - catch (Exception ex) - { - Console.WriteLine(ex); - } - finally - { - this.Socket?.Unhold(); - } - } - - - [Attribute] - public string Username { get; set; } - - [Attribute] - public string Password { get; set; } - - [Attribute] - public string Token { get; set; } - - [Attribute] - public ulong TokenIndex { get; set; } - - [Attribute] - public string Domain { get; set; } - /// - /// Resource interface - /// - /// Resource trigger. - /// - public AsyncReply Trigger(ResourceTrigger trigger) - { - if (trigger == ResourceTrigger.Open) - { - if (this.Server != null) - return new AsyncReply(true); - - var host = Instance.Name.Split(':'); - - var address = host[0]; - var port = host.Length > 1 ? ushort.Parse(host[1]) : (ushort) 10518; - // assign domain from hostname if not provided - var domain = Domain != null ? Domain : address; - - if (Username != null // Instance.Attributes.ContainsKey("username") - && Password != null)/// Instance.Attributes.ContainsKey("password")) - { - return Connect(AuthenticationMethod.Credentials, null, address, port, Username, 0, DC.ToBytes(Password), domain); - } - else if (Token != null) - { - return Connect(AuthenticationMethod.Token, null, address, port, null, TokenIndex, DC.ToBytes(Token), domain); - } - else - { - - return Connect(AuthenticationMethod.None, null, address, port, null, 0, null, domain); - - } - } - - return new AsyncReply(true); - } - - - - - public AsyncReply Connect(AuthenticationMethod method = AuthenticationMethod.Certificate, Sockets.ISocket socket = null, string hostname = null, ushort port = 0, string username = null, ulong tokenIndex = 0, byte[] passwordOrToken = null, string domain = null) - { - if (openReply != null) - throw new AsyncException(ErrorType.Exception, 0, "Connection in progress"); - - openReply = new AsyncReply(); - - if (hostname != null) - { - session = new Session(new ClientAuthentication() - , new HostAuthentication()); - - session.LocalAuthentication.Method = method; - session.LocalAuthentication.TokenIndex = tokenIndex; - session.LocalAuthentication.Domain = domain; - session.LocalAuthentication.Username = username; - localPasswordOrToken = passwordOrToken; - //localPassword = password; - } - - if (session == null) - throw new AsyncException(ErrorType.Exception, 0, "Session not initialized"); - - if (socket == null) - socket = new TCPSocket(); - - if (port > 0) - this._port = port; - if (hostname != null) - this._hostname = hostname; - - socket.Connect(this._hostname, this._port).Then(x => - { - Assign(socket); - }).Error((x) => - { - openReply.TriggerError(x); - openReply = null; - }); - - return openReply; - } - - public async AsyncReply Reconnect() - { - try - { - if (await Connect()) - { - try + if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Acknowledge) { - var bag = new AsyncBag(); - - for (var i = 0; i < resources.Keys.Count; i++) + if (authPacket.RemoteMethod == AuthenticationMethod.None) { - var index = resources.Keys.ElementAt(i); - bag.Add(Fetch(index)); + // send establish + SendParams() + .AddUInt8(0x20) + .AddUInt16(0) + .Done(); } + else if (authPacket.RemoteMethod == AuthenticationMethod.Credentials + || authPacket.RemoteMethod == AuthenticationMethod.Token) + { + remoteNonce = authPacket.RemoteNonce; - bag.Seal(); - await bag; + // send our hash + var hashFunc = SHA256.Create(); + //var localHash = hashFunc.ComputeHash(BinaryList.ToBytes(localPassword, localNonce, remoteNonce)); + var localHash = hashFunc.ComputeHash(new BinaryList() + .AddUInt8Array(localPasswordOrToken) + .AddUInt8Array(localNonce) + .AddUInt8Array(remoteNonce) + .ToArray()); + + SendParams() + .AddUInt8(0) + .AddUInt8Array(localHash) + .Done(); + } + //SendParams((byte)0, localHash); } - catch (Exception ex) + else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Action) { - Global.Log(ex); - //print(ex.toString()); + if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.AuthenticateHash) + { + // check if the server knows my password + var hashFunc = SHA256.Create(); + //var remoteHash = hashFunc.ComputeHash(BinaryList.ToBytes(remoteNonce, localNonce, localPassword)); + var remoteHash = hashFunc.ComputeHash(new BinaryList() + .AddUInt8Array(remoteNonce) + .AddUInt8Array(localNonce) + .AddUInt8Array(localPasswordOrToken) + .ToArray()); + + + if (remoteHash.SequenceEqual(authPacket.Hash)) + { + // send establish request + SendParams() + .AddUInt8(0x20) + .AddUInt16(0) + .Done(); + } + else + { + SendParams() + .AddUInt8(0xc0) + .AddUInt8((byte)ExceptionCode.ChallengeFailed) + .AddUInt16(16) + .AddString("Challenge Failed") + .Done(); + + //SendParams((byte)0xc0, 1, (ushort)5, DC.ToBytes("Error")); + } + } + else if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.ConnectionEstablished) + { + session.Id = authPacket.SessionId; + + ready = true; + // put it in the warehouse + + if (this.Instance == null) + { + Warehouse.Put(this.LocalUsername, this, null, Server).Then(x => + { + openReply?.Trigger(true); + OnReady?.Invoke(this); + + }).Error(x => openReply?.TriggerError(x)); + } + else + { + openReply?.Trigger(true); + OnReady?.Invoke(this); + } + } + } + else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Error) + { + openReply?.TriggerError(new AsyncException(ErrorType.Management, authPacket.ErrorCode, authPacket.ErrorMessage)); + OnError?.Invoke(this, authPacket.ErrorCode, authPacket.ErrorMessage); + Close(); } } } - catch + } + + return offset; + + //if (offset < ends) + // processPacket(msg, offset, ends, data, chunkId); + } + + protected override void DataReceived(NetworkBuffer data) + { + // Console.WriteLine("DR " + hostType + " " + data.Available + " " + RemoteEndPoint.ToString()); + var msg = data.Read(); + uint offset = 0; + uint ends = (uint)msg.Length; + + var packs = new List(); + + var chunkId = (new Random()).Next(1000, 1000000); + + var list = new List();// double, IIPPacketCommand>(); + + + this.Socket.Hold(); + + try + { + while (offset < ends) { - return false; + offset = processPacket(msg, offset, ends, data, chunkId); } - - return true; } - - // AsyncReply connect({ISocket socket, String hostname, int port, String username, DC password, String domain}) - - /// - /// Store interface. - /// - /// Resource. - /// - public AsyncReply Put(IResource resource) + catch (Exception ex) { - if (Codec.IsLocalResource(resource, this)) - resources.Add((resource as DistributedResource).Id, (DistributedResource)resource); - // else ... send it to the peer - return new AsyncReply(true); + Console.WriteLine(ex); } - - public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + finally { - // nothing to do - return true; + this.Socket?.Unhold(); } + } - public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + + [Attribute] + public string Username { get; set; } + + [Attribute] + public string Password { get; set; } + + [Attribute] + public string Token { get; set; } + + [Attribute] + public ulong TokenIndex { get; set; } + + [Attribute] + public string Domain { get; set; } + /// + /// Resource interface + /// + /// Resource trigger. + /// + public AsyncReply Trigger(ResourceTrigger trigger) + { + if (trigger == ResourceTrigger.Open) { - // nothing to do - return true; + if (this.Server != null) + return new AsyncReply(true); + + var host = Instance.Name.Split(':'); + + var address = host[0]; + var port = host.Length > 1 ? ushort.Parse(host[1]) : (ushort)10518; + // assign domain from hostname if not provided + var domain = Domain != null ? Domain : address; + + if (Username != null // Instance.Attributes.ContainsKey("username") + && Password != null)/// Instance.Attributes.ContainsKey("password")) + { + return Connect(AuthenticationMethod.Credentials, null, address, port, Username, 0, DC.ToBytes(Password), domain); + } + else if (Token != null) + { + return Connect(AuthenticationMethod.Token, null, address, port, null, TokenIndex, DC.ToBytes(Token), domain); + } + else + { + + return Connect(AuthenticationMethod.None, null, address, port, null, 0, null, domain); + + } } - AsyncReply IStore.AddChild(IResource parent, IResource child) + return new AsyncReply(true); + } + + + + + public AsyncReply Connect(AuthenticationMethod method = AuthenticationMethod.Certificate, Sockets.ISocket socket = null, string hostname = null, ushort port = 0, string username = null, ulong tokenIndex = 0, byte[] passwordOrToken = null, string domain = null) + { + if (openReply != null) + throw new AsyncException(ErrorType.Exception, 0, "Connection in progress"); + + openReply = new AsyncReply(); + + if (hostname != null) { - // not implemented - throw new NotImplementedException(); + session = new Session(new ClientAuthentication() + , new HostAuthentication()); + + session.LocalAuthentication.Method = method; + session.LocalAuthentication.TokenIndex = tokenIndex; + session.LocalAuthentication.Domain = domain; + session.LocalAuthentication.Username = username; + localPasswordOrToken = passwordOrToken; + //localPassword = password; } - AsyncReply IStore.RemoveChild(IResource parent, IResource child) + if (session == null) + throw new AsyncException(ErrorType.Exception, 0, "Session not initialized"); + + if (socket == null) + socket = new TCPSocket(); + + if (port > 0) + this._port = port; + if (hostname != null) + this._hostname = hostname; + + socket.Connect(this._hostname, this._port).Then(x => { - // not implemeneted - throw new NotImplementedException(); - } - - public AsyncReply AddParent(IResource child, IResource parent) + Assign(socket); + }).Error((x) => { - throw new NotImplementedException(); - } + openReply.TriggerError(x); + openReply = null; + }); - public AsyncReply RemoveParent(IResource child, IResource parent) + return openReply; + } + + public async AsyncReply Reconnect() + { + try { - throw new NotImplementedException(); - } + if (await Connect()) + { + try + { + var bag = new AsyncBag(); - public AsyncBag Children(IResource resource, string name) where T : IResource + for (var i = 0; i < resources.Keys.Count; i++) + { + var index = resources.Keys.ElementAt(i); + bag.Add(Fetch(index)); + } + + bag.Seal(); + await bag; + } + catch (Exception ex) + { + Global.Log(ex); + //print(ex.toString()); + } + } + } + catch { - throw new Exception("SS"); - - //if (Codec.IsLocalResource(resource, this)) - // return new AsyncBag((resource as DistributedResource).children.Where(x => x.GetType() == typeof(T)).Select(x => (T)x)); - - //return null; + return false; } - public AsyncBag Parents(IResource resource, string name) where T : IResource - { - throw new Exception("SS"); - //if (Codec.IsLocalResource(resource, this)) - // return (resource as DistributedResource).parents.Where(x => x.GetType() == typeof(T)).Select(x => (T)x); + return true; + } - } + // AsyncReply connect({ISocket socket, String hostname, int port, String username, DC password, String domain}) + /// + /// Store interface. + /// + /// Resource. + /// + public AsyncReply Put(IResource resource) + { + if (Codec.IsLocalResource(resource, this)) + resources.Add((resource as DistributedResource).Id, (DistributedResource)resource); + // else ... send it to the peer + return new AsyncReply(true); + } - protected override void Connected() - { - if (session.LocalAuthentication.Type == AuthenticationType.Client) - Declare(); - } + public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + { + // nothing to do + return true; + } - protected override void Disconencted() - { - // clean up - readyToEstablish = false; + public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + { + // nothing to do + return true; + } - foreach (var x in requests.Values) - x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed")); + AsyncReply IStore.AddChild(IResource parent, IResource child) + { + // not implemented + throw new NotImplementedException(); + } - foreach (var x in resourceRequests.Values) - x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed")); + AsyncReply IStore.RemoveChild(IResource parent, IResource child) + { + // not implemeneted + throw new NotImplementedException(); + } - foreach (var x in templateRequests.Values) - x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed")); + public AsyncReply AddParent(IResource child, IResource parent) + { + throw new NotImplementedException(); + } - requests.Clear(); - resourceRequests.Clear(); - templateRequests.Clear(); + public AsyncReply RemoveParent(IResource child, IResource parent) + { + throw new NotImplementedException(); + } - foreach (var x in resources.Values) - x.Suspend(); + public AsyncBag Children(IResource resource, string name) where T : IResource + { + throw new Exception("SS"); - UnsubscribeAll(); + //if (Codec.IsLocalResource(resource, this)) + // return new AsyncBag((resource as DistributedResource).children.Where(x => x.GetType() == typeof(T)).Select(x => (T)x)); - Warehouse.Remove(this); + //return null; + } - if (ready) - Server?.Membership.Logout(session); - - ready = false; - } - - /* - public AsyncBag Children(IResource resource) - { - if (Codec.IsLocalReso turce(resource, this)) - return (resource as DistributedResource).children.Where(x => x.GetType() == typeof(T)).Select(x => (T)x); - - return null; - } - - public AsyncBag Parents(IResource resource) - { - if (Codec.IsLocalResource(resource, this)) - return (resource as DistributedResource).parents.Where(x => x.GetType() == typeof(T)).Select(x => (T)x); - - return null; - } - */ + public AsyncBag Parents(IResource resource, string name) where T : IResource + { + throw new Exception("SS"); + //if (Codec.IsLocalResource(resource, this)) + // return (resource as DistributedResource).parents.Where(x => x.GetType() == typeof(T)).Select(x => (T)x); } + + + protected override void Connected() + { + if (session.LocalAuthentication.Type == AuthenticationType.Client) + Declare(); + } + + protected override void Disconencted() + { + // clean up + readyToEstablish = false; + + foreach (var x in requests.Values) + x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed")); + + foreach (var x in resourceRequests.Values) + x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed")); + + foreach (var x in templateRequests.Values) + x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed")); + + requests.Clear(); + resourceRequests.Clear(); + templateRequests.Clear(); + + foreach (var x in resources.Values) + x.Suspend(); + + UnsubscribeAll(); + + Warehouse.Remove(this); + + if (ready) + Server?.Membership.Logout(session); + + ready = false; + } + + /* + public AsyncBag Children(IResource resource) + { + if (Codec.IsLocalReso turce(resource, this)) + return (resource as DistributedResource).children.Where(x => x.GetType() == typeof(T)).Select(x => (T)x); + + return null; + } + + public AsyncBag Parents(IResource resource) + { + if (Codec.IsLocalResource(resource, this)) + return (resource as DistributedResource).parents.Where(x => x.GetType() == typeof(T)).Select(x => (T)x); + + return null; + } + */ + } diff --git a/Esiur/Net/IIP/DistributedConnectionProtocol.cs b/Esiur/Net/IIP/DistributedConnectionProtocol.cs index a9215e8..919b72c 100644 --- a/Esiur/Net/IIP/DistributedConnectionProtocol.cs +++ b/Esiur/Net/IIP/DistributedConnectionProtocol.cs @@ -38,461 +38,461 @@ using System.Text; using System.Threading.Tasks; using System.Security.Cryptography.X509Certificates; -namespace Esiur.Net.IIP +namespace Esiur.Net.IIP; + +partial class DistributedConnection { - partial class DistributedConnection + KeyList resources = new KeyList(); + KeyList> resourceRequests = new KeyList>(); + KeyList> templateRequests = new KeyList>(); + + + KeyList> pathRequests = new KeyList>(); + + Dictionary templates = new Dictionary(); + + KeyList requests = new KeyList(); + + volatile uint callbackCounter = 0; + + //List subscriptions = new List(); + Dictionary> subscriptions = new Dictionary>();// new List(); + + + internal KeyList cache = new(); + + object subscriptionsLock = new object(); + + AsyncQueue queue = new AsyncQueue(); + + /// + /// Send IIP request. + /// + /// Packet action. + /// Arguments to send. + /// + internal SendList SendRequest(IIPPacket.IIPPacketAction action) { - KeyList resources = new KeyList(); - KeyList> resourceRequests = new KeyList>(); - KeyList> templateRequests = new KeyList>(); + var reply = new AsyncReply(); + var c = callbackCounter++; // avoid thread racing + requests.Add(c, reply); + return (SendList)SendParams(reply).AddUInt8((byte)(0x40 | (byte)action)).AddUInt32(c); + } - KeyList> pathRequests = new KeyList>(); + /* + internal IAsyncReply SendRequest(IIPPacket.IIPPacketAction action, params object[] args) + { + var reply = new AsyncReply(); + callbackCounter++; + var bl = new BinaryList((byte)(0x40 | (byte)action), callbackCounter); + bl.AddRange(args); + Send(bl.ToArray()); + requests.Add(callbackCounter, reply); + return reply; + } + */ - Dictionary templates = new Dictionary(); - - KeyList requests = new KeyList(); - - volatile uint callbackCounter = 0; - - //List subscriptions = new List(); - Dictionary> subscriptions = new Dictionary>();// new List(); - - - internal KeyList cache = new(); - - object subscriptionsLock = new object(); - - AsyncQueue queue = new AsyncQueue(); - - /// - /// Send IIP request. - /// - /// Packet action. - /// Arguments to send. - /// - internal SendList SendRequest(IIPPacket.IIPPacketAction action) - { - var reply = new AsyncReply(); - var c = callbackCounter++; // avoid thread racing - requests.Add(c, reply); - - return (SendList)SendParams(reply).AddUInt8((byte)(0x40 | (byte)action)).AddUInt32(c); - } + //uint maxcallerid = 0; + internal SendList SendReply(IIPPacket.IIPPacketAction action, uint callbackId) + { /* - internal IAsyncReply SendRequest(IIPPacket.IIPPacketAction action, params object[] args) + if (callbackId > maxcallerid) { - var reply = new AsyncReply(); - callbackCounter++; - var bl = new BinaryList((byte)(0x40 | (byte)action), callbackCounter); - bl.AddRange(args); - Send(bl.ToArray()); - requests.Add(callbackCounter, reply); - return reply; + maxcallerid = callbackId; + } + else + { + Console.Beep(); + } */ - //uint maxcallerid = 0; + return (SendList)SendParams().AddUInt8((byte)(0x80 | (byte)action)).AddUInt32(callbackId); + } - internal SendList SendReply(IIPPacket.IIPPacketAction action, uint callbackId) + internal SendList SendEvent(IIPPacket.IIPPacketEvent evt) + { + return (SendList)SendParams().AddUInt8((byte)(evt)); + } + + internal AsyncReply SendListenRequest(uint instanceId, byte index) + { + var reply = new AsyncReply(); + var c = callbackCounter++; + requests.Add(c, reply); + + SendParams().AddUInt8((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.Listen)) + .AddUInt32(c) + .AddUInt32(instanceId) + .AddUInt8(index) + .Done(); + + return reply; + } + + internal AsyncReply SendUnlistenRequest(uint instanceId, byte index) + { + var reply = new AsyncReply(); + var c = callbackCounter++; + requests.Add(c, reply); + + SendParams().AddUInt8((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.Unlisten)) + .AddUInt32(c) + .AddUInt32(instanceId) + .AddUInt8(index) + .Done(); + + return reply; + } + + + internal AsyncReply SendInvokeByArrayArguments(uint instanceId, byte index, object[] parameters) + { + var pb = Codec.ComposeVarArray(parameters, this, true); + + var reply = new AsyncReply(); + var c = callbackCounter++; + requests.Add(c, reply); + + SendParams().AddUInt8((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments)) + .AddUInt32(c) + .AddUInt32(instanceId) + .AddUInt8(index) + .AddUInt8Array(pb) + .Done(); + + //var bl = new BinaryList((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments), + // callbackCounter, instanceId, index, pb); + //Send(bl.ToArray()); + + return reply; + } + + internal AsyncReply SendDetachRequest(uint instanceId) + { + try { - /* - if (callbackId > maxcallerid) - { - maxcallerid = callbackId; - } - else - { - Console.Beep(); - - } - */ - - return (SendList)SendParams().AddUInt8((byte)(0x80 | (byte)action)).AddUInt32(callbackId); + return SendRequest(IIPPacket.IIPPacketAction.DetachResource).AddUInt32(instanceId).Done(); } - - internal SendList SendEvent(IIPPacket.IIPPacketEvent evt) + catch { - return (SendList)SendParams().AddUInt8((byte)(evt)); + return null; } + } - internal AsyncReply SendListenRequest(uint instanceId, byte index) - { - var reply = new AsyncReply(); - var c = callbackCounter++; - requests.Add(c, reply); + internal AsyncReply SendInvokeByNamedArguments(uint instanceId, byte index, Structure parameters) + { + var pb = Codec.ComposeStructure(parameters, this, true, true, true); - SendParams().AddUInt8((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.Listen)) - .AddUInt32(c) - .AddUInt32(instanceId) - .AddUInt8(index) - .Done(); + /* + var reply = new AsyncReply(); + callbackCounter++; + var bl = new BinaryList((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments), + callbackCounter, instanceId, index, pb); + Send(bl.ToArray()); + requests.Add(callbackCounter, reply); - return reply; - } + return reply; + */ - internal AsyncReply SendUnlistenRequest(uint instanceId, byte index) - { - var reply = new AsyncReply(); - var c = callbackCounter++; - requests.Add(c, reply); + var reply = new AsyncReply(); + var c = callbackCounter++; + requests.Add(c, reply); - SendParams().AddUInt8((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.Unlisten)) - .AddUInt32(c) - .AddUInt32(instanceId) - .AddUInt8(index) - .Done(); - - return reply; - } + SendParams().AddUInt8((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments)) + .AddUInt32(c) + .AddUInt32(instanceId) + .AddUInt8(index) + .AddUInt8Array(pb) + .Done(); + return reply; + } - internal AsyncReply SendInvokeByArrayArguments(uint instanceId, byte index, object[] parameters) - { - var pb = Codec.ComposeVarArray(parameters, this, true); - - var reply = new AsyncReply(); - var c = callbackCounter++; - requests.Add(c, reply); - - SendParams().AddUInt8((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments)) - .AddUInt32(c) - .AddUInt32(instanceId) - .AddUInt8(index) - .AddUInt8Array(pb) - .Done(); - - //var bl = new BinaryList((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments), - // callbackCounter, instanceId, index, pb); - //Send(bl.ToArray()); - - return reply; - } - - internal AsyncReply SendDetachRequest(uint instanceId) - { - try - { - return SendRequest(IIPPacket.IIPPacketAction.DetachResource).AddUInt32(instanceId).Done(); - } - catch - { - return null; - } - } - - internal AsyncReply SendInvokeByNamedArguments(uint instanceId, byte index, Structure parameters) - { - var pb = Codec.ComposeStructure(parameters, this, true, true, true); - - /* - var reply = new AsyncReply(); - callbackCounter++; - var bl = new BinaryList((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments), - callbackCounter, instanceId, index, pb); - Send(bl.ToArray()); - requests.Add(callbackCounter, reply); - - return reply; - */ - - var reply = new AsyncReply(); - var c = callbackCounter++; - requests.Add(c, reply); - - SendParams().AddUInt8((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments)) - .AddUInt32(c) - .AddUInt32(instanceId) - .AddUInt8(index) - .AddUInt8Array(pb) - .Done(); - return reply; - } - - - void SendError(ErrorType type, uint callbackId, ushort errorCode, string errorMessage = "") - { - var msg = DC.ToBytes(errorMessage); - if (type == ErrorType.Management) - SendParams() - .AddUInt8((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ManagementError)) - .AddUInt32(callbackId) - .AddUInt16(errorCode) - .Done(); - else if (type == ErrorType.Exception) - SendParams() - .AddUInt8((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ExecutionError)) - .AddUInt32(callbackId) - .AddUInt16(errorCode) - .AddUInt16((ushort)msg.Length) - .AddUInt8Array(msg) - .Done(); - } - - void SendProgress(uint callbackId, int value, int max) - { + void SendError(ErrorType type, uint callbackId, ushort errorCode, string errorMessage = "") + { + var msg = DC.ToBytes(errorMessage); + if (type == ErrorType.Management) SendParams() - .AddUInt8((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ProgressReport)) - .AddUInt32(callbackId) - .AddInt32(value) - .AddInt32(max) - .Done(); - //SendParams(, callbackId, value, max); - } - - void SendChunk(uint callbackId, object chunk) - { - var c = Codec.Compose(chunk, this, true); + .AddUInt8((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ManagementError)) + .AddUInt32(callbackId) + .AddUInt16(errorCode) + .Done(); + else if (type == ErrorType.Exception) SendParams() - .AddUInt8((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ChunkStream)) - .AddUInt32(callbackId) - .AddUInt8Array(c) - .Done(); - } + .AddUInt8((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ExecutionError)) + .AddUInt32(callbackId) + .AddUInt16(errorCode) + .AddUInt16((ushort)msg.Length) + .AddUInt8Array(msg) + .Done(); + } - void IIPReply(uint callbackId, params object[] results) + void SendProgress(uint callbackId, int value, int max) + { + SendParams() + .AddUInt8((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ProgressReport)) + .AddUInt32(callbackId) + .AddInt32(value) + .AddInt32(max) + .Done(); + //SendParams(, callbackId, value, max); + } + + void SendChunk(uint callbackId, object chunk) + { + var c = Codec.Compose(chunk, this, true); + SendParams() + .AddUInt8((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ChunkStream)) + .AddUInt32(callbackId) + .AddUInt8Array(c) + .Done(); + } + + void IIPReply(uint callbackId, params object[] results) + { + var req = requests.Take(callbackId); + req?.Trigger(results); + } + + void IIPReplyInvoke(uint callbackId, byte[] result) + { + var req = requests.Take(callbackId); + + Codec.Parse(result, 0, this).Then((rt) => { - var req = requests.Take(callbackId); - req?.Trigger(results); - } + req?.Trigger(rt); + }); + } - void IIPReplyInvoke(uint callbackId, byte[] result) - { - var req = requests.Take(callbackId); + void IIPReportError(uint callbackId, ErrorType errorType, ushort errorCode, string errorMessage) + { + var req = requests.Take(callbackId); + req?.TriggerError(new AsyncException(errorType, errorCode, errorMessage)); + } - Codec.Parse(result, 0, this).Then((rt) => - { - req?.Trigger(rt); - }); - } + void IIPReportProgress(uint callbackId, ProgressType type, int value, int max) + { + var req = requests[callbackId]; + req?.TriggerProgress(type, value, max); + } - void IIPReportError(uint callbackId, ErrorType errorType, ushort errorCode, string errorMessage) - { - var req = requests.Take(callbackId); - req?.TriggerError(new AsyncException(errorType, errorCode, errorMessage)); - } - - void IIPReportProgress(uint callbackId, ProgressType type, int value, int max) + void IIPReportChunk(uint callbackId, byte[] data) + { + if (requests.ContainsKey(callbackId)) { var req = requests[callbackId]; - req?.TriggerProgress(type, value, max); - } - - void IIPReportChunk(uint callbackId, byte[] data) - { - if (requests.ContainsKey(callbackId)) + Codec.Parse(data, 0, this).Then((x) => { - var req = requests[callbackId]; - Codec.Parse(data, 0, this).Then((x) => + req.TriggerChunk(x); + }); + } + } + + void IIPEventResourceReassigned(uint resourceId, uint newResourceId) + { + + } + + void IIPEventResourceDestroyed(uint resourceId) + { + if (resources.Contains(resourceId)) + { + var r = resources[resourceId]; + resources.Remove(resourceId); + r.Destroy(); + } + } + + void IIPEventPropertyUpdated(uint resourceId, byte index, byte[] content) + { + + Fetch(resourceId).Then(r => + { + var item = new AsyncReply(); + queue.Add(item); + + Codec.Parse(content, 0, this).Then((arguments) => + { + var pt = r.Instance.Template.GetPropertyTemplateByIndex(index); + if (pt != null) { - req.TriggerChunk(x); - }); - } - } + item.Trigger(new DistributedResourceQueueItem((DistributedResource)r, + DistributedResourceQueueItem.DistributedResourceQueueItemType.Propery, + arguments, index)); + } + else + { // ft found, fi not found, this should never happen + queue.Remove(item); + } + }); - void IIPEventResourceReassigned(uint resourceId, uint newResourceId) + }); + + /* + if (resources.Contains(resourceId)) { + // push to the queue to gaurantee serialization + var reply = new AsyncReply(); + queue.Add(reply); - } - - void IIPEventResourceDestroyed(uint resourceId) - { - if (resources.Contains(resourceId)) + var r = resources[resourceId]; + Codec.Parse(content, 0, this).Then((arguments) => { - var r = resources[resourceId]; - resources.Remove(resourceId); - r.Destroy(); - } - } - - void IIPEventPropertyUpdated(uint resourceId, byte index, byte[] content) - { - - Fetch(resourceId).Then(r => - { - var item = new AsyncReply(); - queue.Add(item); - - Codec.Parse(content, 0, this).Then((arguments) => + if (!r.IsAttached) { - var pt = r.Instance.Template.GetPropertyTemplateByIndex(index); + // property updated before the template is received + r.AddAfterAttachement(reply, + new DistributedResourceQueueItem((DistributedResource)r, + DistributedResourceQueueItem.DistributedResourceQueueItemType.Propery, + arguments, index)); + } + else + { + var pt = r.Instance.Template.GetPropertyTemplate(index); if (pt != null) { - item.Trigger(new DistributedResourceQueueItem((DistributedResource)r, - DistributedResourceQueueItem.DistributedResourceQueueItemType.Propery, + reply.Trigger(new DistributedResourceQueueItem((DistributedResource)r, + DistributedResourceQueueItem.DistributedResourceQueueItemType.Propery, arguments, index)); } else { // ft found, fi not found, this should never happen - queue.Remove(item); + queue.Remove(reply); } - }); - + } }); - - /* - if (resources.Contains(resourceId)) - { - // push to the queue to gaurantee serialization - var reply = new AsyncReply(); - queue.Add(reply); - - var r = resources[resourceId]; - Codec.Parse(content, 0, this).Then((arguments) => - { - if (!r.IsAttached) - { - // property updated before the template is received - r.AddAfterAttachement(reply, - new DistributedResourceQueueItem((DistributedResource)r, - DistributedResourceQueueItem.DistributedResourceQueueItemType.Propery, - arguments, index)); - } - else - { - var pt = r.Instance.Template.GetPropertyTemplate(index); - if (pt != null) - { - reply.Trigger(new DistributedResourceQueueItem((DistributedResource)r, - DistributedResourceQueueItem.DistributedResourceQueueItemType.Propery, - arguments, index)); - } - else - { // ft found, fi not found, this should never happen - queue.Remove(reply); - } - } - }); - } - */ } + */ + } - void IIPEventEventOccurred(uint resourceId, byte index, byte[] content) + void IIPEventEventOccurred(uint resourceId, byte index, byte[] content) + { + Fetch(resourceId).Then(r => { - Fetch(resourceId).Then(r => - { // push to the queue to gaurantee serialization var item = new AsyncReply(); - queue.Add(item); + queue.Add(item); - Codec.Parse(content, 0, this).Then((arguments) => + Codec.Parse(content, 0, this).Then((arguments) => + { + var et = r.Instance.Template.GetEventTemplateByIndex(index); + if (et != null) { - var et = r.Instance.Template.GetEventTemplateByIndex(index); + item.Trigger(new DistributedResourceQueueItem((DistributedResource)r, + DistributedResourceQueueItem.DistributedResourceQueueItemType.Event, arguments, index)); + } + else + { // ft found, fi not found, this should never happen + queue.Remove(item); + } + + }); + }); + + /* + if (resources.Contains(resourceId)) + { + // push to the queue to gaurantee serialization + var reply = new AsyncReply(); + var r = resources[resourceId]; + + queue.Add(reply); + + Codec.ParseVarArray(content, this).Then((arguments) => + { + if (!r.IsAttached) + { + // event occurred before the template is received + r.AddAfterAttachement(reply, + new DistributedResourceQueueItem((DistributedResource)r, + DistributedResourceQueueItem.DistributedResourceQueueItemType.Event, arguments, index)); + } + else + { + var et = r.Instance.Template.GetEventTemplate(index); if (et != null) { - item.Trigger(new DistributedResourceQueueItem((DistributedResource)r, + reply.Trigger(new DistributedResourceQueueItem((DistributedResource)r, DistributedResourceQueueItem.DistributedResourceQueueItemType.Event, arguments, index)); } else { // ft found, fi not found, this should never happen - queue.Remove(item); + queue.Remove(reply); } - - }); + } }); - - /* - if (resources.Contains(resourceId)) - { - // push to the queue to gaurantee serialization - var reply = new AsyncReply(); - var r = resources[resourceId]; - - queue.Add(reply); - - Codec.ParseVarArray(content, this).Then((arguments) => - { - if (!r.IsAttached) - { - // event occurred before the template is received - r.AddAfterAttachement(reply, - new DistributedResourceQueueItem((DistributedResource)r, - DistributedResourceQueueItem.DistributedResourceQueueItemType.Event, arguments, index)); - } - else - { - var et = r.Instance.Template.GetEventTemplate(index); - if (et != null) - { - reply.Trigger(new DistributedResourceQueueItem((DistributedResource)r, - DistributedResourceQueueItem.DistributedResourceQueueItemType.Event, arguments, index)); - } - else - { // ft found, fi not found, this should never happen - queue.Remove(reply); - } - } - }); - } - */ } + */ + } - void IIPEventChildAdded(uint resourceId, uint childId) + void IIPEventChildAdded(uint resourceId, uint childId) + { + Fetch(resourceId).Then(parent => { - Fetch(resourceId).Then(parent => + Fetch(childId).Then(child => { - Fetch(childId).Then(child => - { - parent.children.Add(child); - child.parents.Add(parent); + parent.children.Add(child); + child.parents.Add(parent); //parent.Instance.Children.Add(child); }); - }); - } + }); + } - void IIPEventChildRemoved(uint resourceId, uint childId) + void IIPEventChildRemoved(uint resourceId, uint childId) + { + Fetch(resourceId).Then(parent => { - Fetch(resourceId).Then(parent => + Fetch(childId).Then(child => { - Fetch(childId).Then(child => - { - parent.children.Remove(child); - child.parents.Remove(parent); + parent.children.Remove(child); + child.parents.Remove(parent); // parent.Instance.Children.Remove(child); }); - }); - } + }); + } - void IIPEventRenamed(uint resourceId, byte[] name) + void IIPEventRenamed(uint resourceId, byte[] name) + { + Fetch(resourceId).Then(resource => { - Fetch(resourceId).Then(resource => - { - resource.Instance.Variables["name"] = name.GetString(0, (uint)name.Length); - }); - } + resource.Instance.Variables["name"] = name.GetString(0, (uint)name.Length); + }); + } - void IIPEventAttributesUpdated(uint resourceId, byte[] attributes) + void IIPEventAttributesUpdated(uint resourceId, byte[] attributes) + { + Fetch(resourceId).Then(resource => { - Fetch(resourceId).Then(resource => - { - var attrs = attributes.GetStringArray(0, (uint)attributes.Length); + var attrs = attributes.GetStringArray(0, (uint)attributes.Length); - GetAttributes(resource, attrs).Then(s => + GetAttributes(resource, attrs).Then(s => + { + resource.Instance.SetAttributes(s); + }); + }); + } + + void IIPRequestAttachResource(uint callback, uint resourceId) + { + + Warehouse.GetById(resourceId).Then((res) => + { + if (res != null) + { + if (res.Instance.Applicable(session, ActionType.Attach, null) == Ruling.Denied) { - resource.Instance.SetAttributes(s); - }); - }); - } + SendError(ErrorType.Management, callback, 6); + return; + } - void IIPRequestAttachResource(uint callback, uint resourceId) - { - - Warehouse.GetById(resourceId).Then((res) => - { - if (res != null) - { - if (res.Instance.Applicable(session, ActionType.Attach, null) == Ruling.Denied) - { - SendError(ErrorType.Management, callback, 6); - return; - } - - var r = res as IResource; + var r = res as IResource; // unsubscribe Unsubscribe(r); @@ -515,28 +515,28 @@ namespace Esiur.Net.IIP var link = DC.ToBytes(r.Instance.Link); - if (r is DistributedResource) - { + if (r is DistributedResource) + { // reply ok SendReply(IIPPacket.IIPPacketAction.AttachResource, callback) - .AddGuid(r.Instance.Template.ClassId) - .AddUInt64(r.Instance.Age) - .AddUInt16((ushort)link.Length) - .AddUInt8Array(link) - .AddUInt8Array(Codec.ComposePropertyValueArray((r as DistributedResource)._Serialize(), this, true)) - .Done(); - } - else - { + .AddGuid(r.Instance.Template.ClassId) + .AddUInt64(r.Instance.Age) + .AddUInt16((ushort)link.Length) + .AddUInt8Array(link) + .AddUInt8Array(Codec.ComposePropertyValueArray((r as DistributedResource)._Serialize(), this, true)) + .Done(); + } + else + { // reply ok SendReply(IIPPacket.IIPPacketAction.AttachResource, callback) - .AddGuid(r.Instance.Template.ClassId) - .AddUInt64(r.Instance.Age) - .AddUInt16((ushort)link.Length) - .AddUInt8Array(link) - .AddUInt8Array(Codec.ComposePropertyValueArray(r.Instance.Serialize(), this, true)) - .Done(); - } + .AddGuid(r.Instance.Template.ClassId) + .AddUInt64(r.Instance.Age) + .AddUInt16((ushort)link.Length) + .AddUInt8Array(link) + .AddUInt8Array(Codec.ComposePropertyValueArray(r.Instance.Serialize(), this, true)) + .Done(); + } @@ -555,78 +555,78 @@ namespace Esiur.Net.IIP } - else - { + else + { // reply failed //SendParams(0x80, r.Instance.Id, r.Instance.Age, r.Instance.Serialize(false, this)); SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - } - }); - } - - private void Attributes_OnModified(string key, object oldValue, object newValue, KeyList sender) - { - if (key == "name") - { - var instance = (sender.Owner as Instance); - var name = DC.ToBytes(newValue.ToString()); - SendEvent(IIPPacket.IIPPacketEvent.ChildRemoved) - .AddUInt32(instance.Id) - .AddUInt16((ushort)name.Length) - .AddUInt8Array(name) - .Done(); } - } + }); + } - private void Children_OnRemoved(Instance sender, IResource value) + private void Attributes_OnModified(string key, object oldValue, object newValue, KeyList sender) + { + if (key == "name") { + var instance = (sender.Owner as Instance); + var name = DC.ToBytes(newValue.ToString()); SendEvent(IIPPacket.IIPPacketEvent.ChildRemoved) - .AddUInt32(sender.Id) - .AddUInt32(value.Instance.Id) - .Done(); + .AddUInt32(instance.Id) + .AddUInt16((ushort)name.Length) + .AddUInt8Array(name) + .Done(); } + } - private void Children_OnAdd(Instance sender, IResource value) + private void Children_OnRemoved(Instance sender, IResource value) + { + SendEvent(IIPPacket.IIPPacketEvent.ChildRemoved) + .AddUInt32(sender.Id) + .AddUInt32(value.Instance.Id) + .Done(); + } + + private void Children_OnAdd(Instance sender, IResource value) + { + //if (sender.Applicable(sender.Resource, this.session, ActionType.)) + SendEvent(IIPPacket.IIPPacketEvent.ChildAdded) + .AddUInt32(sender.Id) + .AddUInt32(value.Instance.Id) + .Done(); + } + + + public bool RemoveChild(IResource parent, IResource child) + { + SendEvent(IIPPacket.IIPPacketEvent.ChildRemoved) + .AddUInt32((parent as DistributedResource).Id) + .AddUInt32((child as DistributedResource).Id) + .Done(); + + return true; + } + + public bool AddChild(IResource parent, IResource child) + { + SendEvent(IIPPacket.IIPPacketEvent.ChildAdded) + .AddUInt32((parent as DistributedResource).Id) + .AddUInt32((child as DistributedResource).Id) + .Done(); + + return true; + } + + + void IIPRequestReattachResource(uint callback, uint resourceId, ulong resourceAge) + { + Warehouse.GetById(resourceId).Then((res) => { - //if (sender.Applicable(sender.Resource, this.session, ActionType.)) - SendEvent(IIPPacket.IIPPacketEvent.ChildAdded) - .AddUInt32(sender.Id) - .AddUInt32(value.Instance.Id) - .Done(); - } - - - public bool RemoveChild(IResource parent, IResource child) - { - SendEvent(IIPPacket.IIPPacketEvent.ChildRemoved) - .AddUInt32((parent as DistributedResource).Id) - .AddUInt32((child as DistributedResource).Id) - .Done(); - - return true; - } - - public bool AddChild(IResource parent, IResource child) - { - SendEvent(IIPPacket.IIPPacketEvent.ChildAdded) - .AddUInt32((parent as DistributedResource).Id) - .AddUInt32((child as DistributedResource).Id) - .Done(); - - return true; - } - - - void IIPRequestReattachResource(uint callback, uint resourceId, ulong resourceAge) - { - Warehouse.GetById(resourceId).Then((res) => + if (res != null) { - if (res != null) - { - var r = res as IResource; + var r = res as IResource; // unsubscribe Unsubscribe(r); - Subscribe(r); + Subscribe(r); //r.Instance.ResourceEventOccurred -= Instance_EventOccurred; //r.Instance.CustomResourceEventOccurred -= Instance_CustomEventOccurred; @@ -651,24 +651,24 @@ namespace Esiur.Net.IIP // reply ok SendReply(IIPPacket.IIPPacketAction.ReattachResource, callback) - .AddUInt64(r.Instance.Age) - .AddUInt8Array(Codec.ComposePropertyValueArray(r.Instance.Serialize(), this, true)) - .Done(); - } - else - { + .AddUInt64(r.Instance.Age) + .AddUInt8Array(Codec.ComposePropertyValueArray(r.Instance.Serialize(), this, true)) + .Done(); + } + else + { // reply failed SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - } - }); - } + } + }); + } - void IIPRequestDetachResource(uint callback, uint resourceId) + void IIPRequestDetachResource(uint callback, uint resourceId) + { + Warehouse.GetById(resourceId).Then((res) => { - Warehouse.GetById(resourceId).Then((res) => + if (res != null) { - if (res != null) - { //var r = res as IResource; //r.Instance.ResourceEventOccurred -= Instance_EventOccurred; //r.Instance.CustomResourceEventOccurred -= Instance_CustomEventOccurred; @@ -682,82 +682,82 @@ namespace Esiur.Net.IIP // reply ok SendReply(IIPPacket.IIPPacketAction.DetachResource, callback).Done(); - } - else - { + } + else + { // reply failed SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - } - }); - } + } + }); + } - void IIPRequestCreateResource(uint callback, uint storeId, uint parentId, byte[] content) + void IIPRequestCreateResource(uint callback, uint storeId, uint parentId, byte[] content) + { + + Warehouse.GetById(storeId).Then(store => { - - Warehouse.GetById(storeId).Then(store => + if (store == null) { - if (store == null) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.StoreNotFound); - return; - } + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.StoreNotFound); + return; + } - if (!(store is IStore)) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceIsNotStore); - return; - } + if (!(store is IStore)) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceIsNotStore); + return; + } // check security if (store.Instance.Applicable(session, ActionType.CreateResource, null) != Ruling.Allowed) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.CreateDenied); - return; - } + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.CreateDenied); + return; + } - Warehouse.GetById(parentId).Then(parent => - { + Warehouse.GetById(parentId).Then(parent => + { // check security if (parent != null) - if (parent.Instance.Applicable(session, ActionType.AddChild, null) != Ruling.Allowed) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AddChildDenied); - return; - } - - uint offset = 0; - - var className = content.GetString(offset + 1, content[0]); - offset += 1 + (uint)content[0]; - - var nameLength = content.GetUInt16(offset); - offset += 2; - var name = content.GetString(offset, nameLength); - - var cl = content.GetUInt32(offset); - offset += 4; - - var type = Type.GetType(className); - - if (type == null) + if (parent.Instance.Applicable(session, ActionType.AddChild, null) != Ruling.Allowed) { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ClassNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AddChildDenied); return; } - Codec.ParseVarArray(content, offset, cl, this).Then(parameters => + uint offset = 0; + + var className = content.GetString(offset + 1, content[0]); + offset += 1 + (uint)content[0]; + + var nameLength = content.GetUInt16(offset); + offset += 2; + var name = content.GetString(offset, nameLength); + + var cl = content.GetUInt32(offset); + offset += 4; + + var type = Type.GetType(className); + + if (type == null) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ClassNotFound); + return; + } + + Codec.ParseVarArray(content, offset, cl, this).Then(parameters => + { + offset += cl; + cl = content.GetUInt32(offset); + Codec.ParseStructure(content, offset, cl, this).Then(attributes => { offset += cl; - cl = content.GetUInt32(offset); - Codec.ParseStructure(content, offset, cl, this).Then(attributes => - { - offset += cl; - cl = (uint)content.Length - offset; + cl = (uint)content.Length - offset; - Codec.ParseStructure(content, offset, cl, this).Then(values => - { + Codec.ParseStructure(content, offset, cl, this).Then(values => + { #if NETSTANDARD var constructors = Type.GetType(className).GetTypeInfo().GetConstructors(); @@ -766,21 +766,520 @@ namespace Esiur.Net.IIP #endif var matching = constructors.Where(x => - { - var ps = x.GetParameters(); - if (ps.Length > 0 && ps.Length == parameters.Length + 1) - if (ps.Last().ParameterType == typeof(DistributedConnection)) - return true; + { + var ps = x.GetParameters(); + if (ps.Length > 0 && ps.Length == parameters.Length + 1) + if (ps.Last().ParameterType == typeof(DistributedConnection)) + return true; - return ps.Length == parameters.Length; - } - ).ToArray(); + return ps.Length == parameters.Length; + } + ).ToArray(); - var pi = matching[0].GetParameters(); + var pi = matching[0].GetParameters(); // cast arguments object[] args = null; + if (pi.Length > 0) + { + int argsCount = pi.Length; + args = new object[pi.Length]; + + if (pi[pi.Length - 1].ParameterType == typeof(DistributedConnection)) + { + args[--argsCount] = this; + } + + if (parameters != null) + { + for (int i = 0; i < argsCount && i < parameters.Length; i++) + { + args[i] = DC.CastConvert(parameters[i], pi[i].ParameterType); + } + } + } + + // create the resource + var resource = Activator.CreateInstance(type, args) as IResource; + + Warehouse.Put(name, resource, store as IStore, parent).Then(ok => + { + SendReply(IIPPacket.IIPPacketAction.CreateResource, callback) + .AddUInt32(resource.Instance.Id) + .Done(); + + }).Error(x => + { + SendError(ErrorType.Exception, callback, (ushort)ExceptionCode.AddToStoreFailed); + }); + + }); + }); + }); + }); + }); + } + + void IIPRequestDeleteResource(uint callback, uint resourceId) + { + Warehouse.GetById(resourceId).Then(r => + { + if (r == null) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + if (r.Instance.Store.Instance.Applicable(session, ActionType.Delete, null) != Ruling.Allowed) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.DeleteDenied); + return; + } + + if (Warehouse.Remove(r)) + SendReply(IIPPacket.IIPPacketAction.DeleteResource, callback).Done(); + //SendParams((byte)0x84, callback); + else + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.DeleteFailed); + }); + } + + void IIPRequestGetAttributes(uint callback, uint resourceId, byte[] attributes, bool all = false) + { + Warehouse.GetById(resourceId).Then(r => + { + if (r == null) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + // if (!r.Instance.Store.Instance.Applicable(r, session, ActionType.InquireAttributes, null)) + if (r.Instance.Applicable(session, ActionType.InquireAttributes, null) != Ruling.Allowed) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ViewAttributeDenied); + return; + } + + string[] attrs = null; + + if (!all) + attrs = attributes.GetStringArray(0, (uint)attributes.Length); + + var st = r.Instance.GetAttributes(attrs); + + if (st != null) + SendReply(all ? IIPPacket.IIPPacketAction.GetAllAttributes : IIPPacket.IIPPacketAction.GetAttributes, callback) + .AddUInt8Array(Codec.ComposeStructure(st, this, true, true, true)) + .Done(); + else + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.GetAttributesFailed); + + }); + } + + void IIPRequestAddChild(uint callback, uint parentId, uint childId) + { + Warehouse.GetById(parentId).Then(parent => + { + if (parent == null) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + Warehouse.GetById(childId).Then(child => + { + if (child == null) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + if (parent.Instance.Applicable(this.session, ActionType.AddChild, null) != Ruling.Allowed) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AddChildDenied); + return; + } + + if (child.Instance.Applicable(this.session, ActionType.AddParent, null) != Ruling.Allowed) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AddParentDenied); + return; + } + + parent.Instance.Store.AddChild(parent, child); + + SendReply(IIPPacket.IIPPacketAction.AddChild, callback).Done(); + //child.Instance.Parents + }); + + }); + } + + void IIPRequestRemoveChild(uint callback, uint parentId, uint childId) + { + Warehouse.GetById(parentId).Then(parent => + { + if (parent == null) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + Warehouse.GetById(childId).Then(child => + { + if (child == null) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + if (parent.Instance.Applicable(this.session, ActionType.RemoveChild, null) != Ruling.Allowed) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AddChildDenied); + return; + } + + if (child.Instance.Applicable(this.session, ActionType.RemoveParent, null) != Ruling.Allowed) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AddParentDenied); + return; + } + + parent.Instance.Store.RemoveChild(parent, child);// Children.Remove(child); + + SendReply(IIPPacket.IIPPacketAction.RemoveChild, callback).Done(); + //child.Instance.Parents + }); + + }); + } + + void IIPRequestRenameResource(uint callback, uint resourceId, byte[] name) + { + Warehouse.GetById(resourceId).Then(resource => + { + if (resource == null) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + if (resource.Instance.Applicable(this.session, ActionType.Rename, null) != Ruling.Allowed) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.RenameDenied); + return; + } + + + resource.Instance.Name = name.GetString(0, (uint)name.Length); + SendReply(IIPPacket.IIPPacketAction.RenameResource, callback).Done(); + }); + } + + void IIPRequestResourceChildren(uint callback, uint resourceId) + { + Warehouse.GetById(resourceId).Then(resource => + { + if (resource == null) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + resource.Instance.Children().Then(children => + { + SendReply(IIPPacket.IIPPacketAction.ResourceChildren, callback) + .AddUInt8Array(Codec.ComposeResourceArray(children, this, true)) + .Done(); + + }); + + + }); + } + + void IIPRequestResourceParents(uint callback, uint resourceId) + { + Warehouse.GetById(resourceId).Then(resource => + { + if (resource == null) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + resource.Instance.Parents().Then(parents => + { + SendReply(IIPPacket.IIPPacketAction.ResourceParents, callback) + .AddUInt8Array(Codec.ComposeResourceArray(parents, this, true)) + .Done(); + + }); + + }); + } + + void IIPRequestClearAttributes(uint callback, uint resourceId, byte[] attributes, bool all = false) + { + Warehouse.GetById(resourceId).Then(r => + { + if (r == null) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + if (r.Instance.Store.Instance.Applicable(session, ActionType.UpdateAttributes, null) != Ruling.Allowed) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeDenied); + return; + } + + string[] attrs = null; + + if (!all) + attrs = attributes.GetStringArray(0, (uint)attributes.Length); + + if (r.Instance.RemoveAttributes(attrs)) + SendReply(all ? IIPPacket.IIPPacketAction.ClearAllAttributes : IIPPacket.IIPPacketAction.ClearAttributes, callback).Done(); + else + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeFailed); + + }); + } + + void IIPRequestUpdateAttributes(uint callback, uint resourceId, byte[] attributes, bool clearAttributes = false) + { + Warehouse.GetById(resourceId).Then(r => + { + if (r == null) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + if (r.Instance.Store.Instance.Applicable(session, ActionType.UpdateAttributes, null) != Ruling.Allowed) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeDenied); + return; + } + + Codec.ParseStructure(attributes, 0, (uint)attributes.Length, this).Then(attrs => + { + if (r.Instance.SetAttributes(attrs, clearAttributes)) + SendReply(clearAttributes ? IIPPacket.IIPPacketAction.ClearAllAttributes : IIPPacket.IIPPacketAction.ClearAttributes, + callback).Done(); + else + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeFailed); + }); + + }); + + } + + void IIPRequestLinkTemplates(uint callback, string resourceLink) + { + Action queryCallback = (r) => + { + if (r == null) + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + else + { + var list = r.Where(x => x.Instance.Applicable(session, ActionType.ViewTemplate, null) != Ruling.Denied).ToArray(); + + if (list.Length == 0) + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + else + { + // get all templates related to this resource + + var msg = new BinaryList(); + + var templates = new List(); + foreach (var resource in list) + templates.AddRange(TypeTemplate.GetDependencies(resource.Instance.Template).Where(x => !templates.Contains(x))); + + foreach (var t in templates) + { + msg.AddInt32(t.Content.Length) + .AddUInt8Array(t.Content); + } + + // digggg + SendReply(IIPPacket.IIPPacketAction.LinkTemplates, callback) + .AddInt32(msg.Length) + .AddUInt8Array(msg.ToArray()) + .Done(); + } + } + }; + + if (Server?.EntryPoint != null) + Server.EntryPoint.Query(resourceLink, this).Then(queryCallback); + else + Warehouse.Query(resourceLink).Then(queryCallback); + } + + void IIPRequestTemplateFromClassName(uint callback, string className) + { + var t = Warehouse.GetTemplateByClassName(className); + + if (t != null) + SendReply(IIPPacket.IIPPacketAction.TemplateFromClassName, callback) + .AddInt32(t.Content.Length) + .AddUInt8Array(t.Content) + .Done(); + else + { + // reply failed + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound); + } + } + + void IIPRequestTemplateFromClassId(uint callback, Guid classId) + { + var t = Warehouse.GetTemplateByClassId(classId); + + if (t != null) + SendReply(IIPPacket.IIPPacketAction.TemplateFromClassId, callback) + .AddInt32(t.Content.Length) + .AddUInt8Array(t.Content) + .Done(); + else + { + // reply failed + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound); + } + } + + + + void IIPRequestTemplateFromResourceId(uint callback, uint resourceId) + { + Warehouse.GetById(resourceId).Then((r) => + { + if (r != null) + SendReply(IIPPacket.IIPPacketAction.TemplateFromResourceId, callback) + .AddInt32(r.Instance.Template.Content.Length) + .AddUInt8Array(r.Instance.Template.Content) + .Done(); + else + { + // reply failed + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound); + } + }); + } + + + + + void IIPRequestQueryResources(uint callback, string resourceLink) + { + + Action queryCallback = (r) => + { + if (r == null) + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + else + { + var list = r.Where(x => x.Instance.Applicable(session, ActionType.Attach, null) != Ruling.Denied).ToArray(); + + if (list.Length == 0) + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + else + SendReply(IIPPacket.IIPPacketAction.QueryLink, callback) + .AddUInt8Array(Codec.ComposeResourceArray(list, this, true)) + .Done(); + } + }; + + if (Server?.EntryPoint != null) + Server.EntryPoint.Query(resourceLink, this).Then(queryCallback); + else + Warehouse.Query(resourceLink).Then(queryCallback); + } + + void IIPRequestResourceAttribute(uint callback, uint resourceId) + { + + } + + [Attribute] + public ExceptionLevel ExceptionLevel { get; set; } + = ExceptionLevel.Code | ExceptionLevel.Message | ExceptionLevel.Source | ExceptionLevel.Trace; + + private Tuple SummerizeException(Exception ex) + { + ex = ex.InnerException != null ? ex.InnerException : ex; + + var code = (ExceptionLevel & ExceptionLevel.Code) == 0 ? 0 : ex is AsyncException ae ? ae.Code : 0; + var msg = (ExceptionLevel & ExceptionLevel.Message) == 0 ? "" : ex.Message; + var source = (ExceptionLevel & ExceptionLevel.Source) == 0 ? "" : ex.Source; + var trace = (ExceptionLevel & ExceptionLevel.Trace) == 0 ? "" : ex.StackTrace; + + return new Tuple((ushort)code, $"{source}: {msg}\n{trace}"); + } + + void IIPRequestInvokeFunctionArrayArguments(uint callback, uint resourceId, byte index, byte[] content) + { + //Console.WriteLine("IIPRequestInvokeFunction " + callback + " " + resourceId + " " + index); + + Warehouse.GetById(resourceId).Then((r) => + { + if (r != null) + { + Codec.ParseVarArray(content, this).Then((arguments) => + { + var ft = r.Instance.Template.GetFunctionTemplateByIndex(index); + if (ft != null) + { + + // un hold the socket to send data immediately + this.Socket.Unhold(); + + if (r is DistributedResource) + { + var rt = (r as DistributedResource)._InvokeByArrayArguments(index, arguments); + if (rt != null) + { + rt.Then(res => + { + SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback) + .AddUInt8Array(Codec.Compose(res, this)) + .Done(); + }); + } + else + { + + // function not found on a distributed object + } + } + else + { +#if NETSTANDARD + var fi = r.GetType().GetTypeInfo().GetMethod(ft.Name); +#else + var fi = r.GetType().GetMethod(ft.Name); +#endif + + if (fi != null) + { + if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied) + { + SendError(ErrorType.Management, callback, + (ushort)ExceptionCode.InvokeDenied); + return; + } + + // cast arguments + ParameterInfo[] pi = fi.GetParameters(); + object[] args = null; + if (pi.Length > 0) { int argsCount = pi.Length; @@ -791,648 +1290,149 @@ namespace Esiur.Net.IIP args[--argsCount] = this; } - if (parameters != null) + if (arguments != null) { - for (int i = 0; i < argsCount && i < parameters.Length; i++) + for (int i = 0; i < argsCount && i < arguments.Length; i++) { - args[i] = DC.CastConvert(parameters[i], pi[i].ParameterType); + args[i] = DC.CastConvert(arguments[i], pi[i].ParameterType); } } } - // create the resource - var resource = Activator.CreateInstance(type, args) as IResource; + object rt; - Warehouse.Put(name, resource, store as IStore, parent).Then(ok => - { - SendReply(IIPPacket.IIPPacketAction.CreateResource, callback) - .AddUInt32(resource.Instance.Id) - .Done(); - - }).Error(x => - { - SendError(ErrorType.Exception, callback, (ushort)ExceptionCode.AddToStoreFailed); - }); - - }); - }); - }); - }); - }); - } - - void IIPRequestDeleteResource(uint callback, uint resourceId) - { - Warehouse.GetById(resourceId).Then(r => - { - if (r == null) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - return; - } - - if (r.Instance.Store.Instance.Applicable(session, ActionType.Delete, null) != Ruling.Allowed) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.DeleteDenied); - return; - } - - if (Warehouse.Remove(r)) - SendReply(IIPPacket.IIPPacketAction.DeleteResource, callback).Done(); - //SendParams((byte)0x84, callback); - else - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.DeleteFailed); - }); - } - - void IIPRequestGetAttributes(uint callback, uint resourceId, byte[] attributes, bool all = false) - { - Warehouse.GetById(resourceId).Then(r => - { - if (r == null) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - return; - } - - // if (!r.Instance.Store.Instance.Applicable(r, session, ActionType.InquireAttributes, null)) - if (r.Instance.Applicable(session, ActionType.InquireAttributes, null) != Ruling.Allowed) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ViewAttributeDenied); - return; - } - - string[] attrs = null; - - if (!all) - attrs = attributes.GetStringArray(0, (uint)attributes.Length); - - var st = r.Instance.GetAttributes(attrs); - - if (st != null) - SendReply(all ? IIPPacket.IIPPacketAction.GetAllAttributes : IIPPacket.IIPPacketAction.GetAttributes, callback) - .AddUInt8Array(Codec.ComposeStructure(st, this, true, true, true)) - .Done(); - else - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.GetAttributesFailed); - - }); - } - - void IIPRequestAddChild(uint callback, uint parentId, uint childId) - { - Warehouse.GetById(parentId).Then(parent => - { - if (parent == null) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - return; - } - - Warehouse.GetById(childId).Then(child => - { - if (child == null) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - return; - } - - if (parent.Instance.Applicable(this.session, ActionType.AddChild, null) != Ruling.Allowed) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AddChildDenied); - return; - } - - if (child.Instance.Applicable(this.session, ActionType.AddParent, null) != Ruling.Allowed) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AddParentDenied); - return; - } - - parent.Instance.Store.AddChild(parent, child); - - SendReply(IIPPacket.IIPPacketAction.AddChild, callback).Done(); - //child.Instance.Parents - }); - - }); - } - - void IIPRequestRemoveChild(uint callback, uint parentId, uint childId) - { - Warehouse.GetById(parentId).Then(parent => - { - if (parent == null) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - return; - } - - Warehouse.GetById(childId).Then(child => - { - if (child == null) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - return; - } - - if (parent.Instance.Applicable(this.session, ActionType.RemoveChild, null) != Ruling.Allowed) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AddChildDenied); - return; - } - - if (child.Instance.Applicable(this.session, ActionType.RemoveParent, null) != Ruling.Allowed) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AddParentDenied); - return; - } - - parent.Instance.Store.RemoveChild(parent, child);// Children.Remove(child); - - SendReply(IIPPacket.IIPPacketAction.RemoveChild, callback).Done(); - //child.Instance.Parents - }); - - }); - } - - void IIPRequestRenameResource(uint callback, uint resourceId, byte[] name) - { - Warehouse.GetById(resourceId).Then(resource => - { - if (resource == null) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - return; - } - - if (resource.Instance.Applicable(this.session, ActionType.Rename, null) != Ruling.Allowed) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.RenameDenied); - return; - } - - - resource.Instance.Name = name.GetString(0, (uint)name.Length); - SendReply(IIPPacket.IIPPacketAction.RenameResource, callback).Done(); - }); - } - - void IIPRequestResourceChildren(uint callback, uint resourceId) - { - Warehouse.GetById(resourceId).Then(resource => - { - if (resource == null) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - return; - } - - resource.Instance.Children().Then(children => - { - SendReply(IIPPacket.IIPPacketAction.ResourceChildren, callback) - .AddUInt8Array(Codec.ComposeResourceArray(children, this, true)) - .Done(); - - }); - - - }); - } - - void IIPRequestResourceParents(uint callback, uint resourceId) - { - Warehouse.GetById(resourceId).Then(resource => - { - if (resource == null) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - return; - } - - resource.Instance.Parents().Then(parents => - { - SendReply(IIPPacket.IIPPacketAction.ResourceParents, callback) - .AddUInt8Array(Codec.ComposeResourceArray(parents, this, true)) - .Done(); - - }); - - }); - } - - void IIPRequestClearAttributes(uint callback, uint resourceId, byte[] attributes, bool all = false) - { - Warehouse.GetById(resourceId).Then(r => - { - if (r == null) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - return; - } - - if (r.Instance.Store.Instance.Applicable(session, ActionType.UpdateAttributes, null) != Ruling.Allowed) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeDenied); - return; - } - - string[] attrs = null; - - if (!all) - attrs = attributes.GetStringArray(0, (uint)attributes.Length); - - if (r.Instance.RemoveAttributes(attrs)) - SendReply(all ? IIPPacket.IIPPacketAction.ClearAllAttributes : IIPPacket.IIPPacketAction.ClearAttributes, callback).Done(); - else - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeFailed); - - }); - } - - void IIPRequestUpdateAttributes(uint callback, uint resourceId, byte[] attributes, bool clearAttributes = false) - { - Warehouse.GetById(resourceId).Then(r => - { - if (r == null) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - return; - } - - if (r.Instance.Store.Instance.Applicable(session, ActionType.UpdateAttributes, null) != Ruling.Allowed) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeDenied); - return; - } - - Codec.ParseStructure(attributes, 0, (uint)attributes.Length, this).Then(attrs => - { - if (r.Instance.SetAttributes(attrs, clearAttributes)) - SendReply(clearAttributes ? IIPPacket.IIPPacketAction.ClearAllAttributes : IIPPacket.IIPPacketAction.ClearAttributes, - callback).Done(); - else - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeFailed); - }); - - }); - - } - - void IIPRequestLinkTemplates(uint callback, string resourceLink) - { - Action queryCallback = (r) => - { - if (r == null) - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - else - { - var list = r.Where(x => x.Instance.Applicable(session, ActionType.ViewTemplate, null) != Ruling.Denied).ToArray(); - - if (list.Length == 0) - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - else - { - // get all templates related to this resource - - var msg = new BinaryList(); - - var templates = new List(); - foreach (var resource in list) - templates.AddRange(TypeTemplate.GetDependencies(resource.Instance.Template).Where(x => !templates.Contains(x))); - - foreach (var t in templates) - { - msg.AddInt32(t.Content.Length) - .AddUInt8Array(t.Content); - } - - // digggg - SendReply(IIPPacket.IIPPacketAction.LinkTemplates, callback) - .AddInt32(msg.Length) - .AddUInt8Array(msg.ToArray()) - .Done(); - } - } - }; - - if (Server?.EntryPoint != null) - Server.EntryPoint.Query(resourceLink, this).Then(queryCallback); - else - Warehouse.Query(resourceLink).Then(queryCallback); - } - - void IIPRequestTemplateFromClassName(uint callback, string className) - { - var t = Warehouse.GetTemplateByClassName(className); - - if (t != null) - SendReply(IIPPacket.IIPPacketAction.TemplateFromClassName, callback) - .AddInt32(t.Content.Length) - .AddUInt8Array(t.Content) - .Done(); - else - { - // reply failed - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound); - } - } - - void IIPRequestTemplateFromClassId(uint callback, Guid classId) - { - var t = Warehouse.GetTemplateByClassId(classId); - - if (t != null) - SendReply(IIPPacket.IIPPacketAction.TemplateFromClassId, callback) - .AddInt32(t.Content.Length) - .AddUInt8Array(t.Content) - .Done(); - else - { - // reply failed - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound); - } - } - - - - void IIPRequestTemplateFromResourceId(uint callback, uint resourceId) - { - Warehouse.GetById(resourceId).Then((r) => - { - if (r != null) - SendReply(IIPPacket.IIPPacketAction.TemplateFromResourceId, callback) - .AddInt32(r.Instance.Template.Content.Length) - .AddUInt8Array(r.Instance.Template.Content) - .Done(); - else - { - // reply failed - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound); - } - }); - } - - - - - void IIPRequestQueryResources(uint callback, string resourceLink) - { - - Action queryCallback = (r) => - { - if (r == null) - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - else - { - var list = r.Where(x => x.Instance.Applicable(session, ActionType.Attach, null) != Ruling.Denied).ToArray(); - - if (list.Length == 0) - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - else - SendReply(IIPPacket.IIPPacketAction.QueryLink, callback) - .AddUInt8Array(Codec.ComposeResourceArray(list, this, true)) - .Done(); - } - }; - - if (Server?.EntryPoint != null) - Server.EntryPoint.Query(resourceLink, this).Then(queryCallback); - else - Warehouse.Query(resourceLink).Then(queryCallback); - } - - void IIPRequestResourceAttribute(uint callback, uint resourceId) - { - - } - - [Attribute] - public ExceptionLevel ExceptionLevel { get; set; } - = ExceptionLevel.Code | ExceptionLevel.Message | ExceptionLevel.Source | ExceptionLevel.Trace; - - private Tuple SummerizeException(Exception ex) - { - ex = ex.InnerException != null ? ex.InnerException : ex; - - var code = (ExceptionLevel & ExceptionLevel.Code) == 0 ? 0 : ex is AsyncException ae ? ae.Code : 0; - var msg = (ExceptionLevel & ExceptionLevel.Message) == 0 ? "" : ex.Message; - var source = (ExceptionLevel & ExceptionLevel.Source) == 0 ? "" : ex.Source; - var trace = (ExceptionLevel & ExceptionLevel.Trace) == 0 ? "" : ex.StackTrace; - - return new Tuple((ushort)code, $"{source}: {msg}\n{trace}"); - } - - void IIPRequestInvokeFunctionArrayArguments(uint callback, uint resourceId, byte index, byte[] content) - { - //Console.WriteLine("IIPRequestInvokeFunction " + callback + " " + resourceId + " " + index); - - Warehouse.GetById(resourceId).Then((r) => - { - if (r != null) - { - Codec.ParseVarArray(content, this).Then((arguments) => - { - var ft = r.Instance.Template.GetFunctionTemplateByIndex(index); - if (ft != null) - { - - // un hold the socket to send data immediately - this.Socket.Unhold(); - - if (r is DistributedResource) - { - var rt = (r as DistributedResource)._InvokeByArrayArguments(index, arguments); - if (rt != null) + try { - rt.Then(res => - { - SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback) - .AddUInt8Array(Codec.Compose(res, this)) - .Done(); - }); + rt = fi.Invoke(r, args); } - else + catch (Exception ex) { - - // function not found on a distributed object + var (code, msg) = SummerizeException(ex); + SendError(ErrorType.Exception, callback, code, msg); + return; } - } - else - { -#if NETSTANDARD - var fi = r.GetType().GetTypeInfo().GetMethod(ft.Name); -#else - var fi = r.GetType().GetMethod(ft.Name); -#endif - if (fi != null) + if (rt is System.Collections.IEnumerable && !(rt is Array || rt is Structure || rt is string)) { - if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied) - { - SendError(ErrorType.Management, callback, - (ushort)ExceptionCode.InvokeDenied); - return; - } - - // cast arguments - ParameterInfo[] pi = fi.GetParameters(); - object[] args = null; - - if (pi.Length > 0) - { - int argsCount = pi.Length; - args = new object[pi.Length]; - - if (pi[pi.Length - 1].ParameterType == typeof(DistributedConnection)) - { - args[--argsCount] = this; - } - - if (arguments != null) - { - for (int i = 0; i < argsCount && i < arguments.Length; i++) - { - args[i] = DC.CastConvert(arguments[i], pi[i].ParameterType); - } - } - } - - object rt; + var enu = rt as System.Collections.IEnumerable; try { - rt = fi.Invoke(r, args); + foreach (var v in enu) + SendChunk(callback, v); + SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback) + .AddUInt8((byte)DataType.Void) + .Done(); } catch (Exception ex) { var (code, msg) = SummerizeException(ex); SendError(ErrorType.Exception, callback, code, msg); - return; } - if (rt is System.Collections.IEnumerable && !(rt is Array || rt is Structure || rt is string)) + } + else if (rt is Task) + { + (rt as Task).ContinueWith(t => { - var enu = rt as System.Collections.IEnumerable; - - try - { - foreach (var v in enu) - SendChunk(callback, v); - SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback) - .AddUInt8((byte)DataType.Void) - .Done(); - } - catch (Exception ex) - { - var (code, msg) = SummerizeException(ex); - SendError(ErrorType.Exception, callback, code, msg); - } - - } - else if (rt is Task) - { - (rt as Task).ContinueWith(t => - { #if NETSTANDARD var res = t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t); #else var res = t.GetType().GetProperty("Result").GetValue(t); #endif SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback) - .AddUInt8Array(Codec.Compose(res, this)) - .Done(); - }); + .AddUInt8Array(Codec.Compose(res, this)) + .Done(); + }); //await t; //SendParams((byte)0x90, callback, Codec.Compose(res, this)); } - else if (rt is AsyncReply)// Codec.ImplementsInterface(rt.GetType(), typeof(IAsyncReply<>)))// rt.GetType().GetTypeInfo().IsGenericType - //&& rt.GetType().GetGenericTypeDefinition() == typeof(IAsyncReply<>)) + else if (rt is AsyncReply)// Codec.ImplementsInterface(rt.GetType(), typeof(IAsyncReply<>)))// rt.GetType().GetTypeInfo().IsGenericType + //&& rt.GetType().GetGenericTypeDefinition() == typeof(IAsyncReply<>)) { - (rt as AsyncReply).Then(res => - { - SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback) - .AddUInt8Array(Codec.Compose(res, this)) - .Done(); - }).Error(ex => - { - var (code, msg) = SummerizeException(ex); - SendError(ErrorType.Exception, callback, code, msg); - }).Progress((pt, pv, pm) => - { - SendProgress(callback, pv, pm); - }).Chunk(v => - { - SendChunk(callback, v); - }); - } - else + (rt as AsyncReply).Then(res => { SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback) - .AddUInt8Array(Codec.Compose(rt, this)) - .Done(); - } + .AddUInt8Array(Codec.Compose(res, this)) + .Done(); + }).Error(ex => + { + var (code, msg) = SummerizeException(ex); + SendError(ErrorType.Exception, callback, code, msg); + }).Progress((pt, pv, pm) => + { + SendProgress(callback, pv, pm); + }).Chunk(v => + { + SendChunk(callback, v); + }); } else { - // ft found, fi not found, this should never happen - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); + SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback) + .AddUInt8Array(Codec.Compose(rt, this)) + .Done(); } } + else + { + // ft found, fi not found, this should never happen + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); + } } - else - { + } + else + { // no function at this index SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); - } - }); - } - else - { + } + }); + } + else + { // no resource with this id SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - } - }); - } + } + }); + } - void IIPRequestInvokeFunctionNamedArguments(uint callback, uint resourceId, byte index, byte[] content) + void IIPRequestInvokeFunctionNamedArguments(uint callback, uint resourceId, byte index, byte[] content) + { + + Warehouse.GetById(resourceId).Then((r) => { - - Warehouse.GetById(resourceId).Then((r) => + if (r != null) { - if (r != null) - { - Codec.ParseStructure(content, 0, (uint)content.Length, this).Then((namedArgs) => + Codec.ParseStructure(content, 0, (uint)content.Length, this).Then((namedArgs) => + { + var ft = r.Instance.Template.GetFunctionTemplateByIndex(index); + if (ft != null) { - var ft = r.Instance.Template.GetFunctionTemplateByIndex(index); - if (ft != null) - { // un hold the socket to send data immediately this.Socket.Unhold(); - if (r is DistributedResource) + if (r is DistributedResource) + { + var rt = (r as DistributedResource)._InvokeByNamedArguments(index, namedArgs); + if (rt != null) { - var rt = (r as DistributedResource)._InvokeByNamedArguments(index, namedArgs); - if (rt != null) + rt.Then(res => { - rt.Then(res => - { - SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback) - .AddUInt8Array(Codec.Compose(res, this)) - .Done(); - }); - } - else - { - - // function not found on a distributed object - } + SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback) + .AddUInt8Array(Codec.Compose(res, this)) + .Done(); + }); } else { + + // function not found on a distributed object + } + } + else + { #if NETSTANDARD var fi = r.GetType().GetTypeInfo().GetMethod(ft.Name); #else @@ -1440,294 +1440,294 @@ namespace Esiur.Net.IIP #endif if (fi != null) + { + if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied) { - if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied) - { - SendError(ErrorType.Management, callback, - (ushort)ExceptionCode.InvokeDenied); - return; - } + SendError(ErrorType.Management, callback, + (ushort)ExceptionCode.InvokeDenied); + return; + } // cast arguments ParameterInfo[] pi = fi.GetParameters(); - object[] args = new object[pi.Length]; + object[] args = new object[pi.Length]; - for (var i = 0; i < pi.Length; i++) + for (var i = 0; i < pi.Length; i++) + { + if (pi[i].ParameterType == typeof(DistributedConnection)) { - if (pi[i].ParameterType == typeof(DistributedConnection)) - { - args[i] = this; - } - else if (namedArgs.ContainsKey(pi[i].Name)) - { - args[i] = DC.CastConvert(namedArgs[pi[i].Name], pi[i].ParameterType); - } + args[i] = this; } + else if (namedArgs.ContainsKey(pi[i].Name)) + { + args[i] = DC.CastConvert(namedArgs[pi[i].Name], pi[i].ParameterType); + } + } - object rt; + object rt; + + try + { + rt = fi.Invoke(r, args); + } + catch (Exception ex) + { + var (code, msg) = SummerizeException(ex); + SendError(ErrorType.Exception, callback, code, msg); + return; + } + + if (rt is System.Collections.IEnumerable && !(rt is Array || rt is Structure || rt is string)) + { + var enu = rt as System.Collections.IEnumerable; try { - rt = fi.Invoke(r, args); + foreach (var v in enu) + SendChunk(callback, v); + + SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback) + .AddUInt8((byte)DataType.Void) + .Done(); } catch (Exception ex) { var (code, msg) = SummerizeException(ex); SendError(ErrorType.Exception, callback, code, msg); - return; } - - if (rt is System.Collections.IEnumerable && !(rt is Array || rt is Structure || rt is string)) + } + else if (rt is Task) + { + (rt as Task).ContinueWith(t => { - var enu = rt as System.Collections.IEnumerable; - - try - { - foreach (var v in enu) - SendChunk(callback, v); - - SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback) - .AddUInt8((byte)DataType.Void) - .Done(); - } - catch (Exception ex) - { - var (code, msg) = SummerizeException(ex); - SendError(ErrorType.Exception, callback, code, msg); - } - } - else if (rt is Task) - { - (rt as Task).ContinueWith(t => - { #if NETSTANDARD var res = t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t); #else var res = t.GetType().GetProperty("Result").GetValue(t); #endif SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback) - .AddUInt8Array(Codec.Compose(res, this)) - .Done(); - }); + .AddUInt8Array(Codec.Compose(res, this)) + .Done(); + }); - } - else if (rt is AsyncReply) - { - (rt as AsyncReply).Then(res => - { - SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback) - .AddUInt8Array(Codec.Compose(res, this)) - .Done(); + } + else if (rt is AsyncReply) + { + (rt as AsyncReply).Then(res => + { + SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback) + .AddUInt8Array(Codec.Compose(res, this)) + .Done(); - }).Error(ex => - { - var (code, msg) = SummerizeException(ex); - SendError(ErrorType.Exception, callback, code, msg); - }).Progress((pt, pv, pm) => - { - SendProgress(callback, pv, pm); - }).Chunk(v => - { - SendChunk(callback, v); - }); - } - else - { - SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback) - .AddUInt8Array(Codec.Compose(rt, this)) - .Done(); - } + }).Error(ex => + { + var (code, msg) = SummerizeException(ex); + SendError(ErrorType.Exception, callback, code, msg); + }).Progress((pt, pv, pm) => + { + SendProgress(callback, pv, pm); + }).Chunk(v => + { + SendChunk(callback, v); + }); } else { + SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback) + .AddUInt8Array(Codec.Compose(rt, this)) + .Done(); + } + } + else + { // ft found, fi not found, this should never happen SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); - } } } - else - { + } + else + { // no function at this index SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); - } - }); - } - else - { + } + }); + } + else + { // no resource with this id SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - } - }); - } + } + }); + } - void IIPRequestListen(uint callback, uint resourceId, byte index) + void IIPRequestListen(uint callback, uint resourceId, byte index) + { + Warehouse.GetById(resourceId).Then((r) => { - Warehouse.GetById(resourceId).Then((r) => + if (r != null) { - if (r != null) + var et = r.Instance.Template.GetEventTemplateByIndex(index); + + if (et != null) { - var et = r.Instance.Template.GetEventTemplateByIndex(index); - - if (et != null) + if (r is DistributedResource) { - if (r is DistributedResource) - { - (r as DistributedResource).Listen(et).Then(x => - { - SendReply(IIPPacket.IIPPacketAction.Listen, callback).Done(); - }).Error(x => SendError(ErrorType.Exception, callback, (ushort)ExceptionCode.GeneralFailure)); - } - else - { - lock (subscriptionsLock) - { - if (!subscriptions.ContainsKey(r)) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.NotAttached); - return; - } - - if (subscriptions[r].Contains(index)) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AlreadyListened); - return; - } - - subscriptions[r].Add(index); - - SendReply(IIPPacket.IIPPacketAction.Listen, callback).Done(); - } - } + (r as DistributedResource).Listen(et).Then(x => + { + SendReply(IIPPacket.IIPPacketAction.Listen, callback).Done(); + }).Error(x => SendError(ErrorType.Exception, callback, (ushort)ExceptionCode.GeneralFailure)); } else { - // pt not found - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); + lock (subscriptionsLock) + { + if (!subscriptions.ContainsKey(r)) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.NotAttached); + return; + } + + if (subscriptions[r].Contains(index)) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AlreadyListened); + return; + } + + subscriptions[r].Add(index); + + SendReply(IIPPacket.IIPPacketAction.Listen, callback).Done(); + } } } else { + // pt not found + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); + } + } + else + { // resource not found SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - } - }); + } + }); - } + } - void IIPRequestUnlisten(uint callback, uint resourceId, byte index) + void IIPRequestUnlisten(uint callback, uint resourceId, byte index) + { + Warehouse.GetById(resourceId).Then((r) => { - Warehouse.GetById(resourceId).Then((r) => + if (r != null) { - if (r != null) + var et = r.Instance.Template.GetEventTemplateByIndex(index); + + if (et != null) { - var et = r.Instance.Template.GetEventTemplateByIndex(index); - - if (et != null) + if (r is DistributedResource) { - if (r is DistributedResource) + (r as DistributedResource).Unlisten(et).Then(x => { - (r as DistributedResource).Unlisten(et).Then(x => - { - SendReply(IIPPacket.IIPPacketAction.Unlisten, callback).Done(); - }).Error(x => SendError(ErrorType.Exception, callback, (ushort)ExceptionCode.GeneralFailure)); - } - else - { - lock (subscriptionsLock) - { - if (!subscriptions.ContainsKey(r)) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.NotAttached); - return; - } - - if (!subscriptions[r].Contains(index)) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AlreadyUnlistened); - return; - } - - subscriptions[r].Remove(index); - - SendReply(IIPPacket.IIPPacketAction.Unlisten, callback).Done(); - } - } + SendReply(IIPPacket.IIPPacketAction.Unlisten, callback).Done(); + }).Error(x => SendError(ErrorType.Exception, callback, (ushort)ExceptionCode.GeneralFailure)); } else { - // pt not found - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); + lock (subscriptionsLock) + { + if (!subscriptions.ContainsKey(r)) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.NotAttached); + return; + } + + if (!subscriptions[r].Contains(index)) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AlreadyUnlistened); + return; + } + + subscriptions[r].Remove(index); + + SendReply(IIPPacket.IIPPacketAction.Unlisten, callback).Done(); + } } } else { + // pt not found + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); + } + } + else + { // resource not found SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - } - }); + } + }); - } + } - // void IIPRequestGetProperty(uint callback, uint resourceId, byte index) - // { - // Warehouse.GetById(resourceId).Then((r) => - // { - // if (r != null) - // { - // var pt = r.Instance.Template.GetPropertyTemplateByIndex(index); - // if (pt != null) - // { - // if (r is DistributedResource) - // { - // SendReply(IIPPacket.IIPPacketAction.GetProperty, callback) - // .AddUInt8Array(Codec.Compose((r as DistributedResource)._Get(pt.Index), this)) - // .Done(); - // } - // else - // { - //#if NETSTANDARD - // var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name); - //#else - // var pi = r.GetType().GetProperty(pt.Name); - //#endif + // void IIPRequestGetProperty(uint callback, uint resourceId, byte index) + // { + // Warehouse.GetById(resourceId).Then((r) => + // { + // if (r != null) + // { + // var pt = r.Instance.Template.GetPropertyTemplateByIndex(index); + // if (pt != null) + // { + // if (r is DistributedResource) + // { + // SendReply(IIPPacket.IIPPacketAction.GetProperty, callback) + // .AddUInt8Array(Codec.Compose((r as DistributedResource)._Get(pt.Index), this)) + // .Done(); + // } + // else + // { + //#if NETSTANDARD + // var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name); + //#else + // var pi = r.GetType().GetProperty(pt.Name); + //#endif - // if (pi != null) - // { - // SendReply(IIPPacket.IIPPacketAction.GetProperty, callback) - // .AddUInt8Array(Codec.Compose(pi.GetValue(r), this)) - // .Done(); - // } - // else - // { - // // pt found, pi not found, this should never happen - // } - // } - // } - // else - // { - // // pt not found - // } - // } - // else - // { - // // resource not found - // } - // }); - // } + // if (pi != null) + // { + // SendReply(IIPPacket.IIPPacketAction.GetProperty, callback) + // .AddUInt8Array(Codec.Compose(pi.GetValue(r), this)) + // .Done(); + // } + // else + // { + // // pt found, pi not found, this should never happen + // } + // } + // } + // else + // { + // // pt not found + // } + // } + // else + // { + // // resource not found + // } + // }); + // } - void IIPRequestInquireResourceHistory(uint callback, uint resourceId, DateTime fromDate, DateTime toDate) + void IIPRequestInquireResourceHistory(uint callback, uint resourceId, DateTime fromDate, DateTime toDate) + { + Warehouse.GetById(resourceId).Then((r) => { - Warehouse.GetById(resourceId).Then((r) => + if (r != null) { - if (r != null) + r.Instance.Store.GetRecord(r, fromDate, toDate).Then((results) => { - r.Instance.Store.GetRecord(r, fromDate, toDate).Then((results) => - { - var history = Codec.ComposeHistory(results, this, true); + var history = Codec.ComposeHistory(results, this, true); /* ulong fromAge = 0; @@ -1746,87 +1746,87 @@ namespace Esiur.Net.IIP }*/ - SendReply(IIPPacket.IIPPacketAction.ResourceHistory, callback) - .AddUInt8Array(history) - .Done(); + SendReply(IIPPacket.IIPPacketAction.ResourceHistory, callback) + .AddUInt8Array(history) + .Done(); - }); - } - }); - } + }); + } + }); + } - // void IIPRequestGetPropertyIfModifiedSince(uint callback, uint resourceId, byte index, ulong age) - // { - // Warehouse.GetById(resourceId).Then((r) => - // { - // if (r != null) - // { - // var pt = r.Instance.Template.GetFunctionTemplateByIndex(index); - // if (pt != null) - // { - // if (r.Instance.GetAge(index) > age) - // { - //#if NETSTANDARD - // var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name); - //#else - // var pi = r.GetType().GetProperty(pt.Name); - //#endif - // if (pi != null) - // { - // SendReply(IIPPacket.IIPPacketAction.GetPropertyIfModified, callback) - // .AddUInt8Array(Codec.Compose(pi.GetValue(r), this)) - // .Done(); - // } - // else - // { - // // pt found, pi not found, this should never happen - // } - // } - // else - // { - // SendReply(IIPPacket.IIPPacketAction.GetPropertyIfModified, callback) - // .AddUInt8((byte)DataType.NotModified) - // .Done(); - // } - // } - // else - // { - // // pt not found - // } - // } - // else - // { - // // resource not found - // } - // }); - // } + // void IIPRequestGetPropertyIfModifiedSince(uint callback, uint resourceId, byte index, ulong age) + // { + // Warehouse.GetById(resourceId).Then((r) => + // { + // if (r != null) + // { + // var pt = r.Instance.Template.GetFunctionTemplateByIndex(index); + // if (pt != null) + // { + // if (r.Instance.GetAge(index) > age) + // { + //#if NETSTANDARD + // var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name); + //#else + // var pi = r.GetType().GetProperty(pt.Name); + //#endif + // if (pi != null) + // { + // SendReply(IIPPacket.IIPPacketAction.GetPropertyIfModified, callback) + // .AddUInt8Array(Codec.Compose(pi.GetValue(r), this)) + // .Done(); + // } + // else + // { + // // pt found, pi not found, this should never happen + // } + // } + // else + // { + // SendReply(IIPPacket.IIPPacketAction.GetPropertyIfModified, callback) + // .AddUInt8((byte)DataType.NotModified) + // .Done(); + // } + // } + // else + // { + // // pt not found + // } + // } + // else + // { + // // resource not found + // } + // }); + // } - void IIPRequestSetProperty(uint callback, uint resourceId, byte index, byte[] content) + void IIPRequestSetProperty(uint callback, uint resourceId, byte index, byte[] content) + { + Warehouse.GetById(resourceId).Then((r) => { - Warehouse.GetById(resourceId).Then((r) => + if (r != null) { - if (r != null) + + + var pt = r.Instance.Template.GetPropertyTemplateByIndex(index); + if (pt != null) { - - - var pt = r.Instance.Template.GetPropertyTemplateByIndex(index); - if (pt != null) + Codec.Parse(content, 0, this).Then((value) => { - Codec.Parse(content, 0, this).Then((value) => + if (r is DistributedResource) { - if (r is DistributedResource) - { // propagation (r as DistributedResource)._Set(index, value).Then((x) => - { - SendReply(IIPPacket.IIPPacketAction.SetProperty, callback).Done(); - }).Error(x => - { - SendError(x.Type, callback, (ushort)x.Code, x.Message); - }); - } - else { + SendReply(IIPPacket.IIPPacketAction.SetProperty, callback).Done(); + }).Error(x => + { + SendError(x.Type, callback, (ushort)x.Code, x.Message); + }); + } + else + { /* #if NETSTANDARD @@ -1835,793 +1835,792 @@ namespace Esiur.Net.IIP var pi = r.GetType().GetProperty(pt.Name); #endif*/ - var pi = pt.PropertyInfo; + var pi = pt.PropertyInfo; - if (pi != null) + if (pi != null) + { + + if (r.Instance.Applicable(session, ActionType.SetProperty, pt, this) == Ruling.Denied) { + SendError(ErrorType.Exception, callback, (ushort)ExceptionCode.SetPropertyDenied); + return; + } - if (r.Instance.Applicable(session, ActionType.SetProperty, pt, this) == Ruling.Denied) - { - SendError(ErrorType.Exception, callback, (ushort)ExceptionCode.SetPropertyDenied); - return; - } - - if (!pi.CanWrite) - { - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ReadOnlyProperty); - return; - } + if (!pi.CanWrite) + { + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ReadOnlyProperty); + return; + } - if (pi.PropertyType == typeof(DistributedPropertyContext)) - { - value = new DistributedPropertyContext(this, value); - } - else - { - // cast new value type to property type - value = DC.CastConvert(value, pi.PropertyType); - } - - - try - { - pi.SetValue(r, value); - SendReply(IIPPacket.IIPPacketAction.SetProperty, callback).Done(); - } - catch (Exception ex) - { - SendError(ErrorType.Exception, callback, 0, ex.Message); - } - + if (pi.PropertyType == typeof(DistributedPropertyContext)) + { + value = new DistributedPropertyContext(this, value); } else { + // cast new value type to property type + value = DC.CastConvert(value, pi.PropertyType); + } + + + try + { + pi.SetValue(r, value); + SendReply(IIPPacket.IIPPacketAction.SetProperty, callback).Done(); + } + catch (Exception ex) + { + SendError(ErrorType.Exception, callback, 0, ex.Message); + } + + } + else + { // pt found, pi not found, this should never happen SendError(ErrorType.Management, callback, (ushort)ExceptionCode.PropertyNotFound); - } } + } - }); - } - else - { + }); + } + else + { // property not found SendError(ErrorType.Management, callback, (ushort)ExceptionCode.PropertyNotFound); - } } - else - { + } + else + { // resource not found SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - } - }); - } + } + }); + } - /* - void IIPReplyAttachResource(uint callback, uint resourceAge, object[] properties) + /* + void IIPReplyAttachResource(uint callback, uint resourceAge, object[] properties) + { + if (requests.ContainsKey(callback)) { - if (requests.ContainsKey(callback)) + var req = requests[callback]; + var r = resources[(uint)req.Arguments[0]]; + + if (r == null) { - var req = requests[callback]; - var r = resources[(uint)req.Arguments[0]]; + r.Instance.Deserialize(properties); + r.Instance.Age = resourceAge; + r.Attached(); - if (r == null) - { - r.Instance.Deserialize(properties); - r.Instance.Age = resourceAge; - r.Attached(); - - // process stack - foreach (var rr in resources.Values) - rr.Stack.ProcessStack(); - } - else - { - // resource not found - } + // process stack + foreach (var rr in resources.Values) + rr.Stack.ProcessStack(); + } + else + { + // resource not found } } + } - void IIPReplyReattachResource(uint callback, uint resourceAge, object[] properties) + void IIPReplyReattachResource(uint callback, uint resourceAge, object[] properties) + { + var req = requests.Take(callback); + + if (req != null) { - var req = requests.Take(callback); + var r = resources[(uint)req.Arguments[0]]; - if (req != null) + if (r == null) { - var r = resources[(uint)req.Arguments[0]]; + r.Instance.Deserialize(properties); + r.Instance.Age = resourceAge; + r.Attached(); - if (r == null) - { - r.Instance.Deserialize(properties); - r.Instance.Age = resourceAge; - r.Attached(); - - // process stack - foreach (var rr in resources.Values) - rr.Stack.ProcessStack(); - } - else - { - // resource not found - } + // process stack + foreach (var rr in resources.Values) + rr.Stack.ProcessStack(); + } + else + { + // resource not found } } + } - - void IIPReplyDetachResource(uint callback) + + void IIPReplyDetachResource(uint callback) + { + var req = requests.Take(callback); + // nothing to do + } + + void IIPReplyCreateResource(uint callback, Guid classId, uint resourceId) + { + var req = requests.Take(callback); + // nothing to do + + } + void IIPReplyDeleteResource(uint callback) + { + var req = requests.Take(callback); + // nothing to do + + } + + void IIPReplyTemplateFromClassName(uint callback, ResourceTemplate template) + { + // cache + if (!templates.ContainsKey(template.ClassId)) + templates.Add(template.ClassId, template); + + var req = requests.Take(callback); + req?.Trigger(template); + } + + void IIPReplyTemplateFromClassId(uint callback, ResourceTemplate template) + { + // cache + if (!templates.ContainsKey(template.ClassId)) + templates.Add(template.ClassId, template); + + var req = requests.Take(callback); + req?.Trigger(template); + + } + + void IIPReplyTemplateFromResourceLink(uint callback, ResourceTemplate template) + { + // cache + if (!templates.ContainsKey(template.ClassId)) + templates.Add(template.ClassId, template); + + var req = requests.Take(callback); + req?.Trigger(template); + } + + void IIPReplyTemplateFromResourceId(uint callback, ResourceTemplate template) + { + // cache + if (!templates.ContainsKey(template.ClassId)) + templates.Add(template.ClassId, template); + + var req = requests.Take(callback); + req?.Trigger(template); + } + + void IIPReplyResourceIdFromResourceLink(uint callback, Guid classId, uint resourceId, uint resourceAge) + { + var req = requests.Take(callback); + req?.Trigger(template); + } + + void IIPReplyInvokeFunction(uint callback, object returnValue) + { + + } + + void IIPReplyGetProperty(uint callback, object value) + { + + } + void IIPReplyGetPropertyIfModifiedSince(uint callback, object value) + { + + } + void IIPReplySetProperty(uint callback) + { + + } + */ + + /// + /// Get the ResourceTemplate for a given class Id. + /// + /// Class GUID. + /// ResourceTemplate. + public AsyncReply GetTemplate(Guid classId) + { + if (templates.ContainsKey(classId)) + return new AsyncReply(templates[classId]); + else if (templateRequests.ContainsKey(classId)) + return templateRequests[classId]; + + var reply = new AsyncReply(); + templateRequests.Add(classId, reply); + + SendRequest(IIPPacket.IIPPacketAction.TemplateFromClassId) + .AddGuid(classId) + .Done() + .Then((rt) => + { + templateRequests.Remove(classId); + templates.Add(((TypeTemplate)rt[0]).ClassId, (TypeTemplate)rt[0]); + Warehouse.PutTemplate(rt[0] as TypeTemplate); + reply.Trigger(rt[0]); + }).Error((ex) => + { + reply.TriggerError(ex); + }); + + return reply; + } + + // IStore interface + /// + /// Get a resource by its path. + /// + /// Path to the resource. + /// Resource + public AsyncReply Get(string path) + { + + var rt = new AsyncReply(); + + Query(path).Then(ar => { - var req = requests.Take(callback); - // nothing to do - } - - void IIPReplyCreateResource(uint callback, Guid classId, uint resourceId) - { - var req = requests.Take(callback); - // nothing to do - - } - void IIPReplyDeleteResource(uint callback) - { - var req = requests.Take(callback); - // nothing to do - - } - - void IIPReplyTemplateFromClassName(uint callback, ResourceTemplate template) - { - // cache - if (!templates.ContainsKey(template.ClassId)) - templates.Add(template.ClassId, template); - - var req = requests.Take(callback); - req?.Trigger(template); - } - - void IIPReplyTemplateFromClassId(uint callback, ResourceTemplate template) - { - // cache - if (!templates.ContainsKey(template.ClassId)) - templates.Add(template.ClassId, template); - - var req = requests.Take(callback); - req?.Trigger(template); - - } - - void IIPReplyTemplateFromResourceLink(uint callback, ResourceTemplate template) - { - // cache - if (!templates.ContainsKey(template.ClassId)) - templates.Add(template.ClassId, template); - - var req = requests.Take(callback); - req?.Trigger(template); - } - - void IIPReplyTemplateFromResourceId(uint callback, ResourceTemplate template) - { - // cache - if (!templates.ContainsKey(template.ClassId)) - templates.Add(template.ClassId, template); - - var req = requests.Take(callback); - req?.Trigger(template); - } - - void IIPReplyResourceIdFromResourceLink(uint callback, Guid classId, uint resourceId, uint resourceAge) - { - var req = requests.Take(callback); - req?.Trigger(template); - } - - void IIPReplyInvokeFunction(uint callback, object returnValue) - { - - } - - void IIPReplyGetProperty(uint callback, object value) - { - - } - void IIPReplyGetPropertyIfModifiedSince(uint callback, object value) - { - - } - void IIPReplySetProperty(uint callback) - { - - } - */ - - /// - /// Get the ResourceTemplate for a given class Id. - /// - /// Class GUID. - /// ResourceTemplate. - public AsyncReply GetTemplate(Guid classId) - { - if (templates.ContainsKey(classId)) - return new AsyncReply(templates[classId]); - else if (templateRequests.ContainsKey(classId)) - return templateRequests[classId]; - - var reply = new AsyncReply(); - templateRequests.Add(classId, reply); - - SendRequest(IIPPacket.IIPPacketAction.TemplateFromClassId) - .AddGuid(classId) - .Done() - .Then((rt) => - { - templateRequests.Remove(classId); - templates.Add(((TypeTemplate)rt[0]).ClassId, (TypeTemplate)rt[0]); - Warehouse.PutTemplate(rt[0] as TypeTemplate); - reply.Trigger(rt[0]); - }).Error((ex) => - { - reply.TriggerError(ex); - }); - - return reply; - } - - // IStore interface - /// - /// Get a resource by its path. - /// - /// Path to the resource. - /// Resource - public AsyncReply Get(string path) - { - - var rt = new AsyncReply(); - - Query(path).Then(ar => - { //if (filter != null) // ar = ar?.Where(filter).ToArray(); // MISSING: should dispatch the unused resources. if (ar?.Length > 0) - rt.Trigger(ar[0]); - else - rt.Trigger(null); - }).Error(ex => rt.TriggerError(ex)); + rt.Trigger(ar[0]); + else + rt.Trigger(null); + }).Error(ex => rt.TriggerError(ex)); - return rt; + return rt; - /* - - if (pathRequests.ContainsKey(path)) - return pathRequests[path]; + /* - var reply = new AsyncReply(); - pathRequests.Add(path, reply); + if (pathRequests.ContainsKey(path)) + return pathRequests[path]; - var bl = new BinaryList(path); - bl.Insert(0, (ushort)bl.Length); - - SendRequest(IIPPacket.IIPPacketAction.QueryLink, bl.ToArray()).Then((rt) => - { - pathRequests.Remove(path); - //(Guid)rt[0], - Fetch((uint)rt[1]).Then((r) => - { - reply.Trigger(r); - }); - }).Error((ex) => - { - reply.TriggerError(ex); - }); ; + var reply = new AsyncReply(); + pathRequests.Add(path, reply); + var bl = new BinaryList(path); + bl.Insert(0, (ushort)bl.Length); - return reply; - */ - } - - /// - /// Retrive a resource by its instance Id. - /// - /// Instance Id - /// Resource - public AsyncReply Retrieve(uint iid) + SendRequest(IIPPacket.IIPPacketAction.QueryLink, bl.ToArray()).Then((rt) => { - foreach (var r in resources.Values) - if (r.Instance.Id == iid) - return new AsyncReply(r); - return new AsyncReply(null); - } - - - public AsyncReply GetLinkTemplates(string link) + pathRequests.Remove(path); + //(Guid)rt[0], + Fetch((uint)rt[1]).Then((r) => + { + reply.Trigger(r); + }); + }).Error((ex) => { - var reply = new AsyncReply(); + reply.TriggerError(ex); + }); ; - var l = DC.ToBytes(link); - SendRequest(IIPPacket.IIPPacketAction.LinkTemplates) - .AddUInt16((ushort)l.Length) - .AddUInt8Array(l) - .Done() - .Then((rt) => - { + return reply; + */ + } - var templates = new List(); + /// + /// Retrive a resource by its instance Id. + /// + /// Instance Id + /// Resource + public AsyncReply Retrieve(uint iid) + { + foreach (var r in resources.Values) + if (r.Instance.Id == iid) + return new AsyncReply(r); + return new AsyncReply(null); + } + + + public AsyncReply GetLinkTemplates(string link) + { + var reply = new AsyncReply(); + + var l = DC.ToBytes(link); + + SendRequest(IIPPacket.IIPPacketAction.LinkTemplates) + .AddUInt16((ushort)l.Length) + .AddUInt8Array(l) + .Done() + .Then((rt) => + { + + var templates = new List(); // parse templates var data = (byte[])rt[0]; //var offset = 0; for (uint offset = 0; offset < data.Length;) - { - var cs = data.GetUInt32(offset); - offset += 4; - templates.Add(TypeTemplate.Parse(data, offset, cs)); - offset += cs; - } - - reply.Trigger(templates.ToArray()); - - }).Error((ex) => { - reply.TriggerError(ex); - }); + var cs = data.GetUInt32(offset); + offset += 4; + templates.Add(TypeTemplate.Parse(data, offset, cs)); + offset += cs; + } - return reply; + reply.Trigger(templates.ToArray()); + + }).Error((ex) => + { + reply.TriggerError(ex); + }); + + return reply; + } + + /// + /// Fetch a resource from the other end + /// + /// Class GUID + /// Resource IdGuid classId + /// DistributedResource + public AsyncReply Fetch(uint id) + { + var resource = resources[id]; + var request = resourceRequests[id]; + + if (request != null) + { + if (resource != null) + // dig for dead locks // or not + return new AsyncReply(resource); + else + return request; + } + else if (resource != null && !resource.Suspended) + { + return new AsyncReply(resource); } - /// - /// Fetch a resource from the other end - /// - /// Class GUID - /// Resource IdGuid classId - /// DistributedResource - public AsyncReply Fetch(uint id) - { - var resource = resources[id]; - var request = resourceRequests[id]; - if (request != null) - { - if (resource != null) - // dig for dead locks // or not - return new AsyncReply(resource); - else - return request; - } - else if (resource != null && !resource.Suspended) - { - return new AsyncReply(resource); - } + var reply = new AsyncReply(); + resourceRequests.Add(id, reply); + SendRequest(IIPPacket.IIPPacketAction.AttachResource) + .AddUInt32(id) + .Done() + .Then((rt) => + { - var reply = new AsyncReply(); - resourceRequests.Add(id, reply); + DistributedResource dr; - SendRequest(IIPPacket.IIPPacketAction.AttachResource) - .AddUInt32(id) - .Done() - .Then((rt) => + if (resource == null) { - - DistributedResource dr; - - if (resource == null) - { - var template = Warehouse.GetTemplateByClassId((Guid)rt[0], TemplateType.Wrapper); - if (template?.DefinedType != null) - dr = Activator.CreateInstance(template.DefinedType, this, id, (ulong)rt[1], (string)rt[2]) as DistributedResource; - else - dr = new DistributedResource(this, id, (ulong)rt[1], (string)rt[2]); - } + var template = Warehouse.GetTemplateByClassId((Guid)rt[0], TemplateType.Wrapper); + if (template?.DefinedType != null) + dr = Activator.CreateInstance(template.DefinedType, this, id, (ulong)rt[1], (string)rt[2]) as DistributedResource; else - dr = resource; + dr = new DistributedResource(this, id, (ulong)rt[1], (string)rt[2]); + } + else + dr = resource; - GetTemplate((Guid)rt[0]).Then((tmp) => - { + GetTemplate((Guid)rt[0]).Then((tmp) => + { // ClassId, ResourceAge, ResourceLink, Content if (resource == null) - { - Warehouse.Put(id.ToString(), dr, this, null, tmp).Then((ok) => - { - Codec.ParsePropertyValueArray((byte[])rt[3], this).Then((ar) => - { - dr._Attach(ar); - resourceRequests.Remove(id); - reply.Trigger(dr); - }); - }).Error(ex => reply.TriggerError(ex)); - } - else + { + Warehouse.Put(id.ToString(), dr, this, null, tmp).Then((ok) => { Codec.ParsePropertyValueArray((byte[])rt[3], this).Then((ar) => { dr._Attach(ar); resourceRequests.Remove(id); reply.Trigger(dr); - }).Error(ex => reply.TriggerError(ex)); - } - - }).Error((ex) => + }); + }).Error(ex => reply.TriggerError(ex)); + } + else { - reply.TriggerError(ex); - }); + Codec.ParsePropertyValueArray((byte[])rt[3], this).Then((ar) => + { + dr._Attach(ar); + resourceRequests.Remove(id); + reply.Trigger(dr); + }).Error(ex => reply.TriggerError(ex)); + } + }).Error((ex) => { reply.TriggerError(ex); }); + }).Error((ex) => + { + reply.TriggerError(ex); + }); - return reply; - } + return reply; + } - public AsyncReply GetChildren(IResource resource) - { - var rt = new AsyncReply(); + public AsyncReply GetChildren(IResource resource) + { + var rt = new AsyncReply(); - SendRequest(IIPPacket.IIPPacketAction.ResourceChildren) - .AddUInt32(resource.Instance.Id) - .Done() - .Then(ar => + SendRequest(IIPPacket.IIPPacketAction.ResourceChildren) + .AddUInt32(resource.Instance.Id) + .Done() + .Then(ar => + { + var d = (byte[])ar[0]; + Codec.ParseResourceArray(d, 0, (uint)d.Length, this).Then(resources => { - var d = (byte[])ar[0]; - Codec.ParseResourceArray(d, 0, (uint)d.Length, this).Then(resources => - { - rt.Trigger(resources); - }).Error(ex => rt.TriggerError(ex)); - }); + rt.Trigger(resources); + }).Error(ex => rt.TriggerError(ex)); + }); - return rt; + return rt; + } + + public AsyncReply GetParents(IResource resource) + { + var rt = new AsyncReply(); + + SendRequest(IIPPacket.IIPPacketAction.ResourceParents) + .AddUInt32(resource.Instance.Id) + .Done() + .Then(ar => + { + var d = (byte[])ar[0]; + Codec.ParseResourceArray(d, 0, (uint)d.Length, this).Then(resources => + { + rt.Trigger(resources); + }).Error(ex => rt.TriggerError(ex)); + }); + + return rt; + } + + public AsyncReply RemoveAttributes(IResource resource, string[] attributes = null) + { + var rt = new AsyncReply(); + + if (attributes == null) + SendRequest(IIPPacket.IIPPacketAction.ClearAllAttributes) + .AddUInt32(resource.Instance.Id) + .Done() + .Then(ar => rt.Trigger(true)) + .Error(ex => rt.TriggerError(ex)); + else + { + var attrs = DC.ToBytes(attributes); + SendRequest(IIPPacket.IIPPacketAction.ClearAttributes) + .AddUInt32(resource.Instance.Id) + .AddInt32(attrs.Length) + .AddUInt8Array(attrs) + .Done() + .Then(ar => rt.Trigger(true)) + .Error(ex => rt.TriggerError(ex)); } - public AsyncReply GetParents(IResource resource) - { - var rt = new AsyncReply(); + return rt; + } - SendRequest(IIPPacket.IIPPacketAction.ResourceParents) + public AsyncReply SetAttributes(IResource resource, Structure attributes, bool clearAttributes = false) + { + var rt = new AsyncReply(); + + SendRequest(clearAttributes ? IIPPacket.IIPPacketAction.UpdateAllAttributes : IIPPacket.IIPPacketAction.UpdateAttributes) + .AddUInt32(resource.Instance.Id) + .AddUInt8Array(Codec.ComposeStructure(attributes, this, true, true, true)) + .Done() + .Then(ar => rt.Trigger(true)) + .Error(ex => rt.TriggerError(ex)); + + return rt; + } + + public AsyncReply GetAttributes(IResource resource, string[] attributes = null) + { + var rt = new AsyncReply(); + + if (attributes == null) + { + SendRequest(IIPPacket.IIPPacketAction.GetAllAttributes) .AddUInt32(resource.Instance.Id) .Done() .Then(ar => { - var d = (byte[])ar[0]; - Codec.ParseResourceArray(d, 0, (uint)d.Length, this).Then(resources => + var d = ar[0] as byte[]; + Codec.ParseStructure(d, 0, (uint)d.Length, this).Then(st => { - rt.Trigger(resources); + + resource.Instance.SetAttributes(st); + + rt.Trigger(st); }).Error(ex => rt.TriggerError(ex)); }); - - return rt; } - - public AsyncReply RemoveAttributes(IResource resource, string[] attributes = null) + else { - var rt = new AsyncReply(); - - if (attributes == null) - SendRequest(IIPPacket.IIPPacketAction.ClearAllAttributes) - .AddUInt32(resource.Instance.Id) - .Done() - .Then(ar => rt.Trigger(true)) - .Error(ex => rt.TriggerError(ex)); - else - { - var attrs = DC.ToBytes(attributes); - SendRequest(IIPPacket.IIPPacketAction.ClearAttributes) - .AddUInt32(resource.Instance.Id) - .AddInt32(attrs.Length) - .AddUInt8Array(attrs) - .Done() - .Then(ar => rt.Trigger(true)) - .Error(ex => rt.TriggerError(ex)); - } - - return rt; - } - - public AsyncReply SetAttributes(IResource resource, Structure attributes, bool clearAttributes = false) - { - var rt = new AsyncReply(); - - SendRequest(clearAttributes ? IIPPacket.IIPPacketAction.UpdateAllAttributes : IIPPacket.IIPPacketAction.UpdateAttributes) + var attrs = DC.ToBytes(attributes); + SendRequest(IIPPacket.IIPPacketAction.GetAttributes) .AddUInt32(resource.Instance.Id) - .AddUInt8Array(Codec.ComposeStructure(attributes, this, true, true, true)) + .AddInt32(attrs.Length) + .AddUInt8Array(attrs) .Done() - .Then(ar => rt.Trigger(true)) - .Error(ex => rt.TriggerError(ex)); + .Then(ar => + { + var d = ar[0] as byte[]; + Codec.ParseStructure(d, 0, (uint)d.Length, this).Then(st => + { - return rt; + resource.Instance.SetAttributes(st); + + rt.Trigger(st); + }).Error(ex => rt.TriggerError(ex)); + }); } - public AsyncReply GetAttributes(IResource resource, string[] attributes = null) + return rt; + } + + /// + /// Get resource history. + /// + /// IResource. + /// From date. + /// To date. + /// + public AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate) + { + if (resource is DistributedResource) { - var rt = new AsyncReply(); + var dr = resource as DistributedResource; - if (attributes == null) - { - SendRequest(IIPPacket.IIPPacketAction.GetAllAttributes) - .AddUInt32(resource.Instance.Id) - .Done() - .Then(ar => - { - var d = ar[0] as byte[]; - Codec.ParseStructure(d, 0, (uint)d.Length, this).Then(st => - { - - resource.Instance.SetAttributes(st); - - rt.Trigger(st); - }).Error(ex => rt.TriggerError(ex)); - }); - } - else - { - var attrs = DC.ToBytes(attributes); - SendRequest(IIPPacket.IIPPacketAction.GetAttributes) - .AddUInt32(resource.Instance.Id) - .AddInt32(attrs.Length) - .AddUInt8Array(attrs) - .Done() - .Then(ar => - { - var d = ar[0] as byte[]; - Codec.ParseStructure(d, 0, (uint)d.Length, this).Then(st => - { - - resource.Instance.SetAttributes(st); - - rt.Trigger(st); - }).Error(ex => rt.TriggerError(ex)); - }); - } - - return rt; - } - - /// - /// Get resource history. - /// - /// IResource. - /// From date. - /// To date. - /// - public AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate) - { - if (resource is DistributedResource) - { - var dr = resource as DistributedResource; - - if (dr.Connection != this) - return new AsyncReply>(null); - - var reply = new AsyncReply>(); - - SendRequest(IIPPacket.IIPPacketAction.ResourceHistory) - .AddUInt32(dr.Id) - .AddDateTime(fromDate) - .AddDateTime(toDate) - .Done() - .Then(rt => - { - var content = (byte[])rt[0]; - - Codec.ParseHistory(content, 0, (uint)content.Length, resource, this) - .Then((history) => reply.Trigger(history)); - - }).Error((ex) => reply.TriggerError(ex)); - - return reply; - } - else + if (dr.Connection != this) return new AsyncReply>(null); - } - /// - /// Query resources at specific link. - /// - /// Link path. - /// - public AsyncReply Query(string path) - { - var str = DC.ToBytes(path); - var reply = new AsyncReply(); + var reply = new AsyncReply>(); - SendRequest(IIPPacket.IIPPacketAction.QueryLink) - .AddUInt16((ushort)str.Length) - .AddUInt8Array(str) - .Done() - .Then(args => - { - var content = args[0] as byte[]; + SendRequest(IIPPacket.IIPPacketAction.ResourceHistory) + .AddUInt32(dr.Id) + .AddDateTime(fromDate) + .AddDateTime(toDate) + .Done() + .Then(rt => + { + var content = (byte[])rt[0]; - Codec.ParseResourceArray(content, 0, (uint)content.Length, this) - .Then(resources => reply.Trigger(resources)); + Codec.ParseHistory(content, 0, (uint)content.Length, resource, this) + .Then((history) => reply.Trigger(history)); - }).Error(ex => reply.TriggerError(ex)); + }).Error((ex) => reply.TriggerError(ex)); return reply; } + else + return new AsyncReply>(null); + } + /// + /// Query resources at specific link. + /// + /// Link path. + /// + public AsyncReply Query(string path) + { + var str = DC.ToBytes(path); + var reply = new AsyncReply(); - /// - /// Create a new resource. - /// - /// The store in which the resource is saved. - /// Class full name. - /// Constructor parameters. - /// Resource attributeds. - /// Values for the resource properties. - /// New resource instance - public AsyncReply Create(IStore store, IResource parent, string className, object[] parameters, Structure attributes, Structure values) - { - var reply = new AsyncReply(); - var pkt = new BinaryList() - .AddUInt32(store.Instance.Id) - .AddUInt32(parent.Instance.Id) - .AddUInt8((byte)className.Length) - .AddString(className) - .AddUInt8Array(Codec.ComposeVarArray(parameters, this, true)) - .AddUInt8Array(Codec.ComposeStructure(attributes, this, true, true, true)) - .AddUInt8Array(Codec.ComposeStructure(values, this)); - - pkt.InsertInt32(8, pkt.Length); - - SendRequest(IIPPacket.IIPPacketAction.CreateResource) - .AddUInt8Array(pkt.ToArray()) - .Done() - .Then(args => - { - var rid = (uint)args[0]; - - Fetch(rid).Then((r) => + SendRequest(IIPPacket.IIPPacketAction.QueryLink) + .AddUInt16((ushort)str.Length) + .AddUInt8Array(str) + .Done() + .Then(args => { - reply.Trigger(r); - }); + var content = args[0] as byte[]; + Codec.ParseResourceArray(content, 0, (uint)content.Length, this) + .Then(resources => reply.Trigger(resources)); + + }).Error(ex => reply.TriggerError(ex)); + + return reply; + } + + + /// + /// Create a new resource. + /// + /// The store in which the resource is saved. + /// Class full name. + /// Constructor parameters. + /// Resource attributeds. + /// Values for the resource properties. + /// New resource instance + public AsyncReply Create(IStore store, IResource parent, string className, object[] parameters, Structure attributes, Structure values) + { + var reply = new AsyncReply(); + var pkt = new BinaryList() + .AddUInt32(store.Instance.Id) + .AddUInt32(parent.Instance.Id) + .AddUInt8((byte)className.Length) + .AddString(className) + .AddUInt8Array(Codec.ComposeVarArray(parameters, this, true)) + .AddUInt8Array(Codec.ComposeStructure(attributes, this, true, true, true)) + .AddUInt8Array(Codec.ComposeStructure(values, this)); + + pkt.InsertInt32(8, pkt.Length); + + SendRequest(IIPPacket.IIPPacketAction.CreateResource) + .AddUInt8Array(pkt.ToArray()) + .Done() + .Then(args => + { + var rid = (uint)args[0]; + + Fetch(rid).Then((r) => + { + reply.Trigger(r); }); - return reply; + }); + + return reply; + } + + private void Subscribe(IResource resource) + { + lock (subscriptionsLock) + { + resource.Instance.ResourceEventOccurred += Instance_EventOccurred; + resource.Instance.CustomResourceEventOccurred += Instance_CustomEventOccurred; + resource.Instance.ResourceModified += Instance_PropertyModified; + resource.Instance.ResourceDestroyed += Instance_ResourceDestroyed; + + subscriptions.Add(resource, new List()); + } + } + + private void Unsubscribe(IResource resource) + { + lock (subscriptionsLock) + { + // do something with the list... + resource.Instance.ResourceEventOccurred -= Instance_EventOccurred; + resource.Instance.CustomResourceEventOccurred -= Instance_CustomEventOccurred; + resource.Instance.ResourceModified -= Instance_PropertyModified; + resource.Instance.ResourceDestroyed -= Instance_ResourceDestroyed; + + subscriptions.Remove(resource); } - private void Subscribe(IResource resource) - { - lock (subscriptionsLock) - { - resource.Instance.ResourceEventOccurred += Instance_EventOccurred; - resource.Instance.CustomResourceEventOccurred += Instance_CustomEventOccurred; - resource.Instance.ResourceModified += Instance_PropertyModified; - resource.Instance.ResourceDestroyed += Instance_ResourceDestroyed; + } - subscriptions.Add(resource, new List()); - } - } - - private void Unsubscribe(IResource resource) + private void UnsubscribeAll() + { + lock (subscriptionsLock) { - lock (subscriptionsLock) + foreach (var resource in subscriptions.Keys) { - // do something with the list... resource.Instance.ResourceEventOccurred -= Instance_EventOccurred; resource.Instance.CustomResourceEventOccurred -= Instance_CustomEventOccurred; resource.Instance.ResourceModified -= Instance_PropertyModified; resource.Instance.ResourceDestroyed -= Instance_ResourceDestroyed; - - subscriptions.Remove(resource); } + subscriptions.Clear(); } + } - private void UnsubscribeAll() + private void Instance_ResourceDestroyed(IResource resource) + { + + Unsubscribe(resource); + // compose the packet + SendEvent(IIPPacket.IIPPacketEvent.ResourceDestroyed) + .AddUInt32(resource.Instance.Id) + .Done(); + + + } + + private void Instance_PropertyModified(IResource resource, string name, object newValue) + { + var pt = resource.Instance.Template.GetPropertyTemplateByName(name); + + if (pt == null) + return; + + SendEvent(IIPPacket.IIPPacketEvent.PropertyUpdated) + .AddUInt32(resource.Instance.Id) + .AddUInt8(pt.Index) + .AddUInt8Array(Codec.Compose(newValue, this)) + .Done(); + + } + + // private void Instance_EventOccurred(IResource resource, string name, string[] users, DistributedConnection[] connections, object[] args) + + private void Instance_CustomEventOccurred(IResource resource, object issuer, Func receivers, string name, object args) + { + var et = resource.Instance.Template.GetEventTemplateByName(name); + + if (et == null) + return; + + if (et.Listenable) { lock (subscriptionsLock) { - foreach (var resource in subscriptions.Keys) - { - resource.Instance.ResourceEventOccurred -= Instance_EventOccurred; - resource.Instance.CustomResourceEventOccurred -= Instance_CustomEventOccurred; - resource.Instance.ResourceModified -= Instance_PropertyModified; - resource.Instance.ResourceDestroyed -= Instance_ResourceDestroyed; - } + // check the client requested listen + if (!subscriptions.ContainsKey(resource)) + return; - subscriptions.Clear(); + if (!subscriptions[resource].Contains(et.Index)) + return; } } - private void Instance_ResourceDestroyed(IResource resource) + if (!receivers(this.session)) + return; + + if (resource.Instance.Applicable(this.session, ActionType.ReceiveEvent, et, issuer) == Ruling.Denied) + return; + + + // compose the packet + SendEvent(IIPPacket.IIPPacketEvent.EventOccurred) + .AddUInt32(resource.Instance.Id) + .AddUInt8((byte)et.Index) + .AddUInt8Array(Codec.Compose(args, this, true)) + .Done(); + } + + private void Instance_EventOccurred(IResource resource, string name, object args) + { + var et = resource.Instance.Template.GetEventTemplateByName(name); + + if (et == null) + return; + + if (et.Listenable) { - - Unsubscribe(resource); - // compose the packet - SendEvent(IIPPacket.IIPPacketEvent.ResourceDestroyed) - .AddUInt32(resource.Instance.Id) - .Done(); - - - } - - private void Instance_PropertyModified(IResource resource, string name, object newValue) - { - var pt = resource.Instance.Template.GetPropertyTemplateByName(name); - - if (pt == null) - return; - - SendEvent(IIPPacket.IIPPacketEvent.PropertyUpdated) - .AddUInt32(resource.Instance.Id) - .AddUInt8(pt.Index) - .AddUInt8Array(Codec.Compose(newValue, this)) - .Done(); - - } - - // private void Instance_EventOccurred(IResource resource, string name, string[] users, DistributedConnection[] connections, object[] args) - - private void Instance_CustomEventOccurred(IResource resource, object issuer, Func receivers, string name, object args) - { - var et = resource.Instance.Template.GetEventTemplateByName(name); - - if (et == null) - return; - - if (et.Listenable) + lock (subscriptionsLock) { - lock (subscriptionsLock) - { - // check the client requested listen - if (!subscriptions.ContainsKey(resource)) - return; + // check the client requested listen + if (!subscriptions.ContainsKey(resource)) + return; - if (!subscriptions[resource].Contains(et.Index)) - return; - } + if (!subscriptions[resource].Contains(et.Index)) + return; } - - if (!receivers(this.session)) - return; - - if (resource.Instance.Applicable(this.session, ActionType.ReceiveEvent, et, issuer) == Ruling.Denied) - return; - - - // compose the packet - SendEvent(IIPPacket.IIPPacketEvent.EventOccurred) - .AddUInt32(resource.Instance.Id) - .AddUInt8((byte)et.Index) - .AddUInt8Array(Codec.Compose(args, this, true)) - .Done(); } - private void Instance_EventOccurred(IResource resource, string name, object args) - { - var et = resource.Instance.Template.GetEventTemplateByName(name); + if (resource.Instance.Applicable(this.session, ActionType.ReceiveEvent, et, null) == Ruling.Denied) + return; - if (et == null) - return; - - if (et.Listenable) - { - lock (subscriptionsLock) - { - // check the client requested listen - if (!subscriptions.ContainsKey(resource)) - return; - - if (!subscriptions[resource].Contains(et.Index)) - return; - } - } - - if (resource.Instance.Applicable(this.session, ActionType.ReceiveEvent, et, null) == Ruling.Denied) - return; - - // compose the packet - SendEvent(IIPPacket.IIPPacketEvent.EventOccurred) - .AddUInt32(resource.Instance.Id) - .AddUInt8((byte)et.Index) - .AddUInt8Array(Codec.Compose(args, this, true)) - .Done(); - } + // compose the packet + SendEvent(IIPPacket.IIPPacketEvent.EventOccurred) + .AddUInt32(resource.Instance.Id) + .AddUInt8((byte)et.Index) + .AddUInt8Array(Codec.Compose(args, this, true)) + .Done(); } } diff --git a/Esiur/Net/IIP/DistributedPropertyContext.cs b/Esiur/Net/IIP/DistributedPropertyContext.cs index d30a034..f1e390c 100644 --- a/Esiur/Net/IIP/DistributedPropertyContext.cs +++ b/Esiur/Net/IIP/DistributedPropertyContext.cs @@ -2,26 +2,24 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Net.IIP +namespace Esiur.Net.IIP; +public class DistributedPropertyContext { - public class DistributedPropertyContext + public object Value { get; private set; } + public DistributedConnection Connection { get; private set; } + public Func Method { get; private set; } + + public DistributedPropertyContext(DistributedConnection connection, object value) { - public object Value { get; private set; } - public DistributedConnection Connection { get; private set; } - public Func Method { get; private set; } - - public DistributedPropertyContext(DistributedConnection connection, object value) - { - this.Value = value; - this.Connection = connection; - } - - public DistributedPropertyContext(Func method) - { - this.Method = method; - } - - public static implicit operator DistributedPropertyContext(Func method) - => new DistributedPropertyContext(method); + this.Value = value; + this.Connection = connection; } + + public DistributedPropertyContext(Func method) + { + this.Method = method; + } + + public static implicit operator DistributedPropertyContext(Func method) + => new DistributedPropertyContext(method); } diff --git a/Esiur/Net/IIP/DistributedResource.cs b/Esiur/Net/IIP/DistributedResource.cs index c13301a..522f8ca 100644 --- a/Esiur/Net/IIP/DistributedResource.cs +++ b/Esiur/Net/IIP/DistributedResource.cs @@ -42,465 +42,463 @@ using System.Threading.Tasks; using Esiur.Resource; using Esiur.Resource.Template; -namespace Esiur.Net.IIP +namespace Esiur.Net.IIP; + +//[System.Runtime.InteropServices.ComVisible(true)] +public class DistributedResource : DynamicObject, IResource { - //[System.Runtime.InteropServices.ComVisible(true)] - public class DistributedResource : DynamicObject, IResource + /// + /// Raised when the distributed resource is destroyed. + /// + public event DestroyedEvent OnDestroy; + public event Instance.ResourceModifiedEvent OnModified; + uint instanceId; + DistributedConnection connection; + + + bool attached = false; + bool destroyed = false; + bool suspended = false; + + //Structure properties = new Structure(); + + string link; + //ulong age; + //ulong[] ages; + protected object[] properties; + internal List parents = new List(); + internal List children = new List(); + + DistributedResourceEvent[] events; + + + + /// + /// Resource template for the remotely located resource. + /// + //public ResourceTemplate Template + //{ + // get { return template; } + //} + + + /// + /// Connection responsible for the distributed resource. + /// + public DistributedConnection Connection + { + get { return connection; } + } + + /// + /// Resource link + /// + public string Link + { + get { return link; } + } + + /// + /// Instance Id given by the other end. + /// + public uint Id + { + get { return instanceId; } + } + + /// + /// IDestructible interface. + /// + public void Destroy() + { + destroyed = true; + attached = false; + connection.SendDetachRequest(instanceId); + OnDestroy?.Invoke(this); + } + + /// + /// Suspend resource + /// + + internal void Suspend() + { + suspended = true; + attached = false; + } + + + /// + /// Resource is attached when all its properties are received. + /// + internal bool Attached => attached; + + internal bool Suspended => suspended; + + + // public DistributedResourceStack Stack + //{ + // get { return stack; } + //} + + /// + /// Create a new distributed resource. + /// + /// Connection responsible for the distributed resource. + /// Resource template. + /// Instance Id given by the other end. + /// Resource age. + public DistributedResource(DistributedConnection connection, uint instanceId, ulong age, string link) + { + this.link = link; + this.connection = connection; + this.instanceId = instanceId; + + //this.Instance.Template = template; + //this.Instance.Age = age; + //this.template = template; + //this.age = age; + + } + + /// + /// Export all properties with ResourceProperty attributed as bytes array. + /// + /// + internal PropertyValue[] _Serialize() { - /// - /// Raised when the distributed resource is destroyed. - /// - public event DestroyedEvent OnDestroy; - public event Instance.ResourceModifiedEvent OnModified; - uint instanceId; - DistributedConnection connection; + var props = new PropertyValue[properties.Length]; - bool attached = false; - bool destroyed = false; - bool suspended = false; + for (byte i = 0; i < properties.Length; i++) + props[i] = new PropertyValue(properties[i], Instance.GetAge(i), Instance.GetModificationDate(i)); - //Structure properties = new Structure(); + return props; + } - string link; - //ulong age; - //ulong[] ages; - protected object[] properties; - internal List parents = new List(); - internal List children = new List(); - - DistributedResourceEvent[] events; - - - - /// - /// Resource template for the remotely located resource. - /// - //public ResourceTemplate Template - //{ - // get { return template; } - //} - - - /// - /// Connection responsible for the distributed resource. - /// - public DistributedConnection Connection + internal bool _Attach(PropertyValue[] properties) + { + if (attached) + return false; + else { - get { return connection; } - } + suspended = false; - /// - /// Resource link - /// - public string Link - { - get { return link; } - } - - /// - /// Instance Id given by the other end. - /// - public uint Id - { - get { return instanceId; } - } - - /// - /// IDestructible interface. - /// - public void Destroy() - { - destroyed = true; - attached = false; - connection.SendDetachRequest(instanceId); - OnDestroy?.Invoke(this); - } - - /// - /// Suspend resource - /// - - internal void Suspend() - { - suspended = true; - attached = false; - } - - - /// - /// Resource is attached when all its properties are received. - /// - internal bool Attached => attached; - - internal bool Suspended => suspended; - - - // public DistributedResourceStack Stack - //{ - // get { return stack; } - //} - - /// - /// Create a new distributed resource. - /// - /// Connection responsible for the distributed resource. - /// Resource template. - /// Instance Id given by the other end. - /// Resource age. - public DistributedResource(DistributedConnection connection, uint instanceId, ulong age, string link) - { - this.link = link; - this.connection = connection; - this.instanceId = instanceId; - - //this.Instance.Template = template; - //this.Instance.Age = age; - //this.template = template; - //this.age = age; - - } - - /// - /// Export all properties with ResourceProperty attributed as bytes array. - /// - /// - internal PropertyValue[] _Serialize() - { - - var props = new PropertyValue[properties.Length]; + this.properties = new object[properties.Length]; + this.events = new DistributedResourceEvent[Instance.Template.Events.Length]; for (byte i = 0; i < properties.Length; i++) - props[i] = new PropertyValue(properties[i], Instance.GetAge(i), Instance.GetModificationDate(i)); - - return props; - } - - internal bool _Attach(PropertyValue[] properties) - { - if (attached) - return false; - else { - suspended = false; - - this.properties = new object[properties.Length]; - - this.events = new DistributedResourceEvent[Instance.Template.Events.Length]; - - for (byte i = 0; i < properties.Length; i++) - { - Instance.SetAge(i, properties[i].Age); - Instance.SetModificationDate(i, properties[i].Date); - this.properties[i] = properties[i].Value; - } - - // trigger holded events/property updates. - //foreach (var r in afterAttachmentTriggers) - // r.Key.Trigger(r.Value); - - //afterAttachmentTriggers.Clear(); - - attached = true; - + Instance.SetAge(i, properties[i].Age); + Instance.SetModificationDate(i, properties[i].Date); + this.properties[i] = properties[i].Value; } - return true; + + // trigger holded events/property updates. + //foreach (var r in afterAttachmentTriggers) + // r.Key.Trigger(r.Value); + + //afterAttachmentTriggers.Clear(); + + attached = true; + } + return true; + } - protected internal virtual void _EmitEventByIndex(byte index, object args) + protected internal virtual void _EmitEventByIndex(byte index, object args) + { + var et = Instance.Template.GetEventTemplateByIndex(index); + events[index]?.Invoke(this, args); + Instance.EmitResourceEvent(et.Name, args); + } + + + + public AsyncReply _InvokeByNamedArguments(byte index, Structure namedArgs) + { + if (destroyed) + throw new Exception("Trying to access destroyed object"); + + if (suspended) + throw new Exception("Trying to access suspended object"); + + if (index >= Instance.Template.Functions.Length) + throw new Exception("Function index is incorrect"); + + + return connection.SendInvokeByNamedArguments(instanceId, index, namedArgs); + } + + + public AsyncReply _InvokeByArrayArguments(byte index, object[] args) + { + if (destroyed) + throw new Exception("Trying to access destroyed object"); + + if (suspended) + throw new Exception("Trying to access suspended object"); + + if (index >= Instance.Template.Functions.Length) + throw new Exception("Function index is incorrect"); + + + return connection.SendInvokeByArrayArguments(instanceId, index, args); + } + + + public AsyncReply Listen(EventTemplate et) + { + if (et == null) + return new AsyncReply().TriggerError(new AsyncException(ErrorType.Management, (ushort)ExceptionCode.MethodNotFound, "")); + + if (!et.Listenable) + return new AsyncReply().TriggerError(new AsyncException(ErrorType.Management, (ushort)ExceptionCode.NotListenable, "")); + + return connection.SendListenRequest(instanceId, et.Index); + } + + public AsyncReply Listen(string eventName) + { + var et = Instance.Template.GetEventTemplateByName(eventName); + + return Listen(et); + } + + + public AsyncReply Unlisten(EventTemplate et) + { + if (et == null) + return new AsyncReply().TriggerError(new AsyncException(ErrorType.Management, (ushort)ExceptionCode.MethodNotFound, "")); + + if (!et.Listenable) + return new AsyncReply().TriggerError(new AsyncException(ErrorType.Management, (ushort)ExceptionCode.NotListenable, "")); + + return connection.SendUnlistenRequest(instanceId, et.Index); + } + + public AsyncReply Unlisten(string eventName) + { + var et = Instance.Template.GetEventTemplateByName(eventName); + + return Unlisten(et); + } + + + public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) + { + var ft = Instance.Template.GetFunctionTemplateByName(binder.Name); + + var reply = new AsyncReply(); + + if (attached && ft != null) { - var et = Instance.Template.GetEventTemplateByIndex(index); - events[index]?.Invoke(this, args); - Instance.EmitResourceEvent(et.Name, args); - } - - - - public AsyncReply _InvokeByNamedArguments(byte index, Structure namedArgs) - { - if (destroyed) - throw new Exception("Trying to access destroyed object"); - - if (suspended) - throw new Exception("Trying to access suspended object"); - - if (index >= Instance.Template.Functions.Length) - throw new Exception("Function index is incorrect"); - - - return connection.SendInvokeByNamedArguments(instanceId, index, namedArgs); - } - - - public AsyncReply _InvokeByArrayArguments(byte index, object[] args) - { - if (destroyed) - throw new Exception("Trying to access destroyed object"); - - if (suspended) - throw new Exception("Trying to access suspended object"); - - if (index >= Instance.Template.Functions.Length) - throw new Exception("Function index is incorrect"); - - - return connection.SendInvokeByArrayArguments(instanceId, index, args); - } - - - public AsyncReply Listen(EventTemplate et) - { - if (et == null) - return new AsyncReply().TriggerError(new AsyncException(ErrorType.Management, (ushort)ExceptionCode.MethodNotFound, "")); - - if (!et.Listenable) - return new AsyncReply().TriggerError(new AsyncException(ErrorType.Management, (ushort)ExceptionCode.NotListenable, "")); - - return connection.SendListenRequest(instanceId, et.Index); - } - - public AsyncReply Listen(string eventName) - { - var et = Instance.Template.GetEventTemplateByName(eventName); - - return Listen(et); - } - - - public AsyncReply Unlisten(EventTemplate et) - { - if (et == null) - return new AsyncReply().TriggerError(new AsyncException(ErrorType.Management, (ushort)ExceptionCode.MethodNotFound, "")); - - if (!et.Listenable) - return new AsyncReply().TriggerError(new AsyncException(ErrorType.Management, (ushort)ExceptionCode.NotListenable, "")); - - return connection.SendUnlistenRequest(instanceId, et.Index); - } - - public AsyncReply Unlisten(string eventName) - { - var et = Instance.Template.GetEventTemplateByName(eventName); - - return Unlisten(et); - } - - - public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) - { - var ft = Instance.Template.GetFunctionTemplateByName(binder.Name); - - var reply = new AsyncReply(); - - if (attached && ft != null) + if (args.Length == 1) { - if (args.Length == 1) + // Detect anonymous types + var type = args[0].GetType(); + if (Codec.IsAnonymous(type)) { - // Detect anonymous types - var type = args[0].GetType(); - if (Codec.IsAnonymous(type)) - { - var namedArgs = new Structure(); - - var pi = type.GetTypeInfo().GetProperties(); - foreach (var p in pi) - namedArgs[p.Name] = p.GetValue(args[0]); - result = _InvokeByNamedArguments(ft.Index, namedArgs); - } - else - { - result = _InvokeByArrayArguments(ft.Index, args); - } + var namedArgs = new Structure(); + var pi = type.GetTypeInfo().GetProperties(); + foreach (var p in pi) + namedArgs[p.Name] = p.GetValue(args[0]); + result = _InvokeByNamedArguments(ft.Index, namedArgs); } else { result = _InvokeByArrayArguments(ft.Index, args); } - return true; + } else { - result = null; - return false; + result = _InvokeByArrayArguments(ft.Index, args); } + return true; } - - /// - /// Get a property value. - /// - /// Zero-based property index. - /// Value - protected internal object _Get(byte index) + else { - if (index >= properties.Length) - return null; - return properties[index]; - } - - public override bool TryGetMember(GetMemberBinder binder, out object result) - { - if (destroyed) - throw new Exception("Trying to access destroyed object"); - - result = null; + return false; + } + } - if (!attached) + /// + /// Get a property value. + /// + /// Zero-based property index. + /// Value + protected internal object _Get(byte index) + { + if (index >= properties.Length) + return null; + return properties[index]; + } + + public override bool TryGetMember(GetMemberBinder binder, out object result) + { + if (destroyed) + throw new Exception("Trying to access destroyed object"); + + + result = null; + + if (!attached) + return false; + + var pt = Instance.Template.GetPropertyTemplateByName(binder.Name); + + if (pt != null) + { + result = properties[pt.Index]; + return true; + } + else + { + var et = Instance.Template.GetEventTemplateByName(binder.Name); + if (et == null) return false; - var pt = Instance.Template.GetPropertyTemplateByName(binder.Name); + result = events[et.Index]; - if (pt != null) - { - result = properties[pt.Index]; - return true; - } - else - { - var et = Instance.Template.GetEventTemplateByName(binder.Name); - if (et == null) - return false; - - result = events[et.Index]; - - return true; - } + return true; } + } - internal void _UpdatePropertyByIndex(byte index, object value) - { - var pt = Instance.Template.GetPropertyTemplateByIndex(index); - properties[index] = value; - Instance.EmitModification(pt, value); - } + internal void _UpdatePropertyByIndex(byte index, object value) + { + var pt = Instance.Template.GetPropertyTemplateByIndex(index); + properties[index] = value; + Instance.EmitModification(pt, value); + } - /// - /// Set property value. - /// - /// Zero-based property index. - /// Value - /// Indicator when the property is set. - protected internal AsyncReply _Set(byte index, object value) - { - if (index >= properties.Length) - return null; + /// + /// Set property value. + /// + /// Zero-based property index. + /// Value + /// Indicator when the property is set. + protected internal AsyncReply _Set(byte index, object value) + { + if (index >= properties.Length) + return null; - var reply = new AsyncReply(); + var reply = new AsyncReply(); - var parameters = Codec.Compose(value, connection); - connection.SendRequest(Packets.IIPPacket.IIPPacketAction.SetProperty) - .AddUInt32(instanceId) - .AddUInt8(index) - .AddUInt8Array(parameters) - .Done() - .Then((res) => - { + var parameters = Codec.Compose(value, connection); + connection.SendRequest(Packets.IIPPacket.IIPPacketAction.SetProperty) + .AddUInt32(instanceId) + .AddUInt8(index) + .AddUInt8Array(parameters) + .Done() + .Then((res) => + { // not really needed, server will always send property modified, // this only happens if the programmer forgot to emit in property setter properties[index] = value; - reply.Trigger(null); - }); + reply.Trigger(null); + }); - return reply; - } + return reply; + } - public override bool TrySetMember(SetMemberBinder binder, object value) + public override bool TrySetMember(SetMemberBinder binder, object value) + { + if (destroyed) + throw new Exception("Trying to access destroyed object"); + + if (suspended) + throw new Exception("Trying to access suspended object"); + + if (!attached) + return false; + + var pt = Instance.Template.GetPropertyTemplateByName(binder.Name); + + if (pt != null) { - if (destroyed) - throw new Exception("Trying to access destroyed object"); - - if (suspended) - throw new Exception("Trying to access suspended object"); - - if (!attached) + _Set(pt.Index, value); + return true; + } + else + { + var et = Instance.Template.GetEventTemplateByName(binder.Name); + if (et == null) return false; - var pt = Instance.Template.GetPropertyTemplateByName(binder.Name); - - if (pt != null) - { - _Set(pt.Index, value); - return true; - } - else - { - var et = Instance.Template.GetEventTemplateByName(binder.Name); - if (et == null) - return false; - - events[et.Index] = (DistributedResourceEvent)value; - - return true; - } + events[et.Index] = (DistributedResourceEvent)value; + return true; } - /* - public async void InvokeMethod(byte index, object[] arguments, DistributedConnection sender) - { - // get function parameters - Type t = this.GetType(); + } - MethodInfo mi = t.GetMethod(GetFunctionName(index), BindingFlags.DeclaredOnly | - BindingFlags.Public | - BindingFlags.Instance | BindingFlags.InvokeMethod); - if (mi != null) + /* + public async void InvokeMethod(byte index, object[] arguments, DistributedConnection sender) + { + // get function parameters + Type t = this.GetType(); + + MethodInfo mi = t.GetMethod(GetFunctionName(index), BindingFlags.DeclaredOnly | + BindingFlags.Public | + BindingFlags.Instance | BindingFlags.InvokeMethod); + if (mi != null) + { + try { - try - { - var res = await invokeMethod(mi, arguments, sender); - object rt = Codec.Compose(res); - sender.SendParams((byte)0x80, instanceId, index, rt); - } - catch(Exception ex) - { - var msg = ex.InnerException != null ? ex.InnerException.Message : ex.Message; - sender.SendParams((byte)0x8E, instanceId, index, Codec.Compose(msg)); - } + var res = await invokeMethod(mi, arguments, sender); + object rt = Codec.Compose(res); + sender.SendParams((byte)0x80, instanceId, index, rt); + } + catch(Exception ex) + { + var msg = ex.InnerException != null ? ex.InnerException.Message : ex.Message; + sender.SendParams((byte)0x8E, instanceId, index, Codec.Compose(msg)); } } - */ + } + */ - /// - /// Resource interface. - /// - public Instance Instance - { - get; - set; - } + /// + /// Resource interface. + /// + public Instance Instance + { + get; + set; + } - /// - /// Create a new instance of distributed resource. - /// - public DistributedResource() - { - //stack = new DistributedResourceStack(this); - //this.Instance.ResourceModified += this.OnModified; + /// + /// Create a new instance of distributed resource. + /// + public DistributedResource() + { + //stack = new DistributedResourceStack(this); + //this.Instance.ResourceModified += this.OnModified; - } + } - /// - /// Resource interface. - /// - /// - /// - public AsyncReply Trigger(ResourceTrigger trigger) - { + /// + /// Resource interface. + /// + /// + /// + public AsyncReply Trigger(ResourceTrigger trigger) + { - if (trigger == ResourceTrigger.Initialize) - this.Instance.ResourceModified += this.OnModified; + if (trigger == ResourceTrigger.Initialize) + this.Instance.ResourceModified += this.OnModified; - // do nothing. - return new AsyncReply(true); - } + // do nothing. + return new AsyncReply(true); } } \ No newline at end of file diff --git a/Esiur/Net/IIP/DistributedResourceEvent.cs b/Esiur/Net/IIP/DistributedResourceEvent.cs index c419b47..fc16eb0 100644 --- a/Esiur/Net/IIP/DistributedResourceEvent.cs +++ b/Esiur/Net/IIP/DistributedResourceEvent.cs @@ -28,7 +28,6 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Net.IIP -{ - public delegate void DistributedResourceEvent(DistributedResource sender, object argument); -} +namespace Esiur.Net.IIP; + +public delegate void DistributedResourceEvent(DistributedResource sender, object argument); diff --git a/Esiur/Net/IIP/DistributedResourceQueueItem.cs b/Esiur/Net/IIP/DistributedResourceQueueItem.cs index 6f4ef36..1e3250d 100644 --- a/Esiur/Net/IIP/DistributedResourceQueueItem.cs +++ b/Esiur/Net/IIP/DistributedResourceQueueItem.cs @@ -28,46 +28,44 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Net.IIP +namespace Esiur.Net.IIP; +public class DistributedResourceQueueItem { - public class DistributedResourceQueueItem + public enum DistributedResourceQueueItemType { - public enum DistributedResourceQueueItemType - { - Propery, - Event - } + Propery, + Event + } - DistributedResourceQueueItemType type; - byte index; - object value; - DistributedResource resource; + DistributedResourceQueueItemType type; + byte index; + object value; + DistributedResource resource; - public DistributedResourceQueueItem(DistributedResource resource, DistributedResourceQueueItemType type, object value, byte index) - { - this.resource = resource; - this.index = index; - this.type = type; - this.value = value; - } + public DistributedResourceQueueItem(DistributedResource resource, DistributedResourceQueueItemType type, object value, byte index) + { + this.resource = resource; + this.index = index; + this.type = type; + this.value = value; + } - public DistributedResource Resource - { - get { return resource; } - } - public DistributedResourceQueueItemType Type - { - get { return type; } - } + public DistributedResource Resource + { + get { return resource; } + } + public DistributedResourceQueueItemType Type + { + get { return type; } + } - public byte Index - { - get { return index; } - } + public byte Index + { + get { return index; } + } - public object Value - { - get { return value; } - } + public object Value + { + get { return value; } } } diff --git a/Esiur/Net/IIP/DistributedServer.cs b/Esiur/Net/IIP/DistributedServer.cs index 6f4ef15..35d2cdd 100644 --- a/Esiur/Net/IIP/DistributedServer.cs +++ b/Esiur/Net/IIP/DistributedServer.cs @@ -35,143 +35,141 @@ using System.Net; using Esiur.Resource; using Esiur.Security.Membership; -namespace Esiur.Net.IIP +namespace Esiur.Net.IIP; +public class DistributedServer : NetworkServer, IResource { - public class DistributedServer : NetworkServer, IResource + [Attribute] + public string IP { - [Attribute] - public string IP - { - get; - set; - } - - [Attribute] - public IMembership Membership - { - get; - set; - } - - [Attribute] - public EntryPoint EntryPoint - { - get; - set; - } - - [Attribute] - public ushort Port - { - get; - set; - } = 10518; - - - [Attribute] - public ExceptionLevel ExceptionLevel { get; set; } - = ExceptionLevel.Code - | ExceptionLevel.Source - | ExceptionLevel.Message - | ExceptionLevel.Trace; - - - public Instance Instance - { - get; - set; - } - - public AsyncReply Trigger(ResourceTrigger trigger) - { - if (trigger == ResourceTrigger.Initialize) - { - TCPSocket listener; - - if (IP != null) - listener = new TCPSocket(new IPEndPoint(IPAddress.Parse(IP), Port)); - else - listener = new TCPSocket(new IPEndPoint(IPAddress.Any, Port)); - - Start(listener); - } - else if (trigger == ResourceTrigger.Terminate) - { - Stop(); - } - else if (trigger == ResourceTrigger.SystemReload) - { - Trigger(ResourceTrigger.Terminate); - Trigger(ResourceTrigger.Initialize); - } - - return new AsyncReply(true); - } - - - - //protected override void DataReceived(DistributedConnection sender, NetworkBuffer data) - //{ - // //throw new NotImplementedException(); - - //} - - - - //protected override void ClientConnected(DistributedConnection sender) - //{ - // //Console.WriteLine("DistributedConnection Client Connected"); - //} - - //private void ConnectionReadyEventReceiver(DistributedConnection sender) - //{ - // sender.OnReady -= ConnectionReadyEventReceiver; - // Warehouse.Put(sender, sender.LocalUsername, null, this); - //} - - - //public override void RemoveConnection(DistributedConnection connection) - //{ - // connection.OnReady -= Sender_OnReady; - // //connection.Server = null; - // base.RemoveConnection(connection); - //} - - //public override void AddConnection(DistributedConnection connection) - //{ - // connection.OnReady += Sender_OnReady; - // connection.Server = this; - // base.AddConnection(connection); - //} - - - - protected override void ClientConnected(DistributedConnection connection) - { - //connection.OnReady += ConnectionReadyEventReceiver; - } - - public override void Add(DistributedConnection connection) - { - connection.Server = this; - connection.ExceptionLevel = ExceptionLevel; - base.Add(connection); - } - - public override void Remove(DistributedConnection connection) - { - connection.Server = null; - base.Remove(connection); - } - - protected override void ClientDisconnected(DistributedConnection connection) - { - //connection.OnReady -= ConnectionReadyEventReceiver; - //Warehouse.Remove(connection); - - - } - - + get; + set; } + + [Attribute] + public IMembership Membership + { + get; + set; + } + + [Attribute] + public EntryPoint EntryPoint + { + get; + set; + } + + [Attribute] + public ushort Port + { + get; + set; + } = 10518; + + + [Attribute] + public ExceptionLevel ExceptionLevel { get; set; } + = ExceptionLevel.Code + | ExceptionLevel.Source + | ExceptionLevel.Message + | ExceptionLevel.Trace; + + + public Instance Instance + { + get; + set; + } + + public AsyncReply Trigger(ResourceTrigger trigger) + { + if (trigger == ResourceTrigger.Initialize) + { + TCPSocket listener; + + if (IP != null) + listener = new TCPSocket(new IPEndPoint(IPAddress.Parse(IP), Port)); + else + listener = new TCPSocket(new IPEndPoint(IPAddress.Any, Port)); + + Start(listener); + } + else if (trigger == ResourceTrigger.Terminate) + { + Stop(); + } + else if (trigger == ResourceTrigger.SystemReload) + { + Trigger(ResourceTrigger.Terminate); + Trigger(ResourceTrigger.Initialize); + } + + return new AsyncReply(true); + } + + + + //protected override void DataReceived(DistributedConnection sender, NetworkBuffer data) + //{ + // //throw new NotImplementedException(); + + //} + + + + //protected override void ClientConnected(DistributedConnection sender) + //{ + // //Console.WriteLine("DistributedConnection Client Connected"); + //} + + //private void ConnectionReadyEventReceiver(DistributedConnection sender) + //{ + // sender.OnReady -= ConnectionReadyEventReceiver; + // Warehouse.Put(sender, sender.LocalUsername, null, this); + //} + + + //public override void RemoveConnection(DistributedConnection connection) + //{ + // connection.OnReady -= Sender_OnReady; + // //connection.Server = null; + // base.RemoveConnection(connection); + //} + + //public override void AddConnection(DistributedConnection connection) + //{ + // connection.OnReady += Sender_OnReady; + // connection.Server = this; + // base.AddConnection(connection); + //} + + + + protected override void ClientConnected(DistributedConnection connection) + { + //connection.OnReady += ConnectionReadyEventReceiver; + } + + public override void Add(DistributedConnection connection) + { + connection.Server = this; + connection.ExceptionLevel = ExceptionLevel; + base.Add(connection); + } + + public override void Remove(DistributedConnection connection) + { + connection.Server = null; + base.Remove(connection); + } + + protected override void ClientDisconnected(DistributedConnection connection) + { + //connection.OnReady -= ConnectionReadyEventReceiver; + //Warehouse.Remove(connection); + + + } + + } diff --git a/Esiur/Net/IIP/DistributedSession.cs b/Esiur/Net/IIP/DistributedSession.cs index c84c66f..360e9ed 100644 --- a/Esiur/Net/IIP/DistributedSession.cs +++ b/Esiur/Net/IIP/DistributedSession.cs @@ -28,11 +28,9 @@ using System.Text; using Esiur.Net.Sockets; using Esiur.Security.Authority; -namespace Esiur.Net.IIP +namespace Esiur.Net.IIP; +public class DistributedSession : NetworkSession { - public class DistributedSession : NetworkSession - { - public Source Source { get; set; } - public Authentication Authentication { get; set; } - } + public Source Source { get; set; } + public Authentication Authentication { get; set; } } diff --git a/Esiur/Net/IIP/EntryPoint.cs b/Esiur/Net/IIP/EntryPoint.cs index 5259189..6644a53 100644 --- a/Esiur/Net/IIP/EntryPoint.cs +++ b/Esiur/Net/IIP/EntryPoint.cs @@ -29,12 +29,11 @@ using Esiur.Data; using Esiur.Resource; using Esiur.Resource.Template; -namespace Esiur.Net.IIP -{ - public abstract class EntryPoint : Esiur.Resource.Resource - { +namespace Esiur.Net.IIP; - public abstract AsyncReply Query(string path, DistributedConnection sender); - protected abstract override bool Create(); - } +public abstract class EntryPoint : Esiur.Resource.Resource +{ + + public abstract AsyncReply Query(string path, DistributedConnection sender); + protected abstract override bool Create(); } diff --git a/Esiur/Net/INetworkReceiver.cs b/Esiur/Net/INetworkReceiver.cs index dc1bc4e..8c38d72 100644 --- a/Esiur/Net/INetworkReceiver.cs +++ b/Esiur/Net/INetworkReceiver.cs @@ -2,14 +2,13 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Net -{ - public interface INetworkReceiver - { - void NetworkClose(T sender); - void NetworkReceive(T sender, NetworkBuffer buffer); - //void NetworkError(T sender); +namespace Esiur.Net; - void NetworkConnect(T sender); - } +public interface INetworkReceiver +{ + void NetworkClose(T sender); + void NetworkReceive(T sender, NetworkBuffer buffer); + //void NetworkError(T sender); + + void NetworkConnect(T sender); } diff --git a/Esiur/Net/NetworkBuffer.cs b/Esiur/Net/NetworkBuffer.cs index ccfd471..6f9b741 100644 --- a/Esiur/Net/NetworkBuffer.cs +++ b/Esiur/Net/NetworkBuffer.cs @@ -29,180 +29,178 @@ using System.Text; using Esiur.Data; using Esiur.Misc; -namespace Esiur.Net +namespace Esiur.Net; +public class NetworkBuffer { - public class NetworkBuffer + byte[] data; + + uint neededDataLength = 0; + //bool trim; + + object syncLock = new object(); + + //public object SyncLock + //{ + // get { return syncLock; } + //} + + public NetworkBuffer() { - byte[] data; + data = new byte[0]; + } - uint neededDataLength = 0; - //bool trim; - - object syncLock = new object(); - - //public object SyncLock - //{ - // get { return syncLock; } - //} - - public NetworkBuffer() + public bool Protected + { + get { - data = new byte[0]; + return neededDataLength > data.Length; } + } - public bool Protected + public uint Available + { + get { - get + return (uint)data.Length; + } + } + + + //public void HoldForAtLeast(byte[] src, uint offset, uint size, uint needed) + //{ + // HoldFor(src, offset, size, needed); + // //trim = false; + //} + + //public void HoldForAtLeast(byte[] src, uint needed) + //{ + // HoldForAtLeast(src, 0, (uint)src.Length, needed); + //} + + public void HoldForNextWrite(byte[] src) + { + //HoldForAtLeast(src, (uint)src.Length + 1); + HoldFor(src, (uint)src.Length + 1); + } + + public void HoldForNextWrite(byte[] src, uint offset, uint size) + { + //HoldForAtLeast(src, offset, size, size + 1); + HoldFor(src, offset, size, size + 1); + } + + + public void HoldFor(byte[] src, uint offset, uint size, uint needed) + { + lock (syncLock) + { + if (size >= needed) + throw new Exception("Size >= Needed !"); + + //trim = true; + data = DC.Combine(src, offset, size, data, 0, (uint)data.Length); + neededDataLength = needed; + + // Console.WriteLine("Hold StackTrace: '{0}'", Environment.StackTrace); + + //Console.WriteLine("Holded {0} {1} {2} {3} - {4}", offset, size, needed, data.Length, GetHashCode()); + } + } + + public void HoldFor(byte[] src, uint needed) + { + HoldFor(src, 0, (uint)src.Length, needed); + } + + public bool Protect(byte[] data, uint offset, uint needed)//, bool exact = false) + { + uint dataLength = (uint)data.Length - offset; + + // protection + if (dataLength < needed) + { + //if (exact) + // HoldFor(data, offset, dataLength, needed); + //else + //HoldForAtLeast(data, offset, dataLength, needed); + HoldFor(data, offset, dataLength, needed); + return true; + } + else + return false; + } + + public void Write(byte[] src) + { + Write(src, 0, (uint)src.Length); + } + + public void Write(byte[] src, uint offset, uint length) + { + //if (data.Length > 0) + // Console.WriteLine(); + + lock (syncLock) + DC.Append(ref data, src, offset, length); + } + + public bool CanRead + { + get + { + if (data.Length == 0) + return false; + if (data.Length < neededDataLength) + return false; + + return true; + } + } + + public byte[] Read() + { + lock (syncLock) + { + if (data.Length == 0) + return null; + + byte[] rt = null; + + if (neededDataLength == 0) { - return neededDataLength > data.Length; - } - } - - public uint Available - { - get - { - return (uint)data.Length; - } - } - - - //public void HoldForAtLeast(byte[] src, uint offset, uint size, uint needed) - //{ - // HoldFor(src, offset, size, needed); - // //trim = false; - //} - - //public void HoldForAtLeast(byte[] src, uint needed) - //{ - // HoldForAtLeast(src, 0, (uint)src.Length, needed); - //} - - public void HoldForNextWrite(byte[] src) - { - //HoldForAtLeast(src, (uint)src.Length + 1); - HoldFor(src, (uint)src.Length + 1); - } - - public void HoldForNextWrite(byte[] src, uint offset, uint size) - { - //HoldForAtLeast(src, offset, size, size + 1); - HoldFor(src, offset, size, size + 1); - } - - - public void HoldFor(byte[] src, uint offset, uint size, uint needed) - { - lock (syncLock) - { - if (size >= needed) - throw new Exception("Size >= Needed !"); - - //trim = true; - data = DC.Combine(src, offset, size, data, 0, (uint)data.Length); - neededDataLength = needed; - - // Console.WriteLine("Hold StackTrace: '{0}'", Environment.StackTrace); - - //Console.WriteLine("Holded {0} {1} {2} {3} - {4}", offset, size, needed, data.Length, GetHashCode()); - } - } - - public void HoldFor(byte[] src, uint needed) - { - HoldFor(src, 0, (uint)src.Length, needed); - } - - public bool Protect(byte[] data, uint offset, uint needed)//, bool exact = false) - { - uint dataLength = (uint)data.Length - offset; - - // protection - if (dataLength < needed) - { - //if (exact) - // HoldFor(data, offset, dataLength, needed); - //else - //HoldForAtLeast(data, offset, dataLength, needed); - HoldFor(data, offset, dataLength, needed); - return true; + rt = data; + data = new byte[0]; } else - return false; - } - - public void Write(byte[] src) - { - Write(src, 0, (uint)src.Length); - } - - public void Write(byte[] src, uint offset, uint length) - { - //if (data.Length > 0) - // Console.WriteLine(); - - lock(syncLock) - DC.Append(ref data, src, offset, length); - } - - public bool CanRead - { - get { - if (data.Length == 0) - return false; - if (data.Length < neededDataLength) - return false; + //Console.WriteLine("P STATE:" + data.Length + " " + neededDataLength); - return true; - } - } - - public byte[] Read() - { - lock (syncLock) - { - if (data.Length == 0) - return null; - - byte[] rt = null; - - if (neededDataLength == 0) + if (data.Length >= neededDataLength) { + //Console.WriteLine("data.Length >= neededDataLength " + data.Length + " >= " + neededDataLength + " " + trim); + + //if (trim) + //{ + // rt = DC.Clip(data, 0, neededDataLength); + // data = DC.Clip(data, neededDataLength, (uint)data.Length - neededDataLength); + //} + //else + //{ + // return all data rt = data; data = new byte[0]; + //} + + neededDataLength = 0; + return rt; } else { - //Console.WriteLine("P STATE:" + data.Length + " " + neededDataLength); - - if (data.Length >= neededDataLength) - { - //Console.WriteLine("data.Length >= neededDataLength " + data.Length + " >= " + neededDataLength + " " + trim); - - //if (trim) - //{ - // rt = DC.Clip(data, 0, neededDataLength); - // data = DC.Clip(data, neededDataLength, (uint)data.Length - neededDataLength); - //} - //else - //{ - // return all data - rt = data; - data = new byte[0]; - //} - - neededDataLength = 0; - return rt; - } - else - { - return null; - } + return null; } + } - return rt; - } + return rt; } } } diff --git a/Esiur/Net/NetworkConnection.cs b/Esiur/Net/NetworkConnection.cs index 4098f54..c876b56 100644 --- a/Esiur/Net/NetworkConnection.cs +++ b/Esiur/Net/NetworkConnection.cs @@ -36,332 +36,330 @@ using Esiur.Data; using Esiur.Net.Sockets; using Esiur.Resource; -namespace Esiur.Net +namespace Esiur.Net; +public abstract class NetworkConnection : IDestructible, INetworkReceiver// : IResource where TS : NetworkSession { - public abstract class NetworkConnection: IDestructible, INetworkReceiver// : IResource where TS : NetworkSession + private Sockets.ISocket sock; + // private bool connected; + + private DateTime lastAction; + + //public delegate void DataReceivedEvent(NetworkConnection sender, NetworkBuffer data); + //public delegate void ConnectionClosedEvent(NetworkConnection sender); + public delegate void NetworkConnectionEvent(NetworkConnection connection); + + public event NetworkConnectionEvent OnConnect; + //public event DataReceivedEvent OnDataReceived; + public event NetworkConnectionEvent OnClose; + + + public event DestroyedEvent OnDestroy; + //object receivingLock = new object(); + + //object sendLock = new object(); + + bool processing = false; + + // public INetworkReceiver Receiver { get; set; } + + public virtual void Destroy() { - private Sockets.ISocket sock; - // private bool connected; + // remove references + //sock.OnClose -= Socket_OnClose; + //sock.OnConnect -= Socket_OnConnect; + //sock.OnReceive -= Socket_OnReceive; + sock?.Destroy(); + //Receiver = null; + Close(); + sock = null; - private DateTime lastAction; + OnClose = null; + OnConnect = null; + //OnDataReceived = null; + OnDestroy?.Invoke(this); + OnDestroy = null; + } - //public delegate void DataReceivedEvent(NetworkConnection sender, NetworkBuffer data); - //public delegate void ConnectionClosedEvent(NetworkConnection sender); - public delegate void NetworkConnectionEvent(NetworkConnection connection); - - public event NetworkConnectionEvent OnConnect; - //public event DataReceivedEvent OnDataReceived; - public event NetworkConnectionEvent OnClose; - - - public event DestroyedEvent OnDestroy; - //object receivingLock = new object(); - - //object sendLock = new object(); - - bool processing = false; - - // public INetworkReceiver Receiver { get; set; } - - public virtual void Destroy() + public ISocket Socket + { + get { - // remove references + return sock; + } + } + + public virtual void Assign(ISocket socket) + { + lastAction = DateTime.Now; + sock = socket; + sock.Receiver = this; + + //socket.OnReceive += Socket_OnReceive; + //socket.OnClose += Socket_OnClose; + //socket.OnConnect += Socket_OnConnect; + } + + //private void Socket_OnConnect() + //{ + // OnConnect?.Invoke(this); + //} + + //private void Socket_OnClose() + //{ + // ConnectionClosed(); + // OnClose?.Invoke(this); + //} + + //protected virtual void ConnectionClosed() + //{ + + //} + + //private void Socket_OnReceive(NetworkBuffer buffer) + //{ + //} + + public ISocket Unassign() + { + if (sock != null) + { + // connected = false; //sock.OnClose -= Socket_OnClose; //sock.OnConnect -= Socket_OnConnect; //sock.OnReceive -= Socket_OnReceive; - sock?.Destroy(); - //Receiver = null; - Close(); + sock.Receiver = null; + + var rt = sock; sock = null; - OnClose = null; - OnConnect = null; - //OnDataReceived = null; - OnDestroy?.Invoke(this); - OnDestroy = null; + return rt; } + else + return null; + } - public ISocket Socket - { - get - { - return sock; - } - } + //protected virtual void DataReceived(NetworkBuffer data) + //{ + // if (OnDataReceived != null) + // { + // try + // { + // OnDataReceived?.Invoke(this, data); + // } + // catch (Exception ex) + // { + // Global.Log("NetworkConenction:DataReceived", LogType.Error, ex.ToString()); + // } + // } + //} - public virtual void Assign(ISocket socket) - { - lastAction = DateTime.Now; - sock = socket; - sock.Receiver = this; + public void Close() + { + //if (!connected) + // return; - //socket.OnReceive += Socket_OnReceive; - //socket.OnClose += Socket_OnClose; - //socket.OnConnect += Socket_OnConnect; - } - //private void Socket_OnConnect() - //{ - // OnConnect?.Invoke(this); - //} - - //private void Socket_OnClose() - //{ - // ConnectionClosed(); - // OnClose?.Invoke(this); - //} - - //protected virtual void ConnectionClosed() - //{ - - //} - - //private void Socket_OnReceive(NetworkBuffer buffer) - //{ - //} - - public ISocket Unassign() + try { if (sock != null) - { - // connected = false; - //sock.OnClose -= Socket_OnClose; - //sock.OnConnect -= Socket_OnConnect; - //sock.OnReceive -= Socket_OnReceive; - sock.Receiver = null; + sock.Close(); + } + catch (Exception ex) + { + Global.Log("NetworkConenction:Close", LogType.Error, ex.ToString()); - var rt = sock; - sock = null; + } - return rt; - } + //finally + //{ + //connected = false; + //} + + } + + public DateTime LastAction + { + get { return lastAction; } + } + + public IPEndPoint RemoteEndPoint + { + get + { + if (sock != null) + return (IPEndPoint)sock.RemoteEndPoint; else return null; } + } - //protected virtual void DataReceived(NetworkBuffer data) - //{ - // if (OnDataReceived != null) - // { - // try - // { - // OnDataReceived?.Invoke(this, data); - // } - // catch (Exception ex) - // { - // Global.Log("NetworkConenction:DataReceived", LogType.Error, ex.ToString()); - // } - // } - //} - - public void Close() + public IPEndPoint LocalEndPoint + { + get { - //if (!connected) - // return; + if (sock != null) + return (IPEndPoint)sock.LocalEndPoint; + else + return null; + } + } - try - { + public bool IsConnected + { + get + { + return sock.State == SocketState.Established; + } + } + + + /* + public void CloseAndWait() + { + try + { + if (!connected) + return; + if (sock != null) sock.Close(); - } - catch (Exception ex) - { - Global.Log("NetworkConenction:Close", LogType.Error, ex.ToString()); - } - - //finally - //{ - //connected = false; - //} - - } - - public DateTime LastAction - { - get { return lastAction; } - } - - public IPEndPoint RemoteEndPoint - { - get - { - if (sock != null) - return (IPEndPoint)sock.RemoteEndPoint; - else - return null; - } - } - - public IPEndPoint LocalEndPoint - { - get - { - if (sock != null) - return (IPEndPoint)sock.LocalEndPoint; - else - return null; - } - } - - - public bool IsConnected - { - get - { - return sock.State == SocketState.Established; - } - } - - - /* - public void CloseAndWait() - { - try - { - if (!connected) - return; - - if (sock != null) - sock.Close(); - - while (connected) - { - Thread.Sleep(100); - } - } - finally - { - - } - } - */ - - public virtual AsyncReply SendAsync(byte[] message, int offset, int length) - { - try - { - lastAction = DateTime.Now; - return sock.SendAsync(message, offset, length); - } - catch - { - return new AsyncReply(false); - } - } - - public virtual void Send(byte[] msg) - { - try - { - sock?.Send(msg); - lastAction = DateTime.Now; - } - catch - { - - } - } - - public virtual void Send(byte[] msg, int offset, int length) - { - try - { - sock.Send(msg, offset, length); - lastAction = DateTime.Now; - } - catch - { - - } - } - - public virtual void Send(string data) - { - Send(Encoding.UTF8.GetBytes(data)); - } - - public void NetworkClose(ISocket socket) - { - Disconencted(); - OnClose?.Invoke(this); - } - - public void NetworkConnect(ISocket socket) - { - Connected(); - OnConnect?.Invoke(this); - } - - //{ - //ConnectionClosed(); - //OnClose?.Invoke(this); - - //Receiver?.NetworkClose(this); - //} - - //public void NetworkConenct(ISocket sender) - //{ - // OnConnect?.Invoke(this); - //} - - protected abstract void DataReceived(NetworkBuffer buffer); - protected abstract void Connected(); - protected abstract void Disconencted(); - - public void NetworkReceive(ISocket sender, NetworkBuffer buffer) - { - try - { - // Unassigned ? - if (sock == null) - return; - - // Closed ? - if (sock.State == SocketState.Closed)// || sock.State == SocketState.Terminated) // || !connected) - return; - - lastAction = DateTime.Now; - - if (!processing) + while (connected) { - processing = true; + Thread.Sleep(100); + } + } + finally + { - try + } + } + */ + + public virtual AsyncReply SendAsync(byte[] message, int offset, int length) + { + try + { + lastAction = DateTime.Now; + return sock.SendAsync(message, offset, length); + } + catch + { + return new AsyncReply(false); + } + } + + public virtual void Send(byte[] msg) + { + try + { + sock?.Send(msg); + lastAction = DateTime.Now; + } + catch + { + + } + } + + public virtual void Send(byte[] msg, int offset, int length) + { + try + { + sock.Send(msg, offset, length); + lastAction = DateTime.Now; + } + catch + { + + } + } + + public virtual void Send(string data) + { + Send(Encoding.UTF8.GetBytes(data)); + } + + public void NetworkClose(ISocket socket) + { + Disconencted(); + OnClose?.Invoke(this); + } + + public void NetworkConnect(ISocket socket) + { + Connected(); + OnConnect?.Invoke(this); + } + + //{ + //ConnectionClosed(); + //OnClose?.Invoke(this); + + //Receiver?.NetworkClose(this); + //} + + //public void NetworkConenct(ISocket sender) + //{ + // OnConnect?.Invoke(this); + //} + + protected abstract void DataReceived(NetworkBuffer buffer); + protected abstract void Connected(); + protected abstract void Disconencted(); + + public void NetworkReceive(ISocket sender, NetworkBuffer buffer) + { + try + { + // Unassigned ? + if (sock == null) + return; + + // Closed ? + if (sock.State == SocketState.Closed)// || sock.State == SocketState.Terminated) // || !connected) + return; + + lastAction = DateTime.Now; + + if (!processing) + { + processing = true; + + try + { + //lock(buffer.SyncLock) + while (buffer.Available > 0 && !buffer.Protected) { - //lock(buffer.SyncLock) - while (buffer.Available > 0 && !buffer.Protected) - { - //Receiver?.NetworkReceive(this, buffer); - DataReceived(buffer); - } + //Receiver?.NetworkReceive(this, buffer); + DataReceived(buffer); } - catch - { + } + catch + { - } - - processing = false; } + processing = false; } - catch (Exception ex) - { - Global.Log("NetworkConnection", LogType.Warning, ex.ToString()); - } + + } + catch (Exception ex) + { + Global.Log("NetworkConnection", LogType.Warning, ex.ToString()); } - - - //{ - // Receiver?.NetworkError(this); - //throw new NotImplementedException(); - //} - - //public void NetworkConnect(ISocket sender) - //{ - // Receiver?.NetworkConnect(this); - //throw new NotImplementedException(); - //} } -} \ No newline at end of file + + + //{ + // Receiver?.NetworkError(this); + //throw new NotImplementedException(); + //} + + //public void NetworkConnect(ISocket sender) + //{ + // Receiver?.NetworkConnect(this); + //throw new NotImplementedException(); + //} +} diff --git a/Esiur/Net/NetworkServer.cs b/Esiur/Net/NetworkServer.cs index 54e0528..1604e7f 100644 --- a/Esiur/Net/NetworkServer.cs +++ b/Esiur/Net/NetworkServer.cs @@ -33,279 +33,277 @@ using Esiur.Resource; using System.Threading.Tasks; using System.Diagnostics; -namespace Esiur.Net +namespace Esiur.Net; + +public abstract class NetworkServer : IDestructible where TConnection : NetworkConnection, new() { + //private bool isRunning; + private Sockets.ISocket listener; + public AutoList> Connections { get; internal set; } - public abstract class NetworkServer : IDestructible where TConnection : NetworkConnection, new() + private Thread thread; + + //protected abstract void DataReceived(TConnection sender, NetworkBuffer data); + //protected abstract void ClientConnected(TConnection sender); + //protected abstract void ClientDisconnected(TConnection sender); + + + private Timer timer; + //public KeyList Sessions = new KeyList(); + + public event DestroyedEvent OnDestroy; + + //public AutoList> Connections => connections; + + private void MinuteThread(object state) { - //private bool isRunning; - private Sockets.ISocket listener; - public AutoList> Connections { get; private set; } - - private Thread thread; - - //protected abstract void DataReceived(TConnection sender, NetworkBuffer data); - //protected abstract void ClientConnected(TConnection sender); - //protected abstract void ClientDisconnected(TConnection sender); + List ToBeClosed = null; - private Timer timer; - //public KeyList Sessions = new KeyList(); - - public event DestroyedEvent OnDestroy; - - //public AutoList> Connections => connections; - - private void MinuteThread(object state) + lock (Connections.SyncRoot) { - List ToBeClosed = null; - - - lock (Connections.SyncRoot) + foreach (TConnection c in Connections) { - foreach (TConnection c in Connections) + if (DateTime.Now.Subtract(c.LastAction).TotalSeconds >= Timeout) { - if (DateTime.Now.Subtract(c.LastAction).TotalSeconds >= Timeout) - { - if (ToBeClosed == null) - ToBeClosed = new List(); - ToBeClosed.Add(c); - } + if (ToBeClosed == null) + ToBeClosed = new List(); + ToBeClosed.Add(c); } } - - if (ToBeClosed != null) - { - //Console.WriteLine("Term: " + ToBeClosed.Count + " " + this.listener.LocalEndPoint.ToString()); - foreach (TConnection c in ToBeClosed) - c.Close();// CloseAndWait(); - - ToBeClosed.Clear(); - ToBeClosed = null; - } } - public void Start(Sockets.ISocket socket)//, uint timeout, uint clock) + if (ToBeClosed != null) { - if (listener != null) - return; + //Console.WriteLine("Term: " + ToBeClosed.Count + " " + this.listener.LocalEndPoint.ToString()); + foreach (TConnection c in ToBeClosed) + c.Close();// CloseAndWait(); + + ToBeClosed.Clear(); + ToBeClosed = null; + } + } + + public void Start(Sockets.ISocket socket)//, uint timeout, uint clock) + { + if (listener != null) + return; - Connections = new AutoList>(this); + Connections = new AutoList>(this); - if (Timeout > 0 & Clock > 0) + if (Timeout > 0 & Clock > 0) + { + timer = new Timer(MinuteThread, null, TimeSpan.FromMinutes(0), TimeSpan.FromSeconds(Clock)); + } + + + listener = socket; + + // Start accepting + //var r = listener.Accept(); + //r.Then(NewConnection); + //r.timeout?.Dispose(); + + //var rt = listener.Accept().Then() + thread = new Thread(new ThreadStart(() => + { + while (true) { - timer = new Timer(MinuteThread, null, TimeSpan.FromMinutes(0), TimeSpan.FromSeconds(Clock)); - } - - - listener = socket; - - // Start accepting - //var r = listener.Accept(); - //r.Then(NewConnection); - //r.timeout?.Dispose(); - - //var rt = listener.Accept().Then() - thread = new Thread(new ThreadStart(() => - { - while (true) + try { - try + var s = listener.Accept(); + + if (s == null) { - var s = listener.Accept(); + Console.Write("sock == null"); + return; + } - if (s == null) - { - Console.Write("sock == null"); - return; - } - - var c = new TConnection(); + var c = new TConnection(); //c.OnClose += ClientDisconnectedEventReceiver; c.Assign(s); - Add(c); + Add(c); //Connections.Add(c); - + try - { + { //ClientConnected(c); ClientConnected(c); //NetworkConnect(c); } - catch - { + catch + { // something wrong with the child. } - s.Begin(); + s.Begin(); // Accept more //listener.Accept().Then(NewConnection); } - catch (Exception ex) - { - Console.WriteLine(ex); - } - } - })); - - thread.Start(); - - } - - - [Attribute] - public uint Timeout - { - get; - set; - } - - - [Attribute] - public uint Clock - { - get; - set; - } - - - public void Stop() - { - var port = 0; - - try - { - if (listener != null) + catch (Exception ex) { - port = listener.LocalEndPoint.Port; - listener.Close(); + Console.WriteLine(ex); } - - // wait until the listener stops - //while (isRunning) - //{ - // Thread.Sleep(100); - //} - - //Console.WriteLine("Listener stopped"); - - var cons = Connections.ToArray(); - - //lock (connections.SyncRoot) - //{ - foreach (TConnection con in cons) - con.Close(); - //} - - //Console.WriteLine("Sockets Closed"); - - //while (connections.Count > 0) - //{ - // Console.WriteLine("Waiting... " + connections.Count); - // Thread.Sleep(1000); - //} - } - finally + })); + + thread.Start(); + + } + + + [Attribute] + public uint Timeout + { + get; + set; + } + + + [Attribute] + public uint Clock + { + get; + set; + } + + + public void Stop() + { + var port = 0; + + try + { + if (listener != null) { - Console.WriteLine("Server@{0} is down", port); + port = listener.LocalEndPoint.Port; + listener.Close(); } + + // wait until the listener stops + //while (isRunning) + //{ + // Thread.Sleep(100); + //} + + //Console.WriteLine("Listener stopped"); + + var cons = Connections.ToArray(); + + //lock (connections.SyncRoot) + //{ + foreach (TConnection con in cons) + con.Close(); + //} + + //Console.WriteLine("Sockets Closed"); + + //while (connections.Count > 0) + //{ + // Console.WriteLine("Waiting... " + connections.Count); + // Thread.Sleep(1000); + //} + } - - - public virtual void Remove(TConnection connection) + finally { - //connection.OnDataReceived -= OnDataReceived; - //connection.OnConnect -= OnClientConnect; - connection.OnClose -= ClientDisconnectedEventReceiver; - Connections.Remove(connection); - } - - public virtual void Add(TConnection connection) - { - //connection.OnDataReceived += OnDataReceived; - //connection.OnConnect += OnClientConnect; - connection.OnClose += ClientDisconnectedEventReceiver;// OnClientClose; - Connections.Add(connection); - } - - - public bool IsRunning - { - get - { - return listener.State == SocketState.Listening; - //isRunning; - } - } - - //public void OnDataReceived(ISocket sender, NetworkBuffer data) - //{ - // DataReceived((TConnection)sender, data); - //} - - //public void OnClientConnect(ISocket sender) - //{ - // if (sender == null) - // return; - - // if (sender.RemoteEndPoint == null || sender.LocalEndPoint == null) - // { } - // //Console.WriteLine("NULL"); - // else - // Global.Log("Connections", LogType.Debug, sender.RemoteEndPoint.Address.ToString() - // + "->" + sender.LocalEndPoint.Port + " at " + DateTime.UtcNow.ToString("d") - // + " " + DateTime.UtcNow.ToString("d"), false); - - // // Console.WriteLine("Connected " + sender.RemoteEndPoint.ToString()); - // ClientConnected((TConnection)sender); - //} - - //public void OnClientClose(ISocket sender) - //{ - //} - - - public void Destroy() - { - Stop(); - OnDestroy?.Invoke(this); - } - - private void ClientDisconnectedEventReceiver(NetworkConnection connection) - { - try - { - var con = connection as TConnection; - con.Destroy(); - // con.OnClose -= ClientDisconnectedEventReceiver; - - Remove(con); - - //Connections.Remove(con); - ClientDisconnected(con); - //RemoveConnection((TConnection)sender); - //connections.Remove(sender) - //ClientDisconnected((TConnection)sender); - } - catch (Exception ex) - { - Global.Log("NetworkServer:OnClientDisconnect", LogType.Error, ex.ToString()); - } - } - - protected abstract void ClientDisconnected(TConnection connection); - protected abstract void ClientConnected(TConnection connection); - - ~NetworkServer() - { - Stop(); - listener = null; + Console.WriteLine("Server@{0} is down", port); } } -} \ No newline at end of file + + public virtual void Remove(TConnection connection) + { + //connection.OnDataReceived -= OnDataReceived; + //connection.OnConnect -= OnClientConnect; + connection.OnClose -= ClientDisconnectedEventReceiver; + Connections.Remove(connection); + } + + public virtual void Add(TConnection connection) + { + //connection.OnDataReceived += OnDataReceived; + //connection.OnConnect += OnClientConnect; + connection.OnClose += ClientDisconnectedEventReceiver;// OnClientClose; + Connections.Add(connection); + } + + + public bool IsRunning + { + get + { + return listener.State == SocketState.Listening; + //isRunning; + } + } + + //public void OnDataReceived(ISocket sender, NetworkBuffer data) + //{ + // DataReceived((TConnection)sender, data); + //} + + //public void OnClientConnect(ISocket sender) + //{ + // if (sender == null) + // return; + + // if (sender.RemoteEndPoint == null || sender.LocalEndPoint == null) + // { } + // //Console.WriteLine("NULL"); + // else + // Global.Log("Connections", LogType.Debug, sender.RemoteEndPoint.Address.ToString() + // + "->" + sender.LocalEndPoint.Port + " at " + DateTime.UtcNow.ToString("d") + // + " " + DateTime.UtcNow.ToString("d"), false); + + // // Console.WriteLine("Connected " + sender.RemoteEndPoint.ToString()); + // ClientConnected((TConnection)sender); + //} + + //public void OnClientClose(ISocket sender) + //{ + //} + + + public void Destroy() + { + Stop(); + OnDestroy?.Invoke(this); + } + + private void ClientDisconnectedEventReceiver(NetworkConnection connection) + { + try + { + var con = connection as TConnection; + con.Destroy(); + // con.OnClose -= ClientDisconnectedEventReceiver; + + Remove(con); + + //Connections.Remove(con); + ClientDisconnected(con); + //RemoveConnection((TConnection)sender); + //connections.Remove(sender) + //ClientDisconnected((TConnection)sender); + } + catch (Exception ex) + { + Global.Log("NetworkServer:OnClientDisconnect", LogType.Error, ex.ToString()); + } + } + + protected abstract void ClientDisconnected(TConnection connection); + protected abstract void ClientConnected(TConnection connection); + + ~NetworkServer() + { + Stop(); + listener = null; + } +} + diff --git a/Esiur/Net/NetworkSession.cs b/Esiur/Net/NetworkSession.cs index ea974c8..591e10f 100644 --- a/Esiur/Net/NetworkSession.cs +++ b/Esiur/Net/NetworkSession.cs @@ -35,96 +35,94 @@ using Esiur.Data; using Esiur.Misc; using Esiur.Core; -namespace Esiur.Net +namespace Esiur.Net; +public class NetworkSession : IDestructible // where T : TClient { - public class NetworkSession:IDestructible // where T : TClient + public delegate void SessionModifiedEvent(NetworkSession session, string key, object oldValue, object newValue); + public delegate void SessionEndedEvent(NetworkSession session); + + private string id; + private Timer timer; + private int timeout; + DateTime creation; + DateTime lastAction; + + private KeyList variables; + + public event SessionEndedEvent OnEnd; + public event SessionModifiedEvent OnModify; + public event DestroyedEvent OnDestroy; + + public KeyList Variables { - public delegate void SessionModifiedEvent(NetworkSession session, string key, object oldValue, object newValue); - public delegate void SessionEndedEvent(NetworkSession session); + get { return variables; } + } - private string id; - private Timer timer; - private int timeout; - DateTime creation; - DateTime lastAction; + public NetworkSession() + { + variables = new KeyList(); + variables.OnModified += new KeyList.Modified(VariablesModified); + creation = DateTime.Now; + } - private KeyList variables; + internal void Set(string id, int timeout) + { + //modified = sessionModifiedEvent; + //ended = sessionEndEvent; + this.id = id; - public event SessionEndedEvent OnEnd; - public event SessionModifiedEvent OnModify; - public event DestroyedEvent OnDestroy; - - public KeyList Variables + if (this.timeout != 0) { - get { return variables; } - } - - public NetworkSession() - { - variables = new KeyList(); - variables.OnModified += new KeyList.Modified(VariablesModified); + this.timeout = timeout; + timer = new Timer(OnSessionEndTimerCallback, null, TimeSpan.FromSeconds(timeout), TimeSpan.FromSeconds(0)); creation = DateTime.Now; } - - internal void Set(string id, int timeout ) - { - //modified = sessionModifiedEvent; - //ended = sessionEndEvent; - this.id = id; - - if (this.timeout != 0) - { - this.timeout = timeout; - timer = new Timer(OnSessionEndTimerCallback, null, TimeSpan.FromSeconds(timeout), TimeSpan.FromSeconds(0)); - creation = DateTime.Now; - } - } - - private void OnSessionEndTimerCallback(object o) - { - OnEnd?.Invoke(this); - } - - void VariablesModified(string key, object oldValue, object newValue, KeyList sender) - { - OnModify?.Invoke(this, key, oldValue, newValue); - } - - public void Destroy() - { - OnDestroy?.Invoke(this); - timer.Dispose(); - timer = null; - } - - internal void Refresh() - { - lastAction = DateTime.Now; - timer.Change(TimeSpan.FromSeconds(timeout), TimeSpan.FromSeconds(0)); - } - - public int Timeout // Seconds - { - get - { - return timeout; - } - set - { - timeout = value; - Refresh(); - } - } - - public string Id - { - get { return id; } - } - - public DateTime LastAction - { - get { return lastAction; } - } } -} \ No newline at end of file + private void OnSessionEndTimerCallback(object o) + { + OnEnd?.Invoke(this); + } + + void VariablesModified(string key, object oldValue, object newValue, KeyList sender) + { + OnModify?.Invoke(this, key, oldValue, newValue); + } + + public void Destroy() + { + OnDestroy?.Invoke(this); + timer.Dispose(); + timer = null; + } + + internal void Refresh() + { + lastAction = DateTime.Now; + timer.Change(TimeSpan.FromSeconds(timeout), TimeSpan.FromSeconds(0)); + } + + public int Timeout // Seconds + { + get + { + return timeout; + } + set + { + timeout = value; + Refresh(); + } + } + + public string Id + { + get { return id; } + } + + public DateTime LastAction + { + get { return lastAction; } + } +} + diff --git a/Esiur/Net/Packets/HTTPRequestPacket.cs b/Esiur/Net/Packets/HTTPRequestPacket.cs index 1755f1e..6ddb003 100644 --- a/Esiur/Net/Packets/HTTPRequestPacket.cs +++ b/Esiur/Net/Packets/HTTPRequestPacket.cs @@ -32,287 +32,284 @@ using Esiur.Data; using System.Net; using System.Text.Json.Serialization; -namespace Esiur.Net.Packets +namespace Esiur.Net.Packets; +public class HTTPRequestPacket : Packet { - public class HTTPRequestPacket : Packet + + public enum HTTPMethod : byte { + GET, + POST, + HEAD, + PUT, + DELETE, + OPTIONS, + TRACE, + CONNECT, + UNKNOWN + } - public enum HTTPMethod:byte + public StringKeyList Query; + public HTTPMethod Method; + public StringKeyList Headers; + + public bool WSMode; + + public string Version; + public StringKeyList Cookies; // String + public string URL; /// With query + public string Filename; /// Without query + //public byte[] PostContents; + public KeyList PostForms; + public byte[] Message; + + + private HTTPMethod getMethod(string method) + { + switch (method.ToLower()) { - GET, - POST, - HEAD, - PUT, - DELETE, - OPTIONS, - TRACE, - CONNECT, - UNKNOWN + case "get": + return HTTPMethod.GET; + case "post": + return HTTPMethod.POST; + case "head": + return HTTPMethod.HEAD; + case "put": + return HTTPMethod.PUT; + case "delete": + return HTTPMethod.DELETE; + case "options": + return HTTPMethod.OPTIONS; + case "trace": + return HTTPMethod.TRACE; + case "connect": + return HTTPMethod.CONNECT; + default: + return HTTPMethod.UNKNOWN; } + } - public StringKeyList Query; - public HTTPMethod Method; - public StringKeyList Headers; + public override string ToString() + { + return "HTTPRequestPacket" + + "\n\tVersion: " + Version + + "\n\tMethod: " + Method + + "\n\tURL: " + URL + + "\n\tMessage: " + (Message != null ? Message.Length.ToString() : "NULL"); + } - public bool WSMode; + public override long Parse(byte[] data, uint offset, uint ends) + { + string[] sMethod = null; + string[] sLines = null; - public string Version; - public StringKeyList Cookies; // String - public string URL; /// With query - public string Filename; /// Without query - //public byte[] PostContents; - public KeyList PostForms; - public byte[] Message; + uint headerSize = 0; - - private HTTPMethod getMethod(string method) + for (uint i = offset; i < ends - 3; i++) { - switch (method.ToLower()) + if (data[i] == '\r' && data[i + 1] == '\n' + && data[i + 2] == '\r' && data[i + 3] == '\n') { - case "get": - return HTTPMethod.GET; - case "post": - return HTTPMethod.POST; - case "head": - return HTTPMethod.HEAD; - case "put": - return HTTPMethod.PUT; - case "delete": - return HTTPMethod.DELETE; - case "options": - return HTTPMethod.OPTIONS; - case "trace": - return HTTPMethod.TRACE; - case "connect": - return HTTPMethod.CONNECT; - default: - return HTTPMethod.UNKNOWN; + sLines = Encoding.ASCII.GetString(data, (int)offset, (int)(i - offset)).Split(new string[] { "\r\n" }, + StringSplitOptions.None); + + headerSize = i + 4; + break; } } - public override string ToString() - { - return "HTTPRequestPacket" - + "\n\tVersion: " + Version - + "\n\tMethod: " + Method - + "\n\tURL: " + URL - + "\n\tMessage: " + (Message != null ? Message.Length.ToString() : "NULL"); - } + if (headerSize == 0) + return -1; - public override long Parse(byte[] data, uint offset, uint ends) - { - string[] sMethod = null; - string[] sLines = null; - - uint headerSize = 0; + Cookies = new StringKeyList(); + PostForms = new KeyList(); + Query = new StringKeyList(); + Headers = new StringKeyList(); - for (uint i = offset; i < ends - 3; i++) + sMethod = sLines[0].Split(' '); + Method = getMethod(sMethod[0].Trim()); + + if (sMethod.Length == 3) + { + sMethod[1] = WebUtility.UrlDecode(sMethod[1]); + if (sMethod[1].Length >= 7) { - if (data[i] == '\r' && data[i + 1] == '\n' - && data[i + 2] == '\r' && data[i + 3] == '\n') + if (sMethod[1].StartsWith("http://")) { - sLines = Encoding.ASCII.GetString(data, (int)offset,(int)( i - offset)).Split(new string[] { "\r\n" }, - StringSplitOptions.None); - - headerSize = i + 4; - break; + sMethod[1] = sMethod[1].Substring(sMethod[1].IndexOf("/", 7)); } } - if (headerSize == 0) - return -1; + URL = sMethod[1].Trim(); - Cookies = new StringKeyList(); - PostForms = new KeyList(); - Query = new StringKeyList(); - Headers = new StringKeyList(); - - sMethod = sLines[0].Split(' '); - Method = getMethod(sMethod[0].Trim()); - - if (sMethod.Length == 3) + if (URL.IndexOf("?", 0) != -1) { - sMethod[1] = WebUtility.UrlDecode(sMethod[1]); - if (sMethod[1].Length >= 7) + Filename = URL.Split(new char[] { '?' }, 2)[0]; + } + else + { + Filename = URL; + } + + if (Filename.IndexOf("%", 0) != -1) + { + Filename = WebUtility.UrlDecode(Filename); + } + + Version = sMethod[2].Trim(); + } + + // Read all headers + + for (int i = 1; i < sLines.Length; i++) + { + if (sLines[i] == String.Empty) + { + // Invalid header + return 0; + } + + if (sLines[i].IndexOf(':') == -1) + { + // Invalid header + return 0; + } + + string[] header = sLines[i].Split(new char[] { ':' }, 2); + + header[0] = header[0].ToLower(); + Headers[header[0]] = header[1].Trim(); + + if (header[0] == "cookie") + { + string[] cookies = header[1].Split(';'); + + foreach (string cookie in cookies) { - if (sMethod[1].StartsWith("http://")) + if (cookie.IndexOf('=') != -1) { - sMethod[1] = sMethod[1].Substring(sMethod[1].IndexOf("/", 7)); + string[] splitCookie = cookie.Split('='); + splitCookie[0] = splitCookie[0].Trim(); + splitCookie[1] = splitCookie[1].Trim(); + if (!(Cookies.ContainsKey(splitCookie[0].Trim()))) + Cookies.Add(splitCookie[0], splitCookie[1]); + } + else + { + if (!(Cookies.ContainsKey(cookie.Trim()))) + { + Cookies.Add(cookie.Trim(), String.Empty); + } } } + } + } - URL = sMethod[1].Trim(); - - if (URL.IndexOf("?", 0) != -1) + // Query String + if (URL.IndexOf("?", 0) != -1) + { + string[] SQ = URL.Split(new char[] { '?' }, 2)[1].Split('&'); + foreach (string S in SQ) + { + if (S.IndexOf("=", 0) != -1) { - Filename = URL.Split(new char[] { '?' }, 2)[0]; + string[] qp = S.Split(new char[] { '=' }, 2); + + if (!Query.ContainsKey(WebUtility.UrlDecode(qp[0]))) + { + Query.Add(WebUtility.UrlDecode(qp[0]), WebUtility.UrlDecode(qp[1])); + } } else { - Filename = URL; - } - - if (Filename.IndexOf("%", 0) != -1) - { - Filename = WebUtility.UrlDecode(Filename); - } - - Version = sMethod[2].Trim(); - } - - // Read all headers - - for (int i = 1; i < sLines.Length; i++) - { - if (sLines[i] == String.Empty) - { - // Invalid header - return 0; - } - - if (sLines[i].IndexOf(':') == -1) - { - // Invalid header - return 0; - } - - string[] header = sLines[i].Split(new char[] { ':' }, 2); - - header[0] = header[0].ToLower(); - Headers[header[0]] = header[1].Trim(); - - if (header[0] == "cookie") - { - string[] cookies = header[1].Split(';'); - - foreach (string cookie in cookies) + if (!(Query.ContainsKey(WebUtility.UrlDecode(S)))) { - if (cookie.IndexOf('=') != -1) + Query.Add(WebUtility.UrlDecode(S), null); + } + } + } + } + + // Post Content-Length + if (Method == HTTPMethod.POST) + { + try + { + + uint postSize = uint.Parse((string)Headers["content-length"]); + + // check limit + if (postSize > data.Length - headerSize) + return -(postSize - (data.Length - headerSize)); + + + if ( + Headers["content-type"] == null + || Headers["content-type"] == "" + || Headers["content-type"].StartsWith("application/x-www-form-urlencoded")) + { + string[] PostVars = null; + PostVars = Encoding.UTF8.GetString(data, (int)headerSize, (int)postSize).Split('&'); + for (int J = 0; J < PostVars.Length; J++) + { + if (PostVars[J].IndexOf("=") != -1) { - string[] splitCookie = cookie.Split('='); - splitCookie[0] = splitCookie[0].Trim(); - splitCookie[1] = splitCookie[1].Trim(); - if (!(Cookies.ContainsKey(splitCookie[0].Trim()))) - Cookies.Add(splitCookie[0], splitCookie[1]); + string key = WebUtility.HtmlDecode( + WebUtility.UrlDecode(PostVars[J].Split(new char[] { '=' }, 2)[0])); + if (PostForms.Contains(key)) + PostForms[key] = WebUtility.HtmlDecode( + WebUtility.UrlDecode(PostVars[J].Split(new char[] { '=' }, 2)[1])); + else + PostForms.Add(key, WebUtility.HtmlDecode( + WebUtility.UrlDecode(PostVars[J].Split(new char[] { '=' }, 2)[1]))); } else - { - if (!(Cookies.ContainsKey(cookie.Trim()))) - { - Cookies.Add(cookie.Trim(), String.Empty); - } - } + if (PostForms.Contains("unknown")) + PostForms["unknown"] = PostForms["unknown"] + + "&" + WebUtility.HtmlDecode(WebUtility.UrlDecode(PostVars[J])); + else + PostForms.Add("unknown", WebUtility.HtmlDecode(WebUtility.UrlDecode(PostVars[J]))); } } - } + else if (Headers["content-type"].StartsWith("multipart/form-data")) + { + int st = 1; + int ed = 0; + string strBoundry = "--" + Headers["content-type"].Substring( + Headers["content-type"].IndexOf("boundary=", 0) + 9); - // Query String - if (URL.IndexOf("?", 0) != -1) + string[] sc = Encoding.UTF8.GetString(data, (int)headerSize, (int)postSize).Split( + new string[] { strBoundry }, StringSplitOptions.None); + + + for (int j = 1; j < sc.Length - 1; j++) + { + string[] ps = sc[j].Split(new string[] { "\r\n\r\n" }, 2, StringSplitOptions.None); + ps[1] = ps[1].Substring(0, ps[1].Length - 2); // remove the empty line + st = ps[0].IndexOf("name=", 0) + 6; + ed = ps[0].IndexOf("\"", st); + PostForms.Add(ps[0].Substring(st, ed - st), ps[1]); + } + } + //else if (Headers["content-type"] == "application/json") + //{ + // var json = DC.Clip(data, headerSize, postSize); + //} + else + { + //PostForms.Add(Headers["content-type"], Encoding.Default.GetString( )); + Message = DC.Clip(data, headerSize, postSize); + } + + return headerSize + postSize; + + } + catch { - string[] SQ = URL.Split(new char[] { '?' }, 2)[1].Split('&'); - foreach (string S in SQ) - { - if (S.IndexOf("=", 0) != -1) - { - string[] qp = S.Split(new char[] { '=' }, 2); - - if (!Query.ContainsKey(WebUtility.UrlDecode(qp[0]))) - { - Query.Add(WebUtility.UrlDecode(qp[0]), WebUtility.UrlDecode(qp[1])); - } - } - else - { - if (!(Query.ContainsKey(WebUtility.UrlDecode(S)))) - { - Query.Add(WebUtility.UrlDecode(S), null); - } - } - } + return 0; } - - // Post Content-Length - if (Method == HTTPMethod.POST) - { - try - { - - uint postSize = uint.Parse((string)Headers["content-length"]); - - // check limit - if (postSize > data.Length - headerSize) - return -(postSize - (data.Length - headerSize)); - - - if ( - Headers["content-type"] == null - || Headers["content-type"] == "" - || Headers["content-type"].StartsWith("application/x-www-form-urlencoded")) - { - string[] PostVars = null; - PostVars = Encoding.UTF8.GetString(data, (int)headerSize, (int)postSize).Split('&'); - for (int J = 0; J < PostVars.Length; J++) - { - if (PostVars[J].IndexOf("=") != -1) - { - string key = WebUtility.HtmlDecode( - WebUtility.UrlDecode(PostVars[J].Split(new char[] { '=' }, 2)[0])); - if (PostForms.Contains(key)) - PostForms[key] = WebUtility.HtmlDecode( - WebUtility.UrlDecode(PostVars[J].Split(new char[] { '=' }, 2)[1])); - else - PostForms.Add(key, WebUtility.HtmlDecode( - WebUtility.UrlDecode(PostVars[J].Split(new char[] { '=' }, 2)[1]))); - } - else - if (PostForms.Contains("unknown")) - PostForms["unknown"] = PostForms["unknown"] - + "&" + WebUtility.HtmlDecode(WebUtility.UrlDecode(PostVars[J])); - else - PostForms.Add("unknown", WebUtility.HtmlDecode(WebUtility.UrlDecode(PostVars[J]))); - } - } - else if (Headers["content-type"].StartsWith("multipart/form-data")) - { - int st = 1; - int ed = 0; - string strBoundry = "--" + Headers["content-type"].Substring( - Headers["content-type"].IndexOf("boundary=", 0) + 9); - - string[] sc = Encoding.UTF8.GetString(data, (int)headerSize, (int)postSize).Split( - new string[] { strBoundry }, StringSplitOptions.None); - - - for (int j = 1; j < sc.Length - 1; j++) - { - string[] ps = sc[j].Split(new string[] { "\r\n\r\n" }, 2, StringSplitOptions.None); - ps[1] = ps[1].Substring(0, ps[1].Length - 2); // remove the empty line - st = ps[0].IndexOf("name=", 0) + 6; - ed = ps[0].IndexOf("\"", st); - PostForms.Add(ps[0].Substring(st, ed - st), ps[1]); - } - } - //else if (Headers["content-type"] == "application/json") - //{ - // var json = DC.Clip(data, headerSize, postSize); - //} - else - { - //PostForms.Add(Headers["content-type"], Encoding.Default.GetString( )); - Message = DC.Clip(data, headerSize, postSize); - } - - return headerSize + postSize; - - } - catch - { - return 0; - } - } - - return headerSize; } + + return headerSize; } } - diff --git a/Esiur/Net/Packets/HTTPResponsePacket.cs b/Esiur/Net/Packets/HTTPResponsePacket.cs index 40d60a7..87a1ea8 100644 --- a/Esiur/Net/Packets/HTTPResponsePacket.cs +++ b/Esiur/Net/Packets/HTTPResponsePacket.cs @@ -27,278 +27,276 @@ using System.Linq; using System.Text; using Esiur.Misc; using Esiur.Data; - -namespace Esiur.Net.Packets + +namespace Esiur.Net.Packets; +public class HTTPResponsePacket : Packet { - public class HTTPResponsePacket : Packet + + public enum ComposeOptions : int { + AllCalculateLength, + AllDontCalculateLength, + SpecifiedHeadersOnly, + DataOnly + } - public enum ComposeOptions : int + public enum ResponseCode : int + { + Switching = 101, + OK = 200, + Created = 201, + Accepted = 202, + NoContent = 204, + MovedPermanently = 301, + Found = 302, + SeeOther = 303, + NotModified = 304, + TemporaryRedirect = 307, + BadRequest = 400, + Unauthorized = 401, + Forbidden = 403, + NotFound = 404, + MethodNotAllowed = 405, + NotAcceptable = 406, + PreconditionFailed = 412, + UnsupportedMediaType = 415, + InternalServerError = 500, + NotImplemented = 501, + } + + public struct HTTPCookie + { + public string Name; + public string Value; + public DateTime Expires; + public string Path; + public bool HttpOnly; + public string Domain; + + public HTTPCookie(string name, string value) { - AllCalculateLength, - AllDontCalculateLength, - SpecifiedHeadersOnly, - DataOnly + this.Name = name; + this.Value = value; + this.Path = null; + this.Expires = DateTime.MinValue; + this.HttpOnly = false; + this.Domain = null; } - public enum ResponseCode : int + public HTTPCookie(string name, string value, DateTime expires) { - Switching= 101, - OK = 200, - Created = 201, - Accepted = 202, - NoContent = 204, - MovedPermanently = 301, - Found = 302, - SeeOther = 303, - NotModified = 304, - TemporaryRedirect = 307, - BadRequest = 400, - Unauthorized = 401, - Forbidden = 403, - NotFound = 404, - MethodNotAllowed = 405, - NotAcceptable = 406, - PreconditionFailed = 412, - UnsupportedMediaType = 415, - InternalServerError = 500, - NotImplemented = 501, + this.Name = name; + this.Value = value; + this.Expires = expires; + this.HttpOnly = false; + this.Domain = null; + this.Path = null; } - public struct HTTPCookie - { - public string Name; - public string Value; - public DateTime Expires; - public string Path; - public bool HttpOnly; - public string Domain; - - public HTTPCookie(string name, string value) - { - this.Name = name; - this.Value = value; - this.Path = null; - this.Expires = DateTime.MinValue; - this.HttpOnly = false; - this.Domain = null; - } - - public HTTPCookie(string name, string value, DateTime expires) - { - this.Name = name; - this.Value = value; - this.Expires = expires; - this.HttpOnly = false; - this.Domain = null; - this.Path = null; - } - - public override string ToString() - { - //Set-Cookie: ckGeneric=CookieBody; expires=Sun, 30-Dec-2001 21:00:00 GMT; domain=.com.au; path=/ - //Set-Cookie: SessionID=another; expires=Fri, 29 Jun 2006 20:47:11 UTC; path=/ - var cookie = Name + "=" + Value; - - if (Expires.Ticks != 0) - cookie += "; expires=" + Expires.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss") + " GMT"; - - if (Domain != null) - cookie += "; domain=" + Domain; - - if (Path != null) - cookie += "; path=" + Path; - - if (HttpOnly) - cookie += "; HttpOnly"; - - return cookie; - } - } - - public StringKeyList Headers = new StringKeyList(true); - public string Version = "HTTP/1.1"; - - public byte[] Message; - public ResponseCode Number; - public string Text; - - public List Cookies = new List(); - public bool Handled; - public override string ToString() { - return "HTTPResponsePacket" - + "\n\tVersion: " + Version - //+ "\n\tMethod: " + Method - //+ "\n\tURL: " + URL - + "\n\tMessage: " + (Message != null ? Message.Length.ToString() : "NULL"); + //Set-Cookie: ckGeneric=CookieBody; expires=Sun, 30-Dec-2001 21:00:00 GMT; domain=.com.au; path=/ + //Set-Cookie: SessionID=another; expires=Fri, 29 Jun 2006 20:47:11 UTC; path=/ + var cookie = Name + "=" + Value; + + if (Expires.Ticks != 0) + cookie += "; expires=" + Expires.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss") + " GMT"; + + if (Domain != null) + cookie += "; domain=" + Domain; + + if (Path != null) + cookie += "; path=" + Path; + + if (HttpOnly) + cookie += "; HttpOnly"; + + return cookie; + } + } + + public StringKeyList Headers = new StringKeyList(true); + public string Version = "HTTP/1.1"; + + public byte[] Message; + public ResponseCode Number; + public string Text; + + public List Cookies = new List(); + public bool Handled; + + public override string ToString() + { + return "HTTPResponsePacket" + + "\n\tVersion: " + Version + //+ "\n\tMethod: " + Method + //+ "\n\tURL: " + URL + + "\n\tMessage: " + (Message != null ? Message.Length.ToString() : "NULL"); + } + + private string MakeHeader(ComposeOptions options) + { + string header = $"{Version} {(int)Number} {Text}\r\nServer: Esiur {Global.Version}\r\nDate: {DateTime.Now.ToUniversalTime().ToString("r")}\r\n"; + + if (options == ComposeOptions.AllCalculateLength) + Headers["Content-Length"] = Message?.Length.ToString() ?? "0"; + + foreach (var kv in Headers) + header += kv.Key + ": " + kv.Value + "\r\n"; + + + // Set-Cookie: ckGeneric=CookieBody; expires=Sun, 30-Dec-2007 21:00:00 GMT; path=/ + // Set-Cookie: ASPSESSIONIDQABBDSQA=IPDPMMMALDGFLMICEJIOCIPM; path=/ + + foreach (var Cookie in Cookies) + header += "Set-Cookie: " + Cookie.ToString() + "\r\n"; + + + header += "\r\n"; + + return header; + } + + + public bool Compose(ComposeOptions options) + { + List msg = new List(); + + if (options != ComposeOptions.DataOnly) + { + msg.AddRange(Encoding.UTF8.GetBytes(MakeHeader(options))); } - private string MakeHeader(ComposeOptions options) + if (options != ComposeOptions.SpecifiedHeadersOnly) { - string header = $"{Version} {(int)Number} {Text}\r\nServer: Esiur {Global.Version}\r\nDate: {DateTime.Now.ToUniversalTime().ToString("r")}\r\n"; - - if (options == ComposeOptions.AllCalculateLength) - Headers["Content-Length"] = Message?.Length.ToString() ?? "0"; - - foreach (var kv in Headers) - header += kv.Key + ": " + kv.Value + "\r\n"; - - - // Set-Cookie: ckGeneric=CookieBody; expires=Sun, 30-Dec-2007 21:00:00 GMT; path=/ - // Set-Cookie: ASPSESSIONIDQABBDSQA=IPDPMMMALDGFLMICEJIOCIPM; path=/ - - foreach (var Cookie in Cookies) - header += "Set-Cookie: " + Cookie.ToString() + "\r\n"; - - - header += "\r\n"; - - return header; + if (Message != null) + msg.AddRange(Message); } + Data = msg.ToArray(); - public bool Compose(ComposeOptions options) + return true; + } + + public override bool Compose() + { + return Compose(ComposeOptions.AllDontCalculateLength); + } + + public override long Parse(byte[] data, uint offset, uint ends) + { + string[] sMethod = null; + string[] sLines = null; + + uint headerSize = 0; + + for (uint i = offset; i < ends - 3; i++) { - List msg = new List(); - - if (options != ComposeOptions.DataOnly) + if (data[i] == '\r' && data[i + 1] == '\n' + && data[i + 2] == '\r' && data[i + 3] == '\n') { - msg.AddRange(Encoding.UTF8.GetBytes(MakeHeader(options))); - } + sLines = Encoding.ASCII.GetString(data, (int)offset, (int)(i - offset)).Split(new string[] { "\r\n" }, + StringSplitOptions.None); - if (options != ComposeOptions.SpecifiedHeadersOnly) - { - if (Message != null) - msg.AddRange(Message); + headerSize = i + 4; + break; } - - Data = msg.ToArray(); - - return true; } - public override bool Compose() + if (headerSize == 0) + return -1; + + //Cookies = new DStringDictionary(); + //Headers = new DStringDictionary(true); + + sMethod = sLines[0].Split(' '); + + if (sMethod.Length == 3) { - return Compose(ComposeOptions.AllDontCalculateLength); + Version = sMethod[0].Trim(); + Number = (ResponseCode)(Convert.ToInt32(sMethod[1].Trim())); + Text = sMethod[2]; } - public override long Parse(byte[] data, uint offset, uint ends) + // Read all headers + + for (int i = 1; i < sLines.Length; i++) { - string[] sMethod = null; - string[] sLines = null; - - uint headerSize = 0; - - for (uint i = offset; i < ends - 3; i++) + if (sLines[i] == String.Empty) { - if (data[i] == '\r' && data[i + 1] == '\n' - && data[i + 2] == '\r' && data[i + 3] == '\n') - { - sLines = Encoding.ASCII.GetString(data, (int)offset, (int)(i - offset)).Split(new string[] { "\r\n" }, - StringSplitOptions.None); - - headerSize = i + 4; - break; - } + // Invalid header + return 0; } - if (headerSize == 0) - return -1; - - //Cookies = new DStringDictionary(); - //Headers = new DStringDictionary(true); - - sMethod = sLines[0].Split(' '); - - if (sMethod.Length == 3) + if (sLines[i].IndexOf(':') == -1) { - Version = sMethod[0].Trim(); - Number = (ResponseCode)(Convert.ToInt32(sMethod[1].Trim())); - Text = sMethod[2]; + // Invalid header + return 0; } - // Read all headers + string[] header = sLines[i].Split(new char[] { ':' }, 2); - for (int i = 1; i < sLines.Length; i++) + header[0] = header[0].ToLower(); + Headers[header[0]] = header[1].Trim(); + + //Set-Cookie: NAME=VALUE; expires=DATE; + + if (header[0] == "set-cookie") { - if (sLines[i] == String.Empty) + string[] cookie = header[1].Split(';'); + + if (cookie.Length >= 1) { - // Invalid header - return 0; - } + string[] splitCookie = cookie[0].Split('='); + HTTPCookie c = new HTTPCookie(splitCookie[0], splitCookie[1]); - if (sLines[i].IndexOf(':') == -1) - { - // Invalid header - return 0; - } - - string[] header = sLines[i].Split(new char[] { ':' }, 2); - - header[0] = header[0].ToLower(); - Headers[header[0]] = header[1].Trim(); - - //Set-Cookie: NAME=VALUE; expires=DATE; - - if (header[0] == "set-cookie") - { - string[] cookie = header[1].Split(';'); - - if (cookie.Length >= 1) + for (int j = 1; j < cookie.Length; j++) { - string[] splitCookie = cookie[0].Split('='); - HTTPCookie c = new HTTPCookie(splitCookie[0], splitCookie[1]); - - for (int j = 1; j < cookie.Length; j++) + splitCookie = cookie[j].Split('='); + switch (splitCookie[0].ToLower()) { - splitCookie = cookie[j].Split('='); - switch (splitCookie[0].ToLower()) - { - case "domain": - c.Domain = splitCookie[1]; - break; - case "path": - c.Path = splitCookie[1]; - break; - case "httponly": - c.HttpOnly = true; - break; - case "expires": - // Wed, 13-Jan-2021 22:23:01 GMT - c.Expires = DateTime.Parse(splitCookie[1]); - break; - } + case "domain": + c.Domain = splitCookie[1]; + break; + case "path": + c.Path = splitCookie[1]; + break; + case "httponly": + c.HttpOnly = true; + break; + case "expires": + // Wed, 13-Jan-2021 22:23:01 GMT + c.Expires = DateTime.Parse(splitCookie[1]); + break; } - } } + } + } - // Content-Length + // Content-Length - try + try + { + + uint contentLength = uint.Parse((string)Headers["content-length"]); + + // check limit + if (contentLength > data.Length - headerSize) { - - uint contentLength = uint.Parse((string)Headers["content-length"]); - - // check limit - if (contentLength > data.Length - headerSize) - { - return contentLength - (data.Length - headerSize); - } - - Message = DC.Clip(data, offset, contentLength); - - return headerSize + contentLength; - - } - catch - { - return 0; + return contentLength - (data.Length - headerSize); } + + Message = DC.Clip(data, offset, contentLength); + + return headerSize + contentLength; + + } + catch + { + return 0; } } } diff --git a/Esiur/Net/Packets/IIPAuthPacket.cs b/Esiur/Net/Packets/IIPAuthPacket.cs index bc1c72d..a53aa21 100644 --- a/Esiur/Net/Packets/IIPAuthPacket.cs +++ b/Esiur/Net/Packets/IIPAuthPacket.cs @@ -31,385 +31,384 @@ using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; -namespace Esiur.Net.Packets +namespace Esiur.Net.Packets; +class IIPAuthPacket : Packet { - class IIPAuthPacket : Packet + public enum IIPAuthPacketCommand : byte { - public enum IIPAuthPacketCommand : byte + Action = 0, + Declare, + Acknowledge, + Error, + } + + public enum IIPAuthPacketAction : byte + { + // Authenticate + AuthenticateHash, + + + //Challenge, + //CertificateRequest, + //CertificateReply, + //EstablishRequest, + //EstablishReply + + NewConnection = 0x20, + ResumeConnection, + + ConnectionEstablished = 0x28 + } + + + + + public IIPAuthPacketCommand Command + { + get; + set; + } + public IIPAuthPacketAction Action + { + get; + set; + } + + public byte ErrorCode { get; set; } + public string ErrorMessage { get; set; } + + public AuthenticationMethod LocalMethod + { + get; + set; + } + + public byte[] SourceInfo + { + get; + set; + } + + public byte[] Hash + { + get; + set; + } + + public byte[] SessionId + { + get; + set; + } + + public AuthenticationMethod RemoteMethod + { + get; + set; + } + + public string Domain + { + get; + set; + } + + public long CertificateId + { + get; set; + } + + public string LocalUsername + { + get; + set; + } + + public string RemoteUsername + { + get; + set; + } + + public byte[] LocalPassword + { + get; + set; + } + public byte[] RemotePassword + { + get; + set; + } + + public byte[] LocalToken + { + get; + set; + } + + public byte[] RemoteToken + { + get; + set; + } + + public byte[] AsymetricEncryptionKey + { + get; + set; + } + + public byte[] LocalNonce + { + get; + set; + } + + public byte[] RemoteNonce + { + get; + set; + } + + public ulong RemoteTokenIndex { get; set; } + + private uint dataLengthNeeded; + + bool NotEnough(uint offset, uint ends, uint needed) + { + if (offset + needed > ends) { - Action = 0, - Declare, - Acknowledge, - Error, + dataLengthNeeded = needed - (ends - offset); + return true; } + else + return false; + } - public enum IIPAuthPacketAction : byte + public override string ToString() + { + return Command.ToString() + " " + Action.ToString(); + } + + public override long Parse(byte[] data, uint offset, uint ends) + { + var oOffset = offset; + + if (NotEnough(offset, ends, 1)) + return -dataLengthNeeded; + + Command = (IIPAuthPacketCommand)(data[offset] >> 6); + + if (Command == IIPAuthPacketCommand.Action) { - // Authenticate - AuthenticateHash, + Action = (IIPAuthPacketAction)(data[offset++] & 0x3f); - - //Challenge, - //CertificateRequest, - //CertificateReply, - //EstablishRequest, - //EstablishReply - - NewConnection = 0x20, - ResumeConnection, - - ConnectionEstablished = 0x28 - } - - - - - public IIPAuthPacketCommand Command - { - get; - set; - } - public IIPAuthPacketAction Action - { - get; - set; - } - - public byte ErrorCode { get; set; } - public string ErrorMessage { get; set; } - - public AuthenticationMethod LocalMethod - { - get; - set; - } - - public byte[] SourceInfo - { - get; - set; - } - - public byte[] Hash - { - get; - set; - } - - public byte[] SessionId - { - get; - set; - } - - public AuthenticationMethod RemoteMethod - { - get; - set; - } - - public string Domain - { - get; - set; - } - - public long CertificateId - { - get; set; - } - - public string LocalUsername - { - get; - set; - } - - public string RemoteUsername - { - get; - set; - } - - public byte[] LocalPassword - { - get; - set; - } - public byte[] RemotePassword - { - get; - set; - } - - public byte[] LocalToken - { - get; - set; - } - - public byte[] RemoteToken - { - get; - set; - } - - public byte[] AsymetricEncryptionKey - { - get; - set; - } - - public byte[] LocalNonce - { - get; - set; - } - - public byte[] RemoteNonce - { - get; - set; - } - - public ulong RemoteTokenIndex { get; set; } - - private uint dataLengthNeeded; - - bool NotEnough(uint offset, uint ends, uint needed) - { - if (offset + needed > ends) + if (Action == IIPAuthPacketAction.AuthenticateHash) { - dataLengthNeeded = needed - (ends - offset); - return true; + if (NotEnough(offset, ends, 32)) + return -dataLengthNeeded; + + Hash = data.Clip(offset, 32); + + //var hash = new byte[32]; + //Buffer.BlockCopy(data, (int)offset, hash, 0, 32); + //Hash = hash; + + offset += 32; } - else - return false; - } + else if (Action == IIPAuthPacketAction.NewConnection) + { + if (NotEnough(offset, ends, 2)) + return -dataLengthNeeded; - public override string ToString() - { - return Command.ToString() + " " + Action.ToString(); - } + var length = data.GetUInt16(offset); - public override long Parse(byte[] data, uint offset, uint ends) + offset += 2; + + if (NotEnough(offset, ends, length)) + return -dataLengthNeeded; + + SourceInfo = data.Clip(offset, length); + + //var sourceInfo = new byte[length]; + //Buffer.BlockCopy(data, (int)offset, sourceInfo, 0, length); + //SourceInfo = sourceInfo; + + offset += 32; + } + else if (Action == IIPAuthPacketAction.ResumeConnection + || Action == IIPAuthPacketAction.ConnectionEstablished) + { + //var sessionId = new byte[32]; + + if (NotEnough(offset, ends, 32)) + return -dataLengthNeeded; + + SessionId = data.Clip(offset, 32); + + //Buffer.BlockCopy(data, (int)offset, sessionId, 0, 32); + //SessionId = sessionId; + + offset += 32; + } + } + else if (Command == IIPAuthPacketCommand.Declare) { - var oOffset = offset; + RemoteMethod = (AuthenticationMethod)((data[offset] >> 4) & 0x3); + LocalMethod = (AuthenticationMethod)((data[offset] >> 2) & 0x3); + var encrypt = ((data[offset++] & 0x2) == 0x2); + if (NotEnough(offset, ends, 1)) return -dataLengthNeeded; - Command = (IIPAuthPacketCommand)(data[offset] >> 6); + var domainLength = data[offset++]; + if (NotEnough(offset, ends, domainLength)) + return -dataLengthNeeded; - if (Command == IIPAuthPacketCommand.Action) + var domain = data.GetString(offset, domainLength); + + Domain = domain; + + offset += domainLength; + + + if (RemoteMethod == AuthenticationMethod.Credentials) { - Action = (IIPAuthPacketAction)(data[offset++] & 0x3f); - - if (Action == IIPAuthPacketAction.AuthenticateHash) + if (LocalMethod == AuthenticationMethod.None) { - if (NotEnough(offset, ends, 32)) + if (NotEnough(offset, ends, 33)) return -dataLengthNeeded; - Hash = data.Clip(offset, 32); + //var remoteNonce = new byte[32]; + //Buffer.BlockCopy(data, (int)offset, remoteNonce, 0, 32); + //RemoteNonce = remoteNonce; - //var hash = new byte[32]; - //Buffer.BlockCopy(data, (int)offset, hash, 0, 32); - //Hash = hash; + RemoteNonce = data.Clip(offset, 32); offset += 32; - } - else if (Action == IIPAuthPacketAction.NewConnection) - { - if (NotEnough(offset, ends, 2)) - return -dataLengthNeeded; - var length = data.GetUInt16(offset); - - offset += 2; + var length = data[offset++]; if (NotEnough(offset, ends, length)) return -dataLengthNeeded; - SourceInfo = data.Clip(offset, length); + RemoteUsername = data.GetString(offset, length); - //var sourceInfo = new byte[length]; - //Buffer.BlockCopy(data, (int)offset, sourceInfo, 0, length); - //SourceInfo = sourceInfo; + + offset += length; + } + } + else if (RemoteMethod == AuthenticationMethod.Token) + { + if (LocalMethod == AuthenticationMethod.None) + { + if (NotEnough(offset, ends, 37)) + return -dataLengthNeeded; + + RemoteNonce = data.Clip(offset, 32); offset += 32; - } - else if (Action == IIPAuthPacketAction.ResumeConnection - || Action == IIPAuthPacketAction.ConnectionEstablished) - { - //var sessionId = new byte[32]; + RemoteTokenIndex = data.GetUInt64(offset); + offset += 8; + } + } + + if (encrypt) + { + if (NotEnough(offset, ends, 2)) + return -dataLengthNeeded; + + var keyLength = data.GetUInt16(offset); + + offset += 2; + + if (NotEnough(offset, ends, keyLength)) + return -dataLengthNeeded; + + //var key = new byte[keyLength]; + //Buffer.BlockCopy(data, (int)offset, key, 0, keyLength); + //AsymetricEncryptionKey = key; + + AsymetricEncryptionKey = data.Clip(offset, keyLength); + + offset += keyLength; + } + } + else if (Command == IIPAuthPacketCommand.Acknowledge) + { + RemoteMethod = (AuthenticationMethod)((data[offset] >> 4) & 0x3); + LocalMethod = (AuthenticationMethod)((data[offset] >> 2) & 0x3); + var encrypt = ((data[offset++] & 0x2) == 0x2); + + if (RemoteMethod == AuthenticationMethod.None) + { + if (LocalMethod == AuthenticationMethod.None) + { + // do nothing + } + } + else if (RemoteMethod == AuthenticationMethod.Credentials + || RemoteMethod == AuthenticationMethod.Token) + { + if (LocalMethod == AuthenticationMethod.None) + { if (NotEnough(offset, ends, 32)) return -dataLengthNeeded; - SessionId = data.Clip(offset, 32); - - //Buffer.BlockCopy(data, (int)offset, sessionId, 0, 32); - //SessionId = sessionId; - + RemoteNonce = data.Clip(offset, 32); offset += 32; + } } - else if (Command == IIPAuthPacketCommand.Declare) + + if (encrypt) { - RemoteMethod = (AuthenticationMethod)((data[offset] >> 4) & 0x3); - LocalMethod = (AuthenticationMethod)((data[offset] >> 2) & 0x3); - var encrypt = ((data[offset++] & 0x2) == 0x2); - - - if (NotEnough(offset, ends, 1)) + if (NotEnough(offset, ends, 2)) return -dataLengthNeeded; - var domainLength = data[offset++]; - if (NotEnough(offset, ends, domainLength)) - return -dataLengthNeeded; + var keyLength = data.GetUInt16(offset); - var domain = data.GetString(offset, domainLength); - - Domain = domain; - - offset += domainLength; - - - if (RemoteMethod == AuthenticationMethod.Credentials) - { - if (LocalMethod == AuthenticationMethod.None) - { - if (NotEnough(offset, ends, 33)) - return -dataLengthNeeded; - - //var remoteNonce = new byte[32]; - //Buffer.BlockCopy(data, (int)offset, remoteNonce, 0, 32); - //RemoteNonce = remoteNonce; - - RemoteNonce = data.Clip(offset, 32); - - offset += 32; - - var length = data[offset++]; - - if (NotEnough(offset, ends, length)) - return -dataLengthNeeded; - - RemoteUsername = data.GetString(offset, length); - - - offset += length; - } - } - else if (RemoteMethod == AuthenticationMethod.Token) - { - if (LocalMethod == AuthenticationMethod.None) - { - if (NotEnough(offset, ends, 37)) - return -dataLengthNeeded; - - RemoteNonce = data.Clip(offset, 32); - - offset += 32; - - RemoteTokenIndex = data.GetUInt64(offset); - offset += 8; - } - } - - if (encrypt) - { - if (NotEnough(offset, ends, 2)) - return -dataLengthNeeded; - - var keyLength = data.GetUInt16(offset); - - offset += 2; - - if (NotEnough(offset, ends, keyLength)) - return -dataLengthNeeded; - - //var key = new byte[keyLength]; - //Buffer.BlockCopy(data, (int)offset, key, 0, keyLength); - //AsymetricEncryptionKey = key; - - AsymetricEncryptionKey = data.Clip(offset, keyLength); - - offset += keyLength; - } - } - else if (Command == IIPAuthPacketCommand.Acknowledge) - { - RemoteMethod = (AuthenticationMethod)((data[offset] >> 4) & 0x3); - LocalMethod = (AuthenticationMethod)((data[offset] >> 2) & 0x3); - var encrypt = ((data[offset++] & 0x2) == 0x2); - - if (RemoteMethod == AuthenticationMethod.None) - { - if (LocalMethod == AuthenticationMethod.None) - { - // do nothing - } - } - else if (RemoteMethod == AuthenticationMethod.Credentials - || RemoteMethod == AuthenticationMethod.Token) - { - if (LocalMethod == AuthenticationMethod.None) - { - if (NotEnough(offset, ends, 32)) - return -dataLengthNeeded; - - RemoteNonce = data.Clip(offset, 32); - offset += 32; - - } - } - - if (encrypt) - { - if (NotEnough(offset, ends, 2)) - return -dataLengthNeeded; - - var keyLength = data.GetUInt16(offset); - - offset += 2; - - if (NotEnough(offset, ends, keyLength)) - return -dataLengthNeeded; - - //var key = new byte[keyLength]; - //Buffer.BlockCopy(data, (int)offset, key, 0, keyLength); - //AsymetricEncryptionKey = key; - - AsymetricEncryptionKey = data.Clip(offset, keyLength); - - offset += keyLength; - } - } - else if (Command == IIPAuthPacketCommand.Error) - { - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; - - offset++; - ErrorCode = data[offset++]; - - - var cl = data.GetUInt16(offset); offset += 2; - if (NotEnough(offset, ends, cl)) + if (NotEnough(offset, ends, keyLength)) return -dataLengthNeeded; - ErrorMessage = data.GetString(offset, cl); - offset += cl; + //var key = new byte[keyLength]; + //Buffer.BlockCopy(data, (int)offset, key, 0, keyLength); + //AsymetricEncryptionKey = key; + AsymetricEncryptionKey = data.Clip(offset, keyLength); + + offset += keyLength; } + } + else if (Command == IIPAuthPacketCommand.Error) + { + if (NotEnough(offset, ends, 4)) + return -dataLengthNeeded; + + offset++; + ErrorCode = data[offset++]; - return offset - oOffset; + var cl = data.GetUInt16(offset); + offset += 2; + + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; + + ErrorMessage = data.GetString(offset, cl); + offset += cl; } + + return offset - oOffset; + } + } + diff --git a/Esiur/Net/Packets/IIPPacket.cs b/Esiur/Net/Packets/IIPPacket.cs index 7f3c9c3..8890206 100644 --- a/Esiur/Net/Packets/IIPPacket.cs +++ b/Esiur/Net/Packets/IIPPacket.cs @@ -32,328 +32,559 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Net.Packets +namespace Esiur.Net.Packets; +class IIPPacket : Packet { - class IIPPacket : Packet + + public override string ToString() { + var rt = Command.ToString(); - public override string ToString() + if (Command == IIPPacketCommand.Event) { - var rt = Command.ToString(); - - if (Command == IIPPacketCommand.Event) + rt += " " + Event.ToString(); + //if (Event == IIPPacketEvent.AttributesUpdated) + // rt += + } + else if (Command == IIPPacketCommand.Request) + { + rt += " " + Action.ToString(); + if (Action == IIPPacketAction.AttachResource) { - rt += " " + Event.ToString(); - //if (Event == IIPPacketEvent.AttributesUpdated) - // rt += + rt += " CID: " + CallbackId + " RID: " + ResourceId; } - else if (Command == IIPPacketCommand.Request) - { - rt += " " + Action.ToString(); - if (Action == IIPPacketAction.AttachResource) - { - rt += " CID: " + CallbackId + " RID: " + ResourceId; - } - } - else if (Command == IIPPacketCommand.Reply) - rt += " " + Action.ToString(); - else if (Command == IIPPacketCommand.Report) - rt += " " + Report.ToString(); - - return rt; } + else if (Command == IIPPacketCommand.Reply) + rt += " " + Action.ToString(); + else if (Command == IIPPacketCommand.Report) + rt += " " + Report.ToString(); - public enum IIPPacketCommand : byte + return rt; + } + + public enum IIPPacketCommand : byte + { + Event = 0, + Request, + Reply, + Report, + } + + public enum IIPPacketEvent : byte + { + // Event Manage + ResourceReassigned = 0, + ResourceDestroyed, + ChildAdded, + ChildRemoved, + Renamed, + // Event Invoke + PropertyUpdated = 0x10, + EventOccurred, + + // Attribute + AttributesUpdated = 0x18 + } + + public enum IIPPacketAction : byte + { + // Request Manage + AttachResource = 0, + ReattachResource, + DetachResource, + CreateResource, + DeleteResource, + AddChild, + RemoveChild, + RenameResource, + + // Request Inquire + TemplateFromClassName = 0x8, + TemplateFromClassId, + TemplateFromResourceId, + QueryLink, + ResourceHistory, + ResourceChildren, + ResourceParents, + LinkTemplates, + + // Request Invoke + InvokeFunctionArrayArguments = 0x10, + InvokeFunctionNamedArguments, + Listen, + Unlisten, + SetProperty, + + // Request Attribute + GetAllAttributes = 0x18, + UpdateAllAttributes, + ClearAllAttributes, + GetAttributes, + UpdateAttributes, + ClearAttributes + } + + public enum IIPPacketReport : byte + { + ManagementError, + ExecutionError, + ProgressReport = 0x8, + ChunkStream = 0x9 + } + + + public IIPPacketReport Report + { + get; + set; + } + + public IIPPacketCommand Command + { + get; + set; + } + public IIPPacketAction Action + { + get; + set; + } + + public IIPPacketEvent Event + { + get; + set; + } + + public IIPPacketCommand PreviousCommand + { + get; + set; + } + public IIPPacketAction PreviousAction + { + get; + set; + } + + public IIPPacketEvent PreviousEvent + { + get; + set; + } + + + public uint ResourceId { get; set; } + public uint NewResourceId { get; set; } + //public uint ParentId { get; set; } + public uint ChildId { get; set; } + public uint StoreId { get; set; } + + public ulong ResourceAge { get; set; } + public byte[] Content { get; set; } + public ushort ErrorCode { get; set; } + public string ErrorMessage { get; set; } + public string ClassName { get; set; } + public string ResourceLink { get; set; } + public Guid ClassId { get; set; } + public byte MethodIndex { get; set; } + public string MethodName { get; set; } + public uint CallbackId { get; set; } + public int ProgressValue { get; set; } + public int ProgressMax { get; set; } + public DateTime FromDate { get; set; } + public DateTime ToDate { get; set; } + public ulong FromAge { get; set; } + public ulong ToAge { get; set; } + + private uint dataLengthNeeded; + private uint originalOffset; + + public override bool Compose() + { + return base.Compose(); + } + + bool NotEnough(uint offset, uint ends, uint needed) + { + if (offset + needed > ends) { - Event = 0, - Request, - Reply, - Report, + dataLengthNeeded = needed - (ends - offset); + //dataLengthNeeded = needed - (ends - originalOffset); + + return true; } + else + return false; + } - public enum IIPPacketEvent : byte + public override long Parse(byte[] data, uint offset, uint ends) + { + originalOffset = offset; + + if (NotEnough(offset, ends, 1)) + return -dataLengthNeeded; + + PreviousCommand = Command; + + Command = (IIPPacketCommand)(data[offset] >> 6); + + if (Command == IIPPacketCommand.Event) { - // Event Manage - ResourceReassigned = 0, - ResourceDestroyed, - ChildAdded, - ChildRemoved, - Renamed, - // Event Invoke - PropertyUpdated = 0x10, - EventOccurred, + Event = (IIPPacketEvent)(data[offset++] & 0x3f); - // Attribute - AttributesUpdated = 0x18 - } - - public enum IIPPacketAction : byte - { - // Request Manage - AttachResource = 0, - ReattachResource, - DetachResource, - CreateResource, - DeleteResource, - AddChild, - RemoveChild, - RenameResource, - - // Request Inquire - TemplateFromClassName = 0x8, - TemplateFromClassId, - TemplateFromResourceId, - QueryLink, - ResourceHistory, - ResourceChildren, - ResourceParents, - LinkTemplates, - - // Request Invoke - InvokeFunctionArrayArguments = 0x10, - InvokeFunctionNamedArguments, - Listen, - Unlisten, - SetProperty, - - // Request Attribute - GetAllAttributes = 0x18, - UpdateAllAttributes, - ClearAllAttributes, - GetAttributes, - UpdateAttributes, - ClearAttributes - } - - public enum IIPPacketReport : byte - { - ManagementError, - ExecutionError, - ProgressReport = 0x8, - ChunkStream = 0x9 - } - - - public IIPPacketReport Report - { - get; - set; - } - - public IIPPacketCommand Command - { - get; - set; - } - public IIPPacketAction Action - { - get; - set; - } - - public IIPPacketEvent Event - { - get; - set; - } - - public IIPPacketCommand PreviousCommand - { - get; - set; - } - public IIPPacketAction PreviousAction - { - get; - set; - } - - public IIPPacketEvent PreviousEvent - { - get; - set; - } - - - public uint ResourceId { get; set; } - public uint NewResourceId { get; set; } - //public uint ParentId { get; set; } - public uint ChildId { get; set; } - public uint StoreId { get; set; } - - public ulong ResourceAge { get; set; } - public byte[] Content { get; set; } - public ushort ErrorCode { get; set; } - public string ErrorMessage { get; set; } - public string ClassName { get; set; } - public string ResourceLink { get; set; } - public Guid ClassId { get; set; } - public byte MethodIndex { get; set; } - public string MethodName { get; set; } - public uint CallbackId { get; set; } - public int ProgressValue { get; set; } - public int ProgressMax { get; set; } - public DateTime FromDate { get; set; } - public DateTime ToDate { get; set; } - public ulong FromAge { get; set; } - public ulong ToAge { get; set; } - - private uint dataLengthNeeded; - private uint originalOffset; - - public override bool Compose() - { - return base.Compose(); - } - - bool NotEnough(uint offset, uint ends, uint needed) - { - if (offset + needed > ends) - { - dataLengthNeeded = needed - (ends - offset); - //dataLengthNeeded = needed - (ends - originalOffset); - - return true; - } - else - return false; - } - - public override long Parse(byte[] data, uint offset, uint ends) - { - originalOffset = offset; - - if (NotEnough(offset, ends, 1)) + if (NotEnough(offset, ends, 4)) return -dataLengthNeeded; - PreviousCommand = Command; + ResourceId = data.GetUInt32(offset); + offset += 4; + } + else if (Command == IIPPacketCommand.Report) + { + Report = (IIPPacketReport)(data[offset++] & 0x3f); - Command = (IIPPacketCommand)(data[offset] >> 6); + if (NotEnough(offset, ends, 4)) + return -dataLengthNeeded; - if (Command == IIPPacketCommand.Event) + CallbackId = data.GetUInt32(offset); + offset += 4; + } + else + { + PreviousAction = Action; + Action = (IIPPacketAction)(data[offset++] & 0x3f); + + if (NotEnough(offset, ends, 4)) + return -dataLengthNeeded; + + CallbackId = data.GetUInt32(offset); + offset += 4; + } + + if (Command == IIPPacketCommand.Event) + { + if (Event == IIPPacketEvent.ResourceReassigned) { - Event = (IIPPacketEvent)(data[offset++] & 0x3f); + if (NotEnough(offset, ends, 4)) + return -dataLengthNeeded; + NewResourceId = data.GetUInt32(offset); + offset += 4; + + } + else if (Event == IIPPacketEvent.ResourceDestroyed) + { + // nothing to parse + } + else if (Event == IIPPacketEvent.ChildAdded + || Event == IIPPacketEvent.ChildRemoved) + { + if (NotEnough(offset, ends, 4)) + return -dataLengthNeeded; + + ChildId = data.GetUInt32(offset); + offset += 4; + } + else if (Event == IIPPacketEvent.Renamed) + { + if (NotEnough(offset, ends, 2)) + return -dataLengthNeeded; + + var cl = data.GetUInt16(offset); + offset += 2; + + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; + + Content = data.Clip(offset, cl); + + offset += cl; + } + else if (Event == IIPPacketEvent.PropertyUpdated + || Event == IIPPacketEvent.EventOccurred) + { + if (NotEnough(offset, ends, 2)) + return -dataLengthNeeded; + + MethodIndex = data[offset++]; + + var dt = (DataType)data[offset++]; + var size = dt.Size();// Codec.SizeOf(dt); + + if (size < 0) + { + if (NotEnough(offset, ends, 4)) + return -dataLengthNeeded; + + var cl = data.GetUInt32(offset); + offset += 4; + + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; + + Content = data.Clip(offset - 5, cl + 5); + offset += cl; + } + else + { + if (NotEnough(offset, ends, (uint)size)) + return -dataLengthNeeded; + + Content = data.Clip(offset - 1, (uint)size + 1); + offset += (uint)size; + } + } + //else if (Event == IIPPacketEvent.EventOccurred) + //{ + // if (NotEnough(offset, ends, 5)) + // return -dataLengthNeeded; + + // MethodIndex = data[offset++]; + + // var cl = data.GetUInt32(offset); + // offset += 4; + + // if (NotEnough(offset, ends, cl)) + // return -dataLengthNeeded; + + // Content = data.Clip(offset, cl); + // offset += cl; + + //} + // Attribute + else if (Event == IIPPacketEvent.AttributesUpdated) + { + if (NotEnough(offset, ends, 4)) + return -dataLengthNeeded; + + var cl = data.GetUInt32(offset); + offset += 4; + + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; + + Content = data.Clip(offset, cl); + + offset += cl; + } + } + else if (Command == IIPPacketCommand.Request) + { + if (Action == IIPPacketAction.AttachResource) + { if (NotEnough(offset, ends, 4)) return -dataLengthNeeded; ResourceId = data.GetUInt32(offset); offset += 4; } - else if (Command == IIPPacketCommand.Report) + else if (Action == IIPPacketAction.ReattachResource) { - Report = (IIPPacketReport)(data[offset++] & 0x3f); + if (NotEnough(offset, ends, 12)) + return -dataLengthNeeded; + ResourceId = data.GetUInt32(offset); + offset += 4; + + ResourceAge = data.GetUInt64(offset); + offset += 8; + + } + else if (Action == IIPPacketAction.DetachResource) + { if (NotEnough(offset, ends, 4)) return -dataLengthNeeded; - CallbackId = data.GetUInt32(offset); + ResourceId = data.GetUInt32(offset); offset += 4; - } - else - { - PreviousAction = Action; - Action = (IIPPacketAction)(data[offset++] & 0x3f); + } + else if (Action == IIPPacketAction.CreateResource) + { + if (NotEnough(offset, ends, 12)) + return -dataLengthNeeded; + + StoreId = data.GetUInt32(offset); + offset += 4; + ResourceId = data.GetUInt32(offset); + offset += 4; + + var cl = data.GetUInt32(offset); + offset += 4; + + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; + + this.Content = data.Clip(offset, cl); + } + else if (Action == IIPPacketAction.DeleteResource) + { if (NotEnough(offset, ends, 4)) return -dataLengthNeeded; - CallbackId = data.GetUInt32(offset); + ResourceId = data.GetUInt32(offset); + offset += 4; + + } + else if (Action == IIPPacketAction.AddChild + || Action == IIPPacketAction.RemoveChild) + { + if (NotEnough(offset, ends, 8)) + return -dataLengthNeeded; + + ResourceId = data.GetUInt32(offset); + offset += 4; + ChildId = data.GetUInt32(offset); offset += 4; } - - if (Command == IIPPacketCommand.Event) + else if (Action == IIPPacketAction.RenameResource) { - if (Event == IIPPacketEvent.ResourceReassigned) - { - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; + if (NotEnough(offset, ends, 6)) + return -dataLengthNeeded; - NewResourceId = data.GetUInt32(offset); - offset += 4; + ResourceId = data.GetUInt32(offset); + offset += 4; + var cl = data.GetUInt16(offset); + offset += 2; - } - else if (Event == IIPPacketEvent.ResourceDestroyed) - { - // nothing to parse - } - else if (Event == IIPPacketEvent.ChildAdded - || Event == IIPPacketEvent.ChildRemoved) - { - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; - ChildId = data.GetUInt32(offset); - offset += 4; - } - else if (Event == IIPPacketEvent.Renamed) - { - if (NotEnough(offset, ends, 2)) - return -dataLengthNeeded; + Content = data.Clip(offset, cl); + offset += cl; + } + else if (Action == IIPPacketAction.TemplateFromClassName) + { + if (NotEnough(offset, ends, 1)) + return -dataLengthNeeded; - var cl = data.GetUInt16(offset); - offset += 2; + var cl = data[offset++]; - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; - Content = data.Clip(offset, cl); + ClassName = data.GetString(offset, cl); + offset += cl; - offset += cl; - } - else if (Event == IIPPacketEvent.PropertyUpdated - || Event == IIPPacketEvent.EventOccurred) - { - if (NotEnough(offset, ends, 2)) - return -dataLengthNeeded; + } + else if (Action == IIPPacketAction.TemplateFromClassId) + { + if (NotEnough(offset, ends, 16)) + return -dataLengthNeeded; - MethodIndex = data[offset++]; + ClassId = data.GetGuid(offset); + offset += 16; - var dt = (DataType)data[offset++]; - var size = dt.Size();// Codec.SizeOf(dt); + } + else if (Action == IIPPacketAction.TemplateFromResourceId) + { + if (NotEnough(offset, ends, 4)) + return -dataLengthNeeded; - if (size < 0) - { - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; + ResourceId = data.GetUInt32(offset); + offset += 4; + } + else if (Action == IIPPacketAction.QueryLink + || Action == IIPPacketAction.LinkTemplates) + { + if (NotEnough(offset, ends, 2)) + return -dataLengthNeeded; - var cl = data.GetUInt32(offset); - offset += 4; + var cl = data.GetUInt16(offset); + offset += 2; - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; - Content = data.Clip(offset - 5, cl + 5); - offset += cl; - } - else - { - if (NotEnough(offset, ends, (uint)size)) - return -dataLengthNeeded; + ResourceLink = data.GetString(offset, cl); + offset += cl; + } + else if (Action == IIPPacketAction.ResourceChildren + || Action == IIPPacketAction.ResourceParents) + { + if (NotEnough(offset, ends, 4)) + return -dataLengthNeeded; - Content = data.Clip(offset - 1, (uint)size + 1); - offset += (uint)size; - } - } - //else if (Event == IIPPacketEvent.EventOccurred) - //{ - // if (NotEnough(offset, ends, 5)) - // return -dataLengthNeeded; + ResourceId = data.GetUInt32(offset); + offset += 4; + } + else if (Action == IIPPacketAction.ResourceHistory) + { + if (NotEnough(offset, ends, 20)) + return -dataLengthNeeded; - // MethodIndex = data[offset++]; + ResourceId = data.GetUInt32(offset); + offset += 4; - // var cl = data.GetUInt32(offset); - // offset += 4; + FromDate = data.GetDateTime(offset); + offset += 8; - // if (NotEnough(offset, ends, cl)) - // return -dataLengthNeeded; + ToDate = data.GetDateTime(offset); + offset += 8; - // Content = data.Clip(offset, cl); - // offset += cl; + } + else if (Action == IIPPacketAction.InvokeFunctionArrayArguments + || Action == IIPPacketAction.InvokeFunctionNamedArguments) + { + if (NotEnough(offset, ends, 9)) + return -dataLengthNeeded; - //} - // Attribute - else if (Event == IIPPacketEvent.AttributesUpdated) + ResourceId = data.GetUInt32(offset); + offset += 4; + + MethodIndex = data[offset++]; + + var cl = data.GetUInt32(offset); + offset += 4; + + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; + + Content = data.Clip(offset, cl); + offset += cl; + + } + else if (Action == IIPPacketAction.Listen + || Action == IIPPacketAction.Unlisten)// .GetProperty) + { + if (NotEnough(offset, ends, 5)) + return -dataLengthNeeded; + + ResourceId = data.GetUInt32(offset); + offset += 4; + + MethodIndex = data[offset++]; + + } + //else if (Action == IIPPacketAction.GetPropertyIfModified) + //{ + // if (NotEnough(offset, ends, 9)) + // return -dataLengthNeeded; + + // ResourceId = data.GetUInt32(offset); + // offset += 4; + + // MethodIndex = data[offset++]; + + // ResourceAge = data.GetUInt64(offset); + // offset += 8; + + //} + else if (Action == IIPPacketAction.SetProperty) + { + if (NotEnough(offset, ends, 6)) + return -dataLengthNeeded; + + ResourceId = data.GetUInt32(offset); + offset += 4; + + MethodIndex = data[offset++]; + + + var dt = (DataType)data[offset++]; + var size = dt.Size();// Codec.SizeOf(dt); + + if (size < 0) { if (NotEnough(offset, ends, 4)) return -dataLengthNeeded; @@ -364,467 +595,234 @@ namespace Esiur.Net.Packets if (NotEnough(offset, ends, cl)) return -dataLengthNeeded; - Content = data.Clip(offset, cl); - + Content = data.Clip(offset - 5, cl + 5); offset += cl; } + else + { + if (NotEnough(offset, ends, (uint)size)) + return -dataLengthNeeded; + + Content = data.Clip(offset - 1, (uint)size + 1); + offset += (uint)size; + } } - else if (Command == IIPPacketCommand.Request) + // Attributes + else if (Action == IIPPacketAction.UpdateAllAttributes + || Action == IIPPacketAction.GetAttributes + || Action == IIPPacketAction.UpdateAttributes + || Action == IIPPacketAction.ClearAttributes) { - if (Action == IIPPacketAction.AttachResource) - { - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; + if (NotEnough(offset, ends, 8)) + return -dataLengthNeeded; - ResourceId = data.GetUInt32(offset); - offset += 4; - } - else if (Action == IIPPacketAction.ReattachResource) - { - if (NotEnough(offset, ends, 12)) - return -dataLengthNeeded; + ResourceId = data.GetUInt32(offset); + offset += 4; + var cl = data.GetUInt32(offset); + offset += 4; - ResourceId = data.GetUInt32(offset); - offset += 4; + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; - ResourceAge = data.GetUInt64(offset); - offset += 8; - - } - else if (Action == IIPPacketAction.DetachResource) - { - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; - - ResourceId = data.GetUInt32(offset); - offset += 4; - - } - else if (Action == IIPPacketAction.CreateResource) - { - if (NotEnough(offset, ends, 12)) - return -dataLengthNeeded; - - StoreId = data.GetUInt32(offset); - offset += 4; - ResourceId = data.GetUInt32(offset); - offset += 4; - - var cl = data.GetUInt32(offset); - offset += 4; - - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; - - this.Content = data.Clip(offset, cl); - } - else if (Action == IIPPacketAction.DeleteResource) - { - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; - - ResourceId = data.GetUInt32(offset); - offset += 4; - - } - else if (Action == IIPPacketAction.AddChild - || Action == IIPPacketAction.RemoveChild) - { - if (NotEnough(offset, ends, 8)) - return -dataLengthNeeded; - - ResourceId = data.GetUInt32(offset); - offset += 4; - ChildId = data.GetUInt32(offset); - offset += 4; - } - else if (Action == IIPPacketAction.RenameResource) - { - if (NotEnough(offset, ends, 6)) - return -dataLengthNeeded; - - ResourceId = data.GetUInt32(offset); - offset += 4; - var cl = data.GetUInt16(offset); - offset += 2; - - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; - - Content = data.Clip(offset, cl); - offset += cl; - } - else if (Action == IIPPacketAction.TemplateFromClassName) - { - if (NotEnough(offset, ends, 1)) - return -dataLengthNeeded; - - var cl = data[offset++]; - - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; - - ClassName = data.GetString(offset, cl); - offset += cl; - - } - else if (Action == IIPPacketAction.TemplateFromClassId) - { - if (NotEnough(offset, ends, 16)) - return -dataLengthNeeded; - - ClassId = data.GetGuid(offset); - offset += 16; - - } - else if (Action == IIPPacketAction.TemplateFromResourceId) - { - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; - - ResourceId = data.GetUInt32(offset); - offset += 4; - } - else if (Action == IIPPacketAction.QueryLink - || Action == IIPPacketAction.LinkTemplates) - { - if (NotEnough(offset, ends, 2)) - return -dataLengthNeeded; - - var cl = data.GetUInt16(offset); - offset += 2; - - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; - - ResourceLink = data.GetString(offset, cl); - offset += cl; - } - else if (Action == IIPPacketAction.ResourceChildren - || Action == IIPPacketAction.ResourceParents) - { - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; - - ResourceId = data.GetUInt32(offset); - offset += 4; - } - else if (Action == IIPPacketAction.ResourceHistory) - { - if (NotEnough(offset, ends, 20)) - return -dataLengthNeeded; - - ResourceId = data.GetUInt32(offset); - offset += 4; - - FromDate = data.GetDateTime(offset); - offset += 8; - - ToDate = data.GetDateTime(offset); - offset += 8; - - } - else if (Action == IIPPacketAction.InvokeFunctionArrayArguments - || Action == IIPPacketAction.InvokeFunctionNamedArguments) - { - if (NotEnough(offset, ends, 9)) - return -dataLengthNeeded; - - ResourceId = data.GetUInt32(offset); - offset += 4; - - MethodIndex = data[offset++]; - - var cl = data.GetUInt32(offset); - offset += 4; - - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; - - Content = data.Clip(offset, cl); - offset += cl; - - } - else if (Action == IIPPacketAction.Listen - || Action == IIPPacketAction.Unlisten)// .GetProperty) - { - if (NotEnough(offset, ends, 5)) - return -dataLengthNeeded; - - ResourceId = data.GetUInt32(offset); - offset += 4; - - MethodIndex = data[offset++]; - - } - //else if (Action == IIPPacketAction.GetPropertyIfModified) - //{ - // if (NotEnough(offset, ends, 9)) - // return -dataLengthNeeded; - - // ResourceId = data.GetUInt32(offset); - // offset += 4; - - // MethodIndex = data[offset++]; - - // ResourceAge = data.GetUInt64(offset); - // offset += 8; - - //} - else if (Action == IIPPacketAction.SetProperty) - { - if (NotEnough(offset, ends, 6)) - return -dataLengthNeeded; - - ResourceId = data.GetUInt32(offset); - offset += 4; - - MethodIndex = data[offset++]; - - - var dt = (DataType)data[offset++]; - var size = dt.Size();// Codec.SizeOf(dt); - - if (size < 0) - { - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; - - var cl = data.GetUInt32(offset); - offset += 4; - - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; - - Content = data.Clip(offset - 5, cl + 5); - offset += cl; - } - else - { - if (NotEnough(offset, ends, (uint)size)) - return -dataLengthNeeded; - - Content = data.Clip(offset - 1, (uint)size + 1); - offset += (uint)size; - } - } - // Attributes - else if (Action == IIPPacketAction.UpdateAllAttributes - || Action == IIPPacketAction.GetAttributes - || Action == IIPPacketAction.UpdateAttributes - || Action == IIPPacketAction.ClearAttributes) - { - if (NotEnough(offset, ends, 8)) - return -dataLengthNeeded; - - ResourceId = data.GetUInt32(offset); - offset += 4; - var cl = data.GetUInt32(offset); - offset += 4; - - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; - - Content = data.Clip(offset, cl); - offset += cl; - } + Content = data.Clip(offset, cl); + offset += cl; } - else if (Command == IIPPacketCommand.Reply) - { - if (Action == IIPPacketAction.AttachResource - || Action == IIPPacketAction.ReattachResource) - { - - if (NotEnough(offset, ends, 26)) - return -dataLengthNeeded; - - ClassId = data.GetGuid(offset); - offset += 16; - - ResourceAge = data.GetUInt64(offset); - offset += 8; - - uint cl = data.GetUInt16(offset); - offset += 2; - - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; - - ResourceLink = data.GetString(offset, cl); - offset += cl; - - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; - - cl = data.GetUInt32(offset); - offset += 4; - - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; - - Content = data.Clip(offset, cl); - offset += cl; - } - else if (Action == IIPPacketAction.DetachResource) - { - // nothing to do - } - else if (Action == IIPPacketAction.CreateResource) - { - if (NotEnough(offset, ends, 20)) - return -dataLengthNeeded; - - //ClassId = data.GetGuid(offset); - //offset += 16; - - ResourceId = data.GetUInt32(offset); - offset += 4; - - } - else if (Action == IIPPacketAction.DetachResource) - { - // nothing to do - } - // Inquire - else if (Action == IIPPacketAction.TemplateFromClassName - || Action == IIPPacketAction.TemplateFromClassId - || Action == IIPPacketAction.TemplateFromResourceId - || Action == IIPPacketAction.QueryLink - || Action == IIPPacketAction.ResourceChildren - || Action == IIPPacketAction.ResourceParents - || Action == IIPPacketAction.ResourceHistory - || Action == IIPPacketAction.LinkTemplates - // Attribute - || Action == IIPPacketAction.GetAllAttributes - || Action == IIPPacketAction.GetAttributes) - { - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; - - var cl = data.GetUInt32(offset); - offset += 4; - - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; - - Content = data.Clip(offset, cl); - offset += cl; - } - else if (Action == IIPPacketAction.InvokeFunctionArrayArguments - || Action == IIPPacketAction.InvokeFunctionNamedArguments) - //|| Action == IIPPacketAction.GetProperty - //|| Action == IIPPacketAction.GetPropertyIfModified) - { - if (NotEnough(offset, ends, 1)) - return -dataLengthNeeded; - - var dt = (DataType)data[offset++]; - var size = dt.Size();// Codec.SizeOf(dt); - - if (size < 0) - { - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; - - var cl = data.GetUInt32(offset); - offset += 4; - - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; - - Content = data.Clip(offset - 5, cl + 5); - offset += cl; - } - else - { - if (NotEnough(offset, ends, (uint)size)) - return -dataLengthNeeded; - - Content = data.Clip(offset - 1, (uint)size + 1); - offset += (uint)size; - } - } - else if (Action == IIPPacketAction.SetProperty - || Action == IIPPacketAction.Listen - || Action == IIPPacketAction.Unlisten) - { - // nothing to do - } - } - else if (Command == IIPPacketCommand.Report) - { - if (Report == IIPPacketReport.ManagementError) - { - if (NotEnough(offset, ends, 2)) - return -dataLengthNeeded; - - ErrorCode = data.GetUInt16(offset); - offset += 2; - } - else if (Report == IIPPacketReport.ExecutionError) - { - if (NotEnough(offset, ends, 2)) - return -dataLengthNeeded; - - ErrorCode = data.GetUInt16(offset); - offset += 2; - - if (NotEnough(offset, ends, 2)) - return -dataLengthNeeded; - - var cl = data.GetUInt16(offset); - offset += 2; - - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; - - ErrorMessage = data.GetString(offset, cl); - offset += cl; - } - else if (Report == IIPPacketReport.ProgressReport) - { - if (NotEnough(offset, ends, 8)) - return -dataLengthNeeded; - - ProgressValue = data.GetInt32(offset); - offset += 4; - ProgressMax = data.GetInt32(offset); - offset += 4; - } - else if (Report == IIPPacketReport.ChunkStream) - { - if (NotEnough(offset, ends, 1)) - return -dataLengthNeeded; - - var dt = (DataType)data[offset++]; - var size = dt.Size();// Codec.SizeOf(dt); - - if (size < 0) - { - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; - - var cl = data.GetUInt32(offset); - offset += 4; - - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; - - Content = data.Clip(offset - 5, cl + 5); - offset += cl; - } - else - { - if (NotEnough(offset, ends, (uint)size)) - return -dataLengthNeeded; - - Content = data.Clip(offset - 1, (uint)size + 1); - offset += (uint)size; - } - } - } - - return offset - originalOffset; } + else if (Command == IIPPacketCommand.Reply) + { + if (Action == IIPPacketAction.AttachResource + || Action == IIPPacketAction.ReattachResource) + { + + if (NotEnough(offset, ends, 26)) + return -dataLengthNeeded; + + ClassId = data.GetGuid(offset); + offset += 16; + + ResourceAge = data.GetUInt64(offset); + offset += 8; + + uint cl = data.GetUInt16(offset); + offset += 2; + + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; + + ResourceLink = data.GetString(offset, cl); + offset += cl; + + if (NotEnough(offset, ends, 4)) + return -dataLengthNeeded; + + cl = data.GetUInt32(offset); + offset += 4; + + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; + + Content = data.Clip(offset, cl); + offset += cl; + } + else if (Action == IIPPacketAction.DetachResource) + { + // nothing to do + } + else if (Action == IIPPacketAction.CreateResource) + { + if (NotEnough(offset, ends, 20)) + return -dataLengthNeeded; + + //ClassId = data.GetGuid(offset); + //offset += 16; + + ResourceId = data.GetUInt32(offset); + offset += 4; + + } + else if (Action == IIPPacketAction.DetachResource) + { + // nothing to do + } + // Inquire + else if (Action == IIPPacketAction.TemplateFromClassName + || Action == IIPPacketAction.TemplateFromClassId + || Action == IIPPacketAction.TemplateFromResourceId + || Action == IIPPacketAction.QueryLink + || Action == IIPPacketAction.ResourceChildren + || Action == IIPPacketAction.ResourceParents + || Action == IIPPacketAction.ResourceHistory + || Action == IIPPacketAction.LinkTemplates + // Attribute + || Action == IIPPacketAction.GetAllAttributes + || Action == IIPPacketAction.GetAttributes) + { + if (NotEnough(offset, ends, 4)) + return -dataLengthNeeded; + + var cl = data.GetUInt32(offset); + offset += 4; + + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; + + Content = data.Clip(offset, cl); + offset += cl; + } + else if (Action == IIPPacketAction.InvokeFunctionArrayArguments + || Action == IIPPacketAction.InvokeFunctionNamedArguments) + //|| Action == IIPPacketAction.GetProperty + //|| Action == IIPPacketAction.GetPropertyIfModified) + { + if (NotEnough(offset, ends, 1)) + return -dataLengthNeeded; + + var dt = (DataType)data[offset++]; + var size = dt.Size();// Codec.SizeOf(dt); + + if (size < 0) + { + if (NotEnough(offset, ends, 4)) + return -dataLengthNeeded; + + var cl = data.GetUInt32(offset); + offset += 4; + + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; + + Content = data.Clip(offset - 5, cl + 5); + offset += cl; + } + else + { + if (NotEnough(offset, ends, (uint)size)) + return -dataLengthNeeded; + + Content = data.Clip(offset - 1, (uint)size + 1); + offset += (uint)size; + } + } + else if (Action == IIPPacketAction.SetProperty + || Action == IIPPacketAction.Listen + || Action == IIPPacketAction.Unlisten) + { + // nothing to do + } + } + else if (Command == IIPPacketCommand.Report) + { + if (Report == IIPPacketReport.ManagementError) + { + if (NotEnough(offset, ends, 2)) + return -dataLengthNeeded; + + ErrorCode = data.GetUInt16(offset); + offset += 2; + } + else if (Report == IIPPacketReport.ExecutionError) + { + if (NotEnough(offset, ends, 2)) + return -dataLengthNeeded; + + ErrorCode = data.GetUInt16(offset); + offset += 2; + + if (NotEnough(offset, ends, 2)) + return -dataLengthNeeded; + + var cl = data.GetUInt16(offset); + offset += 2; + + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; + + ErrorMessage = data.GetString(offset, cl); + offset += cl; + } + else if (Report == IIPPacketReport.ProgressReport) + { + if (NotEnough(offset, ends, 8)) + return -dataLengthNeeded; + + ProgressValue = data.GetInt32(offset); + offset += 4; + ProgressMax = data.GetInt32(offset); + offset += 4; + } + else if (Report == IIPPacketReport.ChunkStream) + { + if (NotEnough(offset, ends, 1)) + return -dataLengthNeeded; + + var dt = (DataType)data[offset++]; + var size = dt.Size();// Codec.SizeOf(dt); + + if (size < 0) + { + if (NotEnough(offset, ends, 4)) + return -dataLengthNeeded; + + var cl = data.GetUInt32(offset); + offset += 4; + + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; + + Content = data.Clip(offset - 5, cl + 5); + offset += cl; + } + else + { + if (NotEnough(offset, ends, (uint)size)) + return -dataLengthNeeded; + + Content = data.Clip(offset - 1, (uint)size + 1); + offset += (uint)size; + } + } + } + + return offset - originalOffset; } } diff --git a/Esiur/Net/Packets/IIPPacketAttachInfo.cs b/Esiur/Net/Packets/IIPPacketAttachInfo.cs index 53723e7..8b7d95e 100644 --- a/Esiur/Net/Packets/IIPPacketAttachInfo.cs +++ b/Esiur/Net/Packets/IIPPacketAttachInfo.cs @@ -2,21 +2,20 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Net.Packets -{ - struct IIPPacketAttachInfo - { - public string Link; - public ulong Age; - public byte[] Content; - public Guid ClassId; +namespace Esiur.Net.Packets; - public IIPPacketAttachInfo(Guid classId, ulong age, string link, byte[] content) - { - ClassId = classId; - Age = age; - Content = content; - Link = link; - } +struct IIPPacketAttachInfo +{ + public string Link; + public ulong Age; + public byte[] Content; + public Guid ClassId; + + public IIPPacketAttachInfo(Guid classId, ulong age, string link, byte[] content) + { + ClassId = classId; + Age = age; + Content = content; + Link = link; } } diff --git a/Esiur/Net/Packets/Packet.cs b/Esiur/Net/Packets/Packet.cs index 1d831ed..52a6513 100644 --- a/Esiur/Net/Packets/Packet.cs +++ b/Esiur/Net/Packets/Packet.cs @@ -38,238 +38,219 @@ using Esiur.Net.DataLink; using System.Net.NetworkInformation; using Esiur.Data; -namespace Esiur.Net.Packets +namespace Esiur.Net.Packets; +internal static class Functions { - internal static class Functions + public static void AddData(ref byte[] dest, byte[] src) { - public static void AddData(ref byte[] dest, byte[] src) + int I = 0; + if (src == null) { - int I = 0; - if (src == null) - { - return; - } - if (dest != null) - { - I = dest.Length; - Array.Resize(ref dest, dest.Length + src.Length); - //dest = (byte[])Resize(dest, dest.Length + src.Length); - } - else - { - dest = new byte[src.Length]; - } - Array.Copy(src, 0, dest, I, src.Length); + return; } - - /* - public static Array Resize(Array array, int newSize) + if (dest != null) { - Type myType = Type.GetType(array.GetType().FullName.TrimEnd('[', ']')); - Array nA = Array.CreateInstance(myType, newSize); - Array.Copy(array, nA, (newSize > array.Length ? array.Length : newSize)); - return nA; - } */ - - //Computes the checksum used in IP, ARP..., ie the - // "The 16 bit one's complement of the one 's complement sum - //of all 16 bit words" as seen in RFCs - // Returns a 4 characters hex string - // data's lenght must be multiple of 4, else zero padding - public static ushort IP_CRC16(byte[] data) - { - ulong Sum = 0; - bool Padding = false; - /// * Padding if needed - if (data.Length % 2 != 0) - { - Array.Resize(ref data, data.Length + 1); - //data = (byte[])Resize(data, data.Length + 1); - Padding = true; - } - int count = data.Length; - ///* add 16-bit words */ - while (count > 0) //1) - { - ///* this is the inner loop */ - Sum += GetInteger(data[count - 2], data[count - 1]); - ///* Fold 32-bit sum to 16-bit */ - while (Sum >> 16 != 0) - { - Sum = (Sum & 0XFFFF) + (Sum >> 16); - } - count -= 2; - } - /// * reverse padding - if (Padding) - { - Array.Resize(ref data, data.Length - 1); - //data = (byte[])Resize(data, data.Length - 1); - } - ///* Return one's compliment of final sum. - //return (ushort)(ushort.MaxValue - (ushort)Sum); - return (ushort)(~Sum); + I = dest.Length; + Array.Resize(ref dest, dest.Length + src.Length); + //dest = (byte[])Resize(dest, dest.Length + src.Length); } - - public static ushort GetInteger(byte B1, byte B2) + else { - return BitConverter.ToUInt16(new byte[] { B2, B1 }, 0); - //return System.Convert.ToUInt16("&h" + GetHex(B1) + GetHex(B2)); + dest = new byte[src.Length]; } - - public static uint GetLong(byte B1, byte B2, byte B3, byte B4) - { - return BitConverter.ToUInt32(new byte[] { B4, B3, B2, B1 }, 0); - //return System.Convert.ToUInt32("&h" + GetHex(B1) + GetHex(B2) + GetHex(B3) + GetHex(B4)); - } - - public static string GetHex(byte B) - { - return (((B < 15) ? 0 + System.Convert.ToString(B, 16).ToUpper() : System.Convert.ToString(B, 16).ToUpper())); - } - - public static bool GetBit(uint B, byte Pos) - { - //return BitConverter.ToBoolean(BitConverter.GetBytes(B), Pos + 1); - return (B & (uint)(Math.Pow(2, (Pos - 1)))) == (Math.Pow(2, (Pos - 1))); - } - - public static ushort RemoveBit(ushort I, byte Pos) - { - return (ushort)RemoveBit((uint)I, Pos); - } - - public static uint RemoveBit(uint I, byte Pos) - { - if (GetBit(I, Pos)) - { - return I - (uint)(Math.Pow(2, (Pos - 1))); - } - else - { - return I; - } - } - - public static void SplitInteger(ushort I, ref byte BLeft, ref byte BRight) - { - byte[] b = BitConverter.GetBytes(I); - BLeft = b[1]; - BRight = b[0]; - //BLeft = I >> 8; - //BRight = (I << 8) >> 8; - } - - public static void SplitLong(uint I, ref byte BLeft, ref byte BLeftMiddle, ref byte BRightMiddle, ref byte BRight) - { - byte[] b = BitConverter.GetBytes(I); - BLeft = b[3]; - BLeftMiddle = b[2]; - BRightMiddle = b[1]; - BRight = b[0]; - //BLeft = I >> 24; - //BLeftMiddle = (I << 8) >> 24; - //BRightMiddle = (I << 16) >> 24; - //BRight = (I << 24) >> 24; - } - + Array.Copy(src, 0, dest, I, src.Length); } - public class PosixTime + /* + public static Array Resize(Array array, int newSize) { - ulong seconds; - ulong microseconds; + Type myType = Type.GetType(array.GetType().FullName.TrimEnd('[', ']')); + Array nA = Array.CreateInstance(myType, newSize); + Array.Copy(array, nA, (newSize > array.Length ? array.Length : newSize)); + return nA; + } */ - PosixTime(ulong Seconds, ulong Microseconds) + //Computes the checksum used in IP, ARP..., ie the + // "The 16 bit one's complement of the one 's complement sum + //of all 16 bit words" as seen in RFCs + // Returns a 4 characters hex string + // data's lenght must be multiple of 4, else zero padding + public static ushort IP_CRC16(byte[] data) + { + ulong Sum = 0; + bool Padding = false; + /// * Padding if needed + if (data.Length % 2 != 0) { - seconds = Seconds; - microseconds = Microseconds; + Array.Resize(ref data, data.Length + 1); + //data = (byte[])Resize(data, data.Length + 1); + Padding = true; } - - public override string ToString() + int count = data.Length; + ///* add 16-bit words */ + while (count > 0) //1) { - return seconds + "." + microseconds; + ///* this is the inner loop */ + Sum += GetInteger(data[count - 2], data[count - 1]); + ///* Fold 32-bit sum to 16-bit */ + while (Sum >> 16 != 0) + { + Sum = (Sum & 0XFFFF) + (Sum >> 16); + } + count -= 2; + } + /// * reverse padding + if (Padding) + { + Array.Resize(ref data, data.Length - 1); + //data = (byte[])Resize(data, data.Length - 1); + } + ///* Return one's compliment of final sum. + //return (ushort)(ushort.MaxValue - (ushort)Sum); + return (ushort)(~Sum); + } + + public static ushort GetInteger(byte B1, byte B2) + { + return BitConverter.ToUInt16(new byte[] { B2, B1 }, 0); + //return System.Convert.ToUInt16("&h" + GetHex(B1) + GetHex(B2)); + } + + public static uint GetLong(byte B1, byte B2, byte B3, byte B4) + { + return BitConverter.ToUInt32(new byte[] { B4, B3, B2, B1 }, 0); + //return System.Convert.ToUInt32("&h" + GetHex(B1) + GetHex(B2) + GetHex(B3) + GetHex(B4)); + } + + public static string GetHex(byte B) + { + return (((B < 15) ? 0 + System.Convert.ToString(B, 16).ToUpper() : System.Convert.ToString(B, 16).ToUpper())); + } + + public static bool GetBit(uint B, byte Pos) + { + //return BitConverter.ToBoolean(BitConverter.GetBytes(B), Pos + 1); + return (B & (uint)(Math.Pow(2, (Pos - 1)))) == (Math.Pow(2, (Pos - 1))); + } + + public static ushort RemoveBit(ushort I, byte Pos) + { + return (ushort)RemoveBit((uint)I, Pos); + } + + public static uint RemoveBit(uint I, byte Pos) + { + if (GetBit(I, Pos)) + { + return I - (uint)(Math.Pow(2, (Pos - 1))); + } + else + { + return I; } } - public class Packet + public static void SplitInteger(ushort I, ref byte BLeft, ref byte BRight) { - //public EtherServer2.EthernetSource Source; + byte[] b = BitConverter.GetBytes(I); + BLeft = b[1]; + BRight = b[0]; + //BLeft = I >> 8; + //BRight = (I << 8) >> 8; + } - public PacketSource Source; + public static void SplitLong(uint I, ref byte BLeft, ref byte BLeftMiddle, ref byte BRightMiddle, ref byte BRight) + { + byte[] b = BitConverter.GetBytes(I); + BLeft = b[3]; + BLeftMiddle = b[2]; + BRightMiddle = b[1]; + BRight = b[0]; + //BLeft = I >> 24; + //BLeftMiddle = (I << 8) >> 24; + //BRightMiddle = (I << 16) >> 24; + //BRight = (I << 24) >> 24; + } - public DateTime Timestamp; +} - public enum PPPType : ushort - { - IP = 0x0021, // Internet Protocol version 4 [RFC1332] - SDTP = 0x0049, // Serial Data Transport Protocol (PPP-SDTP) [RFC1963] - IPv6HeaderCompression = 0x004f, // IPv6 Header Compression - IPv6 = 0x0057, // Internet Protocol version 6 [RFC5072] - W8021dHelloPacket = 0x0201, // 802.1d Hello Packets [RFC3518] - IPv6ControlProtocol = 0x8057, // IPv6 Control Protocol [RFC5072] - } +public class PosixTime +{ + ulong seconds; + ulong microseconds; - public enum ProtocolType : ushort - { - IP = 0x800, // IPv4 - ARP = 0x806, // Address Resolution Protocol - IPv6 = 0x86DD, // IPv6 - FrameRelayARP = 0x0808, // Frame Relay ARP [RFC1701] - VINESLoopback = 0x0BAE, // VINES Loopback [RFC1701] - VINESEcho = 0x0BAF, // VINES ECHO [RFC1701] - TransEtherBridging = 0x6558, // TransEther Bridging [RFC1701] - RawFrameRelay = 0x6559, // Raw Frame Relay [RFC1701] - IEE8021QVLAN = 0x8100, // IEEE 802.1Q VLAN-tagged frames (initially Wellfleet) - SNMP = 0x814C, // SNMP [JKR1] - TCPIP_Compression = 0x876B, // TCP/IP Compression [RFC1144] - IPAutonomousSystems = 0x876C, // IP Autonomous Systems [RFC1701] - SecureData = 0x876D, // Secure Data [RFC1701] - PPP = 0x880B, // PPP [IANA] - MPLS = 0x8847, // MPLS [RFC5332] - MPLS_UpstreamAssignedLabel = 0x8848, // MPLS with upstream-assigned label [RFC5332] - PPPoEDiscoveryStage = 0x8863, // PPPoE Discovery Stage [RFC2516] - PPPoESessionStage = 0x8864, // PPPoE Session Stage [RFC2516] - } + PosixTime(ulong Seconds, ulong Microseconds) + { + seconds = Seconds; + microseconds = Microseconds; + } + + public override string ToString() + { + return seconds + "." + microseconds; + } +} + +public class Packet +{ + //public EtherServer2.EthernetSource Source; + + public PacketSource Source; + + public DateTime Timestamp; + + public enum PPPType : ushort + { + IP = 0x0021, // Internet Protocol version 4 [RFC1332] + SDTP = 0x0049, // Serial Data Transport Protocol (PPP-SDTP) [RFC1963] + IPv6HeaderCompression = 0x004f, // IPv6 Header Compression + IPv6 = 0x0057, // Internet Protocol version 6 [RFC5072] + W8021dHelloPacket = 0x0201, // 802.1d Hello Packets [RFC3518] + IPv6ControlProtocol = 0x8057, // IPv6 Control Protocol [RFC5072] + } + + public enum ProtocolType : ushort + { + IP = 0x800, // IPv4 + ARP = 0x806, // Address Resolution Protocol + IPv6 = 0x86DD, // IPv6 + FrameRelayARP = 0x0808, // Frame Relay ARP [RFC1701] + VINESLoopback = 0x0BAE, // VINES Loopback [RFC1701] + VINESEcho = 0x0BAF, // VINES ECHO [RFC1701] + TransEtherBridging = 0x6558, // TransEther Bridging [RFC1701] + RawFrameRelay = 0x6559, // Raw Frame Relay [RFC1701] + IEE8021QVLAN = 0x8100, // IEEE 802.1Q VLAN-tagged frames (initially Wellfleet) + SNMP = 0x814C, // SNMP [JKR1] + TCPIP_Compression = 0x876B, // TCP/IP Compression [RFC1144] + IPAutonomousSystems = 0x876C, // IP Autonomous Systems [RFC1701] + SecureData = 0x876D, // Secure Data [RFC1701] + PPP = 0x880B, // PPP [IANA] + MPLS = 0x8847, // MPLS [RFC5332] + MPLS_UpstreamAssignedLabel = 0x8848, // MPLS with upstream-assigned label [RFC5332] + PPPoEDiscoveryStage = 0x8863, // PPPoE Discovery Stage [RFC2516] + PPPoESessionStage = 0x8864, // PPPoE Session Stage [RFC2516] + } - /* - public static void GetPacketMACAddresses(Packet packet, out byte[] srcMAC, out byte[] dstMAC) + /* + public static void GetPacketMACAddresses(Packet packet, out byte[] srcMAC, out byte[] dstMAC) + { + + // get the node address + Packet root = packet.RootPacket; + if (root is TZSPPacket) { - // get the node address - Packet root = packet.RootPacket; - if (root is TZSPPacket) + TZSPPacket tp = (TZSPPacket)root; + if (tp.Protocol == TZSPPacket.TZSPEncapsulatedProtocol.Ethernet) { - - TZSPPacket tp = (TZSPPacket)root; - if (tp.Protocol == TZSPPacket.TZSPEncapsulatedProtocol.Ethernet) - { - EthernetPacket ep = (EthernetPacket)tp.SubPacket; - srcMAC = ep.SourceMAC; - dstMAC = ep.DestinationMAC; - } - else if (tp.Protocol == TZSPPacket.TZSPEncapsulatedProtocol.IEEE802_11) - { - W802_11Packet wp = (W802_11Packet)tp.SubPacket; - srcMAC = wp.SA; - dstMAC = wp.DA; - } - else - { - srcMAC = null; - dstMAC = null; - } - } - else if (root is EthernetPacket) - { - EthernetPacket ep = (EthernetPacket)root; + EthernetPacket ep = (EthernetPacket)tp.SubPacket; srcMAC = ep.SourceMAC; dstMAC = ep.DestinationMAC; } - else if (root is W802_11Packet) + else if (tp.Protocol == TZSPPacket.TZSPEncapsulatedProtocol.IEEE802_11) { - W802_11Packet wp = (W802_11Packet)root; + W802_11Packet wp = (W802_11Packet)tp.SubPacket; srcMAC = wp.SA; dstMAC = wp.DA; } @@ -278,92 +259,109 @@ namespace Esiur.Net.Packets srcMAC = null; dstMAC = null; } - + } + else if (root is EthernetPacket) + { + EthernetPacket ep = (EthernetPacket)root; + srcMAC = ep.SourceMAC; + dstMAC = ep.DestinationMAC; + } + else if (root is W802_11Packet) + { + W802_11Packet wp = (W802_11Packet)root; + srcMAC = wp.SA; + dstMAC = wp.DA; + } + else + { + srcMAC = null; + dstMAC = null; } - - public static void GetPacketAddresses(Packet packet, ref string srcMAC, ref string dstMAC, ref string srcIP, ref string dstIP) + } + + + public static void GetPacketAddresses(Packet packet, ref string srcMAC, ref string dstMAC, ref string srcIP, ref string dstIP) + { + + if (packet is TCPv4Packet) + { + if (packet.ParentPacket is IPv4Packet) + { + IPv4Packet ip = (IPv4Packet)packet.ParentPacket; + srcIP = ip.SourceIP.ToString(); + dstIP = ip.DestinationIP.ToString(); + } + } + + // get the node address + Packet root = packet.RootPacket; + if (root is TZSPPacket) { - if (packet is TCPv4Packet) + TZSPPacket tp = (TZSPPacket)root; + if (tp.Protocol == TZSPPacket.TZSPEncapsulatedProtocol.Ethernet) { - if (packet.ParentPacket is IPv4Packet) - { - IPv4Packet ip = (IPv4Packet)packet.ParentPacket; - srcIP = ip.SourceIP.ToString(); - dstIP = ip.DestinationIP.ToString(); - } - } - - // get the node address - Packet root = packet.RootPacket; - if (root is TZSPPacket) - { - - TZSPPacket tp = (TZSPPacket)root; - if (tp.Protocol == TZSPPacket.TZSPEncapsulatedProtocol.Ethernet) - { - EthernetPacket ep = (EthernetPacket)tp.SubPacket; - srcMAC = DC.GetPhysicalAddress(ep.SourceMAC, 0).ToString(); - dstMAC = DC.GetPhysicalAddress(ep.DestinationMAC, 0).ToString(); - } - else if (tp.Protocol == TZSPPacket.TZSPEncapsulatedProtocol.IEEE802_11) - { - W802_11Packet wp = (W802_11Packet)tp.SubPacket; - srcMAC = DC.GetPhysicalAddress(wp.SA, 0).ToString(); - dstMAC = DC.GetPhysicalAddress(wp.DA, 0).ToString(); - } - } - else if (root is EthernetPacket) - { - EthernetPacket ep = (EthernetPacket)root; + EthernetPacket ep = (EthernetPacket)tp.SubPacket; srcMAC = DC.GetPhysicalAddress(ep.SourceMAC, 0).ToString(); dstMAC = DC.GetPhysicalAddress(ep.DestinationMAC, 0).ToString(); } - else if (root is W802_11Packet) + else if (tp.Protocol == TZSPPacket.TZSPEncapsulatedProtocol.IEEE802_11) { - W802_11Packet wp = (W802_11Packet)root; + W802_11Packet wp = (W802_11Packet)tp.SubPacket; srcMAC = DC.GetPhysicalAddress(wp.SA, 0).ToString(); dstMAC = DC.GetPhysicalAddress(wp.DA, 0).ToString(); } } - */ - - //PosixTime Timeval; - public byte[] Header; - public byte[] Preamble; - //public byte[] Payload; - public byte[] Data; - - public Packet SubPacket; - public Packet ParentPacket; - public virtual long Parse(byte[] data, uint offset, uint ends) { return 0; } - public virtual bool Compose() { return false; } - - public Packet RootPacket + else if (root is EthernetPacket) { - get - { - Packet root = this; - while (root.ParentPacket != null) - root = root.ParentPacket; - return root; - } + EthernetPacket ep = (EthernetPacket)root; + srcMAC = DC.GetPhysicalAddress(ep.SourceMAC, 0).ToString(); + dstMAC = DC.GetPhysicalAddress(ep.DestinationMAC, 0).ToString(); } - - public Packet LeafPacket + else if (root is W802_11Packet) { - get - { - Packet leaf = this; - while (leaf.SubPacket != null) - leaf = leaf.SubPacket; - return leaf; - } + W802_11Packet wp = (W802_11Packet)root; + srcMAC = DC.GetPhysicalAddress(wp.SA, 0).ToString(); + dstMAC = DC.GetPhysicalAddress(wp.DA, 0).ToString(); + } + } + */ + + //PosixTime Timeval; + public byte[] Header; + public byte[] Preamble; + //public byte[] Payload; + public byte[] Data; + + public Packet SubPacket; + public Packet ParentPacket; + public virtual long Parse(byte[] data, uint offset, uint ends) { return 0; } + public virtual bool Compose() { return false; } + + public Packet RootPacket + { + get + { + Packet root = this; + while (root.ParentPacket != null) + root = root.ParentPacket; + return root; } } + public Packet LeafPacket + { + get + { + Packet leaf = this; + while (leaf.SubPacket != null) + leaf = leaf.SubPacket; + return leaf; + } + } } + + /************************************ EOF *************************************/ - diff --git a/Esiur/Net/Packets/WebsocketPacket.cs b/Esiur/Net/Packets/WebsocketPacket.cs index 8aee17f..c7e314a 100644 --- a/Esiur/Net/Packets/WebsocketPacket.cs +++ b/Esiur/Net/Packets/WebsocketPacket.cs @@ -29,189 +29,187 @@ using System.Text; using Esiur.Misc; using Esiur.Data; -namespace Esiur.Net.Packets +namespace Esiur.Net.Packets; +public class WebsocketPacket : Packet { - public class WebsocketPacket : Packet + public enum WSOpcode : byte { - public enum WSOpcode : byte + ContinuationFrame = 0x0, // %x0 denotes a continuation frame + + TextFrame = 0x1, // %x1 denotes a text frame + + BinaryFrame = 0x2, // %x2 denotes a binary frame + + // %x3-7 are reserved for further non-control frames + + ConnectionClose = 0x8, // %x8 denotes a connection close + + Ping = 0x9, // %x9 denotes a ping + + Pong = 0xA, // %xA denotes a pong + + //* %xB-F are reserved for further control frames + } + + + public bool FIN; + public bool RSV1; + public bool RSV2; + public bool RSV3; + public WSOpcode Opcode; + public bool Mask; + public long PayloadLength; + // public UInt32 MaskKey; + public byte[] MaskKey; + + public byte[] Message; + + public override string ToString() + { + return "WebsocketPacket" + + "\n\tFIN: " + FIN + + "\n\tOpcode: " + Opcode + + "\n\tPayload: " + PayloadLength + + "\n\tMaskKey: " + MaskKey + + "\n\tMessage: " + (Message != null ? Message.Length.ToString() : "NULL"); + } + + public override bool Compose() + { + var pkt = new List(); + pkt.Add((byte)((FIN ? 0x80 : 0x0) | + (RSV1 ? 0x40 : 0x0) | + (RSV2 ? 0x20 : 0x0) | + (RSV3 ? 0x10 : 0x0) | + (byte)Opcode)); + + // calculate length + if (Message.Length > UInt16.MaxValue) + // 4 bytes { - ContinuationFrame = 0x0, // %x0 denotes a continuation frame - - TextFrame = 0x1, // %x1 denotes a text frame - - BinaryFrame = 0x2, // %x2 denotes a binary frame - - // %x3-7 are reserved for further non-control frames - - ConnectionClose = 0x8, // %x8 denotes a connection close - - Ping = 0x9, // %x9 denotes a ping - - Pong = 0xA, // %xA denotes a pong - - //* %xB-F are reserved for further control frames + pkt.Add((byte)((Mask ? 0x80 : 0x0) | 127)); + pkt.AddRange(DC.ToBytes((UInt64)Message.LongCount())); + } + else if (Message.Length > 125) + // 2 bytes + { + pkt.Add((byte)((Mask ? 0x80 : 0x0) | 126)); + pkt.AddRange(DC.ToBytes((UInt16)Message.Length)); + } + else + { + pkt.Add((byte)((Mask ? 0x80 : 0x0) | Message.Length)); } - - public bool FIN; - public bool RSV1; - public bool RSV2; - public bool RSV3; - public WSOpcode Opcode; - public bool Mask; - public long PayloadLength; - // public UInt32 MaskKey; - public byte[] MaskKey; - - public byte[] Message; - - public override string ToString() + if (Mask) { - return "WebsocketPacket" - + "\n\tFIN: " + FIN - + "\n\tOpcode: " + Opcode - + "\n\tPayload: " + PayloadLength - + "\n\tMaskKey: " + MaskKey - + "\n\tMessage: " + (Message != null ? Message.Length.ToString() : "NULL"); + pkt.AddRange(MaskKey); } - public override bool Compose() - { - var pkt = new List(); - pkt.Add((byte)((FIN ? 0x80 : 0x0) | - (RSV1 ? 0x40 : 0x0) | - (RSV2 ? 0x20 : 0x0) | - (RSV3 ? 0x10 : 0x0) | - (byte)Opcode)); + pkt.AddRange(Message); - // calculate length - if (Message.Length > UInt16.MaxValue) - // 4 bytes + Data = pkt.ToArray(); + + return true; + } + + public override long Parse(byte[] data, uint offset, uint ends) + { + try + { + long needed = 2; + var length = (ends - offset); + if (length < needed) { - pkt.Add((byte)((Mask ? 0x80 : 0x0) | 127)); - pkt.AddRange(DC.ToBytes((UInt64)Message.LongCount())); - } - else if (Message.Length > 125) - // 2 bytes - { - pkt.Add((byte)((Mask ? 0x80 : 0x0) | 126)); - pkt.AddRange(DC.ToBytes((UInt16)Message.Length)); - } - else - { - pkt.Add((byte)((Mask ? 0x80 : 0x0) | Message.Length)); + //Console.WriteLine("stage 1 " + needed); + return length - needed; } + uint oOffset = offset; + FIN = ((data[offset] & 0x80) == 0x80); + RSV1 = ((data[offset] & 0x40) == 0x40); + RSV2 = ((data[offset] & 0x20) == 0x20); + RSV3 = ((data[offset] & 0x10) == 0x10); + Opcode = (WSOpcode)(data[offset++] & 0xF); + Mask = ((data[offset] & 0x80) == 0x80); + PayloadLength = (long)(data[offset++] & 0x7F); + if (Mask) + needed += 4; + + if (PayloadLength == 126) { - pkt.AddRange(MaskKey); - } - - pkt.AddRange(Message); - - Data = pkt.ToArray(); - - return true; - } - - public override long Parse(byte[] data, uint offset, uint ends) - { - try - { - long needed = 2; - var length = (ends - offset); + needed += 2; if (length < needed) { - //Console.WriteLine("stage 1 " + needed); + //Console.WriteLine("stage 2 " + needed); + return length - needed; + } + PayloadLength = data.GetUInt16(offset); + offset += 2; + } + else if (PayloadLength == 127) + { + needed += 8; + if (length < needed) + { + //Console.WriteLine("stage 3 " + needed); return length - needed; } - uint oOffset = offset; - FIN = ((data[offset] & 0x80) == 0x80); - RSV1 = ((data[offset] & 0x40) == 0x40); - RSV2 = ((data[offset] & 0x20) == 0x20); - RSV3 = ((data[offset] & 0x10) == 0x10); - Opcode = (WSOpcode)(data[offset++] & 0xF); - Mask = ((data[offset] & 0x80) == 0x80); - PayloadLength = (long)(data[offset++] & 0x7F); + PayloadLength = data.GetInt64(offset); + offset += 8; + } + + /* + if (Mask) + { + MaskKey = new byte[4]; + MaskKey[0] = data[offset++]; + MaskKey[1] = data[offset++]; + MaskKey[2] = data[offset++]; + MaskKey[3] = data[offset++]; + + //MaskKey = DC.GetUInt32(data, offset); + //offset += 4; + } + */ + + needed += PayloadLength; + if (length < needed) + { + //Console.WriteLine("stage 4"); + return length - needed; + } + else + { if (Mask) - needed += 4; - - if (PayloadLength == 126) { - needed += 2; - if (length < needed) - { - //Console.WriteLine("stage 2 " + needed); - return length - needed; - } - PayloadLength = data.GetUInt16( offset); - offset += 2; - } - else if (PayloadLength == 127) - { - needed += 8; - if (length < needed) - { - //Console.WriteLine("stage 3 " + needed); - return length - needed; - } - - PayloadLength = data.GetInt64(offset); - offset += 8; - } - - /* - if (Mask) - { - MaskKey = new byte[4]; + MaskKey = new byte[4]; MaskKey[0] = data[offset++]; MaskKey[1] = data[offset++]; MaskKey[2] = data[offset++]; MaskKey[3] = data[offset++]; - //MaskKey = DC.GetUInt32(data, offset); - //offset += 4; - } - */ + Message = DC.Clip(data, offset, (uint)PayloadLength); - needed += PayloadLength; - if (length < needed) - { - //Console.WriteLine("stage 4"); - return length - needed; + //var aMask = BitConverter.GetBytes(MaskKey); + for (int i = 0; i < Message.Length; i++) + Message[i] = (byte)(Message[i] ^ MaskKey[i % 4]); } else - { - - if (Mask) - { - MaskKey = new byte[4]; - MaskKey[0] = data[offset++]; - MaskKey[1] = data[offset++]; - MaskKey[2] = data[offset++]; - MaskKey[3] = data[offset++]; - - Message = DC.Clip(data, offset, (uint)PayloadLength); - - //var aMask = BitConverter.GetBytes(MaskKey); - for (int i = 0; i < Message.Length; i++) - Message[i] = (byte)(Message[i] ^ MaskKey[i % 4]); - } - else - Message = DC.Clip(data, offset, (uint)PayloadLength); + Message = DC.Clip(data, offset, (uint)PayloadLength); - return (offset - oOffset) + (int)PayloadLength; - } - } - catch (Exception ex) - { - Console.WriteLine(ex.ToString()); - Console.WriteLine(offset + "::" + DC.ToHex(data)); - throw ex; + return (offset - oOffset) + (int)PayloadLength; } } + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); + Console.WriteLine(offset + "::" + DC.ToHex(data)); + throw ex; + } } } diff --git a/Esiur/Net/SendList.cs b/Esiur/Net/SendList.cs index dd21b50..550f5be 100644 --- a/Esiur/Net/SendList.cs +++ b/Esiur/Net/SendList.cs @@ -4,23 +4,22 @@ using System; using System.Collections.Generic; using System.Text; -namespace Esiur.Net +namespace Esiur.Net; + +public class SendList : BinaryList { - public class SendList : BinaryList + NetworkConnection connection; + AsyncReply reply; + + public SendList(NetworkConnection connection, AsyncReply reply) { - NetworkConnection connection; - AsyncReply reply; + this.reply = reply; + this.connection = connection; + } - public SendList(NetworkConnection connection, AsyncReply reply) - { - this.reply = reply; - this.connection = connection; - } - - public override AsyncReply Done() - { - connection.Send(this.ToArray()); - return reply; - } + public override AsyncReply Done() + { + connection.Send(this.ToArray()); + return reply; } } diff --git a/Esiur/Net/Sockets/ISocket.cs b/Esiur/Net/Sockets/ISocket.cs index 14a10b6..cc41ba4 100644 --- a/Esiur/Net/Sockets/ISocket.cs +++ b/Esiur/Net/Sockets/ISocket.cs @@ -36,39 +36,37 @@ using System.Collections.Concurrent; using Esiur.Resource; using Esiur.Core; -namespace Esiur.Net.Sockets +namespace Esiur.Net.Sockets; +//public delegate void ISocketReceiveEvent(NetworkBuffer buffer); +//public delegate void ISocketConnectEvent(); +//public delegate void ISocketCloseEvent(); + +public interface ISocket : IDestructible { - //public delegate void ISocketReceiveEvent(NetworkBuffer buffer); - //public delegate void ISocketConnectEvent(); - //public delegate void ISocketCloseEvent(); + SocketState State { get; } - public interface ISocket : IDestructible - { - SocketState State { get; } + //event ISocketReceiveEvent OnReceive; + //event ISocketConnectEvent OnConnect; + //event ISocketCloseEvent OnClose; - //event ISocketReceiveEvent OnReceive; - //event ISocketConnectEvent OnConnect; - //event ISocketCloseEvent OnClose; + INetworkReceiver Receiver { get; set; } - INetworkReceiver Receiver { get; set; } + AsyncReply SendAsync(byte[] message, int offset, int length); - AsyncReply SendAsync(byte[] message, int offset, int length); + void Send(byte[] message); + void Send(byte[] message, int offset, int length); + void Close(); + AsyncReply Connect(string hostname, ushort port); + bool Begin(); + AsyncReply BeginAsync(); + //ISocket Accept(); + AsyncReply AcceptAsync(); + ISocket Accept(); - void Send(byte[] message); - void Send(byte[] message, int offset, int length); - void Close(); - AsyncReply Connect(string hostname, ushort port); - bool Begin(); - AsyncReply BeginAsync(); - //ISocket Accept(); - AsyncReply AcceptAsync(); - ISocket Accept(); + IPEndPoint RemoteEndPoint { get; } + IPEndPoint LocalEndPoint { get; } - IPEndPoint RemoteEndPoint { get; } - IPEndPoint LocalEndPoint { get; } + void Hold(); - void Hold(); - - void Unhold(); - } + void Unhold(); } diff --git a/Esiur/Net/Sockets/SSLSocket.cs b/Esiur/Net/Sockets/SSLSocket.cs index fc707ed..0098c34 100644 --- a/Esiur/Net/Sockets/SSLSocket.cs +++ b/Esiur/Net/Sockets/SSLSocket.cs @@ -37,519 +37,518 @@ using Esiur.Resource; using System.Threading.Tasks; using Esiur.Data; -namespace Esiur.Net.Sockets +namespace Esiur.Net.Sockets; +public class SSLSocket : ISocket { - public class SSLSocket : ISocket + + public INetworkReceiver Receiver { get; set; } + + Socket sock; + byte[] receiveBuffer; + + bool held; + + //ArraySegment receiveBufferSegment; + + NetworkBuffer receiveNetworkBuffer = new NetworkBuffer(); + + readonly object sendLock = new object(); + + Queue, byte[]>> sendBufferQueue = new Queue, byte[]>>();// Queue(); + + bool asyncSending; + bool began = false; + + SocketState state = SocketState.Initial; + + //public event ISocketReceiveEvent OnReceive; + //public event ISocketConnectEvent OnConnect; + //public event ISocketCloseEvent OnClose; + public event DestroyedEvent OnDestroy; + + + SslStream ssl; + X509Certificate2 cert; + bool server; + string hostname; + + + public async AsyncReply Connect(string hostname, ushort port) { + var rt = new AsyncReply(); - public INetworkReceiver Receiver { get; set; } + this.hostname = hostname; + this.server = false; - Socket sock; - byte[] receiveBuffer; - - bool held; - - //ArraySegment receiveBufferSegment; - - NetworkBuffer receiveNetworkBuffer = new NetworkBuffer(); - - readonly object sendLock = new object(); - - Queue, byte[]>> sendBufferQueue = new Queue, byte[]>>();// Queue(); - - bool asyncSending; - bool began = false; - - SocketState state = SocketState.Initial; - - //public event ISocketReceiveEvent OnReceive; - //public event ISocketConnectEvent OnConnect; - //public event ISocketCloseEvent OnClose; - public event DestroyedEvent OnDestroy; + state = SocketState.Connecting; + await sock.ConnectAsync(hostname, port); - SslStream ssl; - X509Certificate2 cert; - bool server; - string hostname; - - - public async AsyncReply Connect(string hostname, ushort port) + try { - var rt = new AsyncReply(); - - this.hostname = hostname; - this.server = false; - - state = SocketState.Connecting; - await sock.ConnectAsync(hostname, port); - - - try - { - await BeginAsync(); - state = SocketState.Established; - //OnConnect?.Invoke(); - Receiver?.NetworkConnect(this); - } - catch (Exception ex) - { - state = SocketState.Closed;// .Terminated; - Close(); - Global.Log(ex); - } - - return true; + await BeginAsync(); + state = SocketState.Established; + //OnConnect?.Invoke(); + Receiver?.NetworkConnect(this); + } + catch (Exception ex) + { + state = SocketState.Closed;// .Terminated; + Close(); + Global.Log(ex); } - //private void DataSent(Task task) - //{ - // try - // { + return true; + } - // if (sendBufferQueue.Count > 0) - // { - // byte[] data = sendBufferQueue.Dequeue(); - // lock (sendLock) - // ssl.WriteAsync(data, 0, data.Length).ContinueWith(DataSent); - // } - // else - // { - // asyncSending = false; - // } - // } - // catch (Exception ex) - // { - // if (state != SocketState.Closed && !sock.Connected) - // { - // state = SocketState.Terminated; - // Close(); - // } + //private void DataSent(Task task) + //{ + // try + // { - // asyncSending = false; + // if (sendBufferQueue.Count > 0) + // { + // byte[] data = sendBufferQueue.Dequeue(); + // lock (sendLock) + // ssl.WriteAsync(data, 0, data.Length).ContinueWith(DataSent); + // } + // else + // { + // asyncSending = false; + // } + // } + // catch (Exception ex) + // { + // if (state != SocketState.Closed && !sock.Connected) + // { + // state = SocketState.Terminated; + // Close(); + // } - // Global.Log("SSLSocket", LogType.Error, ex.ToString()); - // } - //} + // asyncSending = false; + + // Global.Log("SSLSocket", LogType.Error, ex.ToString()); + // } + //} - private void SendCallback(IAsyncResult ar) - { - if (ar != null) - { - try - { - ssl.EndWrite(ar); - - if (ar.AsyncState != null) - ((AsyncReply)ar.AsyncState).Trigger(true); - } - catch - { - if (state != SocketState.Closed && !sock.Connected) - { - //state = SocketState.Closed;//.Terminated; - Close(); - } - } - } - - lock (sendLock) - { - - if (sendBufferQueue.Count > 0) - { - var kv = sendBufferQueue.Dequeue(); - - try - { - ssl.BeginWrite(kv.Value, 0, kv.Value.Length, SendCallback, kv.Key); - } - catch //(Exception ex) - { - asyncSending = false; - try - { - if (kv.Key != null) - kv.Key.Trigger(false); - - if (state != SocketState.Closed && !sock.Connected) - { - //state = SocketState.Terminated; - Close(); - } - } - catch //(Exception ex2) - { - //state = SocketState.Closed;// .Terminated; - Close(); - } - - //Global.Log("TCPSocket", LogType.Error, ex.ToString()); - } - } - else - { - asyncSending = false; - } - } - } - - public IPEndPoint LocalEndPoint - { - get { return (IPEndPoint)sock.LocalEndPoint; } - } - - public SSLSocket() - { - sock = new Socket(AddressFamily.InterNetwork, - SocketType.Stream, - ProtocolType.Tcp); - receiveBuffer = new byte[sock.ReceiveBufferSize]; - } - - public SSLSocket(IPEndPoint localEndPoint, X509Certificate2 certificate) - { - // create the socket - sock = new Socket(AddressFamily.InterNetwork, - SocketType.Stream, - ProtocolType.Tcp); - - state = SocketState.Listening; - - // bind - sock.Bind(localEndPoint); - - // start listening - sock.Listen(UInt16.MaxValue); - - cert = certificate; - } - - public IPEndPoint RemoteEndPoint - { - get { return (IPEndPoint)sock.RemoteEndPoint; } - } - - public SocketState State - { - get - { - return state; - } - } - - - - public SSLSocket(Socket socket, X509Certificate2 certificate, bool authenticateAsServer) - { - cert = certificate; - sock = socket; - receiveBuffer = new byte[sock.ReceiveBufferSize]; - - ssl = new SslStream(new NetworkStream(sock)); - - server = authenticateAsServer; - - if (socket.Connected) - state = SocketState.Established; - } - - - public void Close() - { - if (state != SocketState.Closed)// && state != SocketState.Terminated) - { - state = SocketState.Closed; - - if (sock.Connected) - { - try - { - sock.Shutdown(SocketShutdown.Both); - } - catch - { - //state = SocketState.Terminated; - } - } - - Receiver?.NetworkClose(this); - //OnClose?.Invoke(); - } - } - - - public void Send(byte[] message) - { - Send(message, 0, message.Length); - } - - - public void Send(byte[] message, int offset, int size) - { - - - var msg = message.Clip((uint)offset, (uint)size); - - lock (sendLock) - { - - if (!sock.Connected) - return; - - if (asyncSending || held) - { - sendBufferQueue.Enqueue(new KeyValuePair, byte[]>(null, msg));// message.Clip((uint)offset, (uint)size)); - } - else - { - asyncSending = true; - try - { - ssl.BeginWrite(msg, 0, msg.Length, SendCallback, null); - } - catch - { - asyncSending = false; - //state = SocketState.Terminated; - Close(); - } - } - } - } - - //public void Send(byte[] message) - //{ - // Send(message, 0, message.Length); - //} - - //public void Send(byte[] message, int offset, int size) - //{ - // lock (sendLock) - // { - // if (asyncSending) - // { - // sendBufferQueue.Enqueue(message.Clip((uint)offset, (uint)size)); - // } - // else - // { - // asyncSending = true; - // ssl.WriteAsync(message, offset, size).ContinueWith(DataSent); - // } - // } - //} - - - - //private void DataReceived(Task task) - //{ - // try - // { - // if (state == SocketState.Closed || state == SocketState.Terminated) - // return; - - // if (task.Result <= 0) - // { - // Close(); - // return; - // } - - // receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)task.Result); - // OnReceive?.Invoke(receiveNetworkBuffer); - // if (state == SocketState.Established) - // ssl.ReadAsync(receiveBuffer, 0, receiveBuffer.Length).ContinueWith(DataReceived); - // } - // catch (Exception ex) - // { - // if (state != SocketState.Closed && !sock.Connected) - // { - // state = SocketState.Terminated; - // Close(); - // } - - // Global.Log("SSLSocket", LogType.Error, ex.ToString()); - // } - //} - - - public bool Begin() - { - if (began) - return false; - - began = true; - - if (server) - ssl.AuthenticateAsServer(cert); - else - ssl.AuthenticateAsClient(hostname); - - if (state == SocketState.Established) - { - ssl.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReceiveCallback, this); - return true; - } - else - return false; - } - - public async AsyncReply BeginAsync() - { - if (began) - return false; - - began = true; - - if (server) - await ssl.AuthenticateAsServerAsync(cert); - else - await ssl.AuthenticateAsClientAsync(hostname); - - if (state == SocketState.Established) - { - ssl.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReceiveCallback, this); - return true; - } - else - return false; - } - - private void ReceiveCallback(IAsyncResult results) + private void SendCallback(IAsyncResult ar) + { + if (ar != null) { try { - if (state != SocketState.Established) - return; - - var bytesReceived = ssl.EndRead(results); - - if (bytesReceived <= 0) - { - Close(); - return; - } - - receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)bytesReceived); - - //OnReceive?.Invoke(receiveNetworkBuffer); - - Receiver?.NetworkReceive(this, receiveNetworkBuffer); - - ssl.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReceiveCallback, this); + ssl.EndWrite(ar); + if (ar.AsyncState != null) + ((AsyncReply)ar.AsyncState).Trigger(true); } - catch //(Exception ex) + catch { if (state != SocketState.Closed && !sock.Connected) { - //state = SocketState.Terminated; + //state = SocketState.Closed;//.Terminated; Close(); } - - //Global.Log("SSLSocket", LogType.Error, ex.ToString()); } } - public bool Trigger(ResourceTrigger trigger) - { - return true; - } - - public void Destroy() - { - Close(); - Receiver = null; - receiveNetworkBuffer = null; - OnDestroy?.Invoke(this); - OnDestroy = null; - } - - public async AsyncReply AcceptAsync() - { - try - { - var s = await sock.AcceptAsync(); - return new SSLSocket(s, cert, true); - } - catch - { - state = SocketState.Closed;// Terminated; - return null; - } - } - - - public void Hold() - { - held = true; - } - - public void Unhold() - { - try - { - SendCallback(null); - } - catch (Exception ex) - { - Global.Log(ex); - } - finally - { - held = false; - } - } - - - public AsyncReply SendAsync(byte[] message, int offset, int length) + lock (sendLock) { - var msg = message.Clip((uint)offset, (uint)length); - - lock (sendLock) + if (sendBufferQueue.Count > 0) { - if (!sock.Connected) - return new AsyncReply(false); + var kv = sendBufferQueue.Dequeue(); - var rt = new AsyncReply(); - - if (asyncSending || held) + try { - sendBufferQueue.Enqueue(new KeyValuePair, byte[]>(rt, msg)); + ssl.BeginWrite(kv.Value, 0, kv.Value.Length, SendCallback, kv.Key); } - else + catch //(Exception ex) { - asyncSending = true; + asyncSending = false; try { - ssl.BeginWrite(msg, 0, msg.Length, SendCallback, rt);// null); + if (kv.Key != null) + kv.Key.Trigger(false); + + if (state != SocketState.Closed && !sock.Connected) + { + //state = SocketState.Terminated; + Close(); + } } - catch (Exception ex) + catch //(Exception ex2) { - rt.TriggerError(ex); - asyncSending = false; - //state = SocketState.Terminated; + //state = SocketState.Closed;// .Terminated; Close(); } + + //Global.Log("TCPSocket", LogType.Error, ex.ToString()); } - - return rt; } - } - - - public ISocket Accept() - { - try + else { - return new SSLSocket(sock.Accept(), cert, true); - } - catch - { - state = SocketState.Closed;// .Terminated; - return null; + asyncSending = false; } } } -} \ No newline at end of file + + public IPEndPoint LocalEndPoint + { + get { return (IPEndPoint)sock.LocalEndPoint; } + } + + public SSLSocket() + { + sock = new Socket(AddressFamily.InterNetwork, + SocketType.Stream, + ProtocolType.Tcp); + receiveBuffer = new byte[sock.ReceiveBufferSize]; + } + + public SSLSocket(IPEndPoint localEndPoint, X509Certificate2 certificate) + { + // create the socket + sock = new Socket(AddressFamily.InterNetwork, + SocketType.Stream, + ProtocolType.Tcp); + + state = SocketState.Listening; + + // bind + sock.Bind(localEndPoint); + + // start listening + sock.Listen(UInt16.MaxValue); + + cert = certificate; + } + + public IPEndPoint RemoteEndPoint + { + get { return (IPEndPoint)sock.RemoteEndPoint; } + } + + public SocketState State + { + get + { + return state; + } + } + + + + public SSLSocket(Socket socket, X509Certificate2 certificate, bool authenticateAsServer) + { + cert = certificate; + sock = socket; + receiveBuffer = new byte[sock.ReceiveBufferSize]; + + ssl = new SslStream(new NetworkStream(sock)); + + server = authenticateAsServer; + + if (socket.Connected) + state = SocketState.Established; + } + + + public void Close() + { + if (state != SocketState.Closed)// && state != SocketState.Terminated) + { + state = SocketState.Closed; + + if (sock.Connected) + { + try + { + sock.Shutdown(SocketShutdown.Both); + } + catch + { + //state = SocketState.Terminated; + } + } + + Receiver?.NetworkClose(this); + //OnClose?.Invoke(); + } + } + + + public void Send(byte[] message) + { + Send(message, 0, message.Length); + } + + + public void Send(byte[] message, int offset, int size) + { + + + var msg = message.Clip((uint)offset, (uint)size); + + lock (sendLock) + { + + if (!sock.Connected) + return; + + if (asyncSending || held) + { + sendBufferQueue.Enqueue(new KeyValuePair, byte[]>(null, msg));// message.Clip((uint)offset, (uint)size)); + } + else + { + asyncSending = true; + try + { + ssl.BeginWrite(msg, 0, msg.Length, SendCallback, null); + } + catch + { + asyncSending = false; + //state = SocketState.Terminated; + Close(); + } + } + } + } + + //public void Send(byte[] message) + //{ + // Send(message, 0, message.Length); + //} + + //public void Send(byte[] message, int offset, int size) + //{ + // lock (sendLock) + // { + // if (asyncSending) + // { + // sendBufferQueue.Enqueue(message.Clip((uint)offset, (uint)size)); + // } + // else + // { + // asyncSending = true; + // ssl.WriteAsync(message, offset, size).ContinueWith(DataSent); + // } + // } + //} + + + + //private void DataReceived(Task task) + //{ + // try + // { + // if (state == SocketState.Closed || state == SocketState.Terminated) + // return; + + // if (task.Result <= 0) + // { + // Close(); + // return; + // } + + // receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)task.Result); + // OnReceive?.Invoke(receiveNetworkBuffer); + // if (state == SocketState.Established) + // ssl.ReadAsync(receiveBuffer, 0, receiveBuffer.Length).ContinueWith(DataReceived); + // } + // catch (Exception ex) + // { + // if (state != SocketState.Closed && !sock.Connected) + // { + // state = SocketState.Terminated; + // Close(); + // } + + // Global.Log("SSLSocket", LogType.Error, ex.ToString()); + // } + //} + + + public bool Begin() + { + if (began) + return false; + + began = true; + + if (server) + ssl.AuthenticateAsServer(cert); + else + ssl.AuthenticateAsClient(hostname); + + if (state == SocketState.Established) + { + ssl.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReceiveCallback, this); + return true; + } + else + return false; + } + + public async AsyncReply BeginAsync() + { + if (began) + return false; + + began = true; + + if (server) + await ssl.AuthenticateAsServerAsync(cert); + else + await ssl.AuthenticateAsClientAsync(hostname); + + if (state == SocketState.Established) + { + ssl.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReceiveCallback, this); + return true; + } + else + return false; + } + + private void ReceiveCallback(IAsyncResult results) + { + try + { + if (state != SocketState.Established) + return; + + var bytesReceived = ssl.EndRead(results); + + if (bytesReceived <= 0) + { + Close(); + return; + } + + receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)bytesReceived); + + //OnReceive?.Invoke(receiveNetworkBuffer); + + Receiver?.NetworkReceive(this, receiveNetworkBuffer); + + ssl.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReceiveCallback, this); + + } + catch //(Exception ex) + { + if (state != SocketState.Closed && !sock.Connected) + { + //state = SocketState.Terminated; + Close(); + } + + //Global.Log("SSLSocket", LogType.Error, ex.ToString()); + } + } + + public bool Trigger(ResourceTrigger trigger) + { + return true; + } + + public void Destroy() + { + Close(); + Receiver = null; + receiveNetworkBuffer = null; + OnDestroy?.Invoke(this); + OnDestroy = null; + } + + public async AsyncReply AcceptAsync() + { + try + { + var s = await sock.AcceptAsync(); + return new SSLSocket(s, cert, true); + } + catch + { + state = SocketState.Closed;// Terminated; + return null; + } + } + + + public void Hold() + { + held = true; + } + + public void Unhold() + { + try + { + SendCallback(null); + } + catch (Exception ex) + { + Global.Log(ex); + } + finally + { + held = false; + } + } + + + public AsyncReply SendAsync(byte[] message, int offset, int length) + { + + var msg = message.Clip((uint)offset, (uint)length); + + lock (sendLock) + { + if (!sock.Connected) + return new AsyncReply(false); + + var rt = new AsyncReply(); + + if (asyncSending || held) + { + sendBufferQueue.Enqueue(new KeyValuePair, byte[]>(rt, msg)); + } + else + { + asyncSending = true; + try + { + ssl.BeginWrite(msg, 0, msg.Length, SendCallback, rt);// null); + } + catch (Exception ex) + { + rt.TriggerError(ex); + asyncSending = false; + //state = SocketState.Terminated; + Close(); + } + } + + return rt; + } + } + + + public ISocket Accept() + { + try + { + return new SSLSocket(sock.Accept(), cert, true); + } + catch + { + state = SocketState.Closed;// .Terminated; + return null; + } + } +} + diff --git a/Esiur/Net/Sockets/SocketState.cs b/Esiur/Net/Sockets/SocketState.cs index a9dac54..3e85465 100644 --- a/Esiur/Net/Sockets/SocketState.cs +++ b/Esiur/Net/Sockets/SocketState.cs @@ -28,15 +28,13 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Net.Sockets +namespace Esiur.Net.Sockets; +public enum SocketState { - public enum SocketState - { - Initial, - Listening, - Connecting, - Established, - Closed, - //Terminated - } + Initial, + Listening, + Connecting, + Established, + Closed, + //Terminated } diff --git a/Esiur/Net/Sockets/TCPSocket.cs b/Esiur/Net/Sockets/TCPSocket.cs index b6fa2d1..41afcf1 100644 --- a/Esiur/Net/Sockets/TCPSocket.cs +++ b/Esiur/Net/Sockets/TCPSocket.cs @@ -35,625 +35,623 @@ using Esiur.Resource; using System.Threading.Tasks; using Esiur.Data; -namespace Esiur.Net.Sockets +namespace Esiur.Net.Sockets; +public class TCPSocket : ISocket { - public class TCPSocket : ISocket + public INetworkReceiver Receiver { get; set; } + + Socket sock; + byte[] receiveBuffer; + + bool held; + + //ArraySegment receiveBufferSegment; + + NetworkBuffer receiveNetworkBuffer = new NetworkBuffer(); + + readonly object sendLock = new object(); + + Queue, byte[]>> sendBufferQueue = new Queue, byte[]>>();// Queue(); + + bool asyncSending; + bool began = false; + + + SocketState state = SocketState.Initial; + + //public event ISocketReceiveEvent OnReceive; + //public event ISocketConnectEvent OnConnect; + //public event ISocketCloseEvent OnClose; + public event DestroyedEvent OnDestroy; + + //SocketAsyncEventArgs socketArgs = new SocketAsyncEventArgs(); + + private AsyncCallback receiveCallback; + private AsyncCallback sendCallback; + + public AsyncReply BeginAsync() { - public INetworkReceiver Receiver { get; set; } - - Socket sock; - byte[] receiveBuffer; - - bool held; - - //ArraySegment receiveBufferSegment; - - NetworkBuffer receiveNetworkBuffer = new NetworkBuffer(); - - readonly object sendLock = new object(); - - Queue, byte[]>> sendBufferQueue = new Queue, byte[]>>();// Queue(); - - bool asyncSending; - bool began = false; + return new AsyncReply(Begin()); + } - SocketState state = SocketState.Initial; + private AsyncReply currentReply = null; - //public event ISocketReceiveEvent OnReceive; - //public event ISocketConnectEvent OnConnect; - //public event ISocketCloseEvent OnClose; - public event DestroyedEvent OnDestroy; + public bool Begin() + { + if (began) + return false; - //SocketAsyncEventArgs socketArgs = new SocketAsyncEventArgs(); + began = true; + /* - private AsyncCallback receiveCallback; - private AsyncCallback sendCallback; + socketArgs.SetBuffer(receiveBuffer, 0, receiveBuffer.Length); + socketArgs.Completed += SocketArgs_Completed; - public AsyncReply BeginAsync() + if (!sock.ReceiveAsync(socketArgs)) + SocketArgs_Completed(null, socketArgs); + */ + receiveCallback = new AsyncCallback(ReceiveCallback); + sendCallback = new AsyncCallback(SendCallback); + + sock.BeginReceive(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None, receiveCallback, this); + //sock.ReceiveAsync(receiveBufferSegment, SocketFlags.None).ContinueWith(DataReceived); + return true; + } + + private static void ReceiveCallback(IAsyncResult ar) + { + var socket = ar.AsyncState as TCPSocket; + + try { - return new AsyncReply(Begin()); - } - - private AsyncReply currentReply = null; - - public bool Begin() - { - if (began) - return false; - - began = true; - /* - - socketArgs.SetBuffer(receiveBuffer, 0, receiveBuffer.Length); - socketArgs.Completed += SocketArgs_Completed; - - if (!sock.ReceiveAsync(socketArgs)) - SocketArgs_Completed(null, socketArgs); - */ - receiveCallback = new AsyncCallback(ReceiveCallback); - sendCallback = new AsyncCallback(SendCallback); - - sock.BeginReceive(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None, receiveCallback, this); - //sock.ReceiveAsync(receiveBufferSegment, SocketFlags.None).ContinueWith(DataReceived); - return true; - } - - private static void ReceiveCallback(IAsyncResult ar) - { - var socket = ar.AsyncState as TCPSocket; - - try - { - - if (socket.state != SocketState.Established) - return; - - var recCount = socket.sock.EndReceive(ar); - - if (recCount > 0) - { - socket.receiveNetworkBuffer.Write(socket.receiveBuffer, 0, (uint)recCount); - socket.Receiver?.NetworkReceive(socket, socket.receiveNetworkBuffer); - - if (socket.state == SocketState.Established) - socket.sock.BeginReceive(socket.receiveBuffer, 0, socket.receiveBuffer.Length, SocketFlags.None, socket.receiveCallback, socket); - } - else - { - socket.Close(); - return; - } - } - catch //(Exception ex) - { - if (socket.state != SocketState.Closed && !socket.sock.Connected) - { - //socket.state = SocketState.Terminated; - socket.Close(); - } - - //Global.Log("TCPSocket", LogType.Error, ex.ToString()); - } - } - - - public AsyncReply Connect(string hostname, ushort port) - { - var rt = new AsyncReply(); - - try - { - state = SocketState.Connecting; - sock.ConnectAsync(hostname, port).ContinueWith((x) => - { - - if (x.IsFaulted) - rt.TriggerError(x.Exception); - else - { - - state = SocketState.Established; - //OnConnect?.Invoke(); - Receiver?.NetworkConnect(this); - Begin(); - rt.Trigger(true); - } - }); - } - catch (Exception ex) - { - rt.TriggerError(ex); - } - - return rt; - } - - - //private void DataReceived(Task task) - //{ - // try - // { - // // SocketError err; - - // if (state == SocketState.Closed || state == SocketState.Terminated) - // return; - - // if (task.Result <= 0) - // { - // Close(); - // return; - // } - - // receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)task.Result); - // //OnReceive?.Invoke(receiveNetworkBuffer); - // Receiver?.NetworkReceive(this, receiveNetworkBuffer); - // if (state == SocketState.Established) - // sock.ReceiveAsync(receiveBufferSegment, SocketFlags.None).ContinueWith(DataReceived); - - // } - // catch (Exception ex) - // { - // if (state != SocketState.Closed && !sock.Connected) - // { - // state = SocketState.Terminated; - // Close(); - // } - - // Global.Log("TCPSocket", LogType.Error, ex.ToString()); - // } - //} - - //private void SocketArgs_Completed(object sender, SocketAsyncEventArgs e) - //{ - // try - // { - // if (state != SocketState.Established) - // return; - - // if (e.BytesTransferred <= 0) - // { - // Close(); - // return; - // } - // else if (e.SocketError != SocketError.Success) - // { - // Close(); - // return; - - // } - - // var recCount = e.BytesTransferred > e.Count ? e.Count : e.BytesTransferred; - // receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)recCount); - - // //OnReceive?.Invoke(receiveNetworkBuffer); - // Receiver?.NetworkReceive(this, receiveNetworkBuffer); - - // if (state == SocketState.Established) - // while (!sock.ReceiveAsync(e)) - // { - // if (e.SocketError != SocketError.Success) - // { - // Close(); - // return; - // } - - // if (State != SocketState.Established) - // return; - - // //if (e.BytesTransferred < 0) - // // Console.WriteLine("BytesTransferred is less than zero"); - - // if (e.BytesTransferred <= 0) - // { - // Close(); - // return; - // } - // else if (e.SocketError != SocketError.Success) - // { - // Close(); - // return; - // } - - - // //if (e.BytesTransferred > 100000) - // // Console.WriteLine("BytesTransferred is large " + e.BytesTransferred); - - // recCount = e.BytesTransferred > e.Count ? e.Count : e.BytesTransferred; - - // receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)recCount); - - // //OnReceive?.Invoke(receiveNetworkBuffer); - // Receiver?.NetworkReceive(this, receiveNetworkBuffer); - // } - - // } - // catch (Exception ex) - // { - // if (state != SocketState.Closed && !sock.Connected) - // { - // state = SocketState.Terminated; - // Close(); - // } - - // Global.Log("TCPSocket", LogType.Error, ex.ToString()); - // } - //} - - public IPEndPoint LocalEndPoint - { - get { return (IPEndPoint)sock.LocalEndPoint; } - } - - public TCPSocket() - { - sock = new Socket(AddressFamily.InterNetwork, - SocketType.Stream, - ProtocolType.Tcp); - receiveBuffer = new byte[sock.ReceiveBufferSize]; - //receiveBufferSegment = new ArraySegment(receiveBuffer); - - } - - public TCPSocket(string hostname, ushort port) - { - // create the socket - sock = new Socket(AddressFamily.InterNetwork, - SocketType.Stream, - ProtocolType.Tcp); - - receiveBuffer = new byte[sock.ReceiveBufferSize]; - //receiveBufferSegment = new ArraySegment(receiveBuffer); - - Connect(hostname, port); - - } - - //private void DataSent(Task task) - //{ - // try - // { - // lock (sendLock) - // { - - // if (sendBufferQueue.Count > 0) - // { - // byte[] data = sendBufferQueue.Dequeue(); - // //Console.WriteLine(Encoding.UTF8.GetString(data)); - // sock.SendAsync(new ArraySegment(data), SocketFlags.None).ContinueWith(DataSent); - // } - - // else - // { - // asyncSending = false; - // } - // } - // } - // catch (Exception ex) - // { - // if (state != SocketState.Closed && !sock.Connected) - // { - // state = SocketState.Terminated; - // Close(); - // } - - // asyncSending = false; - - // Global.Log("TCPSocket", LogType.Error, ex.ToString()); - // } - //} - - public TCPSocket(IPEndPoint localEndPoint) - { - // create the socket - sock = new Socket(AddressFamily.InterNetwork, - SocketType.Stream, - ProtocolType.Tcp); - - receiveBuffer = new byte[sock.ReceiveBufferSize]; - - state = SocketState.Listening; - - - // bind - sock.Bind(localEndPoint); - - // start listening - sock.Listen(UInt16.MaxValue); - - - } - - - - - public IPEndPoint RemoteEndPoint - { - get { return (IPEndPoint)sock.RemoteEndPoint; } - } - - public SocketState State - { - get - { - return state; - } - } - - - public TCPSocket(Socket socket) - { - sock = socket; - receiveBuffer = new byte[sock.ReceiveBufferSize]; - // receiveBufferSegment = new ArraySegment(receiveBuffer); - if (socket.Connected) - state = SocketState.Established; - } - - public void Close() - { - if (state != SocketState.Closed)// && state != SocketState.Terminated) - { - state = SocketState.Closed; - - if (sock.Connected) - { - try - { - sock.Shutdown(SocketShutdown.Both); - } - catch - { - - } - } - - try - { - sendBufferQueue?.Clear(); - Receiver?.NetworkClose(this); - } - catch (Exception ex) - { - Global.Log(ex); - } - } - } - - public void Send(byte[] message) - { - Send(message, 0, message.Length); - } - - public void Send(byte[] message, int offset, int size) - { - if (state == SocketState.Closed)// || state == SocketState.Terminated) + if (socket.state != SocketState.Established) return; - var msg = message.Clip((uint)offset, (uint)size); + var recCount = socket.sock.EndReceive(ar); - lock (sendLock) + if (recCount > 0) { + socket.receiveNetworkBuffer.Write(socket.receiveBuffer, 0, (uint)recCount); + socket.Receiver?.NetworkReceive(socket, socket.receiveNetworkBuffer); - if (state == SocketState.Closed)// || state == SocketState.Terminated) - return; - - if (!sock.Connected) - return; - - if (asyncSending || held) - { - sendBufferQueue.Enqueue(new KeyValuePair, byte[]>(null, msg));// message.Clip((uint)offset, (uint)size)); - } - else - { - asyncSending = true; - try - { - sock.BeginSend(msg, 0, msg.Length, SocketFlags.None, sendCallback, this); - } - catch - { - asyncSending = false; - //state = SocketState.Closed;//.Terminated; - Close(); - } - //sock.SendAsync(new ArraySegment(msg), SocketFlags.None).ContinueWith(DataSent); - } + if (socket.state == SocketState.Established) + socket.sock.BeginReceive(socket.receiveBuffer, 0, socket.receiveBuffer.Length, SocketFlags.None, socket.receiveCallback, socket); } - - } - - private static void Flush(TCPSocket socket) - { - lock (socket.sendLock) + else { - - socket.currentReply?.Trigger(true); - socket.currentReply = null; - - if (socket.state == SocketState.Closed) //|| socket.state == SocketState.Terminated) - return; - - if (socket.sendBufferQueue.Count > 0) - { - var kv = socket.sendBufferQueue.Dequeue(); - - try - { - socket.currentReply = kv.Key; - socket.sock.BeginSend(kv.Value, 0, kv.Value.Length, SocketFlags.None, - socket.sendCallback, socket); - } - catch (Exception ex) - { - socket.asyncSending = false; - - try - { - kv.Key?.Trigger(false); - - if (socket.state != SocketState.Closed && !socket.sock.Connected) - { - // socket.state = SocketState.Closed;// Terminated; - socket.Close(); - } - } - catch //(Exception ex2) - { - socket.Close(); - //socket.state = SocketState.Closed;// .Terminated; - } - - Global.Log("TCPSocket", LogType.Error, ex.ToString()); - } - } - else - { - socket.asyncSending = false; - } + socket.Close(); + return; } } - - private static void SendCallback(IAsyncResult ar) + catch //(Exception ex) { + if (socket.state != SocketState.Closed && !socket.sock.Connected) + { + //socket.state = SocketState.Terminated; + socket.Close(); + } + + //Global.Log("TCPSocket", LogType.Error, ex.ToString()); + } + } + + + public AsyncReply Connect(string hostname, ushort port) + { + var rt = new AsyncReply(); + + try + { + state = SocketState.Connecting; + sock.ConnectAsync(hostname, port).ContinueWith((x) => + { + + if (x.IsFaulted) + rt.TriggerError(x.Exception); + else + { + + state = SocketState.Established; + //OnConnect?.Invoke(); + Receiver?.NetworkConnect(this); + Begin(); + rt.Trigger(true); + } + }); + } + catch (Exception ex) + { + rt.TriggerError(ex); + } + + return rt; + } + + + //private void DataReceived(Task task) + //{ + // try + // { + // // SocketError err; + + // if (state == SocketState.Closed || state == SocketState.Terminated) + // return; + + // if (task.Result <= 0) + // { + // Close(); + // return; + // } + + // receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)task.Result); + // //OnReceive?.Invoke(receiveNetworkBuffer); + // Receiver?.NetworkReceive(this, receiveNetworkBuffer); + // if (state == SocketState.Established) + // sock.ReceiveAsync(receiveBufferSegment, SocketFlags.None).ContinueWith(DataReceived); + + // } + // catch (Exception ex) + // { + // if (state != SocketState.Closed && !sock.Connected) + // { + // state = SocketState.Terminated; + // Close(); + // } + + // Global.Log("TCPSocket", LogType.Error, ex.ToString()); + // } + //} + + //private void SocketArgs_Completed(object sender, SocketAsyncEventArgs e) + //{ + // try + // { + // if (state != SocketState.Established) + // return; + + // if (e.BytesTransferred <= 0) + // { + // Close(); + // return; + // } + // else if (e.SocketError != SocketError.Success) + // { + // Close(); + // return; + + // } + + // var recCount = e.BytesTransferred > e.Count ? e.Count : e.BytesTransferred; + // receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)recCount); + + // //OnReceive?.Invoke(receiveNetworkBuffer); + // Receiver?.NetworkReceive(this, receiveNetworkBuffer); + + // if (state == SocketState.Established) + // while (!sock.ReceiveAsync(e)) + // { + // if (e.SocketError != SocketError.Success) + // { + // Close(); + // return; + // } + + // if (State != SocketState.Established) + // return; + + // //if (e.BytesTransferred < 0) + // // Console.WriteLine("BytesTransferred is less than zero"); + + // if (e.BytesTransferred <= 0) + // { + // Close(); + // return; + // } + // else if (e.SocketError != SocketError.Success) + // { + // Close(); + // return; + // } + + + // //if (e.BytesTransferred > 100000) + // // Console.WriteLine("BytesTransferred is large " + e.BytesTransferred); + + // recCount = e.BytesTransferred > e.Count ? e.Count : e.BytesTransferred; + + // receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)recCount); + + // //OnReceive?.Invoke(receiveNetworkBuffer); + // Receiver?.NetworkReceive(this, receiveNetworkBuffer); + // } + + // } + // catch (Exception ex) + // { + // if (state != SocketState.Closed && !sock.Connected) + // { + // state = SocketState.Terminated; + // Close(); + // } + + // Global.Log("TCPSocket", LogType.Error, ex.ToString()); + // } + //} + + public IPEndPoint LocalEndPoint + { + get { return (IPEndPoint)sock.LocalEndPoint; } + } + + public TCPSocket() + { + sock = new Socket(AddressFamily.InterNetwork, + SocketType.Stream, + ProtocolType.Tcp); + receiveBuffer = new byte[sock.ReceiveBufferSize]; + //receiveBufferSegment = new ArraySegment(receiveBuffer); + + } + + public TCPSocket(string hostname, ushort port) + { + // create the socket + sock = new Socket(AddressFamily.InterNetwork, + SocketType.Stream, + ProtocolType.Tcp); + + receiveBuffer = new byte[sock.ReceiveBufferSize]; + //receiveBufferSegment = new ArraySegment(receiveBuffer); + + Connect(hostname, port); + + } + + //private void DataSent(Task task) + //{ + // try + // { + // lock (sendLock) + // { + + // if (sendBufferQueue.Count > 0) + // { + // byte[] data = sendBufferQueue.Dequeue(); + // //Console.WriteLine(Encoding.UTF8.GetString(data)); + // sock.SendAsync(new ArraySegment(data), SocketFlags.None).ContinueWith(DataSent); + // } + + // else + // { + // asyncSending = false; + // } + // } + // } + // catch (Exception ex) + // { + // if (state != SocketState.Closed && !sock.Connected) + // { + // state = SocketState.Terminated; + // Close(); + // } + + // asyncSending = false; + + // Global.Log("TCPSocket", LogType.Error, ex.ToString()); + // } + //} + + public TCPSocket(IPEndPoint localEndPoint) + { + // create the socket + sock = new Socket(AddressFamily.InterNetwork, + SocketType.Stream, + ProtocolType.Tcp); + + receiveBuffer = new byte[sock.ReceiveBufferSize]; + + state = SocketState.Listening; + + + // bind + sock.Bind(localEndPoint); + + // start listening + sock.Listen(UInt16.MaxValue); + + + } + + + + + public IPEndPoint RemoteEndPoint + { + get { return (IPEndPoint)sock.RemoteEndPoint; } + } + + public SocketState State + { + get + { + return state; + } + } + + + public TCPSocket(Socket socket) + { + sock = socket; + receiveBuffer = new byte[sock.ReceiveBufferSize]; + // receiveBufferSegment = new ArraySegment(receiveBuffer); + if (socket.Connected) + state = SocketState.Established; + } + + public void Close() + { + if (state != SocketState.Closed)// && state != SocketState.Terminated) + { + state = SocketState.Closed; + + if (sock.Connected) + { + try + { + sock.Shutdown(SocketShutdown.Both); + } + catch + { + + } + } try { - var socket = (TCPSocket)ar.AsyncState; - - socket.sock?.EndSend(ar); - Flush(socket); - + sendBufferQueue?.Clear(); + Receiver?.NetworkClose(this); } catch (Exception ex) { Global.Log(ex); } } + } - public bool Trigger(ResourceTrigger trigger) - { - return true; - } + public void Send(byte[] message) + { + Send(message, 0, message.Length); + } - public void Destroy() - { - Global.Counters["Sck_D_1"]++; + public void Send(byte[] message, int offset, int size) + { + if (state == SocketState.Closed)// || state == SocketState.Terminated) + return; - Close(); + var msg = message.Clip((uint)offset, (uint)size); - receiveNetworkBuffer = null; - receiveCallback = null; - sendCallback = null; - sock = null; - receiveBuffer = null; - receiveNetworkBuffer = null; - sendBufferQueue = null; - - //socketArgs.Completed -= SocketArgs_Completed; - //socketArgs.Dispose(); - //socketArgs = null; - OnDestroy?.Invoke(this); - OnDestroy = null; - - Global.Counters["Sck_D_2"]++; - } - - public ISocket Accept() - { - try - { - var s = sock.Accept(); - return new TCPSocket(s); - } - catch - { - state = SocketState.Closed;// Terminated; - return null; - } - } - - public async AsyncReply AcceptAsync() - { - try - { - var s = await sock.AcceptAsync(); - return new TCPSocket(s); - } - catch - { - state = SocketState.Closed;// Terminated; - return null; - } - } - - - public void Hold() - { - held = true; - } - - public void Unhold() - { - try - { - Flush(this); - //SendCallback(null); - } - catch (Exception ex) - { - Console.WriteLine(ex); - } - finally - { - held = false; - } - } - - public AsyncReply SendAsync(byte[] message, int offset, int length) + lock (sendLock) { if (state == SocketState.Closed)// || state == SocketState.Terminated) - return new AsyncReply(false); + return; - var msg = message.Clip((uint)offset, (uint)length); + if (!sock.Connected) + return; - lock (sendLock) + if (asyncSending || held) { - if (state == SocketState.Closed)// || state == SocketState.Terminated) - return new AsyncReply(false); - - if (!sock.Connected) - return new AsyncReply(false); - - var rt = new AsyncReply(); - - if (asyncSending || held) + sendBufferQueue.Enqueue(new KeyValuePair, byte[]>(null, msg));// message.Clip((uint)offset, (uint)size)); + } + else + { + asyncSending = true; + try { - sendBufferQueue.Enqueue(new KeyValuePair, byte[]>(rt, msg)); + sock.BeginSend(msg, 0, msg.Length, SocketFlags.None, sendCallback, this); } - else + catch { - asyncSending = true; + asyncSending = false; + //state = SocketState.Closed;//.Terminated; + Close(); + } + //sock.SendAsync(new ArraySegment(msg), SocketFlags.None).ContinueWith(DataSent); + } + } + + } + + private static void Flush(TCPSocket socket) + { + lock (socket.sendLock) + { + + socket.currentReply?.Trigger(true); + socket.currentReply = null; + + if (socket.state == SocketState.Closed) //|| socket.state == SocketState.Terminated) + return; + + if (socket.sendBufferQueue.Count > 0) + { + var kv = socket.sendBufferQueue.Dequeue(); + + try + { + socket.currentReply = kv.Key; + socket.sock.BeginSend(kv.Value, 0, kv.Value.Length, SocketFlags.None, + socket.sendCallback, socket); + } + catch (Exception ex) + { + socket.asyncSending = false; + try { - currentReply = rt; - sock.BeginSend(msg, 0, msg.Length, SocketFlags.None, sendCallback, this);// null); - } - catch (Exception ex) - { - rt.TriggerError(ex); - asyncSending = false; - //state = SocketState.Terminated; - Close(); - } - //sock.SendAsync(new ArraySegment(msg), SocketFlags.None).ContinueWith(DataSent); - } + kv.Key?.Trigger(false); - return rt; + if (socket.state != SocketState.Closed && !socket.sock.Connected) + { + // socket.state = SocketState.Closed;// Terminated; + socket.Close(); + } + } + catch //(Exception ex2) + { + socket.Close(); + //socket.state = SocketState.Closed;// .Terminated; + } + + Global.Log("TCPSocket", LogType.Error, ex.ToString()); + } + } + else + { + socket.asyncSending = false; } } } -} \ No newline at end of file + + private static void SendCallback(IAsyncResult ar) + { + + try + { + var socket = (TCPSocket)ar.AsyncState; + + socket.sock?.EndSend(ar); + Flush(socket); + + } + catch (Exception ex) + { + Global.Log(ex); + } + } + + public bool Trigger(ResourceTrigger trigger) + { + return true; + } + + public void Destroy() + { + Global.Counters["Sck_D_1"]++; + + Close(); + + receiveNetworkBuffer = null; + receiveCallback = null; + sendCallback = null; + sock = null; + receiveBuffer = null; + receiveNetworkBuffer = null; + sendBufferQueue = null; + + //socketArgs.Completed -= SocketArgs_Completed; + //socketArgs.Dispose(); + //socketArgs = null; + OnDestroy?.Invoke(this); + OnDestroy = null; + + Global.Counters["Sck_D_2"]++; + } + + public ISocket Accept() + { + try + { + var s = sock.Accept(); + return new TCPSocket(s); + } + catch + { + state = SocketState.Closed;// Terminated; + return null; + } + } + + public async AsyncReply AcceptAsync() + { + try + { + var s = await sock.AcceptAsync(); + return new TCPSocket(s); + } + catch + { + state = SocketState.Closed;// Terminated; + return null; + } + } + + + public void Hold() + { + held = true; + } + + public void Unhold() + { + try + { + Flush(this); + //SendCallback(null); + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + finally + { + held = false; + } + } + + public AsyncReply SendAsync(byte[] message, int offset, int length) + { + + if (state == SocketState.Closed)// || state == SocketState.Terminated) + return new AsyncReply(false); + + var msg = message.Clip((uint)offset, (uint)length); + + lock (sendLock) + { + if (state == SocketState.Closed)// || state == SocketState.Terminated) + return new AsyncReply(false); + + if (!sock.Connected) + return new AsyncReply(false); + + var rt = new AsyncReply(); + + if (asyncSending || held) + { + sendBufferQueue.Enqueue(new KeyValuePair, byte[]>(rt, msg)); + } + else + { + asyncSending = true; + try + { + currentReply = rt; + sock.BeginSend(msg, 0, msg.Length, SocketFlags.None, sendCallback, this);// null); + } + catch (Exception ex) + { + rt.TriggerError(ex); + asyncSending = false; + //state = SocketState.Terminated; + Close(); + } + //sock.SendAsync(new ArraySegment(msg), SocketFlags.None).ContinueWith(DataSent); + } + + return rt; + } + } +} diff --git a/Esiur/Net/Sockets/WSocket.cs b/Esiur/Net/Sockets/WSocket.cs index 6fbfcba..86c9ad2 100644 --- a/Esiur/Net/Sockets/WSocket.cs +++ b/Esiur/Net/Sockets/WSocket.cs @@ -36,326 +36,324 @@ using Esiur.Resource; using Esiur.Data; using System.Globalization; -namespace Esiur.Net.Sockets +namespace Esiur.Net.Sockets; +public class WSocket : ISocket, INetworkReceiver { - public class WSocket : ISocket, INetworkReceiver + WebsocketPacket pkt_receive = new WebsocketPacket(); + WebsocketPacket pkt_send = new WebsocketPacket(); + + ISocket sock; + NetworkBuffer receiveNetworkBuffer = new NetworkBuffer(); + NetworkBuffer sendNetworkBuffer = new NetworkBuffer(); + + object sendLock = new object(); + bool held; + + //public event ISocketReceiveEvent OnReceive; + //public event ISocketConnectEvent OnConnect; + //public event ISocketCloseEvent OnClose; + public event DestroyedEvent OnDestroy; + + long totalSent, totalReceived; + + bool processing = false; + + public IPEndPoint LocalEndPoint { - WebsocketPacket pkt_receive = new WebsocketPacket(); - WebsocketPacket pkt_send = new WebsocketPacket(); + get { return (IPEndPoint)sock.LocalEndPoint; } + } - ISocket sock; - NetworkBuffer receiveNetworkBuffer = new NetworkBuffer(); - NetworkBuffer sendNetworkBuffer = new NetworkBuffer(); + public IPEndPoint RemoteEndPoint + { + get { return sock.RemoteEndPoint; } + } - object sendLock = new object(); - bool held; - //public event ISocketReceiveEvent OnReceive; - //public event ISocketConnectEvent OnConnect; - //public event ISocketCloseEvent OnClose; - public event DestroyedEvent OnDestroy; - - long totalSent, totalReceived; - - bool processing = false; - - public IPEndPoint LocalEndPoint + public SocketState State + { + get { - get { return (IPEndPoint)sock.LocalEndPoint; } - } - - public IPEndPoint RemoteEndPoint - { - get { return sock.RemoteEndPoint; } - } - - - public SocketState State - { - get - { - return sock.State; - } - } - - public INetworkReceiver Receiver { get; set; } - - public WSocket(ISocket socket) - { - pkt_send.FIN = true; - pkt_send.Mask = false; - pkt_send.Opcode = WebsocketPacket.WSOpcode.BinaryFrame; - sock = socket; - - sock.Receiver = this; - - //sock.OnClose += Sock_OnClose; - //sock.OnConnect += Sock_OnConnect; - //sock.OnReceive += Sock_OnReceive; - } - - //private void Sock_OnReceive(NetworkBuffer buffer) - //{ - - //} - - //private void Sock_OnConnect() - //{ - // OnConnect?.Invoke(); - //} - - //private void Sock_OnClose() - //{ - // OnClose?.Invoke(); - //} - - public void Send(WebsocketPacket packet) - { - lock (sendLock) - if (packet.Compose()) - sock.Send(packet.Data); - } - - public void Send(byte[] message) - { - - lock (sendLock) - { - if (held) - { - sendNetworkBuffer.Write(message); - } - else - { - totalSent += message.Length; - //Console.WriteLine("TX " + message.Length +"/"+totalSent);// + " " + DC.ToHex(message, 0, (uint)size)); - - pkt_send.Message = message; - - if (pkt_send.Compose()) - sock?.Send(pkt_send.Data); - - } - } - } - - - public void Send(byte[] message, int offset, int size) - { - lock (sendLock) - { - if (held) - { - sendNetworkBuffer.Write(message, (uint)offset, (uint)size); - } - else - { - totalSent += size; - //Console.WriteLine("TX " + size + "/"+totalSent);// + " " + DC.ToHex(message, 0, (uint)size)); - - pkt_send.Message = new byte[size]; - Buffer.BlockCopy(message, offset, pkt_send.Message, 0, size); - if (pkt_send.Compose()) - sock.Send(pkt_send.Data); - } - } - } - - - public void Close() - { - sock?.Close(); - } - - public AsyncReply Connect(string hostname, ushort port) - { - throw new NotImplementedException(); - } - - - public bool Begin() - { - return sock.Begin(); - } - - public bool Trigger(ResourceTrigger trigger) - { - return true; - } - - public void Destroy() - { - Close(); - //OnClose = null; - //OnConnect = null; - //OnReceive = null; - receiveNetworkBuffer = null; - //sock.OnReceive -= Sock_OnReceive; - //sock.OnClose -= Sock_OnClose; - //sock.OnConnect -= Sock_OnConnect; - sock.Receiver = null; - sock = null; - OnDestroy?.Invoke(this); - OnDestroy = null; - } - - public AsyncReply AcceptAsync() - { - throw new NotImplementedException(); - } - - public void Hold() - { - //Console.WriteLine("WS Hold "); - held = true; - } - - public void Unhold() - { - lock (sendLock) - { - held = false; - - var message = sendNetworkBuffer.Read(); - - //Console.WriteLine("WS Unhold {0}", message == null ? 0 : message.Length); - - if (message == null) - return; - - totalSent += message.Length; - - pkt_send.Message = message; - if (pkt_send.Compose()) - sock.Send(pkt_send.Data); - - } - } - - public AsyncReply SendAsync(byte[] message, int offset, int length) - { - throw new NotImplementedException(); - } - - public ISocket Accept() - { - throw new NotImplementedException(); - } - - public AsyncReply BeginAsync() - { - return sock.BeginAsync(); - } - - public void NetworkClose(ISocket sender) - { - Receiver?.NetworkClose(sender); - } - - public void NetworkReceive(ISocket sender, NetworkBuffer buffer) - { - - if (sock.State == SocketState.Closed)// || sock.State == SocketState.Terminated) - return; - - if (buffer.Protected) - return; - - if (processing) - return; - - - var msg = buffer.Read(); - - if (msg == null) - return; - - var wsPacketLength = pkt_receive.Parse(msg, 0, (uint)msg.Length); - //Console.WriteLine("WSP: " + wsPacketLength); - - if (wsPacketLength < 0) - { - buffer.Protect(msg, 0, (uint)msg.Length + (uint)-wsPacketLength); - return; - } - - uint offset = 0; - - while (wsPacketLength > 0) - { - if (pkt_receive.Opcode == WebsocketPacket.WSOpcode.ConnectionClose) - { - Close(); - return; - } - else if (pkt_receive.Opcode == WebsocketPacket.WSOpcode.Ping) - { - var pkt_pong = new WebsocketPacket(); - - pkt_pong.FIN = true; - pkt_pong.Mask = false; - pkt_pong.Opcode = WebsocketPacket.WSOpcode.Pong; - pkt_pong.Message = pkt_receive.Message; - offset += (uint)wsPacketLength; - - Send(pkt_pong); - } - else if (pkt_receive.Opcode == WebsocketPacket.WSOpcode.Pong) - { - offset += (uint)wsPacketLength; - } - else if (pkt_receive.Opcode == WebsocketPacket.WSOpcode.BinaryFrame - || pkt_receive.Opcode == WebsocketPacket.WSOpcode.TextFrame - || pkt_receive.Opcode == WebsocketPacket.WSOpcode.ContinuationFrame) - { - totalReceived += pkt_receive.Message.Length; - //Console.WriteLine("RX " + pkt_receive.Message.Length + "/" + totalReceived);// + " " + DC.ToHex(message, 0, (uint)size)); - - receiveNetworkBuffer.Write(pkt_receive.Message); - offset += (uint)wsPacketLength; - - //Console.WriteLine("WS IN: " + pkt_receive.Opcode.ToString() + " " + pkt_receive.Message.Length + " | " + offset + " " + string.Join(" ", pkt_receive.Message));// DC.ToHex(pkt_receive.Message)); - - } - else - Console.WriteLine("Unknown WS opcode:" + pkt_receive.Opcode); - - if (offset == msg.Length) - { - - //OnReceive?.Invoke(receiveNetworkBuffer); - Receiver?.NetworkReceive(this, receiveNetworkBuffer); - return; - } - - wsPacketLength = pkt_receive.Parse(msg, offset, (uint)msg.Length); - } - - if (wsPacketLength < 0)//(offset < msg.Length) && (offset > 0)) - { - //receiveNetworkBuffer.HoldFor(msg, offset, (uint)(msg.Length - offset), (uint)msg.Length + (uint)-wsPacketLength); - // save the incomplete packet to the heldBuffer queue - - buffer.HoldFor(msg, offset, (uint)(msg.Length - offset), (uint)(msg.Length - offset) + (uint)-wsPacketLength); - - } - - //Console.WriteLine("WS IN: " + receiveNetworkBuffer.Available); - - //OnReceive?.Invoke(receiveNetworkBuffer); - Receiver?.NetworkReceive(this, receiveNetworkBuffer); - - processing = false; - - if (buffer.Available > 0 && !buffer.Protected) - Receiver?.NetworkReceive(this, buffer); - //Sock_OnReceive(buffer); - } - - - public void NetworkConnect(ISocket sender) - { - Receiver?.NetworkConnect(this); + return sock.State; } } -} \ No newline at end of file + + public INetworkReceiver Receiver { get; set; } + + public WSocket(ISocket socket) + { + pkt_send.FIN = true; + pkt_send.Mask = false; + pkt_send.Opcode = WebsocketPacket.WSOpcode.BinaryFrame; + sock = socket; + + sock.Receiver = this; + + //sock.OnClose += Sock_OnClose; + //sock.OnConnect += Sock_OnConnect; + //sock.OnReceive += Sock_OnReceive; + } + + //private void Sock_OnReceive(NetworkBuffer buffer) + //{ + + //} + + //private void Sock_OnConnect() + //{ + // OnConnect?.Invoke(); + //} + + //private void Sock_OnClose() + //{ + // OnClose?.Invoke(); + //} + + public void Send(WebsocketPacket packet) + { + lock (sendLock) + if (packet.Compose()) + sock.Send(packet.Data); + } + + public void Send(byte[] message) + { + + lock (sendLock) + { + if (held) + { + sendNetworkBuffer.Write(message); + } + else + { + totalSent += message.Length; + //Console.WriteLine("TX " + message.Length +"/"+totalSent);// + " " + DC.ToHex(message, 0, (uint)size)); + + pkt_send.Message = message; + + if (pkt_send.Compose()) + sock?.Send(pkt_send.Data); + + } + } + } + + + public void Send(byte[] message, int offset, int size) + { + lock (sendLock) + { + if (held) + { + sendNetworkBuffer.Write(message, (uint)offset, (uint)size); + } + else + { + totalSent += size; + //Console.WriteLine("TX " + size + "/"+totalSent);// + " " + DC.ToHex(message, 0, (uint)size)); + + pkt_send.Message = new byte[size]; + Buffer.BlockCopy(message, offset, pkt_send.Message, 0, size); + if (pkt_send.Compose()) + sock.Send(pkt_send.Data); + } + } + } + + + public void Close() + { + sock?.Close(); + } + + public AsyncReply Connect(string hostname, ushort port) + { + throw new NotImplementedException(); + } + + + public bool Begin() + { + return sock.Begin(); + } + + public bool Trigger(ResourceTrigger trigger) + { + return true; + } + + public void Destroy() + { + Close(); + //OnClose = null; + //OnConnect = null; + //OnReceive = null; + receiveNetworkBuffer = null; + //sock.OnReceive -= Sock_OnReceive; + //sock.OnClose -= Sock_OnClose; + //sock.OnConnect -= Sock_OnConnect; + sock.Receiver = null; + sock = null; + OnDestroy?.Invoke(this); + OnDestroy = null; + } + + public AsyncReply AcceptAsync() + { + throw new NotImplementedException(); + } + + public void Hold() + { + //Console.WriteLine("WS Hold "); + held = true; + } + + public void Unhold() + { + lock (sendLock) + { + held = false; + + var message = sendNetworkBuffer.Read(); + + //Console.WriteLine("WS Unhold {0}", message == null ? 0 : message.Length); + + if (message == null) + return; + + totalSent += message.Length; + + pkt_send.Message = message; + if (pkt_send.Compose()) + sock.Send(pkt_send.Data); + + } + } + + public AsyncReply SendAsync(byte[] message, int offset, int length) + { + throw new NotImplementedException(); + } + + public ISocket Accept() + { + throw new NotImplementedException(); + } + + public AsyncReply BeginAsync() + { + return sock.BeginAsync(); + } + + public void NetworkClose(ISocket sender) + { + Receiver?.NetworkClose(sender); + } + + public void NetworkReceive(ISocket sender, NetworkBuffer buffer) + { + + if (sock.State == SocketState.Closed)// || sock.State == SocketState.Terminated) + return; + + if (buffer.Protected) + return; + + if (processing) + return; + + + var msg = buffer.Read(); + + if (msg == null) + return; + + var wsPacketLength = pkt_receive.Parse(msg, 0, (uint)msg.Length); + //Console.WriteLine("WSP: " + wsPacketLength); + + if (wsPacketLength < 0) + { + buffer.Protect(msg, 0, (uint)msg.Length + (uint)-wsPacketLength); + return; + } + + uint offset = 0; + + while (wsPacketLength > 0) + { + if (pkt_receive.Opcode == WebsocketPacket.WSOpcode.ConnectionClose) + { + Close(); + return; + } + else if (pkt_receive.Opcode == WebsocketPacket.WSOpcode.Ping) + { + var pkt_pong = new WebsocketPacket(); + + pkt_pong.FIN = true; + pkt_pong.Mask = false; + pkt_pong.Opcode = WebsocketPacket.WSOpcode.Pong; + pkt_pong.Message = pkt_receive.Message; + offset += (uint)wsPacketLength; + + Send(pkt_pong); + } + else if (pkt_receive.Opcode == WebsocketPacket.WSOpcode.Pong) + { + offset += (uint)wsPacketLength; + } + else if (pkt_receive.Opcode == WebsocketPacket.WSOpcode.BinaryFrame + || pkt_receive.Opcode == WebsocketPacket.WSOpcode.TextFrame + || pkt_receive.Opcode == WebsocketPacket.WSOpcode.ContinuationFrame) + { + totalReceived += pkt_receive.Message.Length; + //Console.WriteLine("RX " + pkt_receive.Message.Length + "/" + totalReceived);// + " " + DC.ToHex(message, 0, (uint)size)); + + receiveNetworkBuffer.Write(pkt_receive.Message); + offset += (uint)wsPacketLength; + + //Console.WriteLine("WS IN: " + pkt_receive.Opcode.ToString() + " " + pkt_receive.Message.Length + " | " + offset + " " + string.Join(" ", pkt_receive.Message));// DC.ToHex(pkt_receive.Message)); + + } + else + Console.WriteLine("Unknown WS opcode:" + pkt_receive.Opcode); + + if (offset == msg.Length) + { + + //OnReceive?.Invoke(receiveNetworkBuffer); + Receiver?.NetworkReceive(this, receiveNetworkBuffer); + return; + } + + wsPacketLength = pkt_receive.Parse(msg, offset, (uint)msg.Length); + } + + if (wsPacketLength < 0)//(offset < msg.Length) && (offset > 0)) + { + //receiveNetworkBuffer.HoldFor(msg, offset, (uint)(msg.Length - offset), (uint)msg.Length + (uint)-wsPacketLength); + // save the incomplete packet to the heldBuffer queue + + buffer.HoldFor(msg, offset, (uint)(msg.Length - offset), (uint)(msg.Length - offset) + (uint)-wsPacketLength); + + } + + //Console.WriteLine("WS IN: " + receiveNetworkBuffer.Available); + + //OnReceive?.Invoke(receiveNetworkBuffer); + Receiver?.NetworkReceive(this, receiveNetworkBuffer); + + processing = false; + + if (buffer.Available > 0 && !buffer.Protected) + Receiver?.NetworkReceive(this, buffer); + //Sock_OnReceive(buffer); + } + + + public void NetworkConnect(ISocket sender) + { + Receiver?.NetworkConnect(this); + } +} diff --git a/Esiur/Net/TCP/TCPConnection.cs b/Esiur/Net/TCP/TCPConnection.cs index 32ac8b0..8740fd3 100644 --- a/Esiur/Net/TCP/TCPConnection.cs +++ b/Esiur/Net/TCP/TCPConnection.cs @@ -32,35 +32,34 @@ using System.Collections; using Esiur.Misc; using Esiur.Data; -namespace Esiur.Net.TCP +namespace Esiur.Net.TCP; +public class TCPConnection : NetworkConnection { - public class TCPConnection:NetworkConnection { - private KeyList variables = new KeyList(); + private KeyList variables = new KeyList(); - public TCPServer Server { get; internal set; } + public TCPServer Server { get; internal set; } - public KeyList Variables + public KeyList Variables + { + get { - get - { - return variables; - } - } - - protected override void Connected() - { - // do nothing - } - - protected override void DataReceived(NetworkBuffer buffer) - { - Server?.Execute(this, buffer); - } - - protected override void Disconencted() - { - // do nothing + return variables; } } + + protected override void Connected() + { + // do nothing + } + + protected override void DataReceived(NetworkBuffer buffer) + { + Server?.Execute(this, buffer); + } + + protected override void Disconencted() + { + // do nothing + } } diff --git a/Esiur/Net/TCP/TCPFilter.cs b/Esiur/Net/TCP/TCPFilter.cs index 0e05f85..1091afc 100644 --- a/Esiur/Net/TCP/TCPFilter.cs +++ b/Esiur/Net/TCP/TCPFilter.cs @@ -32,35 +32,34 @@ using Esiur.Net.Sockets; using Esiur.Core; using Esiur.Resource; -namespace Esiur.Net.TCP +namespace Esiur.Net.TCP; + +public abstract class TCPFilter : IResource { - public abstract class TCPFilter: IResource + public Instance Instance { - public Instance Instance - { - get; - set; - } + get; + set; + } - public event DestroyedEvent OnDestroy; + public event DestroyedEvent OnDestroy; - public abstract AsyncReply Trigger(ResourceTrigger trigger); + public abstract AsyncReply Trigger(ResourceTrigger trigger); - public virtual bool Connected(TCPConnection sender) - { - return false; - } + public virtual bool Connected(TCPConnection sender) + { + return false; + } - public virtual bool Disconnected(TCPConnection sender) - { - return false; - } + public virtual bool Disconnected(TCPConnection sender) + { + return false; + } - public abstract bool Execute(byte[] msg, NetworkBuffer data, TCPConnection sender); + public abstract bool Execute(byte[] msg, NetworkBuffer data, TCPConnection sender); - public void Destroy() - { - OnDestroy?.Invoke(this); - } + public void Destroy() + { + OnDestroy?.Invoke(this); } } diff --git a/Esiur/Net/TCP/TCPServer.cs b/Esiur/Net/TCP/TCPServer.cs index 7d30040..acfdad5 100644 --- a/Esiur/Net/TCP/TCPServer.cs +++ b/Esiur/Net/TCP/TCPServer.cs @@ -34,123 +34,121 @@ using Esiur.Core; using System.Net; using Esiur.Resource; -namespace Esiur.Net.TCP +namespace Esiur.Net.TCP; +public class TCPServer : NetworkServer, IResource { - public class TCPServer : NetworkServer, IResource + + [Attribute] + public string IP + { + get; + set; + } + [Attribute] + public ushort Port + { + get; + set; + } + //[Storable] + //public uint Timeout + //{ + // get; + // set; + //} + //[Attribute] + //public uint Clock + //{ + // get; + // set; + //} + public Instance Instance { get; set; } + + TCPFilter[] filters = null; + + + public AsyncReply Trigger(ResourceTrigger trigger) + { + if (trigger == ResourceTrigger.Initialize) + { + TCPSocket listener; + + + if (IP != null) + listener = new TCPSocket(new IPEndPoint(IPAddress.Parse(IP), Port)); + else + listener = new TCPSocket(new IPEndPoint(IPAddress.Any, Port)); + + Start(listener); + + + } + else if (trigger == ResourceTrigger.Terminate) + { + Stop(); + } + else if (trigger == ResourceTrigger.SystemReload) + { + Trigger(ResourceTrigger.Terminate); + Trigger(ResourceTrigger.Initialize); + } + else if (trigger == ResourceTrigger.SystemInitialized) + { + Instance.Children().Then(x => filters = x); + } + + return new AsyncReply(true); + } + + + + + + internal bool Execute(TCPConnection sender, NetworkBuffer data) + { + var msg = data.Read(); + + foreach (var filter in filters) + { + if (filter.Execute(msg, data, sender)) + return true; + } + + return false; + } + + private void SessionModified(TCPConnection session, string key, object newValue) { - [Attribute] - public string IP + } + + protected override void ClientDisconnected(TCPConnection connection) + { + + foreach (var filter in filters) { - get; - set; + filter.Disconnected(connection); } - [Attribute] - public ushort Port + } + + public override void Add(TCPConnection connection) + { + connection.Server = this; + base.Add(connection); + } + + public override void Remove(TCPConnection connection) + { + connection.Server = null; + base.Remove(connection); + } + + protected override void ClientConnected(TCPConnection connection) + { + foreach (var filter in filters) { - get; - set; + filter.Connected(connection); } - //[Storable] - //public uint Timeout - //{ - // get; - // set; - //} - //[Attribute] - //public uint Clock - //{ - // get; - // set; - //} - public Instance Instance { get; set; } + } - TCPFilter[] filters = null; - - - public AsyncReply Trigger(ResourceTrigger trigger) - { - if (trigger == ResourceTrigger.Initialize) - { - TCPSocket listener; - - - if (IP != null) - listener = new TCPSocket(new IPEndPoint(IPAddress.Parse(IP), Port)); - else - listener = new TCPSocket(new IPEndPoint(IPAddress.Any, Port)); - - Start(listener); - - - } - else if (trigger == ResourceTrigger.Terminate) - { - Stop(); - } - else if (trigger == ResourceTrigger.SystemReload) - { - Trigger(ResourceTrigger.Terminate); - Trigger(ResourceTrigger.Initialize); - } - else if (trigger == ResourceTrigger.SystemInitialized) - { - Instance.Children().Then(x => filters = x); - } - - return new AsyncReply(true); - } - - - - - - internal bool Execute(TCPConnection sender, NetworkBuffer data) - { - var msg = data.Read(); - - foreach (var filter in filters) - { - if (filter.Execute(msg, data, sender)) - return true; - } - - return false; - } - - private void SessionModified(TCPConnection session, string key, object newValue) - { - - } - - protected override void ClientDisconnected(TCPConnection connection) - { - - foreach (var filter in filters) - { - filter.Disconnected(connection); - } - } - - public override void Add(TCPConnection connection) - { - connection.Server = this; - base.Add(connection); - } - - public override void Remove(TCPConnection connection) - { - connection.Server = null; - base.Remove(connection); - } - - protected override void ClientConnected(TCPConnection connection) - { - foreach (var filter in filters) - { - filter.Connected(connection); - } - } - - } } diff --git a/Esiur/Net/TCP/TCPSession.cs b/Esiur/Net/TCP/TCPSession.cs index f2cfb52..3a4412d 100644 --- a/Esiur/Net/TCP/TCPSession.cs +++ b/Esiur/Net/TCP/TCPSession.cs @@ -28,10 +28,8 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Net.TCP +namespace Esiur.Net.TCP; +public class TCPSession : NetworkSession { - public class TCPSession : NetworkSession - { - } } diff --git a/Esiur/Net/UDP/UDPFilter.cs b/Esiur/Net/UDP/UDPFilter.cs index b3acde7..7a48e4d 100644 --- a/Esiur/Net/UDP/UDPFilter.cs +++ b/Esiur/Net/UDP/UDPFilter.cs @@ -32,26 +32,24 @@ using Esiur.Data; using Esiur.Core; using Esiur.Resource; -namespace Esiur.Net.UDP +namespace Esiur.Net.UDP; +public abstract class UDPFilter : IResource { - public abstract class UDPFilter : IResource + public Instance Instance { - public Instance Instance - { - get; - set; - } - - - public event DestroyedEvent OnDestroy; - - public abstract AsyncReply Trigger(ResourceTrigger trigger); - - public abstract bool Execute(byte[] data, IPEndPoint sender); - - public void Destroy() - { - OnDestroy?.Invoke(this); - } + get; + set; } -} \ No newline at end of file + + + public event DestroyedEvent OnDestroy; + + public abstract AsyncReply Trigger(ResourceTrigger trigger); + + public abstract bool Execute(byte[] data, IPEndPoint sender); + + public void Destroy() + { + OnDestroy?.Invoke(this); + } +} diff --git a/Esiur/Net/UDP/UDPServer.cs b/Esiur/Net/UDP/UDPServer.cs index b4df1ab..0dc9573 100644 --- a/Esiur/Net/UDP/UDPServer.cs +++ b/Esiur/Net/UDP/UDPServer.cs @@ -33,172 +33,170 @@ using Esiur.Misc; using Esiur.Resource; using Esiur.Core; -namespace Esiur.Net.UDP +namespace Esiur.Net.UDP; + +/* public class IIPConnection { + public EndPoint SenderPoint; + public +}*/ +public class UDPServer : IResource +{ + Thread receiver; + UdpClient udp; + UDPFilter[] filters = new UDPFilter[0]; - /* public class IIPConnection + public event DestroyedEvent OnDestroy; + + public Instance Instance { - public EndPoint SenderPoint; - public - }*/ - public class UDPServer : IResource + get; + set; + } + + [Attribute] + string IP { - Thread receiver; - UdpClient udp; - UDPFilter[] filters = new UDPFilter[0]; + get; + set; + } - public event DestroyedEvent OnDestroy; + [Attribute] + ushort Port + { + get; + set; + } - public Instance Instance + private void Receiving() + { + IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0); + + + while (true) { - get; - set; - } + byte[] b = udp.Receive(ref ep); - [Attribute] - string IP - { - get; - set; - } - - [Attribute] - ushort Port - { - get; - set; - } - - private void Receiving() - { - IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0); - - - while (true) + foreach (var child in filters) { - byte[] b = udp.Receive(ref ep); + var f = child as UDPFilter; - foreach (var child in filters) + try { - var f = child as UDPFilter; - - try + if (f.Execute(b, ep)) { - if (f.Execute(b, ep)) - { - break; - } - } - catch (Exception ex) - { - Global.Log("UDPServer", LogType.Error, ex.ToString()); - //Console.WriteLine(ex.ToString()); + break; } } + catch (Exception ex) + { + Global.Log("UDPServer", LogType.Error, ex.ToString()); + //Console.WriteLine(ex.ToString()); + } } } + } - public bool Send(byte[] Data, int Count, IPEndPoint EP) + public bool Send(byte[] Data, int Count, IPEndPoint EP) + { + try { - try - { - udp.Send(Data, Count, EP); - return true; - } - catch - { - return false; - } - } - public bool Send(byte[] Data, IPEndPoint EP) - { - try - { - udp.Send(Data, Data.Length, EP); - return true; - } - catch - { - return false; - } - } - public bool Send(byte[] Data, int Count, string Host, int Port) - { - try - { - udp.Send(Data, Count, Host, Port); - return true; - } - catch - { - return false; - } - } - public bool Send(byte[] Data, string Host, int Port) - { - try - { - udp.Send(Data, Data.Length, Host, Port); - return true; - } - catch - { - return false; - } - } - public bool Send(string Data, IPEndPoint EP) - { - try - { - udp.Send(Encoding.Default.GetBytes(Data), Data.Length, EP); - return true; - } - catch - { - return false; - } - } - public bool Send(string Data, string Host, int Port) - { - try - { - udp.Send(Encoding.Default.GetBytes(Data), Data.Length, Host, Port); - return true; - } - catch - { - return false; - } - } - - public void Destroy() - { - udp.Close(); - OnDestroy?.Invoke(this); - } - - async AsyncReply IResource.Trigger(ResourceTrigger trigger) - { - if (trigger == ResourceTrigger.Initialize) - { - var address = IP == null ? IPAddress.Any : IPAddress.Parse(IP); - - udp = new UdpClient(new IPEndPoint(address, Port)); - - receiver = new Thread(Receiving); - receiver.Start(); - } - else if (trigger == ResourceTrigger.Terminate) - { - if (receiver != null) - receiver.Abort(); - } - else if (trigger == ResourceTrigger.SystemInitialized) - { - filters = await Instance.Children(); - } - + udp.Send(Data, Count, EP); return true; } + catch + { + return false; + } } -} \ No newline at end of file + public bool Send(byte[] Data, IPEndPoint EP) + { + try + { + udp.Send(Data, Data.Length, EP); + return true; + } + catch + { + return false; + } + } + public bool Send(byte[] Data, int Count, string Host, int Port) + { + try + { + udp.Send(Data, Count, Host, Port); + return true; + } + catch + { + return false; + } + } + public bool Send(byte[] Data, string Host, int Port) + { + try + { + udp.Send(Data, Data.Length, Host, Port); + return true; + } + catch + { + return false; + } + } + public bool Send(string Data, IPEndPoint EP) + { + try + { + udp.Send(Encoding.Default.GetBytes(Data), Data.Length, EP); + return true; + } + catch + { + return false; + } + } + public bool Send(string Data, string Host, int Port) + { + try + { + udp.Send(Encoding.Default.GetBytes(Data), Data.Length, Host, Port); + return true; + } + catch + { + return false; + } + } + + public void Destroy() + { + udp.Close(); + OnDestroy?.Invoke(this); + } + + async AsyncReply IResource.Trigger(ResourceTrigger trigger) + { + if (trigger == ResourceTrigger.Initialize) + { + var address = IP == null ? IPAddress.Any : IPAddress.Parse(IP); + + udp = new UdpClient(new IPEndPoint(address, Port)); + + receiver = new Thread(Receiving); + receiver.Start(); + } + else if (trigger == ResourceTrigger.Terminate) + { + if (receiver != null) + receiver.Abort(); + } + else if (trigger == ResourceTrigger.SystemInitialized) + { + filters = await Instance.Children(); + } + + return true; + } +} diff --git a/Esiur/Proxy/ResourceGenerator.cs b/Esiur/Proxy/ResourceGenerator.cs index ed41035..027b00e 100644 --- a/Esiur/Proxy/ResourceGenerator.cs +++ b/Esiur/Proxy/ResourceGenerator.cs @@ -14,177 +14,176 @@ using Esiur.Data; using System.IO; using Esiur.Core; -namespace Esiur.Proxy +namespace Esiur.Proxy; + +[Generator] +public class ResourceGenerator : ISourceGenerator { - [Generator] - public class ResourceGenerator : ISourceGenerator + + private KeyList cache = new(); + // private List inProgress = new(); + + public void Initialize(GeneratorInitializationContext context) + { + // Register receiver + + context.RegisterForSyntaxNotifications(() => new ResourceGeneratorReceiver()); + } + + + void ReportError(GeneratorExecutionContext context, string title, string msg, string category) + { + context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor("MySG001", title, msg, category, DiagnosticSeverity.Error, true), Location.None)); + } + + + void GenerateModel(GeneratorExecutionContext context, TypeTemplate[] templates) + { + foreach (var tmp in templates) + { + if (tmp.Type == TemplateType.Resource) + { + var source = TemplateGenerator.GenerateClass(tmp, templates); + // File.WriteAllText($@"C:\gen\{tmp.ClassName}.cs", source); + context.AddSource(tmp.ClassName + ".Generated.cs", source); + } + else if (tmp.Type == TemplateType.Record) + { + var source = TemplateGenerator.GenerateRecord(tmp, templates); + // File.WriteAllText($@"C:\gen\{tmp.ClassName}.cs", source); + context.AddSource(tmp.ClassName + ".Generated.cs", source); + } + } + + // generate info class + + + var typesFile = "using System; \r\n namespace Esiur { public static class Generated { public static Type[] Resources {get;} = new Type[] { " + + string.Join(",", templates.Where(x => x.Type == TemplateType.Resource).Select(x => $"typeof({x.ClassName})")) + + " }; \r\n public static Type[] Records { get; } = new Type[] { " + + string.Join(",", templates.Where(x => x.Type == TemplateType.Record).Select(x => $"typeof({x.ClassName})")) + + " }; " + + + "\r\n } \r\n}"; + + //File.WriteAllText($@"C:\gen\Esiur.Generated.cs", gen); + + context.AddSource("Esiur.Generated.cs", typesFile); + + } + + + + public void Execute(GeneratorExecutionContext context) { - private KeyList cache = new(); - // private List inProgress = new(); + if (!(context.SyntaxContextReceiver is ResourceGeneratorReceiver receiver)) + return; - public void Initialize(GeneratorInitializationContext context) + //if (receiver.Imports.Count > 0 && !Debugger.IsAttached) + //{ + // Debugger.Launch(); + //} + + foreach (var path in receiver.Imports) { - // Register receiver + if (!TemplateGenerator.urlRegex.IsMatch(path)) + continue; - context.RegisterForSyntaxNotifications(() => new ResourceGeneratorReceiver()); - } - - void ReportError(GeneratorExecutionContext context, string title, string msg, string category) - { - context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor("MySG001", title, msg, category, DiagnosticSeverity.Error, true), Location.None)); - } + //File.WriteAllLines("C:\\gen\\ref.log", context.Compilation.ReferencedAssemblyNames.Select(x => x.ToString())); - - void GenerateModel(GeneratorExecutionContext context, TypeTemplate[] templates) - { - foreach (var tmp in templates) + if (cache.Contains(path)) { - if (tmp.Type == TemplateType.Resource) - { - var source = TemplateGenerator.GenerateClass(tmp, templates); - // File.WriteAllText($@"C:\gen\{tmp.ClassName}.cs", source); - context.AddSource(tmp.ClassName + ".Generated.cs", source); - } - else if (tmp.Type == TemplateType.Record) - { - var source = TemplateGenerator.GenerateRecord(tmp, templates); - // File.WriteAllText($@"C:\gen\{tmp.ClassName}.cs", source); - context.AddSource(tmp.ClassName + ".Generated.cs", source); - } + GenerateModel(context, cache[path]); + continue; } - // generate info class + // Syncronization + //if (inProgress.Contains(path)) + // continue; + + //inProgress.Add(path); + + var url = TemplateGenerator.urlRegex.Split(path); - var typesFile = "using System; \r\n namespace Esiur { public static class Generated { public static Type[] Resources {get;} = new Type[] { " + - string.Join(",", templates.Where(x => x.Type == TemplateType.Resource).Select(x => $"typeof({x.ClassName})")) - + " }; \r\n public static Type[] Records { get; } = new Type[] { " + - string.Join(",", templates.Where(x => x.Type == TemplateType.Record).Select(x => $"typeof({x.ClassName})")) - + " }; " + + try + { + var con = Warehouse.Get(url[1] + "://" + url[2]).Wait(20000); + var templates = con.GetLinkTemplates(url[3]).Wait(60000); - "\r\n } \r\n}"; + cache[path] = templates; - //File.WriteAllText($@"C:\gen\Esiur.Generated.cs", gen); + // make sources + GenerateModel(context, templates); - context.AddSource("Esiur.Generated.cs", typesFile); + } + catch (Exception ex) + { + ReportError(context, ex.Source, ex.Message, "Esiur"); + //System.IO.File.AppendAllText("c:\\gen\\error.log", ex.ToString() + "\r\n"); + } + //inProgress.Remove(path); } - - public void Execute(GeneratorExecutionContext context) + //#if DEBUG + + //#endif + + //var toImplement = receiver.Classes.Where(x => x.Fields.Length > 0); + + foreach (var ci in receiver.Classes.Values) { - - if (!(context.SyntaxContextReceiver is ResourceGeneratorReceiver receiver)) - return; - - //if (receiver.Imports.Count > 0 && !Debugger.IsAttached) - //{ - // Debugger.Launch(); - //} - - foreach (var path in receiver.Imports) + try { - if (!TemplateGenerator.urlRegex.IsMatch(path)) - continue; - - //File.WriteAllLines("C:\\gen\\ref.log", context.Compilation.ReferencedAssemblyNames.Select(x => x.ToString())); - - if (cache.Contains(path)) - { - GenerateModel(context, cache[path]); - continue; - } - - // Syncronization - //if (inProgress.Contains(path)) - // continue; - - //inProgress.Add(path); - - var url = TemplateGenerator.urlRegex.Split(path); - - - try - { - var con = Warehouse.Get(url[1] + "://" + url[2]).Wait(20000); - var templates = con.GetLinkTemplates(url[3]).Wait(60000); - - cache[path] = templates; - - // make sources - GenerateModel(context, templates); - - } - catch (Exception ex) - { - ReportError(context, ex.Source, ex.Message, "Esiur"); - //System.IO.File.AppendAllText("c:\\gen\\error.log", ex.ToString() + "\r\n"); - } - - //inProgress.Remove(path); - } - - - //#if DEBUG - - //#endif - - //var toImplement = receiver.Classes.Where(x => x.Fields.Length > 0); - - foreach (var ci in receiver.Classes.Values) - { - try - { - - var code = @$"using Esiur.Resource; + var code = @$"using Esiur.Resource; using Esiur.Core; namespace { ci.ClassSymbol.ContainingNamespace.ToDisplayString() } {{ "; - if (ci.HasInterface) - code += $"public partial class {ci.Name} {{"; - else - { - code += @$"public partial class {ci.Name} : IResource {{ + if (ci.HasInterface) + code += $"public partial class {ci.Name} {{"; + else + { + code += @$"public partial class {ci.Name} : IResource {{ public Instance Instance {{ get; set; }} public event DestroyedEvent OnDestroy; public virtual void Destroy() {{ OnDestroy?.Invoke(this); }} "; - if (!ci.HasTrigger) - code += "public AsyncReply Trigger(ResourceTrigger trigger) => new AsyncReply(true);\r\n"; - } - - //Debugger.Launch(); - - foreach (var f in ci.Fields) - { - var givenName = f.GetAttributes().Where(x=>x.AttributeClass.Name == "PublicAttribute").FirstOrDefault()?.ConstructorArguments.FirstOrDefault().Value; - - var fn = f.Name; - var pn = givenName ?? fn.Substring(0, 1).ToUpper() + fn.Substring(1); - - //System.IO.File.AppendAllText("c:\\gen\\fields.txt", fn + " -> " + pn + "\r\n"); - - // copy attributes - var attrs = string.Join(" ", f.GetAttributes().Select(x => $"[{x.ToString()}]")); - code += $"{attrs} public {f.Type} {pn} {{ get => {fn}; set {{ {fn} = value; Instance?.Modified(); }} }}\r\n"; - } - - code += "}}\r\n"; - - //System.IO.File.WriteAllText("c:\\gen\\" + ci.Name + "_esiur.cs", code); - context.AddSource(ci.Name + ".Generated.cs", code); - + if (!ci.HasTrigger) + code += "public AsyncReply Trigger(ResourceTrigger trigger) => new AsyncReply(true);\r\n"; } - catch (Exception ex) + + //Debugger.Launch(); + + foreach (var f in ci.Fields) { - //System.IO.File.AppendAllText("c:\\gen\\error.log", ci.Name + " " + ex.ToString() + "\r\n"); + var givenName = f.GetAttributes().Where(x => x.AttributeClass.Name == "PublicAttribute").FirstOrDefault()?.ConstructorArguments.FirstOrDefault().Value; + + var fn = f.Name; + var pn = givenName ?? fn.Substring(0, 1).ToUpper() + fn.Substring(1); + + //System.IO.File.AppendAllText("c:\\gen\\fields.txt", fn + " -> " + pn + "\r\n"); + + // copy attributes + var attrs = string.Join(" ", f.GetAttributes().Select(x => $"[{x.ToString()}]")); + code += $"{attrs} public {f.Type} {pn} {{ get => {fn}; set {{ {fn} = value; Instance?.Modified(); }} }}\r\n"; } + + code += "}}\r\n"; + + //System.IO.File.WriteAllText("c:\\gen\\" + ci.Name + "_esiur.cs", code); + context.AddSource(ci.Name + ".Generated.cs", code); + + } + catch //(Exception ex) + { + //System.IO.File.AppendAllText("c:\\gen\\error.log", ci.Name + " " + ex.ToString() + "\r\n"); } } } diff --git a/Esiur/Proxy/ResourceGeneratorClassInfo.cs b/Esiur/Proxy/ResourceGeneratorClassInfo.cs index 2f68aa2..ff1d303 100644 --- a/Esiur/Proxy/ResourceGeneratorClassInfo.cs +++ b/Esiur/Proxy/ResourceGeneratorClassInfo.cs @@ -4,18 +4,16 @@ using System; using System.Collections.Generic; using System.Text; -namespace Esiur.Proxy +namespace Esiur.Proxy; +public struct ResourceGeneratorClassInfo { - public struct ResourceGeneratorClassInfo - { - public string Name { get; set; } - public bool HasInterface { get; set; } + public string Name { get; set; } + public bool HasInterface { get; set; } - public bool HasTrigger { get; set; } - public List Fields { get; set; } - public ITypeSymbol ClassSymbol { get; set; } + public bool HasTrigger { get; set; } + public List Fields { get; set; } + public ITypeSymbol ClassSymbol { get; set; } - public ClassDeclarationSyntax ClassDeclaration { get; set; } + public ClassDeclarationSyntax ClassDeclaration { get; set; } - } } diff --git a/Esiur/Proxy/ResourceGeneratorFieldInfo.cs b/Esiur/Proxy/ResourceGeneratorFieldInfo.cs index c65d46b..b40d7db 100644 --- a/Esiur/Proxy/ResourceGeneratorFieldInfo.cs +++ b/Esiur/Proxy/ResourceGeneratorFieldInfo.cs @@ -3,11 +3,9 @@ using System; using System.Collections.Generic; using System.Text; -namespace Esiur.Proxy +namespace Esiur.Proxy; +public struct ResourceGeneratorFieldInfo { - public struct ResourceGeneratorFieldInfo - { - public IFieldSymbol FieldSymbol { get; set; } - public string[] Attributes { get; set; } - } + public IFieldSymbol FieldSymbol { get; set; } + public string[] Attributes { get; set; } } diff --git a/Esiur/Proxy/ResourceGeneratorReceiver.cs b/Esiur/Proxy/ResourceGeneratorReceiver.cs index edc8557..2ae715b 100644 --- a/Esiur/Proxy/ResourceGeneratorReceiver.cs +++ b/Esiur/Proxy/ResourceGeneratorReceiver.cs @@ -6,92 +6,91 @@ using System.Diagnostics; using System.Linq; using System.Text; -namespace Esiur.Proxy +namespace Esiur.Proxy; +public class ResourceGeneratorReceiver : ISyntaxContextReceiver { - public class ResourceGeneratorReceiver : ISyntaxContextReceiver + + public Dictionary Classes { get; } = new(); + + public List Imports { get; } = new(); + + public void OnVisitSyntaxNode(GeneratorSyntaxContext context) { - public Dictionary Classes { get; } = new(); - - public List Imports { get; } = new (); - - public void OnVisitSyntaxNode(GeneratorSyntaxContext context) + if (context.Node is ClassDeclarationSyntax) { + var cds = context.Node as ClassDeclarationSyntax; + var cls = context.SemanticModel.GetDeclaredSymbol(cds) as ITypeSymbol; + var attrs = cls.GetAttributes(); - if (context.Node is ClassDeclarationSyntax) + var imports = attrs.Where(a => a.AttributeClass.ToDisplayString() == "Esiur.Resource.ImportAttribute"); + + foreach (var import in imports) { - var cds = context.Node as ClassDeclarationSyntax; - var cls = context.SemanticModel.GetDeclaredSymbol(cds) as ITypeSymbol; - var attrs = cls.GetAttributes(); + // Debugger.Launch(); - var imports = attrs.Where(a => a.AttributeClass.ToDisplayString() == "Esiur.Resource.ImportAttribute"); + var url = import.ConstructorArguments.First().Value.ToString(); - foreach (var import in imports) + if (!Imports.Contains(url)) + Imports.Add(url); + } + + if (attrs.Any(a => a.AttributeClass.ToDisplayString() == "Esiur.Resource.ResourceAttribute")) + { + + + var hasTrigger = cds.Members + .Where(x => x is MethodDeclarationSyntax) + .Select(x => context.SemanticModel.GetDeclaredSymbol(x) as IMethodSymbol) + .Any(x => x.Name == "Trigger" + && x.Parameters.Length == 1 + && x.Parameters[0].Type.ToDisplayString() == "Esiur.Resource.ResourceTrigger"); + + var fields = cds.Members.Where(x => x is FieldDeclarationSyntax) + .Select(x => context.SemanticModel.GetDeclaredSymbol((x as FieldDeclarationSyntax).Declaration.Variables.First()) as IFieldSymbol) + .Where(x => x.GetAttributes().Any(a => a.AttributeClass.ToDisplayString() == "Esiur.Resource.PublicAttribute")) + .ToArray(); + + //if (!Debugger.IsAttached) + //{ + // if (cls.Name == "User") + // Debugger.Launch(); + //} + + + + // get fields + + var fullName = cls.ContainingAssembly + "." + cls.Name; + + // Partial class check + if (Classes.ContainsKey(fullName)) { - // Debugger.Launch(); - - var url = import.ConstructorArguments.First().Value.ToString(); - - if (!Imports.Contains(url)) - Imports.Add(url); + // append fields + var c = Classes[fullName]; + c.Fields.AddRange(fields); + if (!c.HasInterface) + c.HasInterface = cls.Interfaces.Any(x => x.ToDisplayString() == "Esiur.Resource.IResource"); + if (!c.HasTrigger) + c.HasTrigger = hasTrigger; + } + else + { + Classes.Add(fullName, new ResourceGeneratorClassInfo() + { + Name = cls.Name, + ClassDeclaration = cds, + ClassSymbol = cls, + Fields = fields.ToList(), + HasInterface = cls.Interfaces.Any(x => x.ToDisplayString() == "Esiur.Resource.IResource"), + HasTrigger = hasTrigger + }); } - if (attrs.Any(a => a.AttributeClass.ToDisplayString() == "Esiur.Resource.ResourceAttribute")) - { - - - var hasTrigger = cds.Members - .Where(x => x is MethodDeclarationSyntax) - .Select(x => context.SemanticModel.GetDeclaredSymbol(x) as IMethodSymbol) - .Any(x => x.Name == "Trigger" - && x.Parameters.Length == 1 - && x.Parameters[0].Type.ToDisplayString() == "Esiur.Resource.ResourceTrigger"); - var fields = cds.Members.Where(x => x is FieldDeclarationSyntax) - .Select(x => context.SemanticModel.GetDeclaredSymbol((x as FieldDeclarationSyntax).Declaration.Variables.First()) as IFieldSymbol) - .Where(x => x.GetAttributes().Any(a => a.AttributeClass.ToDisplayString() == "Esiur.Resource.PublicAttribute")) - .ToArray(); - - //if (!Debugger.IsAttached) - //{ - // if (cls.Name == "User") - // Debugger.Launch(); - //} - - - - // get fields - - var fullName = cls.ContainingAssembly + "." + cls.Name; - - // Partial class check - if (Classes.ContainsKey(fullName)) - { - // append fields - var c = Classes[fullName]; - c.Fields.AddRange(fields); - if (!c.HasInterface) - c.HasInterface = cls.Interfaces.Any(x => x.ToDisplayString() == "Esiur.Resource.IResource"); - if (!c.HasTrigger) - c.HasTrigger = hasTrigger; - } else - { - Classes.Add(fullName, new ResourceGeneratorClassInfo() - { - Name = cls.Name, - ClassDeclaration = cds, - ClassSymbol = cls, - Fields = fields.ToList(), - HasInterface = cls.Interfaces.Any(x => x.ToDisplayString() == "Esiur.Resource.IResource"), - HasTrigger = hasTrigger - }); - } - - - return; - } + return; } } } - } + diff --git a/Esiur/Proxy/ResourceProxy.cs b/Esiur/Proxy/ResourceProxy.cs index 2f2026d..30962c2 100644 --- a/Esiur/Proxy/ResourceProxy.cs +++ b/Esiur/Proxy/ResourceProxy.cs @@ -7,72 +7,71 @@ using System.Reflection; using System.Reflection.Emit; using System.Text; -namespace Esiur.Proxy +namespace Esiur.Proxy; +public static class ResourceProxy { - public static class ResourceProxy - { - static Dictionary cache = new Dictionary(); - + static Dictionary cache = new Dictionary(); + #if NETSTANDARD - static MethodInfo modifyMethod = typeof(Instance).GetTypeInfo().GetMethod("Modified"); - static MethodInfo instanceGet = typeof(IResource).GetTypeInfo().GetProperty("Instance").GetGetMethod(); + static MethodInfo modifyMethod = typeof(Instance).GetTypeInfo().GetMethod("Modified"); + static MethodInfo instanceGet = typeof(IResource).GetTypeInfo().GetProperty("Instance").GetGetMethod(); #else static MethodInfo modifyMethod = typeof(Instance).GetMethod("Modified"); static MethodInfo instanceGet = typeof(IResource).GetProperty("Instance").GetGetMethod(); #endif - public static Type GetBaseType(object resource) + public static Type GetBaseType(object resource) + { + return GetBaseType(resource.GetType()); + } + + public static Type GetBaseType(Type type) + { + if (type.Assembly.IsDynamic) + return type.GetTypeInfo().BaseType; + else + return type; + + // if (type.FullName.Contains("Esiur.Proxy.T")) + //#if NETSTANDARD + // return type.GetTypeInfo().BaseType; + //#else + // return type.BaseType; + //#endif + // else + // return type; + } + + public static Type GetProxy(Type type) + { + + if (cache.ContainsKey(type)) + return cache[type]; + + // check if the type was made with code generation + if (type.GetCustomAttribute(false) != null) { - return GetBaseType(resource.GetType()); + cache.Add(type, type); + return type; } - public static Type GetBaseType(Type type) + if (!Codec.ImplementsInterface(type, typeof(IResource))) { - if (type.Assembly.IsDynamic) - return type.GetTypeInfo().BaseType; - else - return type; - -// if (type.FullName.Contains("Esiur.Proxy.T")) -//#if NETSTANDARD -// return type.GetTypeInfo().BaseType; -//#else -// return type.BaseType; -//#endif -// else -// return type; + cache.Add(type, type); + return type; } - public static Type GetProxy(Type type) - { - - if (cache.ContainsKey(type)) - return cache[type]; - - // check if the type was made with code generation - if (type.GetCustomAttribute(false) != null) - { - cache.Add(type, type); - return type; - } - - if (!Codec.ImplementsInterface(type, typeof(IResource))) - { - cache.Add(type, type); - return type; - } - #if NETSTANDARD - var typeInfo = type.GetTypeInfo(); + var typeInfo = type.GetTypeInfo(); - if (typeInfo.IsSealed || typeInfo.IsAbstract) - throw new Exception("Sealed/Abastract classes can't be proxied."); + if (typeInfo.IsSealed || typeInfo.IsAbstract) + throw new Exception("Sealed/Abastract classes can't be proxied."); - var props = from p in typeInfo.GetProperties(BindingFlags.Instance | BindingFlags.Public) - where p.CanWrite && p.SetMethod.IsVirtual && !p.SetMethod.IsFinal && - p.GetCustomAttribute(false) != null - select p; + var props = from p in typeInfo.GetProperties(BindingFlags.Instance | BindingFlags.Public) + where p.CanWrite && p.SetMethod.IsVirtual && !p.SetMethod.IsFinal && + p.GetCustomAttribute(false) != null + select p; #else if (type.IsSealed) @@ -84,172 +83,171 @@ namespace Esiur.Proxy select p; #endif - var assemblyName = new AssemblyName("Esiur.Proxy.T." + type.Assembly.GetName().Name);// type.Namespace); - assemblyName.Version = type.Assembly.GetName().Version; - assemblyName.CultureInfo = type.Assembly.GetName().CultureInfo; - //assemblyName.SetPublicKeyToken(null); + var assemblyName = new AssemblyName("Esiur.Proxy.T." + type.Assembly.GetName().Name);// type.Namespace); + assemblyName.Version = type.Assembly.GetName().Version; + assemblyName.CultureInfo = type.Assembly.GetName().CultureInfo; + //assemblyName.SetPublicKeyToken(null); - var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); - var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); - var typeName = "Esiur.Proxy.T." + type.FullName;// Assembly.CreateQualifiedName(assemblyName.FullName, "Esiur.Proxy.T." + type.FullName); + var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); + var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); + var typeName = "Esiur.Proxy.T." + type.FullName;// Assembly.CreateQualifiedName(assemblyName.FullName, "Esiur.Proxy.T." + type.FullName); - var typeBuilder = moduleBuilder.DefineType(typeName, - TypeAttributes.Public | TypeAttributes.Class, type); + var typeBuilder = moduleBuilder.DefineType(typeName, + TypeAttributes.Public | TypeAttributes.Class, type); - foreach (PropertyInfo propertyInfo in props) - CreateProperty(propertyInfo, typeBuilder, type); + foreach (PropertyInfo propertyInfo in props) + CreateProperty(propertyInfo, typeBuilder, type); #if NETSTANDARD - var t = typeBuilder.CreateTypeInfo().AsType(); - cache.Add(type, t); - return t; + var t = typeBuilder.CreateTypeInfo().AsType(); + cache.Add(type, t); + return t; #else var t = typeBuilder.CreateType(); cache.Add(type, t); return t; #endif - } - - public static Type GetProxy() - where T : IResource - { - return GetProxy(typeof(T)); - } - - - - //private static void C - private static void CreateProperty(PropertyInfo pi, TypeBuilder typeBuilder, Type resourceType) - { - var propertyBuilder = typeBuilder.DefineProperty(pi.Name, PropertyAttributes.None, pi.PropertyType, null); - - // Create set method - MethodBuilder builder = typeBuilder.DefineMethod("set_" + pi.Name, - MethodAttributes.Public | MethodAttributes.Virtual, null, new Type[] { pi.PropertyType }); - builder.DefineParameter(1, ParameterAttributes.None, "value"); - ILGenerator g = builder.GetILGenerator(); - - var getInstance = resourceType.GetTypeInfo().GetProperty("Instance").GetGetMethod(); - - - //g.Emit(OpCodes.Ldarg_0); - //g.Emit(OpCodes.Ldarg_1); - //g.Emit(OpCodes.Call, pi.GetSetMethod()); - //g.Emit(OpCodes.Nop); - - //g.Emit(OpCodes.Ldarg_0); - //g.Emit(OpCodes.Call, getInstance); - //g.Emit(OpCodes.Ldstr, pi.Name); - //g.Emit(OpCodes.Call, modifyMethod); - //g.Emit(OpCodes.Nop); - - //g.Emit(OpCodes.Ret); - - Label exitMethod = g.DefineLabel(); - Label callModified = g.DefineLabel(); - - g.Emit(OpCodes.Nop); - - g.Emit(OpCodes.Ldarg_0); - g.Emit(OpCodes.Ldarg_1); - g.Emit(OpCodes.Call, pi.GetSetMethod()); - g.Emit(OpCodes.Nop); - - g.Emit(OpCodes.Ldarg_0); - g.Emit(OpCodes.Call, getInstance); - g.Emit(OpCodes.Dup); - - g.Emit(OpCodes.Brtrue_S, callModified); - - g.Emit(OpCodes.Pop); - g.Emit(OpCodes.Br_S, exitMethod); - - g.MarkLabel(callModified); - - g.Emit(OpCodes.Ldstr, pi.Name); - g.Emit(OpCodes.Call, modifyMethod); - g.Emit(OpCodes.Nop); - - g.MarkLabel(exitMethod); - g.Emit(OpCodes.Ret); - propertyBuilder.SetSetMethod(builder); - - - builder = typeBuilder.DefineMethod("get_" + pi.Name, MethodAttributes.Public | MethodAttributes.Virtual, pi.PropertyType, null); - g = builder.GetILGenerator(); - g.Emit(OpCodes.Ldarg_0); - g.Emit(OpCodes.Call, pi.GetGetMethod()); - g.Emit(OpCodes.Ret); - - propertyBuilder.SetGetMethod(builder); - - // g.Emit(OpCodes.Ldarg_0); - // g.Emit(OpCodes.Call, pi.GetGetMethod()); - // g.Emit(OpCodes.Ret); - - // propertyBuilder.SetGetMethod(builder); - - - /* - Label callModified = g.DefineLabel(); - Label exitMethod = g.DefineLabel(); - - - // IL_0000: ldarg.0 - //IL_0001: call instance class [Esiur]Esiur.Resource.Instance [Esiur]Esiur.Resource.Resource::get_Instance() - //// (no C# code) - //IL_0006: dup - //IL_0007: brtrue.s IL_000c - //IL_0009: pop - //// } - //IL_000a: br.s IL_0017 - //// (no C# code) - //IL_000c: ldstr "Level3" - //IL_0011: call instance void [Esiur]Esiur.Resource.Instance::Modified(string) - //IL_0016: nop - //IL_0017: ret - - - // Add IL code for set method - g.Emit(OpCodes.Nop); - g.Emit(OpCodes.Ldarg_0); - g.Emit(OpCodes.Ldarg_1); - g.Emit(OpCodes.Call, pi.GetSetMethod()); - - - // IL_0000: ldarg.0 - // IL_0001: call instance class [Esiur]Esiur.Resource.Instance [Esiur]Esiur.Resource.Resource::get_Instance() - // IL_0006: ldstr "Level3" - //IL_000b: callvirt instance void [Esiur]Esiur.Resource.Instance::Modified(string) - //IL_0010: ret - - - // Call property changed for object - g.Emit(OpCodes.Nop); - g.Emit(OpCodes.Ldarg_0); - g.Emit(OpCodes.Call, instanceGet); - - g.Emit(OpCodes.Dup); - g.Emit(OpCodes.Brtrue_S, callModified); - g.Emit(OpCodes.Pop); - g.Emit(OpCodes.Br_S, exitMethod); - - g.MarkLabel(callModified); - g.Emit(OpCodes.Ldstr, pi.Name); - g.Emit(OpCodes.Callvirt, modifyMethod); - g.Emit(OpCodes.Nop); - g.MarkLabel(exitMethod); - g.Emit(OpCodes.Ret); - propertyBuilder.SetSetMethod(builder); - - - // create get method - - */ - } - } + + public static Type GetProxy() + where T : IResource + { + return GetProxy(typeof(T)); + } + + + + //private static void C + private static void CreateProperty(PropertyInfo pi, TypeBuilder typeBuilder, Type resourceType) + { + var propertyBuilder = typeBuilder.DefineProperty(pi.Name, PropertyAttributes.None, pi.PropertyType, null); + + // Create set method + MethodBuilder builder = typeBuilder.DefineMethod("set_" + pi.Name, + MethodAttributes.Public | MethodAttributes.Virtual, null, new Type[] { pi.PropertyType }); + builder.DefineParameter(1, ParameterAttributes.None, "value"); + ILGenerator g = builder.GetILGenerator(); + + var getInstance = resourceType.GetTypeInfo().GetProperty("Instance").GetGetMethod(); + + + //g.Emit(OpCodes.Ldarg_0); + //g.Emit(OpCodes.Ldarg_1); + //g.Emit(OpCodes.Call, pi.GetSetMethod()); + //g.Emit(OpCodes.Nop); + + //g.Emit(OpCodes.Ldarg_0); + //g.Emit(OpCodes.Call, getInstance); + //g.Emit(OpCodes.Ldstr, pi.Name); + //g.Emit(OpCodes.Call, modifyMethod); + //g.Emit(OpCodes.Nop); + + //g.Emit(OpCodes.Ret); + + Label exitMethod = g.DefineLabel(); + Label callModified = g.DefineLabel(); + + g.Emit(OpCodes.Nop); + + g.Emit(OpCodes.Ldarg_0); + g.Emit(OpCodes.Ldarg_1); + g.Emit(OpCodes.Call, pi.GetSetMethod()); + g.Emit(OpCodes.Nop); + + g.Emit(OpCodes.Ldarg_0); + g.Emit(OpCodes.Call, getInstance); + g.Emit(OpCodes.Dup); + + g.Emit(OpCodes.Brtrue_S, callModified); + + g.Emit(OpCodes.Pop); + g.Emit(OpCodes.Br_S, exitMethod); + + g.MarkLabel(callModified); + + g.Emit(OpCodes.Ldstr, pi.Name); + g.Emit(OpCodes.Call, modifyMethod); + g.Emit(OpCodes.Nop); + + g.MarkLabel(exitMethod); + g.Emit(OpCodes.Ret); + propertyBuilder.SetSetMethod(builder); + + + builder = typeBuilder.DefineMethod("get_" + pi.Name, MethodAttributes.Public | MethodAttributes.Virtual, pi.PropertyType, null); + g = builder.GetILGenerator(); + g.Emit(OpCodes.Ldarg_0); + g.Emit(OpCodes.Call, pi.GetGetMethod()); + g.Emit(OpCodes.Ret); + + propertyBuilder.SetGetMethod(builder); + + // g.Emit(OpCodes.Ldarg_0); + // g.Emit(OpCodes.Call, pi.GetGetMethod()); + // g.Emit(OpCodes.Ret); + + // propertyBuilder.SetGetMethod(builder); + + + /* + Label callModified = g.DefineLabel(); + Label exitMethod = g.DefineLabel(); + + + // IL_0000: ldarg.0 + //IL_0001: call instance class [Esiur]Esiur.Resource.Instance [Esiur]Esiur.Resource.Resource::get_Instance() + //// (no C# code) + //IL_0006: dup + //IL_0007: brtrue.s IL_000c + //IL_0009: pop + //// } + //IL_000a: br.s IL_0017 + //// (no C# code) + //IL_000c: ldstr "Level3" + //IL_0011: call instance void [Esiur]Esiur.Resource.Instance::Modified(string) + //IL_0016: nop + //IL_0017: ret + + + // Add IL code for set method + g.Emit(OpCodes.Nop); + g.Emit(OpCodes.Ldarg_0); + g.Emit(OpCodes.Ldarg_1); + g.Emit(OpCodes.Call, pi.GetSetMethod()); + + + // IL_0000: ldarg.0 + // IL_0001: call instance class [Esiur]Esiur.Resource.Instance [Esiur]Esiur.Resource.Resource::get_Instance() + // IL_0006: ldstr "Level3" + //IL_000b: callvirt instance void [Esiur]Esiur.Resource.Instance::Modified(string) + //IL_0010: ret + + + // Call property changed for object + g.Emit(OpCodes.Nop); + g.Emit(OpCodes.Ldarg_0); + g.Emit(OpCodes.Call, instanceGet); + + g.Emit(OpCodes.Dup); + g.Emit(OpCodes.Brtrue_S, callModified); + g.Emit(OpCodes.Pop); + g.Emit(OpCodes.Br_S, exitMethod); + + g.MarkLabel(callModified); + g.Emit(OpCodes.Ldstr, pi.Name); + g.Emit(OpCodes.Callvirt, modifyMethod); + g.Emit(OpCodes.Nop); + g.MarkLabel(exitMethod); + g.Emit(OpCodes.Ret); + propertyBuilder.SetSetMethod(builder); + + + // create get method + + */ + } + } diff --git a/Esiur/Proxy/TemplateGenerator.cs b/Esiur/Proxy/TemplateGenerator.cs index 7223af8..639f043 100644 --- a/Esiur/Proxy/TemplateGenerator.cs +++ b/Esiur/Proxy/TemplateGenerator.cs @@ -10,229 +10,227 @@ using Esiur.Resource; using Esiur.Net.IIP; using System.Diagnostics; -namespace Esiur.Proxy +namespace Esiur.Proxy; +public static class TemplateGenerator { - public static class TemplateGenerator + internal static Regex urlRegex = new Regex(@"^(?:([\S]*)://([^/]*)/?)"); + + internal static string GenerateRecord(TypeTemplate template, TypeTemplate[] templates) { - internal static Regex urlRegex = new Regex(@"^(?:([\S]*)://([^/]*)/?)"); + var cls = template.ClassName.Split('.'); - internal static string GenerateRecord(TypeTemplate template, TypeTemplate[] templates) + var nameSpace = string.Join(".", cls.Take(cls.Length - 1)); + var className = cls.Last(); + + var rt = new StringBuilder(); + + rt.AppendLine("using System;\r\nusing Esiur.Resource;\r\nusing Esiur.Core;\r\nusing Esiur.Data;\r\nusing Esiur.Net.IIP;"); + rt.AppendLine($"namespace { nameSpace} {{"); + rt.AppendLine($"public class {className} : IRecord {{"); + + + foreach (var p in template.Properties) { - var cls = template.ClassName.Split('.'); - - var nameSpace = string.Join(".", cls.Take(cls.Length - 1)); - var className = cls.Last(); - - var rt = new StringBuilder(); - - rt.AppendLine("using System;\r\nusing Esiur.Resource;\r\nusing Esiur.Core;\r\nusing Esiur.Data;\r\nusing Esiur.Net.IIP;"); - rt.AppendLine($"namespace { nameSpace} {{"); - rt.AppendLine($"public class {className} : IRecord {{"); - - - foreach (var p in template.Properties) - { - var ptTypeName = GetTypeName(p.ValueType, templates); - rt.AppendLine($"public {ptTypeName} {p.Name} {{ get; set; }}"); - rt.AppendLine(); - } - - rt.AppendLine("\r\n}\r\n}"); - - return rt.ToString(); + var ptTypeName = GetTypeName(p.ValueType, templates); + rt.AppendLine($"public {ptTypeName} {p.Name} {{ get; set; }}"); + rt.AppendLine(); } - static string GetTypeName(TemplateDataType templateDataType, TypeTemplate[] templates) - { - - if (templateDataType.Type == DataType.Resource) - return templates.First(x => x.ClassId == templateDataType.TypeGuid && (x.Type == TemplateType.Resource || x.Type == TemplateType.Wrapper )).ClassName; - else if (templateDataType.Type == DataType.ResourceArray) - return templates.First(x => x.ClassId == templateDataType.TypeGuid && (x.Type == TemplateType.Resource || x.Type == TemplateType.Wrapper )).ClassName + "[]"; - else if (templateDataType.Type == DataType.Record) - return templates.First(x => x.ClassId == templateDataType.TypeGuid && x.Type == TemplateType.Record).ClassName; - else if (templateDataType.Type == DataType.RecordArray) - return templates.First(x => x.ClassId == templateDataType.TypeGuid && x.Type == TemplateType.Record).ClassName + "[]"; - - var name = templateDataType.Type switch - { - DataType.Bool => "bool", - DataType.BoolArray => "bool[]", - DataType.Char => "char", - DataType.CharArray => "char[]", - DataType.DateTime => "DateTime", - DataType.DateTimeArray => "DateTime[]", - DataType.Decimal => "decimal", - DataType.DecimalArray => "decimal[]", - DataType.Float32 => "float", - DataType.Float32Array => "float[]", - DataType.Float64 => "double", - DataType.Float64Array => "double[]", - DataType.Int16 => "short", - DataType.Int16Array => "short[]", - DataType.Int32 => "int", - DataType.Int32Array => "int[]", - DataType.Int64 => "long", - DataType.Int64Array => "long[]", - DataType.Int8 => "sbyte", - DataType.Int8Array => "sbyte[]", - DataType.String => "string", - DataType.StringArray => "string[]", - DataType.Structure => "Structure", - DataType.StructureArray => "Structure[]", - DataType.UInt16 => "ushort", - DataType.UInt16Array => "ushort[]", - DataType.UInt32 => "uint", - DataType.UInt32Array => "uint[]", - DataType.UInt64 => "ulong", - DataType.UInt64Array => "ulong[]", - DataType.UInt8 => "byte", - DataType.UInt8Array => "byte[]", - DataType.VarArray => "object[]", - DataType.Void => "object", - _ => "object" - }; - - return name; - } - - public static string GetTemplate(string url, string dir = null, string username= null, string password = null) - { - try - { - - if (!urlRegex.IsMatch(url)) - throw new Exception("Invalid IIP URL"); - - var path = urlRegex.Split(url); - var con = Warehouse.Get(path[1] + "://" + path[2], - !string.IsNullOrEmpty( username) && !string.IsNullOrEmpty( password) ? new { Username = username, Password = password } : null - ).Wait(20000); - - if (con == null) - throw new Exception("Can't connect to server"); - - if (string.IsNullOrEmpty(dir)) - dir = path[2].Replace(":", "_"); - - var templates = con.GetLinkTemplates(path[3]).Wait(60000); - // no longer needed - Warehouse.Remove(con); - - var tempDir = new DirectoryInfo(Path.GetTempPath() + Path.DirectorySeparatorChar - + Misc.Global.GenerateCode(20) + Path.DirectorySeparatorChar + dir); - - if (!tempDir.Exists) - tempDir.Create(); - else - { - foreach (FileInfo file in tempDir.GetFiles()) - file.Delete(); - } - - // make sources - foreach (var tmp in templates) - { - if (tmp.Type == TemplateType.Resource) - { - var source = GenerateClass(tmp, templates); - File.WriteAllText(tempDir.FullName + Path.DirectorySeparatorChar + tmp.ClassName + ".Generated.cs", source); - } - else if (tmp.Type == TemplateType.Record) - { - var source = GenerateRecord(tmp, templates); - File.WriteAllText(tempDir.FullName + Path.DirectorySeparatorChar + tmp.ClassName + ".Generated.cs", source); - } - } - - // generate info class - - var typesFile = "using System; \r\n namespace Esiur { public static class Generated { public static Type[] Resources {get;} = new Type[] { " + - string.Join(",", templates.Where(x => x.Type == TemplateType.Resource).Select(x => $"typeof({x.ClassName})")) - + " }; \r\n public static Type[] Records { get; } = new Type[] { " + - string.Join(",", templates.Where(x => x.Type == TemplateType.Record).Select(x => $"typeof({x.ClassName})")) - + " }; " + - - "\r\n } \r\n}"; - - - File.WriteAllText(tempDir.FullName + Path.DirectorySeparatorChar + "Esiur.Generated.cs", typesFile); - - - return tempDir.FullName; - - } - catch(Exception ex) - { - //File.WriteAllText("C:\\gen\\gettemplate.err", ex.ToString()); - throw ex; - } - } - - internal static string GenerateClass(TypeTemplate template, TypeTemplate[] templates) - { - var cls = template.ClassName.Split('.'); - - var nameSpace = string.Join(".", cls.Take(cls.Length - 1)); - var className = cls.Last(); - - var rt = new StringBuilder(); - - rt.AppendLine("using System;\r\nusing Esiur.Resource;\r\nusing Esiur.Core;\r\nusing Esiur.Data;\r\nusing Esiur.Net.IIP;"); - rt.AppendLine($"namespace { nameSpace} {{"); - rt.AppendLine($"public class {className} : DistributedResource {{"); - - rt.AppendLine($"public {className}(DistributedConnection connection, uint instanceId, ulong age, string link) : base(connection, instanceId, age, link) {{}}"); - rt.AppendLine($"public {className}() {{}}"); - - foreach (var f in template.Functions) - { - var rtTypeName = GetTypeName(f.ReturnType, templates); - rt.Append($"public AsyncReply<{rtTypeName}> {f.Name}("); - rt.Append(string.Join(",", f.Arguments.Select(x => GetTypeName(x.Type, templates) + " " + x.Name))); - - rt.AppendLine(") {"); - rt.AppendLine($"var rt = new AsyncReply<{rtTypeName}>();"); - rt.AppendLine($"_InvokeByArrayArguments({f.Index}, new object[] {{ { string.Join(", ", f.Arguments.Select(x => x.Name)) } }})"); - rt.AppendLine($".Then(x => rt.Trigger(({rtTypeName})x))"); - rt.AppendLine($".Error(x => rt.TriggerError(x))"); - rt.AppendLine($".Chunk(x => rt.TriggerChunk(x));"); - rt.AppendLine("return rt; }"); - } - - foreach (var p in template.Properties) - { - var ptTypeName = GetTypeName(p.ValueType, templates); - rt.AppendLine($"public {ptTypeName} {p.Name} {{"); - rt.AppendLine($"get => ({ptTypeName})properties[{p.Index}];"); - rt.AppendLine($"set => _Set({p.Index}, value);"); - rt.AppendLine("}"); - } - - if (template.Events.Length > 0) - { - rt.AppendLine("protected override void _EmitEventByIndex(byte index, object args) {"); - rt.AppendLine("switch (index) {"); - - var eventsList = new StringBuilder(); - - foreach (var e in template.Events) - { - var etTypeName = GetTypeName(e.ArgumentType, templates); - rt.AppendLine($"case {e.Index}: {e.Name}?.Invoke(({etTypeName})args); break;"); - eventsList.AppendLine($"public event ResourceEventHandler<{etTypeName}> {e.Name};"); - } - - rt.AppendLine("}}"); - - rt.AppendLine(eventsList.ToString()); - - } - - rt.AppendLine("\r\n}\r\n}"); - - return rt.ToString(); - } + rt.AppendLine("\r\n}\r\n}"); + return rt.ToString(); } + + static string GetTypeName(TemplateDataType templateDataType, TypeTemplate[] templates) + { + + if (templateDataType.Type == DataType.Resource) + return templates.First(x => x.ClassId == templateDataType.TypeGuid && (x.Type == TemplateType.Resource || x.Type == TemplateType.Wrapper)).ClassName; + else if (templateDataType.Type == DataType.ResourceArray) + return templates.First(x => x.ClassId == templateDataType.TypeGuid && (x.Type == TemplateType.Resource || x.Type == TemplateType.Wrapper)).ClassName + "[]"; + else if (templateDataType.Type == DataType.Record) + return templates.First(x => x.ClassId == templateDataType.TypeGuid && x.Type == TemplateType.Record).ClassName; + else if (templateDataType.Type == DataType.RecordArray) + return templates.First(x => x.ClassId == templateDataType.TypeGuid && x.Type == TemplateType.Record).ClassName + "[]"; + + var name = templateDataType.Type switch + { + DataType.Bool => "bool", + DataType.BoolArray => "bool[]", + DataType.Char => "char", + DataType.CharArray => "char[]", + DataType.DateTime => "DateTime", + DataType.DateTimeArray => "DateTime[]", + DataType.Decimal => "decimal", + DataType.DecimalArray => "decimal[]", + DataType.Float32 => "float", + DataType.Float32Array => "float[]", + DataType.Float64 => "double", + DataType.Float64Array => "double[]", + DataType.Int16 => "short", + DataType.Int16Array => "short[]", + DataType.Int32 => "int", + DataType.Int32Array => "int[]", + DataType.Int64 => "long", + DataType.Int64Array => "long[]", + DataType.Int8 => "sbyte", + DataType.Int8Array => "sbyte[]", + DataType.String => "string", + DataType.StringArray => "string[]", + DataType.Structure => "Structure", + DataType.StructureArray => "Structure[]", + DataType.UInt16 => "ushort", + DataType.UInt16Array => "ushort[]", + DataType.UInt32 => "uint", + DataType.UInt32Array => "uint[]", + DataType.UInt64 => "ulong", + DataType.UInt64Array => "ulong[]", + DataType.UInt8 => "byte", + DataType.UInt8Array => "byte[]", + DataType.VarArray => "object[]", + DataType.Void => "object", + _ => "object" + }; + + return name; + } + + public static string GetTemplate(string url, string dir = null, string username = null, string password = null) + { + try + { + + if (!urlRegex.IsMatch(url)) + throw new Exception("Invalid IIP URL"); + + var path = urlRegex.Split(url); + var con = Warehouse.Get(path[1] + "://" + path[2], + !string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password) ? new { Username = username, Password = password } : null + ).Wait(20000); + + if (con == null) + throw new Exception("Can't connect to server"); + + if (string.IsNullOrEmpty(dir)) + dir = path[2].Replace(":", "_"); + + var templates = con.GetLinkTemplates(path[3]).Wait(60000); + // no longer needed + Warehouse.Remove(con); + + var tempDir = new DirectoryInfo(Path.GetTempPath() + Path.DirectorySeparatorChar + + Misc.Global.GenerateCode(20) + Path.DirectorySeparatorChar + dir); + + if (!tempDir.Exists) + tempDir.Create(); + else + { + foreach (FileInfo file in tempDir.GetFiles()) + file.Delete(); + } + + // make sources + foreach (var tmp in templates) + { + if (tmp.Type == TemplateType.Resource) + { + var source = GenerateClass(tmp, templates); + File.WriteAllText(tempDir.FullName + Path.DirectorySeparatorChar + tmp.ClassName + ".Generated.cs", source); + } + else if (tmp.Type == TemplateType.Record) + { + var source = GenerateRecord(tmp, templates); + File.WriteAllText(tempDir.FullName + Path.DirectorySeparatorChar + tmp.ClassName + ".Generated.cs", source); + } + } + + // generate info class + + var typesFile = "using System; \r\n namespace Esiur { public static class Generated { public static Type[] Resources {get;} = new Type[] { " + + string.Join(",", templates.Where(x => x.Type == TemplateType.Resource).Select(x => $"typeof({x.ClassName})")) + + " }; \r\n public static Type[] Records { get; } = new Type[] { " + + string.Join(",", templates.Where(x => x.Type == TemplateType.Record).Select(x => $"typeof({x.ClassName})")) + + " }; " + + + "\r\n } \r\n}"; + + + File.WriteAllText(tempDir.FullName + Path.DirectorySeparatorChar + "Esiur.Generated.cs", typesFile); + + + return tempDir.FullName; + + } + catch (Exception ex) + { + //File.WriteAllText("C:\\gen\\gettemplate.err", ex.ToString()); + throw ex; + } + } + + internal static string GenerateClass(TypeTemplate template, TypeTemplate[] templates) + { + var cls = template.ClassName.Split('.'); + + var nameSpace = string.Join(".", cls.Take(cls.Length - 1)); + var className = cls.Last(); + + var rt = new StringBuilder(); + + rt.AppendLine("using System;\r\nusing Esiur.Resource;\r\nusing Esiur.Core;\r\nusing Esiur.Data;\r\nusing Esiur.Net.IIP;"); + rt.AppendLine($"namespace { nameSpace} {{"); + rt.AppendLine($"public class {className} : DistributedResource {{"); + + rt.AppendLine($"public {className}(DistributedConnection connection, uint instanceId, ulong age, string link) : base(connection, instanceId, age, link) {{}}"); + rt.AppendLine($"public {className}() {{}}"); + + foreach (var f in template.Functions) + { + var rtTypeName = GetTypeName(f.ReturnType, templates); + rt.Append($"public AsyncReply<{rtTypeName}> {f.Name}("); + rt.Append(string.Join(",", f.Arguments.Select(x => GetTypeName(x.Type, templates) + " " + x.Name))); + + rt.AppendLine(") {"); + rt.AppendLine($"var rt = new AsyncReply<{rtTypeName}>();"); + rt.AppendLine($"_InvokeByArrayArguments({f.Index}, new object[] {{ { string.Join(", ", f.Arguments.Select(x => x.Name)) } }})"); + rt.AppendLine($".Then(x => rt.Trigger(({rtTypeName})x))"); + rt.AppendLine($".Error(x => rt.TriggerError(x))"); + rt.AppendLine($".Chunk(x => rt.TriggerChunk(x));"); + rt.AppendLine("return rt; }"); + } + + foreach (var p in template.Properties) + { + var ptTypeName = GetTypeName(p.ValueType, templates); + rt.AppendLine($"public {ptTypeName} {p.Name} {{"); + rt.AppendLine($"get => ({ptTypeName})properties[{p.Index}];"); + rt.AppendLine($"set => _Set({p.Index}, value);"); + rt.AppendLine("}"); + } + + if (template.Events.Length > 0) + { + rt.AppendLine("protected override void _EmitEventByIndex(byte index, object args) {"); + rt.AppendLine("switch (index) {"); + + var eventsList = new StringBuilder(); + + foreach (var e in template.Events) + { + var etTypeName = GetTypeName(e.ArgumentType, templates); + rt.AppendLine($"case {e.Index}: {e.Name}?.Invoke(({etTypeName})args); break;"); + eventsList.AppendLine($"public event ResourceEventHandler<{etTypeName}> {e.Name};"); + } + + rt.AppendLine("}}"); + + rt.AppendLine(eventsList.ToString()); + + } + + rt.AppendLine("\r\n}\r\n}"); + + return rt.ToString(); + } + } diff --git a/Esiur/Resource/AnnotationAttribute.cs b/Esiur/Resource/AnnotationAttribute.cs index 511b5c2..28d477c 100644 --- a/Esiur/Resource/AnnotationAttribute.cs +++ b/Esiur/Resource/AnnotationAttribute.cs @@ -2,17 +2,15 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Resource +namespace Esiur.Resource; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Event)] +public class AnnotationAttribute : Attribute { - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Event)] - public class AnnotationAttribute : Attribute + public string Annotation { get; set; } + public AnnotationAttribute(string annotation) { - - public string Annotation { get; set; } - public AnnotationAttribute(string annotation) - { - this.Annotation = annotation; - } + this.Annotation = annotation; } } diff --git a/Esiur/Resource/AttributeAttribute.cs b/Esiur/Resource/AttributeAttribute.cs index 0e78663..c121abd 100644 --- a/Esiur/Resource/AttributeAttribute.cs +++ b/Esiur/Resource/AttributeAttribute.cs @@ -27,16 +27,14 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Resource -{ +namespace Esiur.Resource; - [AttributeUsage(AttributeTargets.Property)] - public class AttributeAttribute : System.Attribute +[AttributeUsage(AttributeTargets.Property)] +public class AttributeAttribute : System.Attribute +{ + public string Name { get; set; } + public AttributeAttribute(string name = null) { - public string Name { get; set; } - public AttributeAttribute(string name = null) - { - this.Name = name; - } + this.Name = name; } } diff --git a/Esiur/Resource/IResource.cs b/Esiur/Resource/IResource.cs index 9ca5c58..348ff42 100644 --- a/Esiur/Resource/IResource.cs +++ b/Esiur/Resource/IResource.cs @@ -32,24 +32,23 @@ using System.ComponentModel; using System.Text.Json.Serialization; using System.ComponentModel.DataAnnotations.Schema; -namespace Esiur.Resource +namespace Esiur.Resource; + +public delegate bool QueryFilter(T value); + +//[JsonConverter(typeof(ResourceJsonConverter))] + +public interface IResource : IDestructible///, INotifyPropertyChanged { - public delegate bool QueryFilter(T value); - //[JsonConverter(typeof(ResourceJsonConverter))] + AsyncReply Trigger(ResourceTrigger trigger); - public interface IResource : IDestructible///, INotifyPropertyChanged + [NotMapped] + Instance Instance { - - AsyncReply Trigger(ResourceTrigger trigger); - - [NotMapped] - Instance Instance - { - get; - set; - } - - + get; + set; } + + } diff --git a/Esiur/Resource/IStore.cs b/Esiur/Resource/IStore.cs index 02e4143..c956b96 100644 --- a/Esiur/Resource/IStore.cs +++ b/Esiur/Resource/IStore.cs @@ -33,44 +33,42 @@ using System.Threading.Tasks; using Esiur.Security.Permissions; using Esiur.Security.Authority; -namespace Esiur.Resource +namespace Esiur.Resource; +public interface IStore : IResource { - public interface IStore:IResource - { - AsyncReply Get(string path);//, Func filter = null); - //AsyncReply Retrieve(uint iid); - AsyncReply Put(IResource resource); - string Link(IResource resource); - bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime); - bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime); - bool Remove(IResource resource); + AsyncReply Get(string path);//, Func filter = null); + //AsyncReply Retrieve(uint iid); + AsyncReply Put(IResource resource); + string Link(IResource resource); + bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime); + bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime); + bool Remove(IResource resource); - //bool RemoveAttributes(IResource resource, string[] attributes = null); + //bool RemoveAttributes(IResource resource, string[] attributes = null); - //Structure GetAttributes(IResource resource, string[] attributes = null); + //Structure GetAttributes(IResource resource, string[] attributes = null); - //bool SetAttributes(IResource resource, Structure attributes, bool clearAttributes = false); - - - - AsyncReply AddChild(IResource parent, IResource child); - AsyncReply RemoveChild(IResource parent, IResource child); - - AsyncReply AddParent(IResource child, IResource parent); - AsyncReply RemoveParent(IResource child, IResource parent); - - - AsyncBag Children(IResource resource, string name) where T : IResource; - AsyncBag Parents(IResource resource, string name) where T : IResource; + //bool SetAttributes(IResource resource, Structure attributes, bool clearAttributes = false); - //AsyncReply GetPropertyRecord(IResource resource, string propertyName, ulong fromAge, ulong toAge); - //AsyncReply GetPropertyRecordByDate(IResource resource, string propertyName, DateTime fromDate, DateTime toDate); + AsyncReply AddChild(IResource parent, IResource child); + AsyncReply RemoveChild(IResource parent, IResource child); - //AsyncReply> GetRecord(IResource resource, ulong fromAge, ulong toAge); - // AsyncReply> GetRecordByDate(IResource resource, DateTime fromDate, DateTime toDate); + AsyncReply AddParent(IResource child, IResource parent); + AsyncReply RemoveParent(IResource child, IResource parent); - AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate); - } + + AsyncBag Children(IResource resource, string name) where T : IResource; + AsyncBag Parents(IResource resource, string name) where T : IResource; + + + + //AsyncReply GetPropertyRecord(IResource resource, string propertyName, ulong fromAge, ulong toAge); + //AsyncReply GetPropertyRecordByDate(IResource resource, string propertyName, DateTime fromDate, DateTime toDate); + + //AsyncReply> GetRecord(IResource resource, ulong fromAge, ulong toAge); + // AsyncReply> GetRecordByDate(IResource resource, DateTime fromDate, DateTime toDate); + + AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate); } diff --git a/Esiur/Resource/ImportAttribute.cs b/Esiur/Resource/ImportAttribute.cs index 037c0c8..e40a600 100644 --- a/Esiur/Resource/ImportAttribute.cs +++ b/Esiur/Resource/ImportAttribute.cs @@ -2,14 +2,13 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Resource -{ - [AttributeUsage(AttributeTargets.Class)] - public class ImportAttribute:Attribute - { - public ImportAttribute(string url) - { +namespace Esiur.Resource; + +[AttributeUsage(AttributeTargets.Class)] +public class ImportAttribute : Attribute +{ + public ImportAttribute(string url) + { - } } } diff --git a/Esiur/Resource/Instance.cs b/Esiur/Resource/Instance.cs index 3425519..3e1c8c4 100644 --- a/Esiur/Resource/Instance.cs +++ b/Esiur/Resource/Instance.cs @@ -16,866 +16,792 @@ using Esiur.Core; using System.Text.Json; using System.ComponentModel.DataAnnotations.Schema; -namespace Esiur.Resource +namespace Esiur.Resource; + +[NotMapped] +public class Instance { - [NotMapped] - public class Instance + string name; + + // public int IntVal { get; set; } + + + WeakReference resource; + IStore store; + TypeTemplate template; + AutoList managers; + + + public delegate void ResourceModifiedEvent(IResource resource, string propertyName, object newValue); + public delegate void ResourceEventOccurredEvent(IResource resource, string eventName, object args); + + public delegate void CustomResourceEventOccurredEvent(IResource resource, object issuer, Func receivers, string eventName, object args); + + public delegate void ResourceDestroyedEvent(IResource resource); + + public event ResourceModifiedEvent ResourceModified; + public event ResourceEventOccurredEvent ResourceEventOccurred; + public event CustomResourceEventOccurredEvent CustomResourceEventOccurred; + public event ResourceDestroyedEvent ResourceDestroyed; + + bool loading = false; + + //KeyList attributes; + + List ages = new List(); + List modificationDates = new List(); + private ulong instanceAge; + private DateTime instanceModificationDate; + + uint id; + + public KeyList Variables { get; } = new KeyList(); + + /// + /// Instance attributes are custom properties associated with the instance, a place to store information by IStore. + /// + //public KeyList Attributes + //{ + // get + // { + // return attributes; + // } + //} + + public override string ToString() { - string name; + return name + " (" + Link + ")"; + } - // public int IntVal { get; set; } + public bool RemoveAttributes(string[] attributes = null) + { - - WeakReference resource; - IStore store; - TypeTemplate template; - AutoList managers; - - - public delegate void ResourceModifiedEvent(IResource resource, string propertyName, object newValue); - public delegate void ResourceEventOccurredEvent(IResource resource, string eventName, object args); - - public delegate void CustomResourceEventOccurredEvent(IResource resource, object issuer, Func receivers, string eventName, object args); - - public delegate void ResourceDestroyedEvent(IResource resource); - - public event ResourceModifiedEvent ResourceModified; - public event ResourceEventOccurredEvent ResourceEventOccurred; - public event CustomResourceEventOccurredEvent CustomResourceEventOccurred; - public event ResourceDestroyedEvent ResourceDestroyed; - - bool loading = false; - - //KeyList attributes; - - List ages = new List(); - List modificationDates = new List(); - private ulong instanceAge; - private DateTime instanceModificationDate; - - uint id; - - public KeyList Variables { get; } = new KeyList(); - - /// - /// Instance attributes are custom properties associated with the instance, a place to store information by IStore. - /// - //public KeyList Attributes - //{ - // get - // { - // return attributes; - // } - //} - - public override string ToString() - { - return name + " (" + Link + ")"; - } - - public bool RemoveAttributes(string[] attributes = null) - { - - return false; - - /* - IResource res; - - if (!resource.TryGetTarget(out res)) - return false; - - return store.RemoveAttributes(res, attributes); - */ - - /* - if (attributes == null) - this.attributes.Clear(); - else - { - foreach (var attr in attributes) - this.attributes.Remove(attr); - } - - return true; - */ - } - - public Structure GetAttributes(string[] attributes = null) - { - // @TODO - Structure rt = new Structure(); - - if (attributes != null) - { - for (var i = 0; i < attributes.Length; i++) - { - var at = template.GetAttributeTemplate(attributes[i]); - if (at != null) - { - - } - } - } - - return rt; - - - - /* - var st = new Structure(); - - if (attributes == null) - { - var clone = this.attributes.Keys.ToList(); - clone.Add("managers"); - attributes = clone.ToArray();// this.attributes.Keys.ToList().Add("managers"); - } - - foreach (var attr in attributes) - { - if (attr == "name") - st["name"] = this.name; - else if (attr == "managers") - { - var mngrs = new List(); - - foreach (var manager in this.managers) - mngrs.Add(new Structure() - { - ["type"] = manager.GetType().FullName + "," + manager.GetType().GetTypeInfo().Assembly.GetName().Name, - ["settings"] = manager.Settings - }); - - st["managers"] = mngrs.ToArray(); - } - else if (attr == "parents") - { - //st["parents"] = parents.ToArray(); - } - else if (attr == "children") - { - //st["children"] = children.ToArray(); - } - else if (attr == "childrenCount") - { - //st["childrenCount"] = children.Count; - } - else if (attr == "type") - { - st["type"] = resource.GetType().FullName; - } - else - st[attr] = this.attributes[attr]; - } - - return st; - */ - } - - public bool SetAttributes(Structure attributes, bool clearAttributes = false) - { - - // @ TODO - IResource res; - - if (resource.TryGetTarget(out res)) - { - foreach (var kv in attributes) - { - var at = template.GetAttributeTemplate(kv.Key); - - if (at != null) - if (at.PropertyInfo.CanWrite) - at.PropertyInfo.SetValue(res, DC.CastConvert(kv.Value, at.PropertyInfo.PropertyType)); - - } - } - - return true; - - - /* - try - { - - if (clearAttributes) - this.attributes.Clear(); - - foreach (var attr in attributes) - if (attr.Key == "name") - this.name = attr.Value as string; - else if (attr.Key == "managers") - { - this.managers.Clear(); - - var mngrs = attr.Value as object[]; - - foreach (var mngr in mngrs) - { - var m = mngr as Structure; - var type = Type.GetType(m["type"] as string); - if (Codec.ImplementsInterface(type, typeof(IPermissionsManager))) - { - var settings = m["settings"] as Structure; - var manager = Activator.CreateInstance(type) as IPermissionsManager; - - IResource res; - if (this.resource.TryGetTarget(out res)) - { - manager.Initialize(settings, res); - this.managers.Add(manager); - } - } - else - return false; - } - } - else - { - this.attributes[attr.Key] = attr.Value; - } - - } - catch - { - return false; - } - - return true; - */ - } + return false; /* - public Structure GetAttributes() + IResource res; + + if (!resource.TryGetTarget(out res)) + return false; + + return store.RemoveAttributes(res, attributes); + */ + + /* + if (attributes == null) + this.attributes.Clear(); + else { - var st = new Structure(); - foreach (var a in attributes.Keys) - st[a] = attributes[a]; + foreach (var attr in attributes) + this.attributes.Remove(attr); + } - st["name"] = name; + return true; + */ + } - var mngrs = new List(); + public Structure GetAttributes(string[] attributes = null) + { + // @TODO + Structure rt = new Structure(); - foreach (var manager in managers) + if (attributes != null) + { + for (var i = 0; i < attributes.Length; i++) { - var mngr = new Structure(); - mngr["settings"] = manager.Settings; - mngr["type"] = manager.GetType().FullName; - mngrs.Add(mngr); + var at = template.GetAttributeTemplate(attributes[i]); + if (at != null) + { + + } } + } - st["managers"] = mngrs; + return rt; - return st; - }*/ - /// - /// Get the age of a given property index. - /// - /// Zero-based property index. - /// Age. - public ulong GetAge(byte index) + + /* + var st = new Structure(); + + if (attributes == null) { - if (index < ages.Count) - return ages[index]; + var clone = this.attributes.Keys.ToList(); + clone.Add("managers"); + attributes = clone.ToArray();// this.attributes.Keys.ToList().Add("managers"); + } + + foreach (var attr in attributes) + { + if (attr == "name") + st["name"] = this.name; + else if (attr == "managers") + { + var mngrs = new List(); + + foreach (var manager in this.managers) + mngrs.Add(new Structure() + { + ["type"] = manager.GetType().FullName + "," + manager.GetType().GetTypeInfo().Assembly.GetName().Name, + ["settings"] = manager.Settings + }); + + st["managers"] = mngrs.ToArray(); + } + else if (attr == "parents") + { + //st["parents"] = parents.ToArray(); + } + else if (attr == "children") + { + //st["children"] = children.ToArray(); + } + else if (attr == "childrenCount") + { + //st["childrenCount"] = children.Count; + } + else if (attr == "type") + { + st["type"] = resource.GetType().FullName; + } else - return 0; + st[attr] = this.attributes[attr]; } - /// - /// Set the age of a property. - /// - /// Zero-based property index. - /// Age. - public void SetAge(byte index, ulong value) + return st; + */ + } + + public bool SetAttributes(Structure attributes, bool clearAttributes = false) + { + + // @ TODO + IResource res; + + if (resource.TryGetTarget(out res)) { - if (index < ages.Count) + foreach (var kv in attributes) { - ages[index] = value; - if (value > instanceAge) - instanceAge = value; + var at = template.GetAttributeTemplate(kv.Key); + + if (at != null) + if (at.PropertyInfo.CanWrite) + at.PropertyInfo.SetValue(res, DC.CastConvert(kv.Value, at.PropertyInfo.PropertyType)); + } } - /// - /// Set the modification date of a property. - /// - /// Zero-based property index. - /// Modification date. - public void SetModificationDate(byte index, DateTime value) + return true; + + + /* + try { - if (index < modificationDates.Count) - { - modificationDates[index] = value; - if (value > instanceModificationDate) - instanceModificationDate = value; - } + + if (clearAttributes) + this.attributes.Clear(); + + foreach (var attr in attributes) + if (attr.Key == "name") + this.name = attr.Value as string; + else if (attr.Key == "managers") + { + this.managers.Clear(); + + var mngrs = attr.Value as object[]; + + foreach (var mngr in mngrs) + { + var m = mngr as Structure; + var type = Type.GetType(m["type"] as string); + if (Codec.ImplementsInterface(type, typeof(IPermissionsManager))) + { + var settings = m["settings"] as Structure; + var manager = Activator.CreateInstance(type) as IPermissionsManager; + + IResource res; + if (this.resource.TryGetTarget(out res)) + { + manager.Initialize(settings, res); + this.managers.Add(manager); + } + } + else + return false; + } + } + else + { + this.attributes[attr.Key] = attr.Value; + } + + } + catch + { + return false; } - /// - /// Get modification date of a specific property. - /// - /// Zero-based property index - /// Modification date. - public DateTime GetModificationDate(byte index) + return true; + */ + } + + /* + public Structure GetAttributes() + { + var st = new Structure(); + foreach (var a in attributes.Keys) + st[a] = attributes[a]; + + st["name"] = name; + + var mngrs = new List(); + + foreach (var manager in managers) { - if (index < modificationDates.Count) - return modificationDates[index]; - else - return DateTime.MinValue; + var mngr = new Structure(); + mngr["settings"] = manager.Settings; + mngr["type"] = manager.GetType().FullName; + mngrs.Add(mngr); } + st["managers"] = mngrs; - /// - /// Load property value (used by stores) - /// - /// Property name - /// Property age - /// Property value - /// - public bool LoadProperty(string name, ulong age, DateTime modificationDate, object value) + return st; + }*/ + + /// + /// Get the age of a given property index. + /// + /// Zero-based property index. + /// Age. + public ulong GetAge(byte index) + { + if (index < ages.Count) + return ages[index]; + else + return 0; + } + + /// + /// Set the age of a property. + /// + /// Zero-based property index. + /// Age. + public void SetAge(byte index, ulong value) + { + if (index < ages.Count) { + ages[index] = value; + if (value > instanceAge) + instanceAge = value; + } + } - IResource res; + /// + /// Set the modification date of a property. + /// + /// Zero-based property index. + /// Modification date. + public void SetModificationDate(byte index, DateTime value) + { + if (index < modificationDates.Count) + { + modificationDates[index] = value; + if (value > instanceModificationDate) + instanceModificationDate = value; + } + } - if (!resource.TryGetTarget(out res)) - return false; + /// + /// Get modification date of a specific property. + /// + /// Zero-based property index + /// Modification date. + public DateTime GetModificationDate(byte index) + { + if (index < modificationDates.Count) + return modificationDates[index]; + else + return DateTime.MinValue; + } - var pt = template.GetPropertyTemplateByName(name); - if (pt == null) - return false; + /// + /// Load property value (used by stores) + /// + /// Property name + /// Property age + /// Property value + /// + public bool LoadProperty(string name, ulong age, DateTime modificationDate, object value) + { - /* + IResource res; + + if (!resource.TryGetTarget(out res)) + return false; + + var pt = template.GetPropertyTemplateByName(name); + + if (pt == null) + return false; + + /* #if NETSTANDARD - var pi = resource.GetType().GetTypeInfo().GetProperty(name, new[] { resource.GetType() }); + var pi = resource.GetType().GetTypeInfo().GetProperty(name, new[] { resource.GetType() }); #else - var pi = resource.GetType().GetProperty(pt.Name); + var pi = resource.GetType().GetProperty(pt.Name); #endif */ - if (pt.PropertyInfo.PropertyType == typeof(DistributedPropertyContext)) - return false; + if (pt.PropertyInfo.PropertyType == typeof(DistributedPropertyContext)) + return false; - if (pt.PropertyInfo.CanWrite) + if (pt.PropertyInfo.CanWrite) + { + try { - try - { - loading = true; + loading = true; - pt.PropertyInfo.SetValue(res, DC.CastConvert(value, pt.PropertyInfo.PropertyType)); - } - catch (Exception ex) - { - //Console.WriteLine(resource.ToString() + " " + name); - Global.Log(ex); - } - - loading = false; + pt.PropertyInfo.SetValue(res, DC.CastConvert(value, pt.PropertyInfo.PropertyType)); + } + catch (Exception ex) + { + //Console.WriteLine(resource.ToString() + " " + name); + Global.Log(ex); } - - SetAge(pt.Index, age); - SetModificationDate(pt.Index, modificationDate); - - return true; + loading = false; } - /// - /// Age of the instance, incremented by 1 in every modification. - /// - public ulong Age - { - get { return instanceAge; } - internal set { instanceAge = value; } - } - /// - /// Last modification date. - /// - public DateTime ModificationDate + SetAge(pt.Index, age); + SetModificationDate(pt.Index, modificationDate); + + return true; + } + + /// + /// Age of the instance, incremented by 1 in every modification. + /// + public ulong Age + { + get { return instanceAge; } + internal set { instanceAge = value; } + } + + /// + /// Last modification date. + /// + public DateTime ModificationDate + { + get { - get + return instanceModificationDate; + } + } + + /// + /// Instance Id. + /// + public uint Id + { + get { return id; } + } + + /// + /// Import properties from bytes array. + /// + /// + /// + public bool Deserialize(PropertyValue[] properties) + { + for (byte i = 0; i < properties.Length; i++) + { + var pt = this.template.GetPropertyTemplateByIndex(i); + if (pt != null) { - return instanceModificationDate; + var pv = properties[i]; + LoadProperty(pt.Name, pv.Age, pv.Date, pv.Value); } } - /// - /// Instance Id. - /// - public uint Id - { - get { return id; } - } + return true; + } - /// - /// Import properties from bytes array. - /// - /// - /// - public bool Deserialize(PropertyValue[] properties) - { - for (byte i = 0; i < properties.Length; i++) - { - var pt = this.template.GetPropertyTemplateByIndex(i); - if (pt != null) - { - var pv = properties[i]; - LoadProperty(pt.Name, pv.Age, pv.Date, pv.Value); - } - } + public string ToJson() + { + IResource res; + if (resource.TryGetTarget(out res)) + return JsonSerializer.Serialize(res, Global.SerializeOptions); + else + return null; + } - return true; - } + /// + /// Export all properties with ResourceProperty attributed as bytes array. + /// + /// + public PropertyValue[] Serialize() + { + List props = new List(); - public string ToJson() + foreach (var pt in template.Properties) { IResource res; + if (resource.TryGetTarget(out res)) - return JsonSerializer.Serialize(res, Global.SerializeOptions); - else - return null; - } - - /// - /// Export all properties with ResourceProperty attributed as bytes array. - /// - /// - public PropertyValue[] Serialize() - { - List props = new List(); - - foreach (var pt in template.Properties) { - IResource res; - - if (resource.TryGetTarget(out res)) - { - var rt = pt.PropertyInfo.GetValue(res, null); - props.Add(new PropertyValue(rt, ages[pt.Index], modificationDates[pt.Index])); - } - } - - return props.ToArray(); - } - - /* - public bool Deserialize(byte[] data, uint offset, uint length) - { - - var props = Codec.ParseValues(data, offset, length); - Deserialize(props); - return true; - } - */ - /* - public byte[] Serialize(bool includeLength = false, DistributedConnection sender = null) - { - - //var bl = new BinaryList(); - List props = new List(); - - foreach (var pt in template.Properties) - { - - var pi = resource.GetType().GetProperty(pt.Name); - - var rt = pi.GetValue(resource, null); - - // this is a cool hack to let the property know the sender - if (rt is Func) - rt = (rt as Func)(sender); - - props.Add(rt); - - } - - if (includeLength) - { - return Codec.Compose(props.ToArray(), false); - } - else - { - var rt = Codec.Compose(props.ToArray(), false); - return DC.Clip(rt, 4, (uint)(rt.Length - 4)); + var rt = pt.PropertyInfo.GetValue(res, null); + props.Add(new PropertyValue(rt, ages[pt.Index], modificationDates[pt.Index])); } } - public byte[] StorageSerialize() + return props.ToArray(); + } + + /* + public bool Deserialize(byte[] data, uint offset, uint length) + { + + var props = Codec.ParseValues(data, offset, length); + Deserialize(props); + return true; + } + */ + /* + public byte[] Serialize(bool includeLength = false, DistributedConnection sender = null) + { + + //var bl = new BinaryList(); + List props = new List(); + + foreach (var pt in template.Properties) { - var props = new List(); + var pi = resource.GetType().GetProperty(pt.Name); - foreach(var pt in template.Properties) - { - if (!pt.Storable) - continue; + var rt = pi.GetValue(resource, null); - var pi = resource.GetType().GetProperty(pt.Name); + // this is a cool hack to let the property know the sender + if (rt is Func) + rt = (rt as Func)(sender); - if (!pi.CanWrite) - continue; + props.Add(rt); - var rt = pi.GetValue(resource, null); - - props.Add(rt); - - } + } + if (includeLength) + { return Codec.Compose(props.ToArray(), false); } - */ - - /// - /// If True, the instance can be stored to disk. - /// - /// - public bool IsStorable() + else { + var rt = Codec.Compose(props.ToArray(), false); + return DC.Clip(rt, 4, (uint)(rt.Length - 4)); + } + } + + public byte[] StorageSerialize() + { + + var props = new List(); + + foreach(var pt in template.Properties) + { + if (!pt.Storable) + continue; + + var pi = resource.GetType().GetProperty(pt.Name); + + if (!pi.CanWrite) + continue; + + var rt = pi.GetValue(resource, null); + + props.Add(rt); + + } + + return Codec.Compose(props.ToArray(), false); + } + */ + + /// + /// If True, the instance can be stored to disk. + /// + /// + public bool IsStorable() + { #if NETSTANDARD - var attrs = resource.GetType().GetTypeInfo().GetCustomAttributes(typeof(Storable), true).ToArray(); + var attrs = resource.GetType().GetTypeInfo().GetCustomAttributes(typeof(Storable), true).ToArray(); #else var attrs = resource.GetType().GetCustomAttributes(typeof(Storable), true); #endif - return attrs.Length > 0; + return attrs.Length > 0; - } + } - internal void EmitModification(PropertyTemplate pt, object value) + internal void EmitModification(PropertyTemplate pt, object value) + { + + IResource res; + if (this.resource.TryGetTarget(out res)) { + instanceAge++; + var now = DateTime.UtcNow; - IResource res; - if (this.resource.TryGetTarget(out res)) + ages[pt.Index] = instanceAge; + modificationDates[pt.Index] = now; + + if (pt.Recordable) { - instanceAge++; - var now = DateTime.UtcNow; + store.Record(res, pt.Name, value, ages[pt.Index], now); - ages[pt.Index] = instanceAge; - modificationDates[pt.Index] = now; - - if (pt.Recordable) - { - store.Record(res, pt.Name, value, ages[pt.Index], now); - - } - else //if (pt.Storage == StorageMode.Recordable) - { - store.Modify(res, pt.Name, value, ages[pt.Index], now); - } - - ResourceModified?.Invoke(res, pt.Name, value); } - } - - /// - /// Notify listeners that a property was modified. - /// - /// - /// - /// - public void Modified([CallerMemberName] string propertyName = "") - { - if (loading) - return; - - object value; - if (GetPropertyValue(propertyName, out value)) + else //if (pt.Storage == StorageMode.Recordable) { - var pt = template.GetPropertyTemplateByName(propertyName); - EmitModification(pt, value); + store.Modify(res, pt.Name, value, ages[pt.Index], now); } + + ResourceModified?.Invoke(res, pt.Name, value); } + } - // internal void EmitResourceEvent(string name, string[] users, DistributedConnection[] connections, object[] args) + /// + /// Notify listeners that a property was modified. + /// + /// + /// + /// + public void Modified([CallerMemberName] string propertyName = "") + { + if (loading) + return; - internal void EmitCustomResourceEvent(object issuer, Func receivers, string name, object args) + object value; + if (GetPropertyValue(propertyName, out value)) { - IResource res; - if (this.resource.TryGetTarget(out res)) - { - CustomResourceEventOccurred?.Invoke(res, issuer, receivers, name, args); - } + var pt = template.GetPropertyTemplateByName(propertyName); + EmitModification(pt, value); } + } - internal void EmitResourceEvent(string name, object args) + // internal void EmitResourceEvent(string name, string[] users, DistributedConnection[] connections, object[] args) + + internal void EmitCustomResourceEvent(object issuer, Func receivers, string name, object args) + { + IResource res; + if (this.resource.TryGetTarget(out res)) { - IResource res; - if (this.resource.TryGetTarget(out res)) - { - ResourceEventOccurred?.Invoke(res, name, args); - } + CustomResourceEventOccurred?.Invoke(res, issuer, receivers, name, args); } + } - /// - /// Get the value of a given property by name. - /// - /// Property name - /// Output value - /// True, if the resource has the property. - public bool GetPropertyValue(string name, out object value) + internal void EmitResourceEvent(string name, object args) + { + IResource res; + if (this.resource.TryGetTarget(out res)) { - /* + ResourceEventOccurred?.Invoke(res, name, args); + } + } + + /// + /// Get the value of a given property by name. + /// + /// Property name + /// Output value + /// True, if the resource has the property. + public bool GetPropertyValue(string name, out object value) + { + /* #if NETSTANDARD - PropertyInfo pi = resource.GetType().GetTypeInfo().GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); + PropertyInfo pi = resource.GetType().GetTypeInfo().GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); #else - PropertyInfo pi = resource.GetType().GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); + PropertyInfo pi = resource.GetType().GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); #endif */ - var pt = template.GetPropertyTemplateByName(name); + var pt = template.GetPropertyTemplateByName(name); - if (pt != null && pt.PropertyInfo != null) - { - /* + if (pt != null && pt.PropertyInfo != null) + { + /* #if NETSTANDARD - object[] ca = pi.GetCustomAttributes(typeof(ResourceProperty), false).ToArray(); + object[] ca = pi.GetCustomAttributes(typeof(ResourceProperty), false).ToArray(); #else - object[] ca = pi.GetCustomAttributes(typeof(ResourceProperty), false); + object[] ca = pi.GetCustomAttributes(typeof(ResourceProperty), false); #endif - if (ca.Length > 0) - { - value = pi.GetValue(resource, null); - //if (value is Func) - // value = (value as Func)(sender); - return true; - } - */ - - IResource res; - if (resource.TryGetTarget(out res)) - value = pt.PropertyInfo.GetValue(res, null); - else - { - value = null; - return false; - } - + if (ca.Length > 0) + { + value = pi.GetValue(resource, null); + //if (value is Func) + // value = (value as Func)(sender); return true; - - } - - value = null; - return false; - } - - - /* - public bool Inherit - { - get { return inherit; } - }*/ - - /// - /// List of parents. - /// - //public AutoList Parents => parents; - - /// - /// Store responsible for creating and keeping the resource. - /// - public IStore Store - { - get { return store; } - } - - /// - /// List of children. - /// - // public AutoList Children => children; - - /// - /// The unique and permanent link to the resource. - /// - public string Link - { - get - { - IResource res; - if (this.resource.TryGetTarget(out res)) - { - if (res == res.Instance.store) - return name; // root store - else - return store.Link(res); - } - else - return null; - } - } - - public AsyncBag Children(string name = null) where T : IResource - { - IResource res; - if (this.resource.TryGetTarget(out res)) - { - //if (!(store is null)) - return store.Children(res, name); - //else - // return (res as IStore).Children(res, name); - } - else - return new AsyncBag(null); - } - - public AsyncBag Parents(string name = null) where T : IResource - { - IResource res; - if (this.resource.TryGetTarget(out res)) - { - return store.Parents(res, name); - } - else - return new AsyncBag(null); - } - - /* - { - get - { - if (this.store != null) - return this.store.Link(this.resource); - else - { - var l = new List(); - //l.Add(name); - - var p = this.resource; // parents.First(); - - while (true) - { - l.Insert(0, p.Instance.name); - - if (p.Instance.parents.Count == 0) - break; - - p = p.Instance.parents.First(); - } - - return String.Join("/", l.ToArray()); - } - } - } - * - */ - - /// - /// Instance name. - /// - public string Name - { - get { return name; } - set { name = value; } - } - - - /// - /// Resource managed by this instance. - /// - public IResource Resource - { - get - { - IResource res; - if (this.resource.TryGetTarget(out res)) - { - return res; - } - else - return null; - } - } - - /// - /// Resource template describes the properties, functions and events of the resource. - /// - public TypeTemplate Template - { - get { return template; } - - /* - internal set - { - template = Warehouse.GetTemplate(resource.GetType()); - - // set ages - for (byte i = 0; i < template.Properties.Length; i++) - { - ages.Add(0); - modificationDates.Add(DateTime.MinValue); - } } */ + + IResource res; + if (resource.TryGetTarget(out res)) + value = pt.PropertyInfo.GetValue(res, null); + else + { + value = null; + return false; + } + + return true; + } - /// - /// Check for permission. - /// - /// Caller sessions. - /// Action type - /// Function, property or event to check for permission. - /// Permission inquirer. - /// Ruling. - public Ruling Applicable(Session session, ActionType action, MemberTemplate member, object inquirer = null) + value = null; + return false; + } + + + /* + public bool Inherit + { + get { return inherit; } + }*/ + + /// + /// List of parents. + /// + //public AutoList Parents => parents; + + /// + /// Store responsible for creating and keeping the resource. + /// + public IStore Store + { + get { return store; } + } + + /// + /// List of children. + /// + // public AutoList Children => children; + + /// + /// The unique and permanent link to the resource. + /// + public string Link + { + get { IResource res; if (this.resource.TryGetTarget(out res)) { - //return store.Applicable(res, session, action, member, inquirer); + if (res == res.Instance.store) + return name; // root store + else + return store.Link(res); + } + else + return null; + } + } - foreach (IPermissionsManager manager in managers) + public AsyncBag Children(string name = null) where T : IResource + { + IResource res; + if (this.resource.TryGetTarget(out res)) + { + //if (!(store is null)) + return store.Children(res, name); + //else + // return (res as IStore).Children(res, name); + } + else + return new AsyncBag(null); + } + + public AsyncBag Parents(string name = null) where T : IResource + { + IResource res; + if (this.resource.TryGetTarget(out res)) + { + return store.Parents(res, name); + } + else + return new AsyncBag(null); + } + + /* + { + get + { + if (this.store != null) + return this.store.Link(this.resource); + else + { + var l = new List(); + //l.Add(name); + + var p = this.resource; // parents.First(); + + while (true) { - var r = manager.Applicable(res, session, action, member, inquirer); - if (r != Ruling.DontCare) - return r; + l.Insert(0, p.Instance.name); + + if (p.Instance.parents.Count == 0) + break; + + p = p.Instance.parents.First(); } + return String.Join("/", l.ToArray()); } - - return Ruling.DontCare; - } + } + * + */ - /// - /// Execution managers. - /// - public AutoList Managers => managers; + /// + /// Instance name. + /// + public string Name + { + get { return name; } + set { name = value; } + } - /// - /// Create new instance. - /// - /// Instance Id. - /// Name of the instance. - /// Resource to manage. - /// Store responsible for the resource. - public Instance(uint id, string name, IResource resource, IStore store, TypeTemplate customTemplate = null, ulong age = 0) + + /// + /// Resource managed by this instance. + /// + public IResource Resource + { + get { - this.store = store; - this.resource = new WeakReference(resource); - this.id = id; - this.name = name ?? ""; - this.instanceAge = age; - - //this.attributes = new KeyList(this); - //children = new AutoList(this); - //parents = new AutoList(this); - managers = new AutoList(this); - //children.OnAdd += Children_OnAdd; - //children.OnRemoved += Children_OnRemoved; - //parents.OnAdd += Parents_OnAdd; - //parents.OnRemoved += Parents_OnRemoved; - - resource.OnDestroy += Resource_OnDestroy; - - if (customTemplate != null) - this.template = customTemplate; + IResource res; + if (this.resource.TryGetTarget(out res)) + { + return res; + } else - this.template = Warehouse.GetTemplateByType(resource.GetType()); + return null; + } + } + + /// + /// Resource template describes the properties, functions and events of the resource. + /// + public TypeTemplate Template + { + get { return template; } + + /* + internal set + { + template = Warehouse.GetTemplate(resource.GetType()); // set ages for (byte i = 0; i < template.Properties.Length; i++) @@ -883,115 +809,188 @@ namespace Esiur.Resource ages.Add(0); modificationDates.Add(DateTime.MinValue); } + } + */ + } - // connect events - Type t = ResourceProxy.GetBaseType(resource); + /// + /// Check for permission. + /// + /// Caller sessions. + /// Action type + /// Function, property or event to check for permission. + /// Permission inquirer. + /// Ruling. + public Ruling Applicable(Session session, ActionType action, MemberTemplate member, object inquirer = null) + { + IResource res; + if (this.resource.TryGetTarget(out res)) + { + //return store.Applicable(res, session, action, member, inquirer); + + foreach (IPermissionsManager manager in managers) + { + var r = manager.Applicable(res, session, action, member, inquirer); + if (r != Ruling.DontCare) + return r; + } + + } + + return Ruling.DontCare; + + } + + /// + /// Execution managers. + /// + public AutoList Managers => managers; + + /// + /// Create new instance. + /// + /// Instance Id. + /// Name of the instance. + /// Resource to manage. + /// Store responsible for the resource. + public Instance(uint id, string name, IResource resource, IStore store, TypeTemplate customTemplate = null, ulong age = 0) + { + this.store = store; + this.resource = new WeakReference(resource); + this.id = id; + this.name = name ?? ""; + this.instanceAge = age; + + //this.attributes = new KeyList(this); + //children = new AutoList(this); + //parents = new AutoList(this); + managers = new AutoList(this); + //children.OnAdd += Children_OnAdd; + //children.OnRemoved += Children_OnRemoved; + //parents.OnAdd += Parents_OnAdd; + //parents.OnRemoved += Parents_OnRemoved; + + resource.OnDestroy += Resource_OnDestroy; + + if (customTemplate != null) + this.template = customTemplate; + else + this.template = Warehouse.GetTemplateByType(resource.GetType()); + + // set ages + for (byte i = 0; i < template.Properties.Length; i++) + { + ages.Add(0); + modificationDates.Add(DateTime.MinValue); + } + + // connect events + Type t = ResourceProxy.GetBaseType(resource); #if NETSTANDARD - var events = t.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly); + var events = t.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly); #else var events = t.GetEvents(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly); #endif - foreach (var evt in template.Events) + foreach (var evt in template.Events) + { + //if (evt.EventHandlerType != typeof(ResourceEventHandler)) + // continue; + + if (evt.EventInfo == null) + continue; + + var eventGenericType = evt.EventInfo.EventHandlerType.GetGenericTypeDefinition(); + + if (eventGenericType == typeof(ResourceEventHandler<>)) { - //if (evt.EventHandlerType != typeof(ResourceEventHandler)) - // continue; - if (evt.EventInfo == null) - continue; + // var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); + // if (ca.Length == 0) + // continue; - var eventGenericType = evt.EventInfo.EventHandlerType.GetGenericTypeDefinition(); - - if (eventGenericType == typeof(ResourceEventHandler<>)) - { - - // var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); - // if (ca.Length == 0) - // continue; - - ResourceEventHandler proxyDelegate = (args) => EmitResourceEvent(evt.Name, args); - evt.EventInfo.AddEventHandler(resource, proxyDelegate); - - } - else if (eventGenericType == typeof(CustomResourceEventHandler<>)) - { - //var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); - //if (ca.Length == 0) - // continue; - - CustomResourceEventHandler proxyDelegate = (issuer, receivers, args) => EmitCustomResourceEvent(issuer, receivers, evt.Name, args); - evt.EventInfo.AddEventHandler(resource, proxyDelegate); - } - - - /* - else if (evt.EventHandlerType == typeof(CustomUsersEventHanlder)) - { - var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); - if (ca.Length == 0) - continue; - - CustomUsersEventHanlder proxyDelegate = (users, args) => EmitResourceEvent(evt.Name, users, null, args); - evt.AddEventHandler(resource, proxyDelegate); - } - else if (evt.EventHandlerType == typeof(CustomConnectionsEventHanlder)) - { - var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); - if (ca.Length == 0) - continue; - - CustomConnectionsEventHanlder proxyDelegate = (connections, args) => EmitResourceEvent(evt.Name, null, connections, args); - evt.AddEventHandler(resource, proxyDelegate); - } - else if (evt.EventHandlerType == typeof(CustomReceiversEventHanlder)) - { - var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); - if (ca.Length == 0) - continue; - - CustomReceiversEventHanlder proxyDelegate = (users, connections, args) => EmitResourceEvent(evt.Name, users, connections, args); - evt.AddEventHandler(resource, proxyDelegate); - - } - */ + ResourceEventHandler proxyDelegate = (args) => EmitResourceEvent(evt.Name, args); + evt.EventInfo.AddEventHandler(resource, proxyDelegate); } - } + else if (eventGenericType == typeof(CustomResourceEventHandler<>)) + { + //var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); + //if (ca.Length == 0) + // continue; + + CustomResourceEventHandler proxyDelegate = (issuer, receivers, args) => EmitCustomResourceEvent(issuer, receivers, evt.Name, args); + evt.EventInfo.AddEventHandler(resource, proxyDelegate); + } - //IQueryable Children => store.GetChildren(this); + /* + else if (evt.EventHandlerType == typeof(CustomUsersEventHanlder)) + { + var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); + if (ca.Length == 0) + continue; + CustomUsersEventHanlder proxyDelegate = (users, args) => EmitResourceEvent(evt.Name, users, null, args); + evt.AddEventHandler(resource, proxyDelegate); + } + else if (evt.EventHandlerType == typeof(CustomConnectionsEventHanlder)) + { + var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); + if (ca.Length == 0) + continue; - /* - * private void Children_OnRemoved(Instance parent, IResource value) - { - value.Instance.parents.Remove(resource); - } + CustomConnectionsEventHanlder proxyDelegate = (connections, args) => EmitResourceEvent(evt.Name, null, connections, args); + evt.AddEventHandler(resource, proxyDelegate); + } + else if (evt.EventHandlerType == typeof(CustomReceiversEventHanlder)) + { + var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); + if (ca.Length == 0) + continue; - private void Children_OnAdd(Instance parent, IResource value) - { - if (!value.Instance.parents.Contains(resource)) - value.Instance.parents.Add(resource); - } + CustomReceiversEventHanlder proxyDelegate = (users, connections, args) => EmitResourceEvent(evt.Name, users, connections, args); + evt.AddEventHandler(resource, proxyDelegate); - private void Parents_OnRemoved(Instance parent, IResource value) - { - value.Instance.children.Remove(resource); - } + } + */ - private void Parents_OnAdd(Instance parent, IResource value) - { - if (!value.Instance.children.Contains(resource)) - value.Instance.children.Add(resource); - } - */ - - private void Resource_OnDestroy(object sender) - { - ResourceDestroyed?.Invoke((IResource)sender); } } + + + //IQueryable Children => store.GetChildren(this); + + + /* + * private void Children_OnRemoved(Instance parent, IResource value) + { + value.Instance.parents.Remove(resource); + } + + private void Children_OnAdd(Instance parent, IResource value) + { + if (!value.Instance.parents.Contains(resource)) + value.Instance.parents.Add(resource); + } + + private void Parents_OnRemoved(Instance parent, IResource value) + { + value.Instance.children.Remove(resource); + } + + private void Parents_OnAdd(Instance parent, IResource value) + { + if (!value.Instance.children.Contains(resource)) + value.Instance.children.Add(resource); + } + */ + + private void Resource_OnDestroy(object sender) + { + ResourceDestroyed?.Invoke((IResource)sender); + } } diff --git a/Esiur/Resource/ListenableAttribute.cs b/Esiur/Resource/ListenableAttribute.cs index 3a80acc..58dfdf9 100644 --- a/Esiur/Resource/ListenableAttribute.cs +++ b/Esiur/Resource/ListenableAttribute.cs @@ -27,16 +27,14 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Resource +namespace Esiur.Resource; + +[AttributeUsage(AttributeTargets.Event)] +public class ListenableAttribute : System.Attribute { - [AttributeUsage(AttributeTargets.Event)] - public class ListenableAttribute : System.Attribute + public ListenableAttribute() { - public ListenableAttribute() - { - - } } } diff --git a/Esiur/Resource/PrivateAttribute.cs b/Esiur/Resource/PrivateAttribute.cs index 6587bcd..be4c869 100644 --- a/Esiur/Resource/PrivateAttribute.cs +++ b/Esiur/Resource/PrivateAttribute.cs @@ -2,10 +2,8 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Resource +namespace Esiur.Resource; +public class PrivateAttribute : Attribute { - public class PrivateAttribute:Attribute - { - } } diff --git a/Esiur/Resource/PublicAttribute.cs b/Esiur/Resource/PublicAttribute.cs index 9f70f9b..e24d47c 100644 --- a/Esiur/Resource/PublicAttribute.cs +++ b/Esiur/Resource/PublicAttribute.cs @@ -2,17 +2,16 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Resource +namespace Esiur.Resource; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Event | AttributeTargets.Class)] + +public class PublicAttribute : Attribute { - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Event | AttributeTargets.Class)] + public string Name { get; set; } - public class PublicAttribute : Attribute + public PublicAttribute(string name = null) { - public string Name { get; set; } - - public PublicAttribute(string name = null) - { - Name = name; - } + Name = name; } } diff --git a/Esiur/Resource/Resource.cs b/Esiur/Resource/Resource.cs index d37d606..03709e2 100644 --- a/Esiur/Resource/Resource.cs +++ b/Esiur/Resource/Resource.cs @@ -26,36 +26,34 @@ using System.Collections.Generic; using System.Text; using Esiur.Core; -namespace Esiur.Resource +namespace Esiur.Resource; +public class Resource : IResource { - public class Resource : IResource + public Instance Instance { get; set; } + + public event DestroyedEvent OnDestroy; + + public virtual void Destroy() { - public Instance Instance { get; set; } + OnDestroy?.Invoke(this); + } - public event DestroyedEvent OnDestroy; + public virtual AsyncReply Trigger(ResourceTrigger trigger) + { + if (trigger == ResourceTrigger.Initialize) + return new AsyncReply(this.Create()); + else + return new AsyncReply(true); + } - public virtual void Destroy() - { - OnDestroy?.Invoke(this); - } - public virtual AsyncReply Trigger(ResourceTrigger trigger) - { - if (trigger == ResourceTrigger.Initialize) - return new AsyncReply(this.Create()); - else - return new AsyncReply(true); - } + protected virtual bool Create() + { + return true; + } - - protected virtual bool Create() - { - return true; - } - - ~Resource() - { - Destroy(); - } + ~Resource() + { + Destroy(); } } diff --git a/Esiur/Resource/ResourceAttribute.cs b/Esiur/Resource/ResourceAttribute.cs index 845bcc2..3ad3651 100644 --- a/Esiur/Resource/ResourceAttribute.cs +++ b/Esiur/Resource/ResourceAttribute.cs @@ -2,14 +2,13 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Resource -{ - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] - public class ResourceAttribute : Attribute - { - public ResourceAttribute() - { +namespace Esiur.Resource; + +[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] +public class ResourceAttribute : Attribute +{ + public ResourceAttribute() + { - } } } diff --git a/Esiur/Resource/ResourceEvent.cs b/Esiur/Resource/ResourceEvent.cs index f308d48..e2ff664 100644 --- a/Esiur/Resource/ResourceEvent.cs +++ b/Esiur/Resource/ResourceEvent.cs @@ -27,27 +27,25 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Resource +namespace Esiur.Resource; + +[AttributeUsage(AttributeTargets.Event)] +public class ResourceEvent : System.Attribute { - [AttributeUsage(AttributeTargets.Event)] - public class ResourceEvent : System.Attribute + string expansion; + + public string Expansion { - - string expansion; - - public string Expansion + get { - get - { - return expansion; - } - } - - - public ResourceEvent(string expansion = null) - { - this.expansion = expansion; + return expansion; } } + + + public ResourceEvent(string expansion = null) + { + this.expansion = expansion; + } } diff --git a/Esiur/Resource/ResourceEventHandler.cs b/Esiur/Resource/ResourceEventHandler.cs index 1870097..b579dd4 100644 --- a/Esiur/Resource/ResourceEventHandler.cs +++ b/Esiur/Resource/ResourceEventHandler.cs @@ -31,17 +31,16 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Resource -{ - public delegate R DCovariant(); +namespace Esiur.Resource; - public delegate void ResourceEventHandler(T argument); - // public delegate void CustomUsersEventHanlder(string[] usernames, params object[] args); - //public delegate void CustomReceiversEventHanlder(DistributedConnection[] connections, params object[] args); - //public delegate void CustomInquirerEventHanlder(object inquirer, params object[] args); +public delegate R DCovariant(); - public delegate void CustomResourceEventHandler(object issuer, Func receivers, T argument);// object issuer, Session[] receivers, params object[] args); +public delegate void ResourceEventHandler(T argument); +// public delegate void CustomUsersEventHanlder(string[] usernames, params object[] args); +//public delegate void CustomReceiversEventHanlder(DistributedConnection[] connections, params object[] args); +//public delegate void CustomInquirerEventHanlder(object inquirer, params object[] args); - // public delegate void CustomReceiversEventHanlder(string[] usernames, DistributedConnection[] connections, params object[] args); +public delegate void CustomResourceEventHandler(object issuer, Func receivers, T argument);// object issuer, Session[] receivers, params object[] args); + +// public delegate void CustomReceiversEventHanlder(string[] usernames, DistributedConnection[] connections, params object[] args); -} diff --git a/Esiur/Resource/ResourceFunction.cs b/Esiur/Resource/ResourceFunction.cs index c562e27..7a345db 100644 --- a/Esiur/Resource/ResourceFunction.cs +++ b/Esiur/Resource/ResourceFunction.cs @@ -28,25 +28,24 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Resource +namespace Esiur.Resource; + +[AttributeUsage(AttributeTargets.Method)] +public class ResourceFunction : System.Attribute { - [AttributeUsage(AttributeTargets.Method)] - public class ResourceFunction : System.Attribute + private string expansion = null; + + public string Expansion { - private string expansion = null; - - public string Expansion + get { - get - { - return expansion; - } - } - - - public ResourceFunction(string expansion = null) - { - this.expansion = expansion; + return expansion; } } + + + public ResourceFunction(string expansion = null) + { + this.expansion = expansion; + } } diff --git a/Esiur/Resource/ResourceProperty.cs b/Esiur/Resource/ResourceProperty.cs index 3234025..10049ba 100644 --- a/Esiur/Resource/ResourceProperty.cs +++ b/Esiur/Resource/ResourceProperty.cs @@ -29,49 +29,47 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Resource +namespace Esiur.Resource; + +[AttributeUsage(AttributeTargets.Property)] +public class ResourceProperty : System.Attribute { + bool serialize; + string readExpansion; + string writeExpansion; + // bool recordable; + //bool storable; - [AttributeUsage(AttributeTargets.Property)] - public class ResourceProperty : System.Attribute + //public bool Recordable => recordable; + + //public bool Storable => storable; + StorageMode storage; + + public StorageMode Storage => storage; + + public bool Serialize => serialize; + + public string ReadExpansion { - bool serialize; - string readExpansion; - string writeExpansion; - // bool recordable; - //bool storable; - - //public bool Recordable => recordable; - - //public bool Storable => storable; - StorageMode storage; - - public StorageMode Storage => storage; - - public bool Serialize => serialize; - - public string ReadExpansion + get { - get - { - return readExpansion; - } - } - - public string WriteExpansion - { - get - { - return writeExpansion; - } - } - - public ResourceProperty(StorageMode storage = StorageMode.NonVolatile, bool serialize = true, string readExpansion = null, string writeExpansion = null) - { - this.readExpansion = readExpansion; - this.writeExpansion = writeExpansion; - this.storage = storage; - this.serialize = serialize; + return readExpansion; } } + + public string WriteExpansion + { + get + { + return writeExpansion; + } + } + + public ResourceProperty(StorageMode storage = StorageMode.NonVolatile, bool serialize = true, string readExpansion = null, string writeExpansion = null) + { + this.readExpansion = readExpansion; + this.writeExpansion = writeExpansion; + this.storage = storage; + this.serialize = serialize; + } } diff --git a/Esiur/Resource/ResourceQuery.cs b/Esiur/Resource/ResourceQuery.cs index fb08457..fce25e2 100644 --- a/Esiur/Resource/ResourceQuery.cs +++ b/Esiur/Resource/ResourceQuery.cs @@ -5,24 +5,23 @@ using System.Linq; using System.Linq.Expressions; using System.Text; -namespace Esiur.Resource +namespace Esiur.Resource; + +public class ResourceQuery : IQueryable { - public class ResourceQuery : IQueryable + public Type ElementType => throw new NotImplementedException(); + + public Expression Expression => throw new NotImplementedException(); + + public IQueryProvider Provider => throw new NotImplementedException(); + + public IEnumerator GetEnumerator() { - public Type ElementType => throw new NotImplementedException(); + throw new NotImplementedException(); + } - public Expression Expression => throw new NotImplementedException(); - - public IQueryProvider Provider => throw new NotImplementedException(); - - public IEnumerator GetEnumerator() - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); } } diff --git a/Esiur/Resource/ResourceTrigger.cs b/Esiur/Resource/ResourceTrigger.cs index 237392f..9e4f1d5 100644 --- a/Esiur/Resource/ResourceTrigger.cs +++ b/Esiur/Resource/ResourceTrigger.cs @@ -28,16 +28,14 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Resource +namespace Esiur.Resource; +public enum ResourceTrigger : int { - public enum ResourceTrigger : int - { - Open = 0, - Initialize, - Terminate, - Configure, - SystemInitialized, - SystemTerminated, - SystemReload, - } + Open = 0, + Initialize, + Terminate, + Configure, + SystemInitialized, + SystemTerminated, + SystemReload, } diff --git a/Esiur/Resource/Storable.cs b/Esiur/Resource/Storable.cs index 8701c4f..44f8c76 100644 --- a/Esiur/Resource/Storable.cs +++ b/Esiur/Resource/Storable.cs @@ -30,43 +30,42 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Resource +namespace Esiur.Resource; + +[AttributeUsage(AttributeTargets.All)] +public class Storable : global::System.Attribute { - [AttributeUsage(AttributeTargets.All)] - public class Storable : global::System.Attribute + public delegate object SerializerFunction(object value); + public delegate object DeserializerFunction(object data); + + SerializerFunction serializer; + DeserializerFunction deserializer; + DataType type; + + public Storable() { - public delegate object SerializerFunction(object value); - public delegate object DeserializerFunction(object data); + type = DataType.Void; + } - SerializerFunction serializer; - DeserializerFunction deserializer; - DataType type; + public DeserializerFunction Deserializer + { + get { return deserializer; } + } - public Storable() - { - type = DataType.Void; - } + public SerializerFunction Serializer + { + get { return serializer; } + } - public DeserializerFunction Deserializer - { - get { return deserializer; } - } + public Storable(DataType type) + { + this.type = type; + } - public SerializerFunction Serializer - { - get { return serializer; } - } - - public Storable(DataType type) - { - this.type = type; - } - - public Storable(DataType type, SerializerFunction serializer, DeserializerFunction deserializer) - { - this.type = type; - this.serializer = serializer; - this.deserializer = deserializer; - } + public Storable(DataType type, SerializerFunction serializer, DeserializerFunction deserializer) + { + this.type = type; + this.serializer = serializer; + this.deserializer = deserializer; } } diff --git a/Esiur/Resource/StorageAttribute.cs b/Esiur/Resource/StorageAttribute.cs index 38d2fd1..e608f27 100644 --- a/Esiur/Resource/StorageAttribute.cs +++ b/Esiur/Resource/StorageAttribute.cs @@ -2,15 +2,14 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Resource +namespace Esiur.Resource; + +[AttributeUsage(AttributeTargets.Property)] +public class StorageAttribute : Attribute { - [AttributeUsage(AttributeTargets.Property)] - public class StorageAttribute:Attribute + public StorageMode Mode { get; set; } + public StorageAttribute(StorageMode mode) { - public StorageMode Mode { get; set; } - public StorageAttribute(StorageMode mode) - { - Mode = mode; - } + Mode = mode; } } diff --git a/Esiur/Resource/StorageMode.cs b/Esiur/Resource/StorageMode.cs index 5f557f5..ba8e5cb 100644 --- a/Esiur/Resource/StorageMode.cs +++ b/Esiur/Resource/StorageMode.cs @@ -2,12 +2,10 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Resource +namespace Esiur.Resource; +public enum StorageMode : byte { - public enum StorageMode : byte - { - NonVolatile, - Volatile, - Recordable - } + NonVolatile, + Volatile, + Recordable } diff --git a/Esiur/Resource/StoreGeneric.cs b/Esiur/Resource/StoreGeneric.cs index a3530bc..1568b27 100644 --- a/Esiur/Resource/StoreGeneric.cs +++ b/Esiur/Resource/StoreGeneric.cs @@ -5,53 +5,52 @@ using Esiur.Core; using Esiur.Data; using Esiur.Resource.Template; -namespace Esiur.Resource +namespace Esiur.Resource; +public abstract class Store : IStore where T : IResource { - public abstract class Store : IStore where T:IResource + public Instance Instance { get; set; } + + public event DestroyedEvent OnDestroy; + + public abstract AsyncReply AddChild(IResource parent, IResource child); + + public abstract AsyncReply AddParent(IResource child, IResource parent); + + public abstract AsyncBag Children(IResource resource, string name) where T1 : IResource; + + public virtual void Destroy() { - public Instance Instance { get; set; } + OnDestroy?.Invoke(this); + } - public event DestroyedEvent OnDestroy; + public abstract AsyncReply Get(string path); - public abstract AsyncReply AddChild(IResource parent, IResource child); - - public abstract AsyncReply AddParent(IResource child, IResource parent); - - public abstract AsyncBag Children(IResource resource, string name) where T1 : IResource; - - public virtual void Destroy() - { - OnDestroy?.Invoke(this); - } - - public abstract AsyncReply Get(string path); - - public abstract AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate); + public abstract AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate); - public abstract string Link(IResource resource); + public abstract string Link(IResource resource); - public abstract bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime); + public abstract bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime); - public abstract AsyncBag Parents(IResource resource, string name) where T1 : IResource; + public abstract AsyncBag Parents(IResource resource, string name) where T1 : IResource; - public abstract AsyncReply Put(IResource resource); + public abstract AsyncReply Put(IResource resource); - public abstract bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime); + public abstract bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime); - public abstract bool Remove(IResource resource); + public abstract bool Remove(IResource resource); - public abstract AsyncReply RemoveChild(IResource parent, IResource child); + public abstract AsyncReply RemoveChild(IResource parent, IResource child); - public abstract AsyncReply RemoveParent(IResource child, IResource parent); + public abstract AsyncReply RemoveParent(IResource child, IResource parent); - public abstract AsyncReply Trigger(ResourceTrigger trigger); + public abstract AsyncReply Trigger(ResourceTrigger trigger); - public async AsyncReply New(string name = null, object attributes = null, object properties = null) - { - var resource = await Warehouse.New(name, this, null, null, attributes, properties); - resource.Instance.Managers.AddRange(this.Instance.Managers.ToArray()); - return resource; - } + public async AsyncReply New(string name = null, object attributes = null, object properties = null) + { + var resource = await Warehouse.New(name, this, null, null, attributes, properties); + resource.Instance.Managers.AddRange(this.Instance.Managers.ToArray()); + return resource; } } + diff --git a/Esiur/Resource/Template/ArgumentTemplate.cs b/Esiur/Resource/Template/ArgumentTemplate.cs index e83649c..538491f 100644 --- a/Esiur/Resource/Template/ArgumentTemplate.cs +++ b/Esiur/Resource/Template/ArgumentTemplate.cs @@ -4,46 +4,44 @@ using System.Collections.Generic; using System.Text; using System.Reflection; -namespace Esiur.Resource.Template +namespace Esiur.Resource.Template; +public class ArgumentTemplate { - public class ArgumentTemplate + public string Name { get; set; } + + public TemplateDataType Type { get; set; } + + public ParameterInfo ParameterInfo { get; set; } + + public static (uint, ArgumentTemplate) Parse(byte[] data, uint offset) { - public string Name { get; set; } + var cs = (uint)data[offset++]; + var name = data.GetString(offset, cs); + offset += cs; + var (size, type) = TemplateDataType.Parse(data, offset); - public TemplateDataType Type { get; set; } + return (cs + 1 + size, new ArgumentTemplate(name, type)); + } - public ParameterInfo ParameterInfo { get; set; } + public ArgumentTemplate() + { - public static (uint, ArgumentTemplate) Parse(byte[] data, uint offset) - { - var cs = (uint)data[offset++]; - var name = data.GetString(offset, cs); - offset += cs; - var (size, type) = TemplateDataType.Parse(data, offset); + } - return (cs + 1 + size, new ArgumentTemplate(name, type)); - } + public ArgumentTemplate(string name, TemplateDataType type) + { + Name = name; + Type = type; + } - public ArgumentTemplate() - { + public byte[] Compose() + { + var name = DC.ToBytes(Name); - } - - public ArgumentTemplate(string name, TemplateDataType type) - { - Name = name; - Type = type; - } - - public byte[] Compose() - { - var name = DC.ToBytes(Name); - - return new BinaryList() - .AddUInt8((byte)name.Length) - .AddUInt8Array(name) - .AddUInt8Array(Type.Compose()) - .ToArray(); - } + return new BinaryList() + .AddUInt8((byte)name.Length) + .AddUInt8Array(name) + .AddUInt8Array(Type.Compose()) + .ToArray(); } } diff --git a/Esiur/Resource/Template/AttributeTemplate.cs b/Esiur/Resource/Template/AttributeTemplate.cs index 199ca5b..2d2f767 100644 --- a/Esiur/Resource/Template/AttributeTemplate.cs +++ b/Esiur/Resource/Template/AttributeTemplate.cs @@ -6,21 +6,19 @@ using System.Reflection; using System.Text; using System.Threading.Tasks; -namespace Esiur.Resource.Template +namespace Esiur.Resource.Template; +public class AttributeTemplate : MemberTemplate { - public class AttributeTemplate : MemberTemplate + public PropertyInfo PropertyInfo { - public PropertyInfo PropertyInfo - { - get; - set; - } + get; + set; + } - public AttributeTemplate(TypeTemplate template, byte index, string name) - : base(template, MemberType.Attribute, index, name) - { + public AttributeTemplate(TypeTemplate template, byte index, string name) + : base(template, MemberType.Attribute, index, name) + { - } } } diff --git a/Esiur/Resource/Template/EventTemplate.cs b/Esiur/Resource/Template/EventTemplate.cs index 7b4830e..d81ee7f 100644 --- a/Esiur/Resource/Template/EventTemplate.cs +++ b/Esiur/Resource/Template/EventTemplate.cs @@ -6,54 +6,52 @@ using System.Reflection; using System.Text; using System.Threading.Tasks; -namespace Esiur.Resource.Template +namespace Esiur.Resource.Template; +public class EventTemplate : MemberTemplate { - public class EventTemplate : MemberTemplate + public string Expansion { - public string Expansion + get; + set; + } + + public bool Listenable { get; set; } + + public EventInfo EventInfo { get; set; } + + public TemplateDataType ArgumentType { get; set; } + + public override byte[] Compose() + { + var name = base.Compose(); + + if (Expansion != null) { - get; - set; - } - - public bool Listenable { get; set; } - - public EventInfo EventInfo { get; set; } - - public TemplateDataType ArgumentType { get; set; } - - public override byte[] Compose() - { - var name = base.Compose(); - - if (Expansion != null) - { - var exp = DC.ToBytes(Expansion); - return new BinaryList() - .AddUInt8(Listenable ? (byte) 0x58 : (byte) 0x50) - .AddUInt8((byte)name.Length) - .AddUInt8Array(name) - .AddUInt8Array(ArgumentType.Compose()) - .AddInt32(exp.Length) - .AddUInt8Array(exp) - .ToArray(); - } - else - return new BinaryList() - .AddUInt8(Listenable ? (byte) 0x48 : (byte) 0x40) - .AddUInt8((byte)name.Length) - .AddUInt8Array(name) - .AddUInt8Array(ArgumentType.Compose()) - .ToArray(); + var exp = DC.ToBytes(Expansion); + return new BinaryList() + .AddUInt8(Listenable ? (byte)0x58 : (byte)0x50) + .AddUInt8((byte)name.Length) + .AddUInt8Array(name) + .AddUInt8Array(ArgumentType.Compose()) + .AddInt32(exp.Length) + .AddUInt8Array(exp) + .ToArray(); } + else + return new BinaryList() + .AddUInt8(Listenable ? (byte)0x48 : (byte)0x40) + .AddUInt8((byte)name.Length) + .AddUInt8Array(name) + .AddUInt8Array(ArgumentType.Compose()) + .ToArray(); + } - public EventTemplate(TypeTemplate template, byte index, string name, TemplateDataType argumentType, string expansion = null, bool listenable=false) - :base(template, MemberType.Property, index, name) - { - this.Expansion = expansion; - this.Listenable = listenable; - this.ArgumentType = argumentType; - } + public EventTemplate(TypeTemplate template, byte index, string name, TemplateDataType argumentType, string expansion = null, bool listenable = false) + : base(template, MemberType.Property, index, name) + { + this.Expansion = expansion; + this.Listenable = listenable; + this.ArgumentType = argumentType; } } diff --git a/Esiur/Resource/Template/FunctionTemplate.cs b/Esiur/Resource/Template/FunctionTemplate.cs index 92ea1c0..668c61a 100644 --- a/Esiur/Resource/Template/FunctionTemplate.cs +++ b/Esiur/Resource/Template/FunctionTemplate.cs @@ -6,71 +6,69 @@ using System.Reflection; using System.Text; using System.Threading.Tasks; -namespace Esiur.Resource.Template +namespace Esiur.Resource.Template; +public class FunctionTemplate : MemberTemplate { - public class FunctionTemplate : MemberTemplate + + public string Expansion + { + get; + set; + } + + //public bool IsVoid + //{ + // get; + // set; + //} + + public TemplateDataType ReturnType { get; set; } + + public ArgumentTemplate[] Arguments { get; set; } + + public MethodInfo MethodInfo + { + get; + set; + } + + + public override byte[] Compose() { - public string Expansion + var name = base.Compose(); + + var bl = new BinaryList() + //.AddUInt8(Expansion != null ? (byte)0x10 : (byte)0) + .AddUInt8((byte)name.Length) + .AddUInt8Array(name) + .AddUInt8Array(ReturnType.Compose()) + .AddUInt8((byte)Arguments.Length); + + for (var i = 0; i < Arguments.Length; i++) + bl.AddUInt8Array(Arguments[i].Compose()); + + + if (Expansion != null) { - get; - set; + var exp = DC.ToBytes(Expansion); + bl.AddInt32(exp.Length) + .AddUInt8Array(exp); + bl.InsertUInt8(0, 0x10); } + else + bl.InsertUInt8(0, 0x0); - //public bool IsVoid - //{ - // get; - // set; - //} - - public TemplateDataType ReturnType { get; set; } - - public ArgumentTemplate[] Arguments { get; set; } - - public MethodInfo MethodInfo - { - get; - set; - } + return bl.ToArray(); + } - public override byte[] Compose() - { - - var name = base.Compose(); - - var bl = new BinaryList() - //.AddUInt8(Expansion != null ? (byte)0x10 : (byte)0) - .AddUInt8((byte)name.Length) - .AddUInt8Array(name) - .AddUInt8Array(ReturnType.Compose()) - .AddUInt8((byte)Arguments.Length); - - for (var i = 0; i < Arguments.Length; i++) - bl.AddUInt8Array(Arguments[i].Compose()); - - - if (Expansion != null) - { - var exp = DC.ToBytes(Expansion); - bl.AddInt32(exp.Length) - .AddUInt8Array(exp); - bl.InsertUInt8(0, 0x10); - } - else - bl.InsertUInt8(0, 0x0); - - return bl.ToArray(); - } - - - public FunctionTemplate(TypeTemplate template, byte index, string name, ArgumentTemplate[] arguments, TemplateDataType returnType, string expansion = null) - : base(template, MemberType.Property, index, name) - { - //this.IsVoid = isVoid; - this.Arguments = arguments; - this.ReturnType = returnType; - this.Expansion = expansion; - } + public FunctionTemplate(TypeTemplate template, byte index, string name, ArgumentTemplate[] arguments, TemplateDataType returnType, string expansion = null) + : base(template, MemberType.Property, index, name) + { + //this.IsVoid = isVoid; + this.Arguments = arguments; + this.ReturnType = returnType; + this.Expansion = expansion; } } diff --git a/Esiur/Resource/Template/MemberTemplate.cs b/Esiur/Resource/Template/MemberTemplate.cs index 4378f63..78a504c 100644 --- a/Esiur/Resource/Template/MemberTemplate.cs +++ b/Esiur/Resource/Template/MemberTemplate.cs @@ -5,43 +5,41 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Resource.Template +namespace Esiur.Resource.Template; +public class MemberTemplate { - public class MemberTemplate + public enum MemberType { - public enum MemberType - { - Function = 0, - Property = 1, - Event = 2, - Attribute = 3 - } - - public byte Index => index; - public string Name => name; - public MemberType Type => type; - - TypeTemplate template; - string name; - MemberType type; - byte index; - - public TypeTemplate Template => template; - - public MemberTemplate(TypeTemplate template, MemberType type, byte index, string name) - { - this.template = template; - this.type = type; - this.index = index; - this.name = name; - } - - public string Fullname => template.ClassName + "." + Name; - - public virtual byte[] Compose() - { - return DC.ToBytes(Name); - } + Function = 0, + Property = 1, + Event = 2, + Attribute = 3 } + public byte Index => index; + public string Name => name; + public MemberType Type => type; + + TypeTemplate template; + string name; + MemberType type; + byte index; + + public TypeTemplate Template => template; + + public MemberTemplate(TypeTemplate template, MemberType type, byte index, string name) + { + this.template = template; + this.type = type; + this.index = index; + this.name = name; + } + + public string Fullname => template.ClassName + "." + Name; + + public virtual byte[] Compose() + { + return DC.ToBytes(Name); + } } + diff --git a/Esiur/Resource/Template/PropertyTemplate.cs b/Esiur/Resource/Template/PropertyTemplate.cs index f4508bc..38e33ad 100644 --- a/Esiur/Resource/Template/PropertyTemplate.cs +++ b/Esiur/Resource/Template/PropertyTemplate.cs @@ -6,138 +6,136 @@ using System.Reflection; using System.Text; using System.Threading.Tasks; -namespace Esiur.Resource.Template +namespace Esiur.Resource.Template; +public class PropertyTemplate : MemberTemplate { - public class PropertyTemplate : MemberTemplate + public enum PropertyPermission : byte { - public enum PropertyPermission : byte + Read = 1, + Write, + ReadWrite + } + + + public PropertyInfo PropertyInfo + { + get; + set; + } + + public TemplateDataType ValueType { get; set; } + + + /* + public bool Serilize + { + get;set; + } + */ + //bool ReadOnly; + //IIPTypes::DataType ReturnType; + public PropertyPermission Permission + { + get; + set; + } + + + public bool Recordable + { + get; + set; + } + + /* + public PropertyType Mode + { + get; + set; + }*/ + + public string ReadExpansion + { + get; + set; + } + + public string WriteExpansion + { + get; + set; + } + + /* + public bool Storable + { + get; + set; + }*/ + + + public override byte[] Compose() + { + var name = base.Compose(); + var pv = ((byte)(Permission) << 1) | (Recordable ? 1 : 0); + + if (WriteExpansion != null && ReadExpansion != null) { - Read = 1, - Write, - ReadWrite + var rexp = DC.ToBytes(ReadExpansion); + var wexp = DC.ToBytes(WriteExpansion); + return new BinaryList() + .AddUInt8((byte)(0x38 | pv)) + .AddUInt8((byte)name.Length) + .AddUInt8Array(name) + .AddUInt8Array(ValueType.Compose()) + .AddInt32(wexp.Length) + .AddUInt8Array(wexp) + .AddInt32(rexp.Length) + .AddUInt8Array(rexp) + .ToArray(); } - - - public PropertyInfo PropertyInfo + else if (WriteExpansion != null) { - get; - set; + var wexp = DC.ToBytes(WriteExpansion); + return new BinaryList() + .AddUInt8((byte)(0x30 | pv)) + .AddUInt8((byte)name.Length) + .AddUInt8Array(name) + .AddUInt8Array(ValueType.Compose()) + .AddInt32(wexp.Length) + .AddUInt8Array(wexp) + .ToArray(); } - - public TemplateDataType ValueType { get; set; } - - - /* - public bool Serilize + else if (ReadExpansion != null) { - get;set; + var rexp = DC.ToBytes(ReadExpansion); + return new BinaryList() + .AddUInt8((byte)(0x28 | pv)) + .AddUInt8((byte)name.Length) + .AddUInt8Array(name) + .AddUInt8Array(ValueType.Compose()) + .AddInt32(rexp.Length) + .AddUInt8Array(rexp) + .ToArray(); } - */ - //bool ReadOnly; - //IIPTypes::DataType ReturnType; - public PropertyPermission Permission + else { - get; - set; - } - - - public bool Recordable - { - get; - set; - } - - /* - public PropertyType Mode - { - get; - set; - }*/ - - public string ReadExpansion - { - get; - set; - } - - public string WriteExpansion - { - get; - set; - } - - /* - public bool Storable - { - get; - set; - }*/ - - - public override byte[] Compose() - { - var name = base.Compose(); - var pv = ((byte)(Permission) << 1) | (Recordable ? 1 : 0); - - if (WriteExpansion != null && ReadExpansion != null) - { - var rexp = DC.ToBytes(ReadExpansion); - var wexp = DC.ToBytes(WriteExpansion); - return new BinaryList() - .AddUInt8((byte)(0x38 | pv)) - .AddUInt8((byte)name.Length) - .AddUInt8Array(name) - .AddUInt8Array(ValueType.Compose()) - .AddInt32(wexp.Length) - .AddUInt8Array(wexp) - .AddInt32(rexp.Length) - .AddUInt8Array(rexp) - .ToArray(); - } - else if (WriteExpansion != null) - { - var wexp = DC.ToBytes(WriteExpansion); - return new BinaryList() - .AddUInt8((byte)(0x30 | pv)) - .AddUInt8((byte)name.Length) - .AddUInt8Array(name) - .AddUInt8Array(ValueType.Compose()) - .AddInt32(wexp.Length) - .AddUInt8Array(wexp) - .ToArray(); - } - else if (ReadExpansion != null) - { - var rexp = DC.ToBytes(ReadExpansion); - return new BinaryList() - .AddUInt8((byte)(0x28 | pv)) - .AddUInt8((byte)name.Length) - .AddUInt8Array(name) - .AddUInt8Array(ValueType.Compose()) - .AddInt32(rexp.Length) - .AddUInt8Array(rexp) - .ToArray(); - } - else - { - return new BinaryList() - .AddUInt8((byte)(0x20 | pv)) - .AddUInt8((byte)name.Length) - .AddUInt8Array(name) - .AddUInt8Array(ValueType.Compose()) - .ToArray(); - } - } - - public PropertyTemplate(TypeTemplate template, byte index, string name, TemplateDataType valueType, string read = null, string write = null, bool recordable = false) - : base(template, MemberType.Property, index, name) - { - this.Recordable = recordable; - //this.Storage = storage; - this.ReadExpansion = read; - this.WriteExpansion = write; - this.ValueType = valueType; + return new BinaryList() + .AddUInt8((byte)(0x20 | pv)) + .AddUInt8((byte)name.Length) + .AddUInt8Array(name) + .AddUInt8Array(ValueType.Compose()) + .ToArray(); } } + + public PropertyTemplate(TypeTemplate template, byte index, string name, TemplateDataType valueType, string read = null, string write = null, bool recordable = false) + : base(template, MemberType.Property, index, name) + { + this.Recordable = recordable; + //this.Storage = storage; + this.ReadExpansion = read; + this.WriteExpansion = write; + this.ValueType = valueType; + } } diff --git a/Esiur/Resource/Template/TemplateDataType.cs b/Esiur/Resource/Template/TemplateDataType.cs index 25d84f5..136f31e 100644 --- a/Esiur/Resource/Template/TemplateDataType.cs +++ b/Esiur/Resource/Template/TemplateDataType.cs @@ -4,106 +4,104 @@ using System.Collections.Generic; using System.Dynamic; using System.Text; -namespace Esiur.Resource.Template +namespace Esiur.Resource.Template; +public struct TemplateDataType { - public struct TemplateDataType + public DataType Type { get; set; } + //public string TypeName { get; set; } + public TypeTemplate TypeTemplate => TypeGuid == null ? null : Warehouse.GetTemplateByClassId((Guid)TypeGuid); + + public Guid? TypeGuid { get; set; } + //public TemplateDataType(DataType type, string typeName) + //{ + // Type = type; + // TypeName = typeName; + //} + + + + public static TemplateDataType FromType(Type type) { - public DataType Type { get; set; } - //public string TypeName { get; set; } - public TypeTemplate TypeTemplate => TypeGuid == null ? null : Warehouse.GetTemplateByClassId((Guid)TypeGuid); - public Guid? TypeGuid { get; set; } - //public TemplateDataType(DataType type, string typeName) - //{ - // Type = type; - // TypeName = typeName; - //} - - - - public static TemplateDataType FromType(Type type) + var t = type switch { + { IsArray: true } => type.GetElementType(), + { IsEnum: true } => type.GetEnumUnderlyingType(), + (_) => type + }; - var t = type switch - { - { IsArray: true } => type.GetElementType(), - { IsEnum: true } => type.GetEnumUnderlyingType(), - (_) => type - }; - - DataType dt = t switch - { - _ when t == typeof(bool) => DataType.Bool, - _ when t == typeof(char) => DataType.Char, - _ when t == typeof(byte) => DataType.UInt8, - _ when t == typeof(sbyte) => DataType.Int8, - _ when t == typeof(short) => DataType.Int16, - _ when t == typeof(ushort) => DataType.UInt16, - _ when t == typeof(int) => DataType.Int32, - _ when t == typeof(uint) => DataType.UInt32, - _ when t == typeof(long) => DataType.Int64, - _ when t == typeof(ulong) => DataType.UInt64, - _ when t == typeof(float) => DataType.Float32, - _ when t == typeof(double) => DataType.Float64, - _ when t == typeof(decimal) => DataType.Decimal, - _ when t == typeof(string) => DataType.String, - _ when t == typeof(DateTime) => DataType.DateTime, - _ when t == typeof(IResource) => DataType.Void, // Dynamic resource (unspecified type) - _ when t == typeof(IRecord) => DataType.Void, // Dynamic record (unspecified type) - _ when typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject) => DataType.Structure, - _ when Codec.ImplementsInterface(t, typeof(IResource)) => DataType.Resource, - _ when Codec.ImplementsInterface(t, typeof(IRecord)) => DataType.Record, - _ => DataType.Void - }; - - - Guid? typeGuid = null; - - if (dt == DataType.Resource || dt == DataType.Record) - typeGuid = TypeTemplate.GetTypeGuid(t); - - if (type.IsArray) - dt = (DataType)((byte)dt | 0x80); - - return new TemplateDataType() - { - Type = dt, - TypeGuid = typeGuid - }; - } - - public byte[] Compose() + DataType dt = t switch { - if (Type == DataType.Resource || - Type == DataType.ResourceArray || - Type == DataType.Record || - Type == DataType.RecordArray) - { - var guid = DC.ToBytes((Guid)TypeGuid); - return new BinaryList() - .AddUInt8((byte)Type) - .AddUInt8Array(guid).ToArray(); - } - else - return new byte[] { (byte)Type }; - } - - public override string ToString() => Type.ToString() + TypeTemplate != null ? "<" + TypeTemplate.ClassName + ">" : ""; + _ when t == typeof(bool) => DataType.Bool, + _ when t == typeof(char) => DataType.Char, + _ when t == typeof(byte) => DataType.UInt8, + _ when t == typeof(sbyte) => DataType.Int8, + _ when t == typeof(short) => DataType.Int16, + _ when t == typeof(ushort) => DataType.UInt16, + _ when t == typeof(int) => DataType.Int32, + _ when t == typeof(uint) => DataType.UInt32, + _ when t == typeof(long) => DataType.Int64, + _ when t == typeof(ulong) => DataType.UInt64, + _ when t == typeof(float) => DataType.Float32, + _ when t == typeof(double) => DataType.Float64, + _ when t == typeof(decimal) => DataType.Decimal, + _ when t == typeof(string) => DataType.String, + _ when t == typeof(DateTime) => DataType.DateTime, + _ when t == typeof(IResource) => DataType.Void, // Dynamic resource (unspecified type) + _ when t == typeof(IRecord) => DataType.Void, // Dynamic record (unspecified type) + _ when typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject) => DataType.Structure, + _ when Codec.ImplementsInterface(t, typeof(IResource)) => DataType.Resource, + _ when Codec.ImplementsInterface(t, typeof(IRecord)) => DataType.Record, + _ => DataType.Void + }; - public static (uint, TemplateDataType) Parse(byte[] data, uint offset) + Guid? typeGuid = null; + + if (dt == DataType.Resource || dt == DataType.Record) + typeGuid = TypeTemplate.GetTypeGuid(t); + + if (type.IsArray) + dt = (DataType)((byte)dt | 0x80); + + return new TemplateDataType() { - var type = (DataType)data[offset++]; - if (type == DataType.Resource || - type == DataType.ResourceArray || - type == DataType.Record || - type == DataType.RecordArray) - { - var guid = data.GetGuid(offset); - return (17, new TemplateDataType() { Type = type, TypeGuid = guid }); - } - else - return (1, new TemplateDataType() { Type = type }); + Type = dt, + TypeGuid = typeGuid + }; + } + + public byte[] Compose() + { + if (Type == DataType.Resource || + Type == DataType.ResourceArray || + Type == DataType.Record || + Type == DataType.RecordArray) + { + var guid = DC.ToBytes((Guid)TypeGuid); + return new BinaryList() + .AddUInt8((byte)Type) + .AddUInt8Array(guid).ToArray(); } + else + return new byte[] { (byte)Type }; + } + + public override string ToString() => Type.ToString() + TypeTemplate != null ? "<" + TypeTemplate.ClassName + ">" : ""; + + + public static (uint, TemplateDataType) Parse(byte[] data, uint offset) + { + var type = (DataType)data[offset++]; + if (type == DataType.Resource || + type == DataType.ResourceArray || + type == DataType.Record || + type == DataType.RecordArray) + { + var guid = data.GetGuid(offset); + return (17, new TemplateDataType() { Type = type, TypeGuid = guid }); + } + else + return (1, new TemplateDataType() { Type = type }); } } diff --git a/Esiur/Resource/Template/TemplateType.cs b/Esiur/Resource/Template/TemplateType.cs index f29edde..4542866 100644 --- a/Esiur/Resource/Template/TemplateType.cs +++ b/Esiur/Resource/Template/TemplateType.cs @@ -2,13 +2,11 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Resource.Template +namespace Esiur.Resource.Template; +public enum TemplateType : byte { - public enum TemplateType:byte - { - Unspecified, - Resource, - Record, - Wrapper, - } + Unspecified, + Resource, + Record, + Wrapper, } diff --git a/Esiur/Resource/Template/TypeTemplate.cs b/Esiur/Resource/Template/TypeTemplate.cs index a9c5eed..228dea0 100644 --- a/Esiur/Resource/Template/TypeTemplate.cs +++ b/Esiur/Resource/Template/TypeTemplate.cs @@ -10,200 +10,217 @@ using System.Security.Cryptography; using Esiur.Proxy; using Esiur.Net.IIP; -namespace Esiur.Resource.Template +namespace Esiur.Resource.Template; + +//public enum TemplateType +//{ +// Resource, +// Record +//} + +public class TypeTemplate { - //public enum TemplateType + + protected Guid classId; + protected string className; + protected List members = new List(); + protected List functions = new List(); + protected List events = new List(); + protected List properties = new List(); + protected List attributes = new List(); + protected int version; + protected TemplateType templateType; + + // protected TemplateType + //bool isReady; + + protected byte[] content; + + public byte[] Content + { + get { return content; } + } + + public TemplateType Type => templateType; + + + public Type DefinedType { get; set; } + + + + + //public MemberTemplate GetMemberTemplate(MemberInfo member) //{ - // Resource, - // Record + // if (member is MethodInfo) + // return GetFunctionTemplateByName(member.Name); + // else if (member is EventInfo) + // return GetEventTemplateByName(member.Name); + // else if (member is PropertyInfo) + // return GetPropertyTemplateByName(member.Name); + // else + // return null; //} - public class TypeTemplate + public EventTemplate GetEventTemplateByName(string eventName) + { + foreach (var i in events) + if (i.Name == eventName) + return i; + return null; + } + + public EventTemplate GetEventTemplateByIndex(byte index) + { + foreach (var i in events) + if (i.Index == index) + return i; + return null; + } + + public FunctionTemplate GetFunctionTemplateByName(string functionName) + { + foreach (var i in functions) + if (i.Name == functionName) + return i; + return null; + } + public FunctionTemplate GetFunctionTemplateByIndex(byte index) + { + foreach (var i in functions) + if (i.Index == index) + return i; + return null; + } + + public PropertyTemplate GetPropertyTemplateByIndex(byte index) + { + foreach (var i in properties) + if (i.Index == index) + return i; + return null; + } + + public PropertyTemplate GetPropertyTemplateByName(string propertyName) + { + foreach (var i in properties) + if (i.Name == propertyName) + return i; + return null; + } + + public AttributeTemplate GetAttributeTemplate(string attributeName) + { + foreach (var i in attributes) + if (i.Name == attributeName) + return i; + return null; + } + + public Guid ClassId + { + get { return classId; } + } + public string ClassName + { + get { return className; } + } + + public MemberTemplate[] Methods + { + get { return members.ToArray(); } + } + + public FunctionTemplate[] Functions + { + get { return functions.ToArray(); } + } + + public EventTemplate[] Events + { + get { return events.ToArray(); } + } + + public PropertyTemplate[] Properties + { + get { return properties.ToArray(); } + } + + + + public TypeTemplate() { - protected Guid classId; - protected string className; - protected List members = new List(); - protected List functions = new List(); - protected List events = new List(); - protected List properties = new List(); - protected List attributes = new List(); - protected int version; - protected TemplateType templateType; + } - // protected TemplateType - //bool isReady; - protected byte[] content; + public static Guid GetTypeGuid(Type type) => GetTypeGuid(type.FullName); - public byte[] Content + public static Guid GetTypeGuid(string typeName) + { + var tn = Encoding.UTF8.GetBytes(typeName); + var hash = SHA256.Create().ComputeHash(tn).Clip(0, 16); + + return new Guid(hash); + } + + static Type GetElementType(Type type) => type switch + { + { IsArray: true } => type.GetElementType(), + { IsEnum: true } => type.GetEnumUnderlyingType(), + (_) => type + }; + + + + public static TypeTemplate[] GetDependencies(TypeTemplate template) + { + + var list = new List(); + + list.Add(template); + + Action> getDependenciesFunc = null; + + getDependenciesFunc = (TypeTemplate tmp, List bag) => { - get { return content; } - } - - public TemplateType Type => templateType; - - - public Type DefinedType { get; set; } - - - - - //public MemberTemplate GetMemberTemplate(MemberInfo member) - //{ - // if (member is MethodInfo) - // return GetFunctionTemplateByName(member.Name); - // else if (member is EventInfo) - // return GetEventTemplateByName(member.Name); - // else if (member is PropertyInfo) - // return GetPropertyTemplateByName(member.Name); - // else - // return null; - //} - - public EventTemplate GetEventTemplateByName(string eventName) - { - foreach (var i in events) - if (i.Name == eventName) - return i; - return null; - } - - public EventTemplate GetEventTemplateByIndex(byte index) - { - foreach (var i in events) - if (i.Index == index) - return i; - return null; - } - - public FunctionTemplate GetFunctionTemplateByName(string functionName) - { - foreach (var i in functions) - if (i.Name == functionName) - return i; - return null; - } - public FunctionTemplate GetFunctionTemplateByIndex(byte index) - { - foreach (var i in functions) - if (i.Index == index) - return i; - return null; - } - - public PropertyTemplate GetPropertyTemplateByIndex(byte index) - { - foreach (var i in properties) - if (i.Index == index) - return i; - return null; - } - - public PropertyTemplate GetPropertyTemplateByName(string propertyName) - { - foreach (var i in properties) - if (i.Name == propertyName) - return i; - return null; - } - - public AttributeTemplate GetAttributeTemplate(string attributeName) - { - foreach (var i in attributes) - if (i.Name == attributeName) - return i; - return null; - } - - public Guid ClassId - { - get { return classId; } - } - public string ClassName - { - get { return className; } - } - - public MemberTemplate[] Methods - { - get{return members.ToArray();} - } - - public FunctionTemplate[] Functions - { - get { return functions.ToArray(); } - } - - public EventTemplate[] Events - { - get { return events.ToArray(); } - } - - public PropertyTemplate[] Properties - { - get { return properties.ToArray(); } - } - - - - public TypeTemplate() - { - - } - - - public static Guid GetTypeGuid(Type type) => GetTypeGuid(type.FullName); - - public static Guid GetTypeGuid(string typeName) - { - var tn = Encoding.UTF8.GetBytes(typeName); - var hash = SHA256.Create().ComputeHash(tn).Clip(0, 16); - - return new Guid(hash); - } - - static Type GetElementType(Type type) => type switch - { - { IsArray: true } => type.GetElementType(), - { IsEnum: true } => type.GetEnumUnderlyingType(), - (_) => type - }; - - - - public static TypeTemplate[] GetDependencies(TypeTemplate template) - { - - var list = new List(); - - list.Add(template); - - Action> getDependenciesFunc = null; - - getDependenciesFunc = (TypeTemplate tmp, List bag) => - { - if (template.DefinedType == null) - return; + if (template.DefinedType == null) + return; // functions foreach (var f in tmp.functions) + { + var frtt = Warehouse.GetTemplateByType(GetElementType(f.MethodInfo.ReturnType)); + if (frtt != null) { - var frtt = Warehouse.GetTemplateByType(GetElementType(f.MethodInfo.ReturnType)); - if (frtt != null) + if (!bag.Contains(frtt)) { - if (!bag.Contains(frtt)) + list.Add(frtt); + getDependenciesFunc(frtt, bag); + } + } + + var args = f.MethodInfo.GetParameters(); + + for (var i = 0; i < args.Length - 1; i++) + { + var fpt = Warehouse.GetTemplateByType(GetElementType(args[i].ParameterType)); + if (fpt != null) + { + if (!bag.Contains(fpt)) { - list.Add(frtt); - getDependenciesFunc(frtt, bag); + bag.Add(fpt); + getDependenciesFunc(fpt, bag); } } + } - var args = f.MethodInfo.GetParameters(); - - for(var i = 0; i < args.Length - 1; i++) + // skip DistributedConnection argument + if (args.Length > 0) + { + var last = args.Last(); + if (last.ParameterType != typeof(DistributedConnection)) { - var fpt = Warehouse.GetTemplateByType(GetElementType(args[i].ParameterType)); + var fpt = Warehouse.GetTemplateByType(GetElementType(last.ParameterType)); if (fpt != null) { if (!bag.Contains(fpt)) @@ -213,96 +230,79 @@ namespace Esiur.Resource.Template } } } - - // skip DistributedConnection argument - if (args.Length > 0) - { - var last = args.Last(); - if (last.ParameterType != typeof(DistributedConnection)) - { - var fpt = Warehouse.GetTemplateByType(GetElementType(last.ParameterType)); - if (fpt != null) - { - if (!bag.Contains(fpt)) - { - bag.Add(fpt); - getDependenciesFunc(fpt, bag); - } - } - } - } - } + } + // properties foreach (var p in tmp.properties) + { + var pt = Warehouse.GetTemplateByType(GetElementType(p.PropertyInfo.PropertyType)); + if (pt != null) { - var pt = Warehouse.GetTemplateByType(GetElementType(p.PropertyInfo.PropertyType)); - if (pt != null) + if (!bag.Contains(pt)) { - if (!bag.Contains(pt)) - { - bag.Add(pt); - getDependenciesFunc(pt, bag); - } + bag.Add(pt); + getDependenciesFunc(pt, bag); } } + } // events foreach (var e in tmp.events) - { - var et = Warehouse.GetTemplateByType(GetElementType(e.EventInfo.EventHandlerType.GenericTypeArguments[0])); + { + var et = Warehouse.GetTemplateByType(GetElementType(e.EventInfo.EventHandlerType.GenericTypeArguments[0])); - if (et != null) + if (et != null) + { + if (!bag.Contains(et)) { - if (!bag.Contains(et)) - { - bag.Add(et); - getDependenciesFunc(et, bag); - } + bag.Add(et); + getDependenciesFunc(et, bag); } } - }; + } + }; - getDependenciesFunc(template, list); - return list.ToArray(); - } + getDependenciesFunc(template, list); + return list.ToArray(); + } - public TypeTemplate(Type type, bool addToWarehouse = false) - { - if (Codec.InheritsClass(type, typeof(DistributedResource))) - templateType = TemplateType.Wrapper; - else if (Codec.ImplementsInterface(type, typeof(IResource))) - templateType = TemplateType.Resource; - else if (Codec.ImplementsInterface(type, typeof(IRecord))) - templateType = TemplateType.Record; - else - throw new Exception("Type must implement IResource, IRecord or inherit from DistributedResource."); + public TypeTemplate(Type type, bool addToWarehouse = false) + { + if (Codec.InheritsClass(type, typeof(DistributedResource))) + templateType = TemplateType.Wrapper; + else if (Codec.ImplementsInterface(type, typeof(IResource))) + templateType = TemplateType.Resource; + else if (Codec.ImplementsInterface(type, typeof(IRecord))) + templateType = TemplateType.Record; + else + throw new Exception("Type must implement IResource, IRecord or inherit from DistributedResource."); - //if (isRecord && isResource) - // throw new Exception("Type can't have both IResource and IRecord interfaces"); + //if (isRecord && isResource) + // throw new Exception("Type can't have both IResource and IRecord interfaces"); - //if (!(isResource || isRecord)) - // throw new Exception("Type is neither a resource nor a record."); + //if (!(isResource || isRecord)) + // throw new Exception("Type is neither a resource nor a record."); - type = ResourceProxy.GetBaseType(type); + type = ResourceProxy.GetBaseType(type); - DefinedType = type; + DefinedType = type; - className = type.FullName; + className = type.FullName; - //Console.WriteLine($"Creating {className}"); + //Console.WriteLine($"Creating {className}"); - // set guid - classId = GetTypeGuid(className); + // set guid + classId = GetTypeGuid(className); - if (addToWarehouse) - Warehouse.PutTemplate(this); + if (addToWarehouse) + Warehouse.PutTemplate(this); #if NETSTANDARD - PropertyInfo[] propsInfo = type.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly); - EventInfo[] eventsInfo = type.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly); - MethodInfo[] methodsInfo = type.GetTypeInfo().GetMethods(BindingFlags.Public | BindingFlags.Instance); // | BindingFlags.DeclaredOnly); + PropertyInfo[] propsInfo = type.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly); + EventInfo[] eventsInfo = type.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly); + MethodInfo[] methodsInfo = type.GetTypeInfo().GetMethods(BindingFlags.Public | BindingFlags.Instance); // | BindingFlags.DeclaredOnly); #else PropertyInfo[] propsInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly); @@ -311,422 +311,421 @@ namespace Esiur.Resource.Template #endif - bool classIsPublic = type.GetCustomAttribute() != null; + bool classIsPublic = type.GetCustomAttribute() != null; - byte i = 0; + byte i = 0; - if (classIsPublic) + if (classIsPublic) + { + foreach (var pi in propsInfo) { - foreach (var pi in propsInfo) - { - var privateAttr = pi.GetCustomAttribute(true); + var privateAttr = pi.GetCustomAttribute(true); + if (privateAttr == null) + { + var annotationAttr = pi.GetCustomAttribute(true); + var storageAttr = pi.GetCustomAttribute(true); + + var pt = new PropertyTemplate(this, i++, pi.Name, TemplateDataType.FromType(pi.PropertyType)); + + if (storageAttr != null) + pt.Recordable = storageAttr.Mode == StorageMode.Recordable; + + if (annotationAttr != null) + pt.ReadExpansion = annotationAttr.Annotation; + else + pt.ReadExpansion = pi.PropertyType.Name; + + pt.PropertyInfo = pi; + //pt.Serilize = publicAttr.Serialize; + properties.Add(pt); + } + else + { + var attributeAttr = pi.GetCustomAttribute(true); + if (attributeAttr != null) + { + var an = attributeAttr.Name ?? pi.Name; + var at = new AttributeTemplate(this, 0, an); + at.PropertyInfo = pi; + attributes.Add(at); + } + } + } + + if (templateType == TemplateType.Resource) + { + i = 0; + + foreach (var ei in eventsInfo) + { + var privateAttr = ei.GetCustomAttribute(true); if (privateAttr == null) { - var annotationAttr = pi.GetCustomAttribute(true); - var storageAttr = pi.GetCustomAttribute(true); - - var pt = new PropertyTemplate(this, i++, pi.Name, TemplateDataType.FromType(pi.PropertyType)); + var annotationAttr = ei.GetCustomAttribute(true); + var listenableAttr = ei.GetCustomAttribute(true); - if (storageAttr != null) - pt.Recordable = storageAttr.Mode == StorageMode.Recordable; + var argType = ei.EventHandlerType.GenericTypeArguments[0]; + var et = new EventTemplate(this, i++, ei.Name, TemplateDataType.FromType(argType)); + et.EventInfo = ei; if (annotationAttr != null) - pt.ReadExpansion = annotationAttr.Annotation; - else - pt.ReadExpansion = pi.PropertyType.Name; - - pt.PropertyInfo = pi; - //pt.Serilize = publicAttr.Serialize; - properties.Add(pt); - } - else - { - var attributeAttr = pi.GetCustomAttribute(true); - if (attributeAttr != null) - { - var an = attributeAttr.Name ?? pi.Name; - var at = new AttributeTemplate(this, 0, an); - at.PropertyInfo = pi; - attributes.Add(at); - } + et.Expansion = annotationAttr.Annotation; + + if (listenableAttr != null) + et.Listenable = true; + + events.Add(et); } } - if (templateType == TemplateType.Resource) + i = 0; + foreach (MethodInfo mi in methodsInfo) { - i = 0; - - foreach (var ei in eventsInfo) + var privateAttr = mi.GetCustomAttribute(true); + if (privateAttr == null) { - var privateAttr = ei.GetCustomAttribute(true); - if (privateAttr == null) + var annotationAttr = mi.GetCustomAttribute(true); + + var returnType = TemplateDataType.FromType(mi.ReturnType); + + var args = mi.GetParameters(); + + if (args.Length > 0) { - var annotationAttr = ei.GetCustomAttribute(true); - var listenableAttr = ei.GetCustomAttribute(true); - - var argType = ei.EventHandlerType.GenericTypeArguments[0]; - var et = new EventTemplate(this, i++, ei.Name, TemplateDataType.FromType(argType)); - et.EventInfo = ei; - - if (annotationAttr != null) - et.Expansion = annotationAttr.Annotation; - - if (listenableAttr != null) - et.Listenable = true; - - events.Add(et); + if (args.Last().ParameterType == typeof(DistributedConnection)) + args = args.Take(args.Count() - 1).ToArray(); } - } - i = 0; - foreach (MethodInfo mi in methodsInfo) - { - var privateAttr = mi.GetCustomAttribute(true); - if (privateAttr == null) + var arguments = args.Select(x => new ArgumentTemplate() { - var annotationAttr = mi.GetCustomAttribute(true); + Name = x.Name, + Type = TemplateDataType.FromType(x.ParameterType), + ParameterInfo = x + }).ToArray(); - var returnType = TemplateDataType.FromType(mi.ReturnType); + var ft = new FunctionTemplate(this, i++, mi.Name, arguments, returnType);// mi.ReturnType == typeof(void)); - var args = mi.GetParameters(); + if (annotationAttr != null) + ft.Expansion = annotationAttr.Annotation; + else + ft.Expansion = "(" + String.Join(",", mi.GetParameters().Where(x => x.ParameterType != typeof(DistributedConnection)).Select(x => "[" + x.ParameterType.Name + "] " + x.Name)) + ") -> " + mi.ReturnType.Name; - if (args.Length > 0) - { - if (args.Last().ParameterType == typeof(DistributedConnection)) - args = args.Take(args.Count() - 1).ToArray(); - } - - var arguments = args.Select(x => new ArgumentTemplate() - { - Name = x.Name, - Type = TemplateDataType.FromType(x.ParameterType), - ParameterInfo = x - }).ToArray(); - - var ft = new FunctionTemplate(this, i++, mi.Name, arguments, returnType);// mi.ReturnType == typeof(void)); - - if (annotationAttr != null) - ft.Expansion = annotationAttr.Annotation; - else - ft.Expansion = "(" + String.Join(",", mi.GetParameters().Where(x => x.ParameterType != typeof(DistributedConnection)).Select(x => "[" + x.ParameterType.Name + "] " + x.Name)) + ") -> " + mi.ReturnType.Name; - - ft.MethodInfo = mi; - functions.Add(ft); - } + ft.MethodInfo = mi; + functions.Add(ft); } } } - else + } + else + { + + foreach (var pi in propsInfo) { + var publicAttr = pi.GetCustomAttribute(true); - foreach (var pi in propsInfo) + if (publicAttr != null) { - var publicAttr = pi.GetCustomAttribute(true); + var annotationAttr = pi.GetCustomAttribute(true); + var storageAttr = pi.GetCustomAttribute(true); + var valueType = TemplateDataType.FromType(pi.PropertyType); + var pn = publicAttr.Name ?? pi.Name; + var pt = new PropertyTemplate(this, i++, pn, valueType);//, rp.ReadExpansion, rp.WriteExpansion, rp.Storage); + if (storageAttr != null) + pt.Recordable = storageAttr.Mode == StorageMode.Recordable; + + if (annotationAttr != null) + pt.ReadExpansion = annotationAttr.Annotation; + else + pt.ReadExpansion = pi.PropertyType.Name; + + pt.PropertyInfo = pi; + //pt.Serilize = publicAttr.Serialize; + properties.Add(pt); + } + else + { + var attributeAttr = pi.GetCustomAttribute(true); + if (attributeAttr != null) + { + var pn = attributeAttr.Name ?? pi.Name; + var at = new AttributeTemplate(this, 0, pn); + at.PropertyInfo = pi; + attributes.Add(at); + } + } + } + + if (templateType == TemplateType.Resource) + { + i = 0; + + foreach (var ei in eventsInfo) + { + var publicAttr = ei.GetCustomAttribute(true); if (publicAttr != null) { - var annotationAttr = pi.GetCustomAttribute(true); - var storageAttr = pi.GetCustomAttribute(true); - var valueType = TemplateDataType.FromType(pi.PropertyType); - var pn = publicAttr.Name ?? pi.Name; + var annotationAttr = ei.GetCustomAttribute(true); + var listenableAttr = ei.GetCustomAttribute(true); + + var argType = ei.EventHandlerType.GenericTypeArguments[0]; + + var en = publicAttr.Name ?? ei.Name; + + var et = new EventTemplate(this, i++, en, TemplateDataType.FromType(argType)); + et.EventInfo = ei; - var pt = new PropertyTemplate(this, i++, pn, valueType);//, rp.ReadExpansion, rp.WriteExpansion, rp.Storage); - if (storageAttr != null) - pt.Recordable = storageAttr.Mode == StorageMode.Recordable; - if (annotationAttr != null) - pt.ReadExpansion = annotationAttr.Annotation; + et.Expansion = annotationAttr.Annotation; + + if (listenableAttr != null) + et.Listenable = true; + + events.Add(et); + } + } + + i = 0; + foreach (MethodInfo mi in methodsInfo) + { + var publicAttr = mi.GetCustomAttribute(true); + if (publicAttr != null) + { + var annotationAttr = mi.GetCustomAttribute(true); + var returnType = TemplateDataType.FromType(mi.ReturnType); + + var args = mi.GetParameters(); + + if (args.Length > 0) + { + if (args.Last().ParameterType == typeof(DistributedConnection)) + args = args.Take(args.Count() - 1).ToArray(); + } + + var arguments = args.Select(x => new ArgumentTemplate() + { + Name = x.Name, + Type = TemplateDataType.FromType(x.ParameterType), + ParameterInfo = x + }) + .ToArray(); + + var fn = publicAttr.Name ?? mi.Name; + + var ft = new FunctionTemplate(this, i++, fn, arguments, returnType);// mi.ReturnType == typeof(void)); + + if (annotationAttr != null) + ft.Expansion = annotationAttr.Annotation; else - pt.ReadExpansion = pi.PropertyType.Name; + ft.Expansion = "(" + String.Join(",", mi.GetParameters().Where(x => x.ParameterType != typeof(DistributedConnection)).Select(x => "[" + x.ParameterType.Name + "] " + x.Name)) + ") -> " + mi.ReturnType.Name; - pt.PropertyInfo = pi; - //pt.Serilize = publicAttr.Serialize; - properties.Add(pt); - } - else - { - var attributeAttr = pi.GetCustomAttribute(true); - if (attributeAttr != null) - { - var pn = attributeAttr.Name ?? pi.Name; - var at = new AttributeTemplate(this, 0, pn); - at.PropertyInfo = pi; - attributes.Add(at); - } - } - } - - if (templateType == TemplateType.Resource) - { - i = 0; - - foreach (var ei in eventsInfo) - { - var publicAttr = ei.GetCustomAttribute(true); - if (publicAttr != null) - { - var annotationAttr = ei.GetCustomAttribute(true); - var listenableAttr = ei.GetCustomAttribute(true); - - var argType = ei.EventHandlerType.GenericTypeArguments[0]; - - var en = publicAttr.Name ?? ei.Name; - - var et = new EventTemplate(this, i++, en, TemplateDataType.FromType(argType)); - et.EventInfo = ei; - - if (annotationAttr != null) - et.Expansion = annotationAttr.Annotation; - - if (listenableAttr != null) - et.Listenable = true; - - events.Add(et); - } - } - - i = 0; - foreach (MethodInfo mi in methodsInfo) - { - var publicAttr = mi.GetCustomAttribute(true); - if (publicAttr != null) - { - var annotationAttr = mi.GetCustomAttribute(true); - var returnType = TemplateDataType.FromType(mi.ReturnType); - - var args = mi.GetParameters(); - - if (args.Length > 0) - { - if (args.Last().ParameterType == typeof(DistributedConnection)) - args = args.Take(args.Count() - 1).ToArray(); - } - - var arguments = args.Select(x => new ArgumentTemplate() - { - Name = x.Name, - Type = TemplateDataType.FromType(x.ParameterType), - ParameterInfo = x - }) - .ToArray(); - - var fn = publicAttr.Name ?? mi.Name; - - var ft = new FunctionTemplate(this, i++, fn, arguments, returnType);// mi.ReturnType == typeof(void)); - - if (annotationAttr != null) - ft.Expansion = annotationAttr.Annotation; - else - ft.Expansion = "(" + String.Join(",", mi.GetParameters().Where(x => x.ParameterType != typeof(DistributedConnection)).Select(x => "[" + x.ParameterType.Name + "] " + x.Name)) + ") -> " + mi.ReturnType.Name; - - ft.MethodInfo = mi; - functions.Add(ft); - } + ft.MethodInfo = mi; + functions.Add(ft); } } } - - // append signals - for (i = 0; i < events.Count; i++) - members.Add(events[i]); - // append slots - for (i = 0; i < functions.Count; i++) - members.Add(functions[i]); - // append properties - for (i = 0; i < properties.Count; i++) - members.Add(properties[i]); - - // bake it binarily - var b = new BinaryList(); - b.AddUInt8((byte)templateType) - .AddGuid(classId) - .AddUInt8((byte)className.Length) - .AddString(className) - .AddInt32(version) - .AddUInt16((ushort)members.Count); - - - foreach (var ft in functions) - b.AddUInt8Array(ft.Compose()); - foreach (var pt in properties) - b.AddUInt8Array(pt.Compose()); - foreach (var et in events) - b.AddUInt8Array(et.Compose()); - - content = b.ToArray(); - } - public static TypeTemplate Parse(byte[] data) - { - return Parse(data, 0, (uint)data.Length); - } + // append signals + for (i = 0; i < events.Count; i++) + members.Add(events[i]); + // append slots + for (i = 0; i < functions.Count; i++) + members.Add(functions[i]); + // append properties + for (i = 0; i < properties.Count; i++) + members.Add(properties[i]); - - public static TypeTemplate Parse(byte[] data, uint offset, uint contentLength) - { - - uint ends = offset + contentLength; - - uint oOffset = offset; - - // start parsing... - - var od = new TypeTemplate(); - od.content = data.Clip(offset, contentLength); - - od.templateType = (TemplateType)data[offset++]; - - od.classId = data.GetGuid(offset); - offset += 16; - od.className = data.GetString(offset + 1, data[offset]); - offset += (uint)data[offset] + 1; - - od.version = data.GetInt32(offset); - offset += 4; - - ushort methodsCount = data.GetUInt16(offset); - offset += 2; - - byte functionIndex = 0; - byte propertyIndex = 0; - byte eventIndex = 0; - - for (int i = 0; i < methodsCount; i++) - { - var type = data[offset] >> 5; - - if (type == 0) // function - { - string expansion = null; - var hasExpansion = ((data[offset++] & 0x10) == 0x10); - - var name = data.GetString(offset + 1, data[offset]); - offset += (uint)data[offset] + 1; - - // return type - var (rts, returnType) = TemplateDataType.Parse(data, offset); - offset += rts; - - // arguments count - var argsCount = data[offset++]; - List arguments = new(); - - for (var a = 0; a < argsCount; a++) - { - var (cs, argType) = ArgumentTemplate.Parse(data, offset); - arguments.Add(argType); - offset += cs; - } - - // arguments - if (hasExpansion) // expansion ? - { - var cs = data.GetUInt32(offset); - offset += 4; - expansion = data.GetString(offset, cs); - offset += cs; - } - - var ft = new FunctionTemplate(od, functionIndex++, name, arguments.ToArray(), returnType, expansion); - - od.functions.Add(ft); - } - else if (type == 1) // property - { - - string readExpansion = null, writeExpansion = null; - - var hasReadExpansion = ((data[offset] & 0x8) == 0x8); - var hasWriteExpansion = ((data[offset] & 0x10) == 0x10); - var recordable = ((data[offset] & 1) == 1); - var permission = (PropertyTemplate.PropertyPermission)((data[offset++] >> 1) & 0x3); - var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]); - - offset += (uint)data[offset] + 1; - - var (dts, valueType) = TemplateDataType.Parse(data, offset); - - offset += dts; - - if (hasReadExpansion) // expansion ? - { - var cs = data.GetUInt32(offset); - offset += 4; - readExpansion = data.GetString(offset, cs); - offset += cs; - } - - if (hasWriteExpansion) // expansion ? - { - var cs = data.GetUInt32(offset); - offset += 4; - writeExpansion = data.GetString(offset, cs); - offset += cs; - } - - var pt = new PropertyTemplate(od, propertyIndex++, name, valueType, readExpansion, writeExpansion, recordable); - - od.properties.Add(pt); - } - else if (type == 2) // Event - { - - string expansion = null; - var hasExpansion = ((data[offset] & 0x10) == 0x10); - var listenable = ((data[offset++] & 0x8) == 0x8); - - var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, (int)data[offset]); - offset += (uint)data[offset] + 1; - - var (dts, argType) = TemplateDataType.Parse(data, offset); - - offset += dts; - - if (hasExpansion) // expansion ? - { - var cs = data.GetUInt32(offset); - offset += 4; - expansion = data.GetString(offset, cs); - offset += cs; - } - - var et = new EventTemplate(od, eventIndex++, name, argType, expansion, listenable); - - od.events.Add(et); - - } - } - - // append signals - for (int i = 0; i < od.events.Count; i++) - od.members.Add(od.events[i]); - // append slots - for (int i = 0; i < od.functions.Count; i++) - od.members.Add(od.functions[i]); - // append properties - for (int i = 0; i < od.properties.Count; i++) - od.members.Add(od.properties[i]); + // bake it binarily + var b = new BinaryList(); + b.AddUInt8((byte)templateType) + .AddGuid(classId) + .AddUInt8((byte)className.Length) + .AddString(className) + .AddInt32(version) + .AddUInt16((ushort)members.Count); - //od.isReady = true; - /* - var oo = owner.Socket.Engine.GetObjectDescription(od.GUID); - if (oo != null) - { - Console.WriteLine("Already there ! description"); - return oo; - } - else - { - owner.Socket.Engine.AddObjectDescription(od); - return od; - } - */ + foreach (var ft in functions) + b.AddUInt8Array(ft.Compose()); + foreach (var pt in properties) + b.AddUInt8Array(pt.Compose()); + foreach (var et in events) + b.AddUInt8Array(et.Compose()); + + content = b.ToArray(); - return od; - } } + public static TypeTemplate Parse(byte[] data) + { + return Parse(data, 0, (uint)data.Length); + } + + + public static TypeTemplate Parse(byte[] data, uint offset, uint contentLength) + { + + uint ends = offset + contentLength; + + uint oOffset = offset; + + // start parsing... + + var od = new TypeTemplate(); + od.content = data.Clip(offset, contentLength); + + od.templateType = (TemplateType)data[offset++]; + + od.classId = data.GetGuid(offset); + offset += 16; + od.className = data.GetString(offset + 1, data[offset]); + offset += (uint)data[offset] + 1; + + od.version = data.GetInt32(offset); + offset += 4; + + ushort methodsCount = data.GetUInt16(offset); + offset += 2; + + byte functionIndex = 0; + byte propertyIndex = 0; + byte eventIndex = 0; + + for (int i = 0; i < methodsCount; i++) + { + var type = data[offset] >> 5; + + if (type == 0) // function + { + string expansion = null; + var hasExpansion = ((data[offset++] & 0x10) == 0x10); + + var name = data.GetString(offset + 1, data[offset]); + offset += (uint)data[offset] + 1; + + // return type + var (rts, returnType) = TemplateDataType.Parse(data, offset); + offset += rts; + + // arguments count + var argsCount = data[offset++]; + List arguments = new(); + + for (var a = 0; a < argsCount; a++) + { + var (cs, argType) = ArgumentTemplate.Parse(data, offset); + arguments.Add(argType); + offset += cs; + } + + // arguments + if (hasExpansion) // expansion ? + { + var cs = data.GetUInt32(offset); + offset += 4; + expansion = data.GetString(offset, cs); + offset += cs; + } + + var ft = new FunctionTemplate(od, functionIndex++, name, arguments.ToArray(), returnType, expansion); + + od.functions.Add(ft); + } + else if (type == 1) // property + { + + string readExpansion = null, writeExpansion = null; + + var hasReadExpansion = ((data[offset] & 0x8) == 0x8); + var hasWriteExpansion = ((data[offset] & 0x10) == 0x10); + var recordable = ((data[offset] & 1) == 1); + var permission = (PropertyTemplate.PropertyPermission)((data[offset++] >> 1) & 0x3); + var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]); + + offset += (uint)data[offset] + 1; + + var (dts, valueType) = TemplateDataType.Parse(data, offset); + + offset += dts; + + if (hasReadExpansion) // expansion ? + { + var cs = data.GetUInt32(offset); + offset += 4; + readExpansion = data.GetString(offset, cs); + offset += cs; + } + + if (hasWriteExpansion) // expansion ? + { + var cs = data.GetUInt32(offset); + offset += 4; + writeExpansion = data.GetString(offset, cs); + offset += cs; + } + + var pt = new PropertyTemplate(od, propertyIndex++, name, valueType, readExpansion, writeExpansion, recordable); + + od.properties.Add(pt); + } + else if (type == 2) // Event + { + + string expansion = null; + var hasExpansion = ((data[offset] & 0x10) == 0x10); + var listenable = ((data[offset++] & 0x8) == 0x8); + + var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, (int)data[offset]); + offset += (uint)data[offset] + 1; + + var (dts, argType) = TemplateDataType.Parse(data, offset); + + offset += dts; + + if (hasExpansion) // expansion ? + { + var cs = data.GetUInt32(offset); + offset += 4; + expansion = data.GetString(offset, cs); + offset += cs; + } + + var et = new EventTemplate(od, eventIndex++, name, argType, expansion, listenable); + + od.events.Add(et); + + } + } + + // append signals + for (int i = 0; i < od.events.Count; i++) + od.members.Add(od.events[i]); + // append slots + for (int i = 0; i < od.functions.Count; i++) + od.members.Add(od.functions[i]); + // append properties + for (int i = 0; i < od.properties.Count; i++) + od.members.Add(od.properties[i]); + + + //od.isReady = true; + /* + var oo = owner.Socket.Engine.GetObjectDescription(od.GUID); + if (oo != null) + { + Console.WriteLine("Already there ! description"); + return oo; + } + else + { + owner.Socket.Engine.AddObjectDescription(od); + return od; + } + */ + + return od; + } } + diff --git a/Esiur/Resource/Warehouse.cs b/Esiur/Resource/Warehouse.cs index 14e0bef..aed3c72 100644 --- a/Esiur/Resource/Warehouse.cs +++ b/Esiur/Resource/Warehouse.cs @@ -39,264 +39,202 @@ using System.Collections.Concurrent; using System.Collections; using System.Data; -namespace Esiur.Resource +namespace Esiur.Resource; + +// Centeral Resource Issuer +public static class Warehouse { - // Centeral Resource Issuer - public static class Warehouse + //static byte prefixCounter; + + //static AutoList stores = new AutoList(null); + static ConcurrentDictionary> resources = new ConcurrentDictionary>(); + static ConcurrentDictionary>> stores = new ConcurrentDictionary>>(); + + + static uint resourceCounter = 0; + + //static KeyList templates = new KeyList(); + //static KeyList wrapperTemplates = new KeyList(); + + static KeyList> templates + = new KeyList>() + { + [TemplateType.Unspecified] = new KeyList(), + [TemplateType.Resource] = new KeyList(), + [TemplateType.Record] = new KeyList(), + [TemplateType.Wrapper] = new KeyList(), + }; + + static bool warehouseIsOpen = false; + + public delegate void StoreEvent(IStore store);//, string name); + // public delegate void StoreDisconnectedEvent(IStore store); + + public static event StoreEvent StoreConnected; + //public static event StoreEvent StoreOpen; + public static event StoreEvent StoreDisconnected; + + public delegate AsyncReply ProtocolInstance(string name, object properties); + + public static KeyList Protocols { get; } = GetSupportedProtocols(); + + private static Regex urlRegex = new Regex(@"^(?:([\S]*)://([^/]*)/?)"); + + //private static object resourcesLock = new object(); + + static KeyList GetSupportedProtocols() { - //static byte prefixCounter; + var rt = new KeyList(); + rt.Add("iip", async (name, attributes) => await Warehouse.New(name, null, null, null, attributes)); + return rt; + } - //static AutoList stores = new AutoList(null); - static ConcurrentDictionary> resources = new ConcurrentDictionary>(); - static ConcurrentDictionary>> stores = new ConcurrentDictionary>>(); + /// + /// Get a store by its name. + /// + /// Store instance name + /// + public static IStore GetStore(string name) + { + foreach (var s in stores) + if (s.Key.Instance.Name == name) + return s.Key; + return null; + } + public static WeakReference[] Resources => resources.Values.ToArray(); - static uint resourceCounter = 0; - - //static KeyList templates = new KeyList(); - //static KeyList wrapperTemplates = new KeyList(); - - static KeyList> templates - = new KeyList>() - { - [TemplateType.Unspecified] = new KeyList(), - [TemplateType.Resource] = new KeyList(), - [TemplateType.Record] = new KeyList(), - [TemplateType.Wrapper] = new KeyList(), - }; - - static bool warehouseIsOpen = false; - - public delegate void StoreEvent(IStore store);//, string name); - // public delegate void StoreDisconnectedEvent(IStore store); - - public static event StoreEvent StoreConnected; - //public static event StoreEvent StoreOpen; - public static event StoreEvent StoreDisconnected; - - public delegate AsyncReply ProtocolInstance(string name, object properties); - - public static KeyList Protocols { get; } = GetSupportedProtocols(); - - private static Regex urlRegex = new Regex(@"^(?:([\S]*)://([^/]*)/?)"); - - //private static object resourcesLock = new object(); - - static KeyList GetSupportedProtocols() + /// + /// Get a resource by instance Id. + /// + /// Instance Id + /// + public static AsyncReply GetById(uint id) + { + if (resources.ContainsKey(id)) { - var rt = new KeyList(); - rt.Add("iip", async (name, attributes) => await Warehouse.New(name, null, null, null, attributes)); - return rt; - } - - /// - /// Get a store by its name. - /// - /// Store instance name - /// - public static IStore GetStore(string name) - { - foreach (var s in stores) - if (s.Key.Instance.Name == name) - return s.Key; - return null; - } - - public static WeakReference[] Resources => resources.Values.ToArray(); - - /// - /// Get a resource by instance Id. - /// - /// Instance Id - /// - public static AsyncReply GetById(uint id) - { - if (resources.ContainsKey(id)) - { - IResource r; - if (resources[id].TryGetTarget(out r)) - return new AsyncReply(r); - else - return new AsyncReply(null); - } + IResource r; + if (resources[id].TryGetTarget(out r)) + return new AsyncReply(r); else return new AsyncReply(null); } + else + return new AsyncReply(null); + } - static void LoadGenerated() + static void LoadGenerated() + { + foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { - foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) + var generatedType = assembly.GetType("Esiur.Generated"); + if (generatedType != null) { - var generatedType = assembly.GetType("Esiur.Generated"); - if (generatedType != null) + var resourceTypes = (Type[])generatedType.GetProperty("Resources").GetValue(null); + foreach (var t in resourceTypes) { - var resourceTypes = (Type[])generatedType.GetProperty("Resources").GetValue(null); - foreach (var t in resourceTypes) - { - PutTemplate(new TypeTemplate(t)); - } + PutTemplate(new TypeTemplate(t)); + } - var recordTypes = (Type[])generatedType.GetProperty("Records").GetValue(null); - foreach (var t in recordTypes) - { - PutTemplate(new TypeTemplate(t)); - } + var recordTypes = (Type[])generatedType.GetProperty("Records").GetValue(null); + foreach (var t in recordTypes) + { + PutTemplate(new TypeTemplate(t)); } } } + } - /// - /// Open the warehouse. - /// This function issues the initialize trigger to all stores and resources. - /// - /// True, if no problem occurred. - public static async AsyncReply Open() + /// + /// Open the warehouse. + /// This function issues the initialize trigger to all stores and resources. + /// + /// True, if no problem occurred. + public static async AsyncReply Open() + { + if (warehouseIsOpen) + return false; + + // Load generated models + LoadGenerated(); + + + warehouseIsOpen = true; + + var resSnap = resources.Select(x => { - if (warehouseIsOpen) - return false; + IResource r; + if (x.Value.TryGetTarget(out r)) + return r; + else + return null; + }).Where(r => r != null).ToArray(); - // Load generated models - LoadGenerated(); + foreach (var r in resSnap) + { + //IResource r; + //if (rk.Value.TryGetTarget(out r)) + //{ + var rt = await r.Trigger(ResourceTrigger.Initialize); + //if (!rt) + // return false; - - warehouseIsOpen = true; - - var resSnap = resources.Select(x => + if (!rt) { - IResource r; - if (x.Value.TryGetTarget(out r)) - return r; - else - return null; - }).Where(r => r != null).ToArray(); - - foreach (var r in resSnap) - { - //IResource r; - //if (rk.Value.TryGetTarget(out r)) - //{ - var rt = await r.Trigger(ResourceTrigger.Initialize); - //if (!rt) - // return false; - - if (!rt) - { - Console.WriteLine($"Resource failed at Initialize {r.Instance.Name} [{r.Instance.Template.ClassName}]"); - } - //} + Console.WriteLine($"Resource failed at Initialize {r.Instance.Name} [{r.Instance.Template.ClassName}]"); } - - foreach (var r in resSnap) - { - //IResource r; - //if (rk.Value.TryGetTarget(out r)) - //{ - var rt = await r.Trigger(ResourceTrigger.SystemInitialized); - if (!rt) - { - Console.WriteLine($"Resource failed at SystemInitialized {r.Instance.Name} [{r.Instance.Template.ClassName}]"); - } - //return false; - //} - } - - - return true; - - /* - var bag = new AsyncBag(); - - //foreach (var store in stores) - // bag.Add(store.Trigger(ResourceTrigger.Initialize)); - - - bag.Seal(); - - var rt = new AsyncReply(); - bag.Then((x) => - { - foreach (var b in x) - if (!b) - { - rt.Trigger(false); - return; - } - - var rBag = new AsyncBag(); - foreach (var rk in resources) - { - IResource r; - if (rk.Value.TryGetTarget(out r)) - rBag.Add(r.Trigger(ResourceTrigger.Initialize)); - } - - rBag.Seal(); - - rBag.Then(y => - { - foreach (var b in y) - if (!b) - { - rt.Trigger(false); - return; - } - - rt.Trigger(true); - warehouseIsOpen = true; - }); - - }); - - - return rt; - */ + //} } - /// - /// Close the warehouse. - /// This function issues terminate trigger to all resources and stores. - /// - /// True, if no problem occurred. - public static AsyncReply Close() + foreach (var r in resSnap) { + //IResource r; + //if (rk.Value.TryGetTarget(out r)) + //{ + var rt = await r.Trigger(ResourceTrigger.SystemInitialized); + if (!rt) + { + Console.WriteLine($"Resource failed at SystemInitialized {r.Instance.Name} [{r.Instance.Template.ClassName}]"); + } + //return false; + //} + } - var bag = new AsyncBag(); - foreach (var resource in resources.Values) + return true; + + /* + var bag = new AsyncBag(); + + //foreach (var store in stores) + // bag.Add(store.Trigger(ResourceTrigger.Initialize)); + + + bag.Seal(); + + var rt = new AsyncReply(); + bag.Then((x) => + { + foreach (var b in x) + if (!b) + { + rt.Trigger(false); + return; + } + + var rBag = new AsyncBag(); + foreach (var rk in resources) { IResource r; - if (resource.TryGetTarget(out r)) - { - if (!(r is IStore)) - bag.Add(r.Trigger(ResourceTrigger.Terminate)); - - } + if (rk.Value.TryGetTarget(out r)) + rBag.Add(r.Trigger(ResourceTrigger.Initialize)); } - foreach (var store in stores) - bag.Add(store.Key.Trigger(ResourceTrigger.Terminate)); + rBag.Seal(); - - foreach (var resource in resources.Values) + rBag.Then(y => { - IResource r; - if (resource.TryGetTarget(out r)) - { - if (!(r is IStore)) - bag.Add(r.Trigger(ResourceTrigger.SystemTerminated)); - } - } - - - foreach (var store in stores) - bag.Add(store.Key.Trigger(ResourceTrigger.SystemTerminated)); - - bag.Seal(); - - var rt = new AsyncReply(); - bag.Then((x) => - { - foreach (var b in x) + foreach (var b in y) if (!b) { rt.Trigger(false); @@ -304,611 +242,672 @@ namespace Esiur.Resource } rt.Trigger(true); + warehouseIsOpen = true; + }); + + }); + + + return rt; + */ + } + + /// + /// Close the warehouse. + /// This function issues terminate trigger to all resources and stores. + /// + /// True, if no problem occurred. + public static AsyncReply Close() + { + + var bag = new AsyncBag(); + + foreach (var resource in resources.Values) + { + IResource r; + if (resource.TryGetTarget(out r)) + { + if (!(r is IStore)) + bag.Add(r.Trigger(ResourceTrigger.Terminate)); + + } + } + + foreach (var store in stores) + bag.Add(store.Key.Trigger(ResourceTrigger.Terminate)); + + + foreach (var resource in resources.Values) + { + IResource r; + if (resource.TryGetTarget(out r)) + { + if (!(r is IStore)) + bag.Add(r.Trigger(ResourceTrigger.SystemTerminated)); + } + } + + + foreach (var store in stores) + bag.Add(store.Key.Trigger(ResourceTrigger.SystemTerminated)); + + bag.Seal(); + + var rt = new AsyncReply(); + bag.Then((x) => + { + foreach (var b in x) + if (!b) + { + rt.Trigger(false); + return; + } + + rt.Trigger(true); + }); + + return rt; + } + + + /* + private static IResource[] QureyIn(string[] path, int index, IEnumerable resources)// AutoList resources) + { + var rt = new List(); + + if (index == path.Length - 1) + { + if (path[index] == "") + foreach (IResource child in resources) + rt.Add(child); + else + foreach (IResource child in resources) + if (child.Instance.Name == path[index]) + rt.Add(child); + } + else + foreach (IResource child in resources) + if (child.Instance.Name == path[index]) + rt.AddRange(QureyIn(path, index+1, child.Instance.Children())); + + return rt.ToArray(); + } + + public static AsyncReply Query(string path) + { + if (path == null || path == "") + { + var roots = stores.Where(s => s.Instance.Parents().Count() == 0).ToArray(); + return new AsyncReply(roots); + } + else + { + var rt = new AsyncReply(); + Get(path).Then(x => + { + var p = path.Split('/'); + + if (x == null) + { + rt.Trigger(QureyIn(p, 0, stores)); + } + else + { + var ar = QureyIn(p, 0, stores).Where(r => r != x).ToList(); + ar.Insert(0, x); + rt.Trigger(ar.ToArray()); + } }); return rt; + } + } + */ + + + + public static async AsyncReply Query(string path) + { + var rt = new AsyncReply(); + + var p = path.Trim().Split('/'); + IResource resource; + + foreach (var store in stores.Keys) + if (p[0] == store.Instance.Name) + { + + if (p.Length == 1) + return new IResource[] { store }; + + var res = await store.Get(String.Join("/", p.Skip(1).ToArray())); + if (res != null) + return new IResource[] { res }; + + + resource = store; + for (var i = 1; i < p.Length; i++) + { + var children = await resource.Instance.Children(p[i]); + if (children.Length > 0) + { + if (i == p.Length - 1) + return children; + else + resource = children[0]; + } + else + break; + } + + return null; + } + + + + return null; + } + + /// + /// Get a resource by its path. + /// Resource path is sperated by '/' character, e.g. "system/http". + /// + /// + /// Resource instance. + public static async AsyncReply Get(string path, object attributes = null, IResource parent = null, IPermissionsManager manager = null) + where T : IResource + { + //var rt = new AsyncReply(); + + // Should we create a new store ? + + if (urlRegex.IsMatch(path)) + { + + var url = urlRegex.Split(path); + + if (Protocols.ContainsKey(url[1])) + { + if (!warehouseIsOpen) + await Open(); + + var handler = Protocols[url[1]]; + var store = await handler(url[2], attributes); + + try + { + //await Put(store, url[2], null, parent, null, 0, manager, attributes); + + if (url[3].Length > 0 && url[3] != "") + return (T)await store.Get(url[3]); + else + return (T)store; + + } + catch (Exception ex) + { + Warehouse.Remove(store); + throw ex; + } + + } + + + // store.Get(url[3]).Then(r => + // { + // rt.Trigger(r); + // }).Error(e => + // { + // Warehouse.Remove(store); + // rt.TriggerError(e); + // }); + // else + // rt.Trigger(store); + + // store.Trigger(ResourceTrigger.Open).Then(x => + // { + + // warehouseIsOpen = true; + // await Put(store, url[2], null, parent, null, 0, manager, attributes); + + // if (url[3].Length > 0 && url[3] != "") + // store.Get(url[3]).Then(r => + // { + // rt.Trigger(r); + // }).Error(e => + // { + // Warehouse.Remove(store); + // rt.TriggerError(e); + // }); + // else + // rt.Trigger(store); + // }).Error(e => + // { + // rt.TriggerError(e); + // //Warehouse.Remove(store); + // }); + + // return rt; + //} + } + + + //await Query(path).Then(rs => + //{ + // // rt.TriggerError(new Exception()); + // if (rs != null && rs.Length > 0) + // rt.Trigger(rs.First()); + // else + // rt.Trigger(null); + //}); + + //return rt; + + var res = await Query(path); + + if (res.Length == 0) + return default(T); + else + return (T)res.First(); + + } + + + //public static async AsyncReply Push(string path, T resource) where T : IResource + //{ + // await Put(path, resource); + // return resource; + //} + + /// + /// Put a resource in the warehouse. + /// + /// Resource name. + /// Resource instance. + /// IStore that manages the resource. Can be null if the resource is a store. + /// Parent resource. if not presented the store becomes the parent for the resource. + public static async AsyncReply Put(string name, T resource, IStore store = null, IResource parent = null, TypeTemplate customTemplate = null, ulong age = 0, IPermissionsManager manager = null, object attributes = null) where T : IResource + { + if (resource.Instance != null) + throw new Exception("Resource has a store."); + + var path = name.TrimStart('/').Split('/'); + + if (path.Length > 1) + { + if (parent != null) + throw new Exception("Parent can't be set when using path in instance name"); + + parent = await Warehouse.Get(string.Join("/", path.Take(path.Length - 1))); + + if (parent == null) + throw new Exception("Can't find parent"); + + store = store ?? parent.Instance.Store; + } + + var instanceName = path.Last(); + + + var resourceReference = new WeakReference(resource); + + if (store == null) + { + // assign parent's store as a store + if (parent != null) + { + // assign parent as a store + if (parent is IStore) + { + store = (IStore)parent; + List> list; + if (stores.TryGetValue(store, out list)) + lock (((ICollection)list).SyncRoot) + list.Add(resourceReference); + //stores[store].Add(resourceReference); + } + else + { + store = parent.Instance.Store; + + List> list; + if (stores.TryGetValue(store, out list)) + lock (((ICollection)list).SyncRoot) + list.Add(resourceReference); + } + } + // assign self as a store (root store) + else if (resource is IStore) + { + store = (IStore)resource; + } + else + throw new Exception("Can't find a store for the resource."); + } + + resource.Instance = new Instance(resourceCounter++, instanceName, resource, store, customTemplate, age); + + if (attributes != null) + resource.Instance.SetAttributes(Structure.FromObject(attributes)); + + if (manager != null) + resource.Instance.Managers.Add(manager); + + if (store == parent) + parent = null; + + + + + try + { + if (resource is IStore) + stores.TryAdd(resource as IStore, new List>()); + + + if (!await store.Put(resource)) + throw new Exception("Store failed to put the resource"); + //return default(T); + + + if (parent != null) + { + await parent.Instance.Store.AddChild(parent, resource); + await store.AddParent(resource, parent); + } + + var t = resource.GetType(); + Global.Counters["T-" + t.Namespace + "." + t.Name]++; + + + resources.TryAdd(resource.Instance.Id, resourceReference); + + if (warehouseIsOpen) + { + await resource.Trigger(ResourceTrigger.Initialize); + if (resource is IStore) + await resource.Trigger(ResourceTrigger.Open); + } + + if (resource is IStore) + StoreConnected?.Invoke(resource as IStore); + } + catch (Exception ex) + { + Warehouse.Remove(resource); + throw ex; + } + + return resource; + + } + + public static async AsyncReply New(Type type, string name = null, IStore store = null, IResource parent = null, IPermissionsManager manager = null, object attributes = null, object properties = null) + { + + type = ResourceProxy.GetProxy(type); + /* - private static IResource[] QureyIn(string[] path, int index, IEnumerable resources)// AutoList resources) + if (arguments != null) { - var rt = new List(); + var constructors = type.GetConstructors(System.Reflection.BindingFlags.Public); - if (index == path.Length - 1) + foreach(var constructor in constructors) { - if (path[index] == "") - foreach (IResource child in resources) - rt.Add(child); - else - foreach (IResource child in resources) - if (child.Instance.Name == path[index]) - rt.Add(child); + var pi = constructor.GetParameters(); + if (pi.Length == constructor.le) } - else - foreach (IResource child in resources) - if (child.Instance.Name == path[index]) - rt.AddRange(QureyIn(path, index+1, child.Instance.Children())); - return rt.ToArray(); - } + // cast arguments + ParameterInfo[] pi = fi.GetParameters(); - public static AsyncReply Query(string path) - { - if (path == null || path == "") + object[] args = new object[pi.Length]; + + for (var i = 0; i < pi.Length; i++) { - var roots = stores.Where(s => s.Instance.Parents().Count() == 0).ToArray(); - return new AsyncReply(roots); - } - else - { - var rt = new AsyncReply(); - Get(path).Then(x => + if (pi[i].ParameterType == typeof(DistributedConnection)) { - var p = path.Split('/'); - - if (x == null) - { - rt.Trigger(QureyIn(p, 0, stores)); - } - else - { - var ar = QureyIn(p, 0, stores).Where(r => r != x).ToList(); - ar.Insert(0, x); - rt.Trigger(ar.ToArray()); - } - }); - - return rt; - + args[i] = this; + } + else if (namedArgs.ContainsKey(pi[i].Name)) + { + args[i] = DC.CastConvert(namedArgs[pi[i].Name], pi[i].ParameterType); + } } + constructors[0]. } */ + var res = Activator.CreateInstance(type) as IResource; - - public static async AsyncReply Query(string path) + if (properties != null) { - var rt = new AsyncReply(); + var ps = Structure.FromObject(properties); - var p = path.Trim().Split('/'); - IResource resource; + foreach (var p in ps) + { - foreach (var store in stores.Keys) - if (p[0] == store.Instance.Name) + var pi = type.GetProperty(p.Key, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + if (pi != null) { - - if (p.Length == 1) - return new IResource[] { store }; - - var res = await store.Get(String.Join("/", p.Skip(1).ToArray())); - if (res != null) - return new IResource[] { res }; - - - resource = store; - for (var i = 1; i < p.Length; i++) + if (pi.CanWrite) { - var children = await resource.Instance.Children(p[i]); - if (children.Length > 0) + try { - if (i == p.Length - 1) - return children; - else - resource = children[0]; + pi.SetValue(res, p.Value); + } + catch (Exception ex) + { + Global.Log(ex); } - else - break; } - - return null; - } - - - - return null; - } - - /// - /// Get a resource by its path. - /// Resource path is sperated by '/' character, e.g. "system/http". - /// - /// - /// Resource instance. - public static async AsyncReply Get(string path, object attributes = null, IResource parent = null, IPermissionsManager manager = null) - where T: IResource - { - //var rt = new AsyncReply(); - - // Should we create a new store ? - - if (urlRegex.IsMatch(path)) - { - - var url = urlRegex.Split(path); - - if (Protocols.ContainsKey(url[1])) - { - if (!warehouseIsOpen) - await Open(); - - var handler = Protocols[url[1]]; - var store = await handler(url[2], attributes); - - try - { - //await Put(store, url[2], null, parent, null, 0, manager, attributes); - - if (url[3].Length > 0 && url[3] != "") - return (T)await store.Get(url[3]); - else - return (T)store; - - } - catch (Exception ex) - { - Warehouse.Remove(store); - throw ex; - } - - } - - - // store.Get(url[3]).Then(r => - // { - // rt.Trigger(r); - // }).Error(e => - // { - // Warehouse.Remove(store); - // rt.TriggerError(e); - // }); - // else - // rt.Trigger(store); - - // store.Trigger(ResourceTrigger.Open).Then(x => - // { - - // warehouseIsOpen = true; - // await Put(store, url[2], null, parent, null, 0, manager, attributes); - - // if (url[3].Length > 0 && url[3] != "") - // store.Get(url[3]).Then(r => - // { - // rt.Trigger(r); - // }).Error(e => - // { - // Warehouse.Remove(store); - // rt.TriggerError(e); - // }); - // else - // rt.Trigger(store); - // }).Error(e => - // { - // rt.TriggerError(e); - // //Warehouse.Remove(store); - // }); - - // return rt; - //} - } - - - //await Query(path).Then(rs => - //{ - // // rt.TriggerError(new Exception()); - // if (rs != null && rs.Length > 0) - // rt.Trigger(rs.First()); - // else - // rt.Trigger(null); - //}); - - //return rt; - - var res = await Query(path); - - if (res.Length == 0) - return default(T); - else - return (T)res.First(); - - } - - - //public static async AsyncReply Push(string path, T resource) where T : IResource - //{ - // await Put(path, resource); - // return resource; - //} - - /// - /// Put a resource in the warehouse. - /// - /// Resource name. - /// Resource instance. - /// IStore that manages the resource. Can be null if the resource is a store. - /// Parent resource. if not presented the store becomes the parent for the resource. - public static async AsyncReply Put(string name, T resource, IStore store = null, IResource parent = null, TypeTemplate customTemplate = null, ulong age = 0, IPermissionsManager manager = null, object attributes = null) where T:IResource - { - if (resource.Instance != null) - throw new Exception("Resource has a store."); - - var path = name.TrimStart('/').Split('/'); - - if (path.Length > 1) - { - if (parent != null) - throw new Exception("Parent can't be set when using path in instance name"); - - parent = await Warehouse.Get(string.Join("/", path.Take(path.Length - 1))); - - if (parent == null) - throw new Exception("Can't find parent"); - - store = store ?? parent.Instance.Store; - } - - var instanceName = path.Last(); - - - var resourceReference = new WeakReference(resource); - - if (store == null) - { - // assign parent's store as a store - if (parent != null) - { - // assign parent as a store - if (parent is IStore) - { - store = (IStore)parent; - List> list; - if (stores.TryGetValue(store, out list)) - lock (((ICollection)list).SyncRoot) - list.Add(resourceReference); - //stores[store].Add(resourceReference); - } - else - { - store = parent.Instance.Store; - - List> list; - if (stores.TryGetValue(store, out list)) - lock (((ICollection)list).SyncRoot) - list.Add(resourceReference); - } - } - // assign self as a store (root store) - else if (resource is IStore) - { - store = (IStore)resource; } else - throw new Exception("Can't find a store for the resource."); - } - - resource.Instance = new Instance(resourceCounter++, instanceName, resource, store, customTemplate, age); - - if (attributes != null) - resource.Instance.SetAttributes(Structure.FromObject(attributes)); - - if (manager != null) - resource.Instance.Managers.Add(manager); - - if (store == parent) - parent = null; - - - - - try - { - if (resource is IStore) - stores.TryAdd(resource as IStore, new List>()); - - - if (!await store.Put(resource)) - throw new Exception("Store failed to put the resource"); - //return default(T); - - - if (parent != null) { - await parent.Instance.Store.AddChild(parent, resource); - await store.AddParent(resource, parent); - } - - var t = resource.GetType(); - Global.Counters["T-" + t.Namespace + "." + t.Name]++; - - - resources.TryAdd(resource.Instance.Id, resourceReference); - - if (warehouseIsOpen) - { - await resource.Trigger(ResourceTrigger.Initialize); - if (resource is IStore) - await resource.Trigger(ResourceTrigger.Open); - } - - if (resource is IStore) - StoreConnected?.Invoke(resource as IStore); - } - catch (Exception ex) - { - Warehouse.Remove(resource); - throw ex; - } - - return resource; - - } - - public static async AsyncReply New(Type type, string name = null, IStore store = null, IResource parent = null, IPermissionsManager manager = null, object attributes = null, object properties = null) - { - - type = ResourceProxy.GetProxy(type); - - - /* - if (arguments != null) - { - var constructors = type.GetConstructors(System.Reflection.BindingFlags.Public); - - foreach(var constructor in constructors) - { - var pi = constructor.GetParameters(); - if (pi.Length == constructor.le) - } - - // cast arguments - ParameterInfo[] pi = fi.GetParameters(); - - object[] args = new object[pi.Length]; - - for (var i = 0; i < pi.Length; i++) - { - if (pi[i].ParameterType == typeof(DistributedConnection)) + var fi = type.GetField(p.Key, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + if (fi != null) { - args[i] = this; - } - else if (namedArgs.ContainsKey(pi[i].Name)) - { - args[i] = DC.CastConvert(namedArgs[pi[i].Name], pi[i].ParameterType); - } - } - - constructors[0]. - } - */ - var res = Activator.CreateInstance(type) as IResource; - - - if (properties != null) - { - var ps = Structure.FromObject(properties); - - foreach (var p in ps) - { - - var pi = type.GetProperty(p.Key, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); - if (pi != null) - { - if (pi.CanWrite) + try { - try - { - pi.SetValue(res, p.Value); - } - catch (Exception ex) - { - Global.Log(ex); - } + fi.SetValue(res, p.Value); } - } - else - { - var fi = type.GetField(p.Key, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); - if (fi != null) + catch (Exception ex) { - try - { - fi.SetValue(res, p.Value); - } - catch (Exception ex) - { - Global.Log(ex); - } + Global.Log(ex); } } } } - - if (store != null || parent != null || res is IStore) - { - //if (!await Put(name, res, store, parent, null, 0, manager, attributes)) - // return null; - - await Put(name, res, store, parent, null, 0, manager, attributes); - } - - return res; - } - public static async AsyncReply New(string name, IStore store = null, IResource parent = null, IPermissionsManager manager = null, object attributes = null, object properties = null) - where T : IResource + if (store != null || parent != null || res is IStore) { - return (T)(await New(typeof(T), name, store, parent, manager, attributes, properties)); + //if (!await Put(name, res, store, parent, null, 0, manager, attributes)) + // return null; + + await Put(name, res, store, parent, null, 0, manager, attributes); } - /// - /// Put a resource template in the templates warehouse. - /// - /// Resource template. - public static void PutTemplate(TypeTemplate template) + return res; + + } + + public static async AsyncReply New(string name, IStore store = null, IResource parent = null, IPermissionsManager manager = null, object attributes = null, object properties = null) + where T : IResource + { + return (T)(await New(typeof(T), name, store, parent, manager, attributes, properties)); + } + + /// + /// Put a resource template in the templates warehouse. + /// + /// Resource template. + public static void PutTemplate(TypeTemplate template) + { + templates[template.Type][template.ClassId] = template; + } + + + /// + /// Get a template by type from the templates warehouse. If not in the warehouse, a new ResourceTemplate is created and added to the warehouse. + /// + /// .Net type. + /// Resource template. + public static TypeTemplate GetTemplateByType(Type type) + { + + TemplateType templateType = TemplateType.Unspecified; + + if (Codec.InheritsClass(type, typeof(DistributedResource))) + templateType = TemplateType.Wrapper; + if (Codec.ImplementsInterface(type, typeof(IResource))) + templateType = TemplateType.Resource; + else if (Codec.ImplementsInterface(type, typeof(IRecord))) + templateType = TemplateType.Record; + else + return null; + + var baseType = ResourceProxy.GetBaseType(type); + + if (baseType == typeof(IResource) + || baseType == typeof(IRecord)) + return null; + + var template = templates[templateType].Values.FirstOrDefault(x => x.DefinedType == type); + + // loaded ? + if (template == null) + template = new TypeTemplate(baseType, true); + + return template; + } + + /// + /// Get a template by class Id from the templates warehouse. If not in the warehouse, a new ResourceTemplate is created and added to the warehouse. + /// + /// Class Id. + /// Resource template. + public static TypeTemplate GetTemplateByClassId(Guid classId, TemplateType templateType = TemplateType.Unspecified) + { + if (templateType == TemplateType.Unspecified) { - templates[template.Type][template.ClassId] = template; - } + // look in resources + var template = templates[TemplateType.Resource][classId]; + if (template != null) + return template; + // look in records + template = templates[TemplateType.Record][classId]; + if (template != null) + return template; - /// - /// Get a template by type from the templates warehouse. If not in the warehouse, a new ResourceTemplate is created and added to the warehouse. - /// - /// .Net type. - /// Resource template. - public static TypeTemplate GetTemplateByType(Type type) - { - - TemplateType templateType = TemplateType.Unspecified; - - if (Codec.InheritsClass(type, typeof(DistributedResource))) - templateType = TemplateType.Wrapper; - if (Codec.ImplementsInterface(type, typeof(IResource))) - templateType = TemplateType.Resource; - else if (Codec.ImplementsInterface(type, typeof(IRecord))) - templateType = TemplateType.Record; - else - return null; - - var baseType = ResourceProxy.GetBaseType(type); - - if (baseType == typeof(IResource) - || baseType == typeof(IRecord)) - return null; - - var template = templates[templateType].Values.FirstOrDefault(x => x.DefinedType == type); - - // loaded ? - if (template == null) - template = new TypeTemplate(baseType, true); - + // look in wrappers + template = templates[TemplateType.Wrapper][classId]; return template; } + else + return templates[templateType][classId]; + } - /// - /// Get a template by class Id from the templates warehouse. If not in the warehouse, a new ResourceTemplate is created and added to the warehouse. - /// - /// Class Id. - /// Resource template. - public static TypeTemplate GetTemplateByClassId(Guid classId, TemplateType templateType = TemplateType.Unspecified) + /// + /// Get a template by class name from the templates warehouse. If not in the warehouse, a new ResourceTemplate is created and added to the warehouse. + /// + /// Class name. + /// Resource template. + public static TypeTemplate GetTemplateByClassName(string className, TemplateType templateType = TemplateType.Unspecified) + { + if (templateType == TemplateType.Unspecified) { - if (templateType == TemplateType.Unspecified) - { - // look in resources - var template = templates[TemplateType.Resource][classId]; - if (template != null) - return template; - - // look in records - template = templates[TemplateType.Record][classId]; - if (template != null) - return template; - - // look in wrappers - template = templates[TemplateType.Wrapper][classId]; + // look in resources + var template = templates[TemplateType.Resource].Values.FirstOrDefault(x => x.ClassName == className); + if (template != null) return template; - } - else - return templates[templateType][classId]; - } - /// - /// Get a template by class name from the templates warehouse. If not in the warehouse, a new ResourceTemplate is created and added to the warehouse. - /// - /// Class name. - /// Resource template. - public static TypeTemplate GetTemplateByClassName(string className, TemplateType templateType = TemplateType.Unspecified) - { - if (templateType == TemplateType.Unspecified) - { - // look in resources - var template = templates[TemplateType.Resource].Values.FirstOrDefault(x => x.ClassName == className); - if (template != null) - return template; - - // look in records - template = templates[TemplateType.Record].Values.FirstOrDefault(x => x.ClassName == className); - if (template != null) - return template; - - // look in wrappers - template = templates[TemplateType.Wrapper].Values.FirstOrDefault(x => x.ClassName == className); + // look in records + template = templates[TemplateType.Record].Values.FirstOrDefault(x => x.ClassName == className); + if (template != null) return template; - } - else - { - return templates[templateType].Values.FirstOrDefault(x => x.ClassName == className); - } + + // look in wrappers + template = templates[TemplateType.Wrapper].Values.FirstOrDefault(x => x.ClassName == className); + return template; } - - public static bool Remove(IResource resource) + else { + return templates[templateType].Values.FirstOrDefault(x => x.ClassName == className); + } + } - if (resource.Instance == null) - return false; + public static bool Remove(IResource resource) + { + + if (resource.Instance == null) + return false; + + //lock (resourcesLock) + //{ + + WeakReference resourceReference; + + if (resources.ContainsKey(resource.Instance.Id)) + resources.TryRemove(resource.Instance.Id, out resourceReference); + else + return false; + //} + + if (resource != resource.Instance.Store) + { + List> list; + if (stores.TryGetValue(resource.Instance.Store, out list)) + { + + lock (((ICollection)list).SyncRoot) + list.Remove(resourceReference); + + //list.TryTake(resourceReference); + }//.Remove(resourceReference); + } + if (resource is IStore) + { + var store = resource as IStore; + + List> toBeRemoved;// = stores[store]; + + stores.TryRemove(store, out toBeRemoved); //lock (resourcesLock) //{ - - WeakReference resourceReference; - - if (resources.ContainsKey(resource.Instance.Id)) - resources.TryRemove(resource.Instance.Id, out resourceReference); - else - return false; + // // remove all objects associated with the store + // toBeRemoved = resources.Values.Where(x => + // { + // IResource r; + // if (x.TryGetTarget(out r)) + // return r.Instance.Store == resource; + // else + // return false; + // }).ToArray(); //} - if (resource != resource.Instance.Store) + + foreach (var o in toBeRemoved) { - List> list; - if (stores.TryGetValue(resource.Instance.Store, out list)) - { - - lock (((ICollection)list).SyncRoot) - list.Remove(resourceReference); - - //list.TryTake(resourceReference); - }//.Remove(resourceReference); - } - if (resource is IStore) - { - var store = resource as IStore; - - List> toBeRemoved;// = stores[store]; - - stores.TryRemove(store, out toBeRemoved); - - //lock (resourcesLock) - //{ - // // remove all objects associated with the store - // toBeRemoved = resources.Values.Where(x => - // { - // IResource r; - // if (x.TryGetTarget(out r)) - // return r.Instance.Store == resource; - // else - // return false; - // }).ToArray(); - //} - - - foreach (var o in toBeRemoved) - { - IResource r; - if (o.TryGetTarget(out r)) - Remove(r); - } - - StoreDisconnected?.Invoke(resource as IStore); + IResource r; + if (o.TryGetTarget(out r)) + Remove(r); } - if (resource.Instance.Store != null) - resource.Instance.Store.Remove(resource); - - resource.Destroy(); - - return true; + StoreDisconnected?.Invoke(resource as IStore); } + + if (resource.Instance.Store != null) + resource.Instance.Store.Remove(resource); + + resource.Destroy(); + + return true; } } diff --git a/Esiur/Security/Authority/AlienAuthentication.cs b/Esiur/Security/Authority/AlienAuthentication.cs index 137c911..871ecb8 100644 --- a/Esiur/Security/Authority/AlienAuthentication.cs +++ b/Esiur/Security/Authority/AlienAuthentication.cs @@ -28,14 +28,13 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Authority -{ - public class AlienAuthentication : Authentication - { - public AlienAuthentication() : - base(AuthenticationType.Alien) - { +namespace Esiur.Security.Authority; + +public class AlienAuthentication : Authentication +{ + public AlienAuthentication() : + base(AuthenticationType.Alien) + { - } } } diff --git a/Esiur/Security/Authority/Authentication.cs b/Esiur/Security/Authority/Authentication.cs index ae78131..cb1762c 100644 --- a/Esiur/Security/Authority/Authentication.cs +++ b/Esiur/Security/Authority/Authentication.cs @@ -29,38 +29,37 @@ using System.Text; using System.Threading.Tasks; using static Esiur.Net.Packets.IIPAuthPacket; -namespace Esiur.Security.Authority +namespace Esiur.Security.Authority; + +public class Authentication { - public class Authentication + AuthenticationType type; + + public AuthenticationMethod Method { get; set; } + + public ulong TokenIndex { get; set; } + + public string Username { get; set; } + public Certificate Certificate { get; set; } + public string Domain { get; set; } + + public string FullName => Username + "@" + Domain; + + public Source Source { get; } = new Source(); + + public AuthenticationState State { - AuthenticationType type; + get; + set; + } - public AuthenticationMethod Method { get; set; } + public AuthenticationType Type + { + get => type; + } - public ulong TokenIndex { get; set; } - - public string Username { get; set; } - public Certificate Certificate { get; set; } - public string Domain { get; set; } - - public string FullName => Username + "@" + Domain; - - public Source Source { get; } = new Source(); - - public AuthenticationState State - { - get; - set; - } - - public AuthenticationType Type - { - get => type; - } - - public Authentication(AuthenticationType type) - { - this.type = type; - } + public Authentication(AuthenticationType type) + { + this.type = type; } } diff --git a/Esiur/Security/Authority/AuthenticationMethod.cs b/Esiur/Security/Authority/AuthenticationMethod.cs index 571038d..fdaa3a9 100644 --- a/Esiur/Security/Authority/AuthenticationMethod.cs +++ b/Esiur/Security/Authority/AuthenticationMethod.cs @@ -2,13 +2,12 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Security.Authority +namespace Esiur.Security.Authority; + +public enum AuthenticationMethod : byte { - public enum AuthenticationMethod : byte - { - None, - Certificate, - Credentials, - Token - } + None, + Certificate, + Credentials, + Token } diff --git a/Esiur/Security/Authority/AuthenticationState.cs b/Esiur/Security/Authority/AuthenticationState.cs index 90515d8..afd3953 100644 --- a/Esiur/Security/Authority/AuthenticationState.cs +++ b/Esiur/Security/Authority/AuthenticationState.cs @@ -28,15 +28,13 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Authority +namespace Esiur.Security.Authority; +public enum AuthenticationState : int { - public enum AuthenticationState : int - { - Denied = 0x1, - Succeeded = 0x2, - Blocked = 0x4, - Rejected = 0x8, - NeedsUpdate = 0x10, - NotFound = 0x20 - } + Denied = 0x1, + Succeeded = 0x2, + Blocked = 0x4, + Rejected = 0x8, + NeedsUpdate = 0x10, + NotFound = 0x20 } diff --git a/Esiur/Security/Authority/AuthenticationType.cs b/Esiur/Security/Authority/AuthenticationType.cs index 3b4bcf5..6ebb97e 100644 --- a/Esiur/Security/Authority/AuthenticationType.cs +++ b/Esiur/Security/Authority/AuthenticationType.cs @@ -28,13 +28,12 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Authority +namespace Esiur.Security.Authority; + +public enum AuthenticationType { - public enum AuthenticationType - { - Host, - CoHost, - Client, - Alien - } + Host, + CoHost, + Client, + Alien } diff --git a/Esiur/Security/Authority/CACertificate.cs b/Esiur/Security/Authority/CACertificate.cs index 3dac45c..2ff0d08 100644 --- a/Esiur/Security/Authority/CACertificate.cs +++ b/Esiur/Security/Authority/CACertificate.cs @@ -35,168 +35,167 @@ using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Authority +namespace Esiur.Security.Authority; + +public class CACertificate : Certificate { - public class CACertificate : Certificate + + string name; + + public string Name + { + get { return name; } + } + + public CACertificate(byte[] data, uint offset, uint length, bool privateKeyIncluded = false) + : base(0, DateTime.MinValue, DateTime.MinValue, HashFunctionType.MD5) { - string name; + uint oOffset = offset; - public string Name + this.id = DC.GetUInt64(data, offset); + offset += 8; + this.issueDate = DC.GetDateTime(data, offset); + offset += 8; + this.expireDate = DC.GetDateTime(data, offset); + offset += 8; + this.hashFunction = (HashFunctionType)(data[offset++] >> 4); + + + this.name = (Encoding.ASCII.GetString(data, (int)offset + 1, data[offset])); + offset += (uint)data[offset] + 1; + + + var aea = (AsymetricEncryptionAlgorithmType)(data[offset] >> 5); + + if (aea == AsymetricEncryptionAlgorithmType.RSA) { - get { return name; } - } + var key = new RSAParameters(); + uint exponentLength = (uint)data[offset++] & 0x1F; - public CACertificate(byte[] data, uint offset, uint length, bool privateKeyIncluded = false) - :base(0, DateTime.MinValue, DateTime.MinValue, HashFunctionType.MD5) - { - - uint oOffset = offset; + key.Exponent = DC.Clip(data, offset, exponentLength); - this.id = DC.GetUInt64(data, offset); - offset += 8; - this.issueDate = DC.GetDateTime(data, offset); - offset += 8; - this.expireDate = DC.GetDateTime(data, offset); - offset += 8; - this.hashFunction = (HashFunctionType)(data[offset++] >> 4); + offset += exponentLength; + uint keySize = DC.GetUInt16(data, offset); + offset += 2; - this.name = (Encoding.ASCII.GetString(data, (int)offset + 1, data[offset])); - offset += (uint)data[offset] + 1; + key.Modulus = DC.Clip(data, offset, keySize); - - var aea = (AsymetricEncryptionAlgorithmType)(data[offset] >> 5); + offset += keySize; - if (aea == AsymetricEncryptionAlgorithmType.RSA) + // copy cert data + this.publicRawData = new byte[offset - oOffset]; + Buffer.BlockCopy(data, (int)oOffset, publicRawData, 0, publicRawData.Length); + + if (privateKeyIncluded) { - var key = new RSAParameters(); - uint exponentLength = (uint)data[offset++] & 0x1F; + uint privateKeyLength = (keySize * 3) + (keySize / 2); + uint halfKeySize = keySize / 2; - key.Exponent = DC.Clip(data, offset, exponentLength); - - offset += exponentLength; - - uint keySize = DC.GetUInt16(data, offset); - offset += 2; - - key.Modulus = DC.Clip(data, offset, keySize); + privateRawData = DC.Clip(data, offset, privateKeyLength); + key.D = DC.Clip(data, offset, keySize); offset += keySize; - // copy cert data - this.publicRawData = new byte[offset - oOffset]; - Buffer.BlockCopy(data, (int)oOffset, publicRawData, 0, publicRawData.Length); + key.DP = DC.Clip(data, offset, halfKeySize); + offset += halfKeySize; - if (privateKeyIncluded) - { - uint privateKeyLength = (keySize * 3) + (keySize / 2); - uint halfKeySize = keySize / 2; - - privateRawData = DC.Clip(data, offset, privateKeyLength); - - key.D = DC.Clip(data, offset, keySize); - offset += keySize; - - key.DP = DC.Clip(data, offset, halfKeySize); - offset += halfKeySize; - - key.DQ = DC.Clip(data, offset, halfKeySize); - offset += halfKeySize; + key.DQ = DC.Clip(data, offset, halfKeySize); + offset += halfKeySize; - key.InverseQ = DC.Clip(data, offset, halfKeySize); - offset += halfKeySize; + key.InverseQ = DC.Clip(data, offset, halfKeySize); + offset += halfKeySize; - key.P = DC.Clip(data, offset, halfKeySize); - offset += halfKeySize; + key.P = DC.Clip(data, offset, halfKeySize); + offset += halfKeySize; - key.Q = DC.Clip(data, offset, halfKeySize); - offset += halfKeySize; + key.Q = DC.Clip(data, offset, halfKeySize); + offset += halfKeySize; - } - - // setup rsa - this.rsa = RSA.Create();// new RSACryptoServiceProvider(); - this.rsa.ImportParameters(key); } + + // setup rsa + this.rsa = RSA.Create();// new RSACryptoServiceProvider(); + this.rsa.ImportParameters(key); } + } - public CACertificate(ulong id, string authorityName, DateTime issueDate, DateTime expireDate, - HashFunctionType hashFunction = HashFunctionType.SHA1, uint ip = 0, byte[] ip6 = null) - : base(id, issueDate, expireDate, hashFunction) - { - // assign type + public CACertificate(ulong id, string authorityName, DateTime issueDate, DateTime expireDate, + HashFunctionType hashFunction = HashFunctionType.SHA1, uint ip = 0, byte[] ip6 = null) + : base(id, issueDate, expireDate, hashFunction) + { + // assign type - BinaryList cr = new BinaryList(); + BinaryList cr = new BinaryList(); - // make header + // make header - cr.AddUInt64(id) - .AddDateTime(issueDate) - .AddDateTime(expireDate); + cr.AddUInt64(id) + .AddDateTime(issueDate) + .AddDateTime(expireDate); - // hash function - cr.AddUInt8((byte)((byte)hashFunction << 4)); - this.hashFunction = hashFunction; + // hash function + cr.AddUInt8((byte)((byte)hashFunction << 4)); + this.hashFunction = hashFunction; - // CA Name - this.name = authorityName; - cr.AddUInt8((byte)(authorityName.Length)) - .AddUInt8Array(Encoding.ASCII.GetBytes(authorityName)); + // CA Name + this.name = authorityName; + cr.AddUInt8((byte)(authorityName.Length)) + .AddUInt8Array(Encoding.ASCII.GetBytes(authorityName)); - // public key - rsa = RSA.Create();// new RSACryptoServiceProvider(2048); - rsa.KeySize = 2048; - RSAParameters dRSAKey = rsa.ExportParameters(true); + // public key + rsa = RSA.Create();// new RSACryptoServiceProvider(2048); + rsa.KeySize = 2048; + RSAParameters dRSAKey = rsa.ExportParameters(true); - cr.AddUInt8((byte)dRSAKey.Exponent.Length) - .AddUInt8Array(dRSAKey.Exponent) - .AddUInt16((ushort)dRSAKey.Modulus.Length) - .AddUInt8Array(dRSAKey.Modulus); + cr.AddUInt8((byte)dRSAKey.Exponent.Length) + .AddUInt8Array(dRSAKey.Exponent) + .AddUInt16((ushort)dRSAKey.Modulus.Length) + .AddUInt8Array(dRSAKey.Modulus); - publicRawData = cr.ToArray(); + publicRawData = cr.ToArray(); - privateRawData = DC.Merge(dRSAKey.D, dRSAKey.DP, dRSAKey.DQ, dRSAKey.InverseQ, dRSAKey.P, dRSAKey.Q); - - } - - public override bool Save(string filename, bool includePrivate = false) - { - try - { - if (includePrivate) - File.WriteAllBytes(filename, new BinaryList() - .AddUInt8((byte)CertificateType.CAPrivate) - .AddUInt8Array(publicRawData) - .AddUInt8Array(privateRawData) - .ToArray()); - else - File.WriteAllBytes(filename, new BinaryList() - .AddUInt8((byte)CertificateType.CAPublic) - .AddUInt8Array(publicRawData).ToArray()); - - return true; - } - catch - { - return false; - } - } - - public override byte[] Serialize(bool includePrivate = false) - { - if (includePrivate) - return new BinaryList() - .AddUInt8Array(publicRawData) - .AddUInt8Array(privateRawData) - .ToArray(); - else - return publicRawData; - } + privateRawData = DC.Merge(dRSAKey.D, dRSAKey.DP, dRSAKey.DQ, dRSAKey.InverseQ, dRSAKey.P, dRSAKey.Q); } + + public override bool Save(string filename, bool includePrivate = false) + { + try + { + if (includePrivate) + File.WriteAllBytes(filename, new BinaryList() + .AddUInt8((byte)CertificateType.CAPrivate) + .AddUInt8Array(publicRawData) + .AddUInt8Array(privateRawData) + .ToArray()); + else + File.WriteAllBytes(filename, new BinaryList() + .AddUInt8((byte)CertificateType.CAPublic) + .AddUInt8Array(publicRawData).ToArray()); + + return true; + } + catch + { + return false; + } + } + + public override byte[] Serialize(bool includePrivate = false) + { + if (includePrivate) + return new BinaryList() + .AddUInt8Array(publicRawData) + .AddUInt8Array(privateRawData) + .ToArray(); + else + return publicRawData; + } + } diff --git a/Esiur/Security/Authority/Certificate.cs b/Esiur/Security/Authority/Certificate.cs index f23ed87..fd3c92b 100644 --- a/Esiur/Security/Authority/Certificate.cs +++ b/Esiur/Security/Authority/Certificate.cs @@ -35,188 +35,187 @@ using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Authority +namespace Esiur.Security.Authority; + +public abstract class Certificate { - public abstract class Certificate + protected DateTime issueDate, expireDate; + protected RSA rsa; + protected Aes aes; + + protected byte[] publicRawData; + protected byte[] privateRawData; + protected ulong id; + protected HashFunctionType hashFunction; + + public Certificate(ulong id, DateTime issueDate, DateTime expireDate, HashFunctionType hashFunction) { - protected DateTime issueDate, expireDate; - protected RSA rsa; - protected Aes aes; + this.id = id; + this.issueDate = issueDate; + this.expireDate = expireDate; + this.hashFunction = hashFunction; + } - protected byte[] publicRawData; - protected byte[] privateRawData; - protected ulong id; - protected HashFunctionType hashFunction; + public ulong Id + { + get { return id; } + } - public Certificate(ulong id, DateTime issueDate, DateTime expireDate, HashFunctionType hashFunction) - { - this.id = id; - this.issueDate = issueDate; - this.expireDate = expireDate; - this.hashFunction = hashFunction; - } + public AsymetricEncryptionAlgorithmType AsymetricEncryptionAlgorithm + { + get { return AsymetricEncryptionAlgorithmType.RSA; } + } - public ulong Id - { - get { return id; } - } + public byte[] AsymetricEncrypt(byte[] message) + { + return rsa.Encrypt(message, RSAEncryptionPadding.OaepSHA512); + } - public AsymetricEncryptionAlgorithmType AsymetricEncryptionAlgorithm - { - get { return AsymetricEncryptionAlgorithmType.RSA; } - } - public byte[] AsymetricEncrypt(byte[] message) - { + public byte[] AsymetricEncrypt(byte[] message, uint offset, uint length) + { + if (message.Length != length) + return rsa.Encrypt(DC.Clip(message, offset, length), RSAEncryptionPadding.OaepSHA512); + else return rsa.Encrypt(message, RSAEncryptionPadding.OaepSHA512); - } + } - - public byte[] AsymetricEncrypt(byte[] message, uint offset, uint length) + public byte[] AsymetricDecrypt(byte[] message) + { + try { - if (message.Length != length) - return rsa.Encrypt(DC.Clip(message, offset, length), RSAEncryptionPadding.OaepSHA512); - else - return rsa.Encrypt(message, RSAEncryptionPadding.OaepSHA512); + return rsa.Decrypt(message, RSAEncryptionPadding.OaepSHA512); } - - public byte[] AsymetricDecrypt(byte[] message) + catch (Exception ex) { - try - { - return rsa.Decrypt(message, RSAEncryptionPadding.OaepSHA512); - } - catch (Exception ex) - { - Global.Log("Certificate", LogType.Error, ex.ToString()); - return null; - } - } - - public byte[] AsymetricDecrypt(byte[] message, uint offset, uint length) - { - try - { - if (message.Length != length) - return rsa.Decrypt(DC.Clip(message, offset, length), RSAEncryptionPadding.OaepSHA512); - else - return rsa.Decrypt(message, RSAEncryptionPadding.OaepSHA512); - - } - catch (Exception ex) - { - Global.Log("Certificate", LogType.Error, ex.ToString()); - return null; - } - } - - public byte[] SymetricEncrypt(byte[] message, uint offset, uint length) - { - byte[] rt = null; - - using (var ms = new MemoryStream()) - { - using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write)) - cs.Write(message, (int)offset, (int)length); - - rt = ms.ToArray(); - } - - return rt; - } - - public byte[] SymetricEncrypt(byte[] message) - { - return SymetricEncrypt(message, 0, (uint)message.Length); - } - - public byte[] SymetricDecrypt(byte[] message, uint offset, uint length) - { - byte[] rt = null; - - using (var ms = new MemoryStream()) - { - using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write)) - cs.Write(message, (int)offset, (int)length); - - rt = ms.ToArray(); - } - - return rt; - } - - public byte[] SymetricDecrypt(byte[] message) - { - return SymetricDecrypt(message, 0, (uint)message.Length); - } - - public byte[] Sign(byte[] message) - { - return Sign(message, 0, (uint)message.Length); - } - - public byte[] Sign(byte[] message, uint offset, uint length) - { - if (hashFunction == HashFunctionType.SHA1) - return rsa.SignData(message, (int)offset, (int)length, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); - else if (hashFunction == HashFunctionType.MD5) - return rsa.SignData(message, (int)offset, (int)length, HashAlgorithmName.MD5, RSASignaturePadding.Pkcs1); - else if (hashFunction == HashFunctionType.SHA256) - return rsa.SignData(message, (int)offset, (int)length, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); - else if (hashFunction == HashFunctionType.SHA384) - return rsa.SignData(message, (int)offset, (int)length, HashAlgorithmName.SHA384, RSASignaturePadding.Pkcs1); - else if (hashFunction == HashFunctionType.SHA512) - return rsa.SignData(message, (int)offset, (int)length, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1); - - return null; - } - - public bool InitializeSymetricCipher(SymetricEncryptionAlgorithmType algorithm, int keyLength, byte[] key, byte[] iv) - { - if (algorithm == SymetricEncryptionAlgorithmType.AES) - { - if (keyLength == 0) // 128 bit - { - aes = Aes.Create(); - aes.Mode = CipherMode.CBC; - aes.Padding = PaddingMode.PKCS7; - aes.Key = key; - aes.IV = iv; - - return true; - } - } - - return false; - } - - - public abstract bool Save(string filename, bool includePrivate = false); - public abstract byte[] Serialize(bool includePrivate = false); - - public static Certificate Load(string filename) - { - byte[] ar = File.ReadAllBytes(filename); - var t = (CertificateType)ar[0]; - - switch (t) - { - case CertificateType.CAPublic: - return new CACertificate(ar, 1, (uint)ar.Length - 1); - case CertificateType.CAPrivate: - return new CACertificate(ar, 1, (uint)ar.Length - 1, true); - case CertificateType.DomainPublic: - return new DomainCertificate(ar, 1, (uint)ar.Length - 1); - case CertificateType.DomainPrivate: - return new DomainCertificate(ar, 1, (uint)ar.Length - 1, true); - case CertificateType.UserPublic: - return new UserCertificate(ar, 1, (uint)ar.Length - 1); - case CertificateType.UserPrivate: - return new UserCertificate(ar, 1, (uint)ar.Length - 1, true); - } - + Global.Log("Certificate", LogType.Error, ex.ToString()); return null; } } + public byte[] AsymetricDecrypt(byte[] message, uint offset, uint length) + { + try + { + if (message.Length != length) + return rsa.Decrypt(DC.Clip(message, offset, length), RSAEncryptionPadding.OaepSHA512); + else + return rsa.Decrypt(message, RSAEncryptionPadding.OaepSHA512); + + } + catch (Exception ex) + { + Global.Log("Certificate", LogType.Error, ex.ToString()); + return null; + } + } + + public byte[] SymetricEncrypt(byte[] message, uint offset, uint length) + { + byte[] rt = null; + + using (var ms = new MemoryStream()) + { + using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write)) + cs.Write(message, (int)offset, (int)length); + + rt = ms.ToArray(); + } + + return rt; + } + + public byte[] SymetricEncrypt(byte[] message) + { + return SymetricEncrypt(message, 0, (uint)message.Length); + } + + public byte[] SymetricDecrypt(byte[] message, uint offset, uint length) + { + byte[] rt = null; + + using (var ms = new MemoryStream()) + { + using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write)) + cs.Write(message, (int)offset, (int)length); + + rt = ms.ToArray(); + } + + return rt; + } + + public byte[] SymetricDecrypt(byte[] message) + { + return SymetricDecrypt(message, 0, (uint)message.Length); + } + + public byte[] Sign(byte[] message) + { + return Sign(message, 0, (uint)message.Length); + } + + public byte[] Sign(byte[] message, uint offset, uint length) + { + if (hashFunction == HashFunctionType.SHA1) + return rsa.SignData(message, (int)offset, (int)length, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); + else if (hashFunction == HashFunctionType.MD5) + return rsa.SignData(message, (int)offset, (int)length, HashAlgorithmName.MD5, RSASignaturePadding.Pkcs1); + else if (hashFunction == HashFunctionType.SHA256) + return rsa.SignData(message, (int)offset, (int)length, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); + else if (hashFunction == HashFunctionType.SHA384) + return rsa.SignData(message, (int)offset, (int)length, HashAlgorithmName.SHA384, RSASignaturePadding.Pkcs1); + else if (hashFunction == HashFunctionType.SHA512) + return rsa.SignData(message, (int)offset, (int)length, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1); + + return null; + } + + public bool InitializeSymetricCipher(SymetricEncryptionAlgorithmType algorithm, int keyLength, byte[] key, byte[] iv) + { + if (algorithm == SymetricEncryptionAlgorithmType.AES) + { + if (keyLength == 0) // 128 bit + { + aes = Aes.Create(); + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; + aes.Key = key; + aes.IV = iv; + + return true; + } + } + + return false; + } + + + public abstract bool Save(string filename, bool includePrivate = false); + public abstract byte[] Serialize(bool includePrivate = false); + + public static Certificate Load(string filename) + { + byte[] ar = File.ReadAllBytes(filename); + var t = (CertificateType)ar[0]; + + switch (t) + { + case CertificateType.CAPublic: + return new CACertificate(ar, 1, (uint)ar.Length - 1); + case CertificateType.CAPrivate: + return new CACertificate(ar, 1, (uint)ar.Length - 1, true); + case CertificateType.DomainPublic: + return new DomainCertificate(ar, 1, (uint)ar.Length - 1); + case CertificateType.DomainPrivate: + return new DomainCertificate(ar, 1, (uint)ar.Length - 1, true); + case CertificateType.UserPublic: + return new UserCertificate(ar, 1, (uint)ar.Length - 1); + case CertificateType.UserPrivate: + return new UserCertificate(ar, 1, (uint)ar.Length - 1, true); + } + + return null; + } } + diff --git a/Esiur/Security/Authority/CertificateType.cs b/Esiur/Security/Authority/CertificateType.cs index 5bbc8ff..3178c76 100644 --- a/Esiur/Security/Authority/CertificateType.cs +++ b/Esiur/Security/Authority/CertificateType.cs @@ -28,15 +28,14 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Authority +namespace Esiur.Security.Authority; + +public enum CertificateType { - public enum CertificateType - { - CAPublic = 0, - CAPrivate, - DomainPublic, - DomainPrivate, - UserPublic, - UserPrivate - } + CAPublic = 0, + CAPrivate, + DomainPublic, + DomainPrivate, + UserPublic, + UserPrivate } diff --git a/Esiur/Security/Authority/ClientAuthentication.cs b/Esiur/Security/Authority/ClientAuthentication.cs index 8863613..ac83935 100644 --- a/Esiur/Security/Authority/ClientAuthentication.cs +++ b/Esiur/Security/Authority/ClientAuthentication.cs @@ -27,46 +27,44 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Authority +namespace Esiur.Security.Authority; +public class ClientAuthentication : Authentication { - public class ClientAuthentication : Authentication + /* + string username; + byte[] password; + string domain; + byte[] token; + UserCertificate certificate; + + public string Username => username; + public byte[] Password => password; + //public string Domain => domain; + public byte[] Token => token; + + public byte[] Nounce { get; set; } + */ + + public ClientAuthentication() + : base(AuthenticationType.Client) { - /* - string username; - byte[] password; - string domain; - byte[] token; - UserCertificate certificate; - public string Username => username; - public byte[] Password => password; - //public string Domain => domain; - public byte[] Token => token; - - public byte[] Nounce { get; set; } - */ - - public ClientAuthentication() - :base(AuthenticationType.Client) - { - - } - - - /* - public ClientAuthentication(byte[] token) - : base(AuthenticationType.Client) - { - this.token = token; - } - - public ClientAuthentication(string username, byte[] password) - : base(AuthenticationType.Client) - { - this.username = username; - this.password = password; - //this.domain = domain; - } - */ } + + + /* + public ClientAuthentication(byte[] token) + : base(AuthenticationType.Client) + { + this.token = token; + } + + public ClientAuthentication(string username, byte[] password) + : base(AuthenticationType.Client) + { + this.username = username; + this.password = password; + //this.domain = domain; + } + */ } diff --git a/Esiur/Security/Authority/CoHostAuthentication.cs b/Esiur/Security/Authority/CoHostAuthentication.cs index 33f5557..e29942c 100644 --- a/Esiur/Security/Authority/CoHostAuthentication.cs +++ b/Esiur/Security/Authority/CoHostAuthentication.cs @@ -28,14 +28,13 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Authority -{ - public class CoHostAuthentication : Authentication - { - public CoHostAuthentication() - : base(AuthenticationType.CoHost) - { +namespace Esiur.Security.Authority; + +public class CoHostAuthentication : Authentication +{ + public CoHostAuthentication() + : base(AuthenticationType.CoHost) + { - } } } diff --git a/Esiur/Security/Authority/DomainCertificate.cs b/Esiur/Security/Authority/DomainCertificate.cs index ca034d2..42882c3 100644 --- a/Esiur/Security/Authority/DomainCertificate.cs +++ b/Esiur/Security/Authority/DomainCertificate.cs @@ -34,217 +34,216 @@ using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Authority +namespace Esiur.Security.Authority; + +public class DomainCertificate : Certificate { - public class DomainCertificate : Certificate + uint ip; + byte[] ip6; + string domain; + + //CACertificate ca; + string caName; + ulong caId; + byte[] signature; + + string authorityName; + + public string AuthorityName { - uint ip; - byte[] ip6; - string domain; + get { return authorityName; } + } - //CACertificate ca; - string caName; - ulong caId; - byte[] signature; + public string Domain + { + get { return domain; } + } - string authorityName; + public byte[] Signature + { + get { return signature; } + } - public string AuthorityName + public uint IPAddress + { + get { return ip; } + } + + public byte[] IPv6Address + { + get { return ip6; } + } + + public DomainCertificate(byte[] data, uint offset, uint length, bool privateKeyIncluded = false) + : base(0, DateTime.MinValue, DateTime.MinValue, HashFunctionType.MD5) + { + var oOffset = offset; + + this.id = DC.GetUInt64(data, offset); + offset += 8; + + // load IPs + this.ip = DC.GetUInt32(data, offset); + offset += 4; + this.ip6 = DC.Clip(data, offset, 16); + + offset += 16; + + this.issueDate = DC.GetDateTime(data, offset); + offset += 8; + this.expireDate = DC.GetDateTime(data, offset); + offset += 8; + + this.domain = Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]); + offset += (uint)data[offset] + 1; + + this.authorityName = (Encoding.ASCII.GetString(data, (int)offset + 1, data[offset])); + offset += (uint)data[offset] + 1; + + caId = DC.GetUInt64(data, offset); + offset += 8; + + var aea = (AsymetricEncryptionAlgorithmType)(data[offset] >> 5); + + if (aea == AsymetricEncryptionAlgorithmType.RSA) { - get { return authorityName; } - } + var key = new RSAParameters(); + uint exponentLength = (uint)data[offset++] & 0x1F; - public string Domain - { - get { return domain; } - } + key.Exponent = DC.Clip(data, offset, exponentLength); + offset += exponentLength; - public byte[] Signature - { - get { return signature; } - } + uint keySize = DC.GetUInt16(data, offset); + offset += 2; - public uint IPAddress - { - get { return ip; } - } + key.Modulus = DC.Clip(data, offset, keySize); - public byte[] IPv6Address - { - get { return ip6; } - } + offset += keySize; - public DomainCertificate(byte[] data, uint offset, uint length, bool privateKeyIncluded = false) - :base(0, DateTime.MinValue, DateTime.MinValue, HashFunctionType.MD5) - { - var oOffset = offset; + // copy cert data + publicRawData = new byte[offset - oOffset]; + Buffer.BlockCopy(data, (int)oOffset, publicRawData, 0, publicRawData.Length); - this.id = DC.GetUInt64(data, offset); - offset += 8; - - // load IPs - this.ip = DC.GetUInt32(data, offset); - offset += 4; - this.ip6 = DC.Clip(data, offset, 16); - - offset += 16; - - this.issueDate = DC.GetDateTime(data, offset); - offset += 8; - this.expireDate = DC.GetDateTime(data, offset); - offset += 8; - - this.domain = Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]); - offset += (uint)data[offset] + 1; - - this.authorityName = (Encoding.ASCII.GetString(data, (int)offset + 1, data[offset])); - offset += (uint)data[offset] + 1; - - caId = DC.GetUInt64(data, offset); - offset += 8; - - var aea = (AsymetricEncryptionAlgorithmType)(data[offset] >> 5); - - if (aea == AsymetricEncryptionAlgorithmType.RSA) + if (privateKeyIncluded) { - var key = new RSAParameters(); - uint exponentLength = (uint)data[offset++] & 0x1F; - key.Exponent = DC.Clip(data, offset, exponentLength); - offset += exponentLength; + uint privateKeyLength = (keySize * 3) + (keySize / 2); + privateRawData = DC.Clip(data, offset, privateKeyLength); - uint keySize = DC.GetUInt16(data, offset); - offset += 2; - - key.Modulus = DC.Clip(data, offset, keySize); + uint halfKeySize = keySize / 2; + key.D = DC.Clip(data, offset, keySize); offset += keySize; - - // copy cert data - publicRawData = new byte[offset - oOffset]; - Buffer.BlockCopy(data, (int)oOffset, publicRawData, 0, publicRawData.Length); - - if (privateKeyIncluded) - { - - uint privateKeyLength = (keySize * 3) + (keySize / 2); - privateRawData = DC.Clip(data, offset, privateKeyLength); - - uint halfKeySize = keySize / 2; - - key.D = DC.Clip(data, offset, keySize); - offset += keySize; - key.DP = DC.Clip(data, offset, halfKeySize); - offset += halfKeySize; - key.DQ = DC.Clip(data, offset, halfKeySize); - offset += halfKeySize; - key.InverseQ = DC.Clip(data, offset, halfKeySize); - offset += halfKeySize; - key.P = DC.Clip(data, offset, halfKeySize); - offset += halfKeySize; - key.Q = DC.Clip(data, offset, halfKeySize); - offset += halfKeySize; - - } - - // setup rsa - rsa = RSA.Create();// new RSACryptoServiceProvider(); - rsa.ImportParameters(key); - - this.signature = DC.Clip(data, offset, length - (offset - oOffset)); + key.DP = DC.Clip(data, offset, halfKeySize); + offset += halfKeySize; + key.DQ = DC.Clip(data, offset, halfKeySize); + offset += halfKeySize; + key.InverseQ = DC.Clip(data, offset, halfKeySize); + offset += halfKeySize; + key.P = DC.Clip(data, offset, halfKeySize); + offset += halfKeySize; + key.Q = DC.Clip(data, offset, halfKeySize); + offset += halfKeySize; } - } + // setup rsa + rsa = RSA.Create();// new RSACryptoServiceProvider(); + rsa.ImportParameters(key); - public DomainCertificate(ulong id, string domain, CACertificate authority, DateTime issueDate, - DateTime expireDate, HashFunctionType hashFunction = HashFunctionType.SHA1, uint ip = 0, byte[] ip6 = null) - : base (id, issueDate, expireDate, hashFunction) - { - // assign type + this.signature = DC.Clip(data, offset, length - (offset - oOffset)); - var cr = new BinaryList(); - - // id - cr.AddUInt64(id); - - // ip - this.ip = ip; - this.ip6 = ip6; - - cr.AddUInt32(ip); - - - if (ip6?.Length == 16) - cr.AddUInt8Array(ip6); - else - cr.AddUInt8Array(new byte[16]); - - - cr.AddDateTime(issueDate) - .AddDateTime(expireDate); - - // domain - this.domain = domain; - cr.AddUInt8((byte)(domain.Length)) - .AddUInt8Array(Encoding.ASCII.GetBytes(domain)); - - // CA - this.caName = authority.Name; - cr.AddUInt8((byte)(authority.Name.Length)) - .AddUInt8Array(Encoding.ASCII.GetBytes(authority.Name)); - - this.authorityName = authority.Name; - - // CA Index - //co.KeyIndex = authority.KeyIndex; - this.caId = authority.Id; - cr.AddUInt64(caId); - - - // public key - rsa = RSA.Create();// new RSACryptoServiceProvider(2048); - rsa.KeySize = 2048; - RSAParameters dRSAKey = rsa.ExportParameters(true); - cr.AddUInt8((byte)dRSAKey.Exponent.Length) - .AddUInt8Array(dRSAKey.Exponent) - .AddUInt16((ushort)dRSAKey.Modulus.Length) - .AddUInt8Array(dRSAKey.Modulus); - - - publicRawData = cr.ToArray(); - - // private key - this.privateRawData = DC.Merge(dRSAKey.D, dRSAKey.DP, dRSAKey.DQ, dRSAKey.InverseQ, dRSAKey.P, dRSAKey.Q); - - this.signature = authority.Sign(publicRawData); - - } - - public override bool Save(string filename, bool includePrivate = false) - { - try - { - if (includePrivate) - File.WriteAllBytes(filename, DC.Merge(new byte[] { (byte)CertificateType.DomainPrivate }, publicRawData, signature, privateRawData)); - else - File.WriteAllBytes(filename, DC.Merge(new byte[] { (byte)CertificateType.DomainPublic }, publicRawData, signature)); - - return true; - } - catch - { - return false; - } - } - - public override byte[] Serialize(bool includePrivate = false) - { - if (includePrivate) - return DC.Merge(publicRawData, signature, privateRawData); - else - return DC.Merge(publicRawData, signature); } } + + public DomainCertificate(ulong id, string domain, CACertificate authority, DateTime issueDate, + DateTime expireDate, HashFunctionType hashFunction = HashFunctionType.SHA1, uint ip = 0, byte[] ip6 = null) + : base(id, issueDate, expireDate, hashFunction) + { + // assign type + + var cr = new BinaryList(); + + // id + cr.AddUInt64(id); + + // ip + this.ip = ip; + this.ip6 = ip6; + + cr.AddUInt32(ip); + + + if (ip6?.Length == 16) + cr.AddUInt8Array(ip6); + else + cr.AddUInt8Array(new byte[16]); + + + cr.AddDateTime(issueDate) + .AddDateTime(expireDate); + + // domain + this.domain = domain; + cr.AddUInt8((byte)(domain.Length)) + .AddUInt8Array(Encoding.ASCII.GetBytes(domain)); + + // CA + this.caName = authority.Name; + cr.AddUInt8((byte)(authority.Name.Length)) + .AddUInt8Array(Encoding.ASCII.GetBytes(authority.Name)); + + this.authorityName = authority.Name; + + // CA Index + //co.KeyIndex = authority.KeyIndex; + this.caId = authority.Id; + cr.AddUInt64(caId); + + + // public key + rsa = RSA.Create();// new RSACryptoServiceProvider(2048); + rsa.KeySize = 2048; + RSAParameters dRSAKey = rsa.ExportParameters(true); + cr.AddUInt8((byte)dRSAKey.Exponent.Length) + .AddUInt8Array(dRSAKey.Exponent) + .AddUInt16((ushort)dRSAKey.Modulus.Length) + .AddUInt8Array(dRSAKey.Modulus); + + + publicRawData = cr.ToArray(); + + // private key + this.privateRawData = DC.Merge(dRSAKey.D, dRSAKey.DP, dRSAKey.DQ, dRSAKey.InverseQ, dRSAKey.P, dRSAKey.Q); + + this.signature = authority.Sign(publicRawData); + + } + + public override bool Save(string filename, bool includePrivate = false) + { + try + { + if (includePrivate) + File.WriteAllBytes(filename, DC.Merge(new byte[] { (byte)CertificateType.DomainPrivate }, publicRawData, signature, privateRawData)); + else + File.WriteAllBytes(filename, DC.Merge(new byte[] { (byte)CertificateType.DomainPublic }, publicRawData, signature)); + + return true; + } + catch + { + return false; + } + } + + public override byte[] Serialize(bool includePrivate = false) + { + if (includePrivate) + return DC.Merge(publicRawData, signature, privateRawData); + else + return DC.Merge(publicRawData, signature); + } + } diff --git a/Esiur/Security/Authority/HostAuthentication.cs b/Esiur/Security/Authority/HostAuthentication.cs index 9ed62c5..c774cc8 100644 --- a/Esiur/Security/Authority/HostAuthentication.cs +++ b/Esiur/Security/Authority/HostAuthentication.cs @@ -28,16 +28,14 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Authority +namespace Esiur.Security.Authority; +public class HostAuthentication : Authentication { - public class HostAuthentication : Authentication + + public HostAuthentication() + : base(AuthenticationType.Host) { - public HostAuthentication() - :base(AuthenticationType.Host) - { + } - } - - } } diff --git a/Esiur/Security/Authority/Session.cs b/Esiur/Security/Authority/Session.cs index c502aeb..391e96c 100644 --- a/Esiur/Security/Authority/Session.cs +++ b/Esiur/Security/Authority/Session.cs @@ -31,31 +31,29 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Authority +namespace Esiur.Security.Authority; +public class Session { - public class Session + public Authentication LocalAuthentication => localAuth; + public Authentication RemoteAuthentication => remoteAuth; + + // public Source Source { get; } + public byte[] Id { get; set; } + public DateTime Creation { get; } + public DateTime Modification { get; } + public KeyList Variables { get; } = new KeyList(); + + //KeyList Variables { get; } + //IStore Store { get; } + + //string id; + Authentication localAuth, remoteAuth; + //string domain; + + public Session(Authentication localAuthentication, Authentication remoteAuthentication) { - public Authentication LocalAuthentication => localAuth; - public Authentication RemoteAuthentication => remoteAuth; - // public Source Source { get; } - public byte[] Id { get; set; } - public DateTime Creation { get; } - public DateTime Modification { get; } - public KeyList Variables {get;} = new KeyList(); - - //KeyList Variables { get; } - //IStore Store { get; } - - //string id; - Authentication localAuth, remoteAuth; - //string domain; - - public Session(Authentication localAuthentication, Authentication remoteAuthentication) - { - - this.localAuth = localAuthentication; - this.remoteAuth = remoteAuthentication; - } + this.localAuth = localAuthentication; + this.remoteAuth = remoteAuthentication; } } diff --git a/Esiur/Security/Authority/Source.cs b/Esiur/Security/Authority/Source.cs index e740f90..52d7a16 100644 --- a/Esiur/Security/Authority/Source.cs +++ b/Esiur/Security/Authority/Source.cs @@ -29,31 +29,30 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Authority +namespace Esiur.Security.Authority; + +public class Source { - public class Source + + //string id; + KeyList attributes; + + public string Id { get; set; } + + public KeyList Attributes { - - //string id; - KeyList attributes; - - public string Id { get; set; } - - public KeyList Attributes - { - get => attributes; - } - - public Source(string id, KeyList attributes) - { - Id = id; - this.attributes = attributes; - } - - public Source() - { - attributes = new KeyList(); - } - + get => attributes; } + + public Source(string id, KeyList attributes) + { + Id = id; + this.attributes = attributes; + } + + public Source() + { + attributes = new KeyList(); + } + } diff --git a/Esiur/Security/Authority/SourceAttributeType.cs b/Esiur/Security/Authority/SourceAttributeType.cs index f773d8b..1e606a0 100644 --- a/Esiur/Security/Authority/SourceAttributeType.cs +++ b/Esiur/Security/Authority/SourceAttributeType.cs @@ -29,52 +29,51 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Authority +namespace Esiur.Security.Authority; + +public enum SourceAttributeType { - public enum SourceAttributeType - { - Mobility, // Stationary/Mobile - CPU, // Arc, Speed, Cores - IPv4, // IPv4, IPv6 Address - IPv6, // IPv4, IPv6 Address - Port, // TCP or UDP port - Proxy, // Proxy - Route, // Trace Root - Location, // Lon, Lat, Alt, Accuracy - OS, // OS name, version, distro, kernel - Application, // lib version, app version - Network, // Bandwidth, MAC, IP, Route - Display, // Screen WxH - Media, // AudioIn, AudioOut, VideoIn, - Identity, // IMEI, IMSI, Manufacture - } - /* - public class SourceAttribute - { - SourceAttributeType type; - Structure value; - - public SourceAttributeType Type - { - get - { - return type; - } - } - - public Structure Value - { - get - { - return value; - } - } - - public SourceAttribute(SourceAttributeType type, Structure value) - { - this.type = type; - this.value = value; - } - } - */ + Mobility, // Stationary/Mobile + CPU, // Arc, Speed, Cores + IPv4, // IPv4, IPv6 Address + IPv6, // IPv4, IPv6 Address + Port, // TCP or UDP port + Proxy, // Proxy + Route, // Trace Root + Location, // Lon, Lat, Alt, Accuracy + OS, // OS name, version, distro, kernel + Application, // lib version, app version + Network, // Bandwidth, MAC, IP, Route + Display, // Screen WxH + Media, // AudioIn, AudioOut, VideoIn, + Identity, // IMEI, IMSI, Manufacture } +/* +public class SourceAttribute +{ + SourceAttributeType type; + Structure value; + + public SourceAttributeType Type + { + get + { + return type; + } + } + + public Structure Value + { + get + { + return value; + } + } + + public SourceAttribute(SourceAttributeType type, Structure value) + { + this.type = type; + this.value = value; + } +} +*/ diff --git a/Esiur/Security/Authority/UserCertificate.cs b/Esiur/Security/Authority/UserCertificate.cs index 6e62678..0feb33c 100644 --- a/Esiur/Security/Authority/UserCertificate.cs +++ b/Esiur/Security/Authority/UserCertificate.cs @@ -33,228 +33,227 @@ using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Authority +namespace Esiur.Security.Authority; + +public class UserCertificate : Certificate { - public class UserCertificate : Certificate + uint ip; + byte[] ip6; + byte[] signature; + string domain; + string username; + ulong domainId; + + public ulong DomainId { - uint ip; - byte[] ip6; - byte[] signature; - string domain; - string username; - ulong domainId; + get { return domainId; } + } - public ulong DomainId + public string Username + { + get { return username; } + } + + public string Domain + { + get { return domain; } + } + + public byte[] Signature + { + get { return signature; } + } + + public uint IPAddress + { + get { return ip; } + } + + public byte[] IPv6Address + { + get { return ip6; } + } + + public UserCertificate(byte[] data, uint offset, uint length, bool privateKeyIncluded = false) + : base(0, DateTime.MinValue, DateTime.MinValue, HashFunctionType.MD5) + { + var oOffset = offset; + + this.id = DC.GetUInt64(data, offset); + offset += 8; + + // load IPs + this.ip = DC.GetUInt32(data, offset); + offset += 4; + ip6 = DC.Clip(data, offset, 16); + offset += 16; + + this.issueDate = DC.GetDateTime(data, offset); + offset += 8; + this.expireDate = DC.GetDateTime(data, offset); + offset += 8; + + this.domainId = DC.GetUInt64(data, offset); + offset += 8; + + this.domain = Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]); + offset += (uint)data[offset] + 1; + + this.username = Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]); + offset += (uint)data[offset] + 1; + + // Hash Function + this.hashFunction = (HashFunctionType)(data[offset++] >> 4); + + // Public Key Encryption Algorithm + var aea = (AsymetricEncryptionAlgorithmType)(data[offset] >> 5); + + if (aea == AsymetricEncryptionAlgorithmType.RSA) { - get { return domainId; } - } - public string Username - { - get { return username; } - } + var key = new RSAParameters(); - public string Domain - { - get { return domain; } - } + uint exponentLength = (uint)data[offset++] & 0x1F; - public byte[] Signature - { - get { return signature; } - } + key.Exponent = DC.Clip(data, offset, exponentLength); + offset += exponentLength; - public uint IPAddress - { - get { return ip; } - } - public byte[] IPv6Address - { - get { return ip6; } - } + uint keySize = DC.GetUInt16(data, offset); + offset += 2; - public UserCertificate(byte[] data, uint offset, uint length, bool privateKeyIncluded = false) - : base(0, DateTime.MinValue, DateTime.MinValue, HashFunctionType.MD5) - { - var oOffset = offset; + key.Modulus = DC.Clip(data, offset, keySize); - this.id = DC.GetUInt64(data, offset); - offset += 8; + offset += keySize; - // load IPs - this.ip = DC.GetUInt32(data, offset); - offset += 4; - ip6 = DC.Clip(data, offset, 16); - offset += 16; + // copy cert data + this.publicRawData = new byte[offset - oOffset]; + Buffer.BlockCopy(data, (int)oOffset, publicRawData, 0, publicRawData.Length); - this.issueDate = DC.GetDateTime(data, offset); - offset += 8; - this.expireDate = DC.GetDateTime(data, offset); - offset += 8; - this.domainId = DC.GetUInt64(data, offset); - offset += 8; - - this.domain = Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]); - offset += (uint)data[offset] + 1; - - this.username = Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]); - offset += (uint)data[offset] + 1; - - // Hash Function - this.hashFunction = (HashFunctionType)(data[offset++] >> 4); - - // Public Key Encryption Algorithm - var aea = (AsymetricEncryptionAlgorithmType)(data[offset] >> 5); - - if (aea == AsymetricEncryptionAlgorithmType.RSA) + if (privateKeyIncluded) { + uint privateKeyLength = (keySize * 3) + (keySize / 2); + uint halfKeySize = keySize / 2; - var key = new RSAParameters(); - - uint exponentLength = (uint)data[offset++] & 0x1F; - - key.Exponent = DC.Clip(data, offset, exponentLength); - offset += exponentLength; - - - uint keySize = DC.GetUInt16(data, offset); - offset += 2; - - key.Modulus = DC.Clip(data, offset, keySize); + this.privateRawData = DC.Clip(data, offset, privateKeyLength); + key.D = DC.Clip(data, offset, keySize); offset += keySize; - - // copy cert data - this.publicRawData = new byte[offset - oOffset]; - Buffer.BlockCopy(data, (int)oOffset, publicRawData, 0, publicRawData.Length); - - - if (privateKeyIncluded) - { - uint privateKeyLength = (keySize * 3) + (keySize / 2); - uint halfKeySize = keySize / 2; - - this.privateRawData = DC.Clip(data, offset, privateKeyLength); - - key.D = DC.Clip(data, offset, keySize); - offset += keySize; - key.DP = DC.Clip(data, offset, halfKeySize); - offset += halfKeySize; - key.DQ = DC.Clip(data, offset, halfKeySize); - offset += halfKeySize; - key.InverseQ = DC.Clip(data, offset, halfKeySize); - offset += halfKeySize; - key.P = DC.Clip(data, offset, halfKeySize); - offset += halfKeySize; - key.Q = DC.Clip(data, offset, halfKeySize); - offset += halfKeySize; - } - - // setup rsa - this.rsa = RSA.Create();// new RSACryptoServiceProvider(); - this.rsa.ImportParameters(key); - - this.signature = DC.Clip(data, offset, length - (offset - oOffset)); + key.DP = DC.Clip(data, offset, halfKeySize); + offset += halfKeySize; + key.DQ = DC.Clip(data, offset, halfKeySize); + offset += halfKeySize; + key.InverseQ = DC.Clip(data, offset, halfKeySize); + offset += halfKeySize; + key.P = DC.Clip(data, offset, halfKeySize); + offset += halfKeySize; + key.Q = DC.Clip(data, offset, halfKeySize); + offset += halfKeySize; } + // setup rsa + this.rsa = RSA.Create();// new RSACryptoServiceProvider(); + this.rsa.ImportParameters(key); + this.signature = DC.Clip(data, offset, length - (offset - oOffset)); } - public UserCertificate(ulong id, string username, DomainCertificate domainCertificate, DateTime issueDate, - DateTime expireDate, HashFunctionType hashFunction = HashFunctionType.SHA1, uint ip = 0, byte[] ip6 = null) - : base(id, issueDate, expireDate, hashFunction) - { - // assign type - var cr = new BinaryList(); - //id - cr.AddUInt64(id); + } - // ip - this.ip = ip; - this.ip6 = ip6; + public UserCertificate(ulong id, string username, DomainCertificate domainCertificate, DateTime issueDate, + DateTime expireDate, HashFunctionType hashFunction = HashFunctionType.SHA1, uint ip = 0, byte[] ip6 = null) + : base(id, issueDate, expireDate, hashFunction) + { + // assign type + var cr = new BinaryList(); - cr.AddUInt32(ip); + //id + cr.AddUInt64(id); + + // ip + this.ip = ip; + this.ip6 = ip6; + + cr.AddUInt32(ip); - if (ip6?.Length == 16) - cr.AddUInt8Array(ip6); - else - cr.AddUInt8Array(new byte[16]); + if (ip6?.Length == 16) + cr.AddUInt8Array(ip6); + else + cr.AddUInt8Array(new byte[16]); - // dates - this.issueDate = DateTime.UtcNow; - this.expireDate = expireDate; + // dates + this.issueDate = DateTime.UtcNow; + this.expireDate = expireDate; - cr.AddDateTime(issueDate) - .AddDateTime(expireDate); + cr.AddDateTime(issueDate) + .AddDateTime(expireDate); - // domain - this.domainId = domainCertificate.Id; - cr.AddUInt64(domainCertificate.Id); - this.domain = domainCertificate.Domain; - cr.AddUInt8((byte)domainCertificate.Domain.Length) - .AddUInt8Array(Encoding.ASCII.GetBytes(domainCertificate.Domain)); + // domain + this.domainId = domainCertificate.Id; + cr.AddUInt64(domainCertificate.Id); + this.domain = domainCertificate.Domain; + cr.AddUInt8((byte)domainCertificate.Domain.Length) + .AddUInt8Array(Encoding.ASCII.GetBytes(domainCertificate.Domain)); - // username - this.username = username; + // username + this.username = username; - cr.AddUInt8((byte)(username.Length)) - .AddUInt8Array(Encoding.ASCII.GetBytes(username)); + cr.AddUInt8((byte)(username.Length)) + .AddUInt8Array(Encoding.ASCII.GetBytes(username)); - // hash function (SHA1) - cr.AddUInt8((byte)((byte)hashFunction << 4));// (byte)0x10); + // hash function (SHA1) + cr.AddUInt8((byte)((byte)hashFunction << 4));// (byte)0x10); - // public key + // public key - rsa = RSA.Create();// new RSACryptoServiceProvider(2048); - rsa.KeySize = 2048; - // write public certificate file + rsa = RSA.Create();// new RSACryptoServiceProvider(2048); + rsa.KeySize = 2048; + // write public certificate file - var key = rsa.ExportParameters(true); - publicRawData = new BinaryList().AddUInt8((byte)key.Exponent.Length) - .AddUInt8Array(key.Exponent) - .AddUInt16((ushort)key.Modulus.Length) - .AddUInt8Array(key.Modulus).ToArray(); + var key = rsa.ExportParameters(true); + publicRawData = new BinaryList().AddUInt8((byte)key.Exponent.Length) + .AddUInt8Array(key.Exponent) + .AddUInt16((ushort)key.Modulus.Length) + .AddUInt8Array(key.Modulus).ToArray(); - // sign it - this.signature = domainCertificate.Sign(publicRawData); + // sign it + this.signature = domainCertificate.Sign(publicRawData); - // store private info - privateRawData = DC.Merge(key.D, key.DP, key.DQ, key.InverseQ, key.P, key.Q, signature); + // store private info + privateRawData = DC.Merge(key.D, key.DP, key.DQ, key.InverseQ, key.P, key.Q, signature); - } + } - public override bool Save(string filename, bool includePrivate = false) - { - try - { - if (includePrivate) - File.WriteAllBytes(filename, DC.Merge(new byte[] { (byte)CertificateType.DomainPrivate }, publicRawData, signature, privateRawData)); - else - File.WriteAllBytes(filename, DC.Merge(new byte[] { (byte)CertificateType.DomainPublic }, publicRawData, signature)); - - return true; - } - catch - { - return false; - } - } - - public override byte[] Serialize(bool includePrivate = false) + public override bool Save(string filename, bool includePrivate = false) + { + try { if (includePrivate) - return DC.Merge(publicRawData, signature, privateRawData); + File.WriteAllBytes(filename, DC.Merge(new byte[] { (byte)CertificateType.DomainPrivate }, publicRawData, signature, privateRawData)); else - return DC.Merge(publicRawData, signature); + File.WriteAllBytes(filename, DC.Merge(new byte[] { (byte)CertificateType.DomainPublic }, publicRawData, signature)); + + return true; + } + catch + { + return false; } } + + public override byte[] Serialize(bool includePrivate = false) + { + if (includePrivate) + return DC.Merge(publicRawData, signature, privateRawData); + else + return DC.Merge(publicRawData, signature); + } } diff --git a/Esiur/Security/Cryptography/AsymetricEncryptionAlgorithmType.cs b/Esiur/Security/Cryptography/AsymetricEncryptionAlgorithmType.cs index a2ee1f0..e1fb36a 100644 --- a/Esiur/Security/Cryptography/AsymetricEncryptionAlgorithmType.cs +++ b/Esiur/Security/Cryptography/AsymetricEncryptionAlgorithmType.cs @@ -28,13 +28,12 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Cryptography +namespace Esiur.Security.Cryptography; + +// Enums +public enum AsymetricEncryptionAlgorithmType { - // Enums - public enum AsymetricEncryptionAlgorithmType - { - RSA = 0, - DSA = 1, - ECDSA = 2 - } + RSA = 0, + DSA = 1, + ECDSA = 2 } diff --git a/Esiur/Security/Cryptography/SymetricEncryptionAlgorithmType.cs b/Esiur/Security/Cryptography/SymetricEncryptionAlgorithmType.cs index e2a4348..0c1f308 100644 --- a/Esiur/Security/Cryptography/SymetricEncryptionAlgorithmType.cs +++ b/Esiur/Security/Cryptography/SymetricEncryptionAlgorithmType.cs @@ -27,12 +27,11 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Cryptography +namespace Esiur.Security.Cryptography; + +public enum SymetricEncryptionAlgorithmType { - public enum SymetricEncryptionAlgorithmType - { - AES = 0, - Blowfish = 1, - DES = 2 - } + AES = 0, + Blowfish = 1, + DES = 2 } diff --git a/Esiur/Security/Integrity/CRC16IBM.cs b/Esiur/Security/Integrity/CRC16IBM.cs index da15d68..565f03e 100644 --- a/Esiur/Security/Integrity/CRC16IBM.cs +++ b/Esiur/Security/Integrity/CRC16IBM.cs @@ -2,12 +2,11 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Security.Integrity -{ +namespace Esiur.Security.Integrity; - public class CRC16IBM - { - static UInt16[] table = { +public class CRC16IBM +{ + static UInt16[] table = { 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, @@ -41,42 +40,40 @@ namespace Esiur.Security.Integrity 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040}; - public static ushort Compute(byte[] data) + public static ushort Compute(byte[] data) + { + return Compute(data, 0, (uint)data.Length); + } + + + public static ushort Compute(byte[] data, uint offset, uint length) + { + ushort crc = 0;// 0xffff; + ushort x; + for (var i = offset; i < length; i++) { - return Compute(data, 0, (uint)data.Length); + x = (ushort)(crc ^ data[i]); + crc = (UInt16)((crc >> 8) ^ table[x & 0x00FF]); } + return crc; + } - public static ushort Compute(byte[] data, uint offset, uint length) + public static ushort Compute2(byte[] data, uint offset, uint length) + { + ushort crc = 0; + for (var i = offset; i < length; i++) { - ushort crc = 0;// 0xffff; - ushort x; - for (var i = offset; i < length; i++) + crc ^= data[i]; + + for (var j = 0; j < 8; j++) { - x = (ushort)(crc ^ data[i]); - crc = (UInt16)((crc >> 8) ^ table[x & 0x00FF]); + var carry = crc & 0x1; + crc >>= 1; + if (carry == 1) + crc ^= 0xa001; } - - return crc; - } - - public static ushort Compute2(byte[] data, uint offset, uint length) - { - ushort crc = 0; - for (var i = offset; i < length; i++) - { - crc ^= data[i]; - - for (var j = 0; j < 8; j++) - { - var carry = crc & 0x1; - crc >>= 1; - if (carry == 1) - crc ^= 0xa001; - } - } - return crc; } + return crc; } } - diff --git a/Esiur/Security/Integrity/CRC16ITU.cs b/Esiur/Security/Integrity/CRC16ITU.cs index 0f25819..2d7384a 100644 --- a/Esiur/Security/Integrity/CRC16ITU.cs +++ b/Esiur/Security/Integrity/CRC16ITU.cs @@ -2,12 +2,11 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Security.Integrity -{ +namespace Esiur.Security.Integrity; - public class CRC16ITU - { - static UInt16[] table = +public class CRC16ITU +{ + static UInt16[] table = { 0X0000, 0X1189, 0X2312, 0X329B, 0X4624, 0X57AD, 0X6536, 0X74BF, 0X8C48, 0X9DC1, 0XAF5A, 0XBED3, 0XCA6C, 0XDBE5, 0XE97E, 0XF8F7, @@ -44,23 +43,22 @@ namespace Esiur.Security.Integrity }; - public static ushort Compute(byte[] data) + public static ushort Compute(byte[] data) + { + return Compute(data, 0, (uint)data.Length); + } + + + public static ushort Compute(byte[] data, uint offset, uint length) + { + ushort fcs = 0xffff; // initialization + while (length > 0) { - return Compute(data, 0, (uint)data.Length); + fcs = (ushort)((fcs >> 8) ^ table[(fcs ^ data[offset++]) & 0xff]); + length--; } - - - public static ushort Compute(byte[] data, uint offset, uint length) - { - ushort fcs = 0xffff; // initialization - while (length > 0) - { - fcs = (ushort)((fcs >> 8) ^ table[(fcs ^ data[offset++]) & 0xff]); - length--; - } - return (ushort)~fcs; // negated - } - + return (ushort)~fcs; // negated } } + diff --git a/Esiur/Security/Integrity/HashFunctionType.cs b/Esiur/Security/Integrity/HashFunctionType.cs index b1e1ac9..2bcbf48 100644 --- a/Esiur/Security/Integrity/HashFunctionType.cs +++ b/Esiur/Security/Integrity/HashFunctionType.cs @@ -28,14 +28,13 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Integrity +namespace Esiur.Security.Integrity; + +public enum HashFunctionType { - public enum HashFunctionType - { - MD5 = 0, - SHA1, - SHA256, - SHA384, - SHA512 - } + MD5 = 0, + SHA1, + SHA256, + SHA384, + SHA512 } diff --git a/Esiur/Security/Integrity/NMEA0183.cs b/Esiur/Security/Integrity/NMEA0183.cs index 277106b..575b8dc 100644 --- a/Esiur/Security/Integrity/NMEA0183.cs +++ b/Esiur/Security/Integrity/NMEA0183.cs @@ -2,25 +2,23 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Security.Integrity +namespace Esiur.Security.Integrity; + +public class NMEA0183 { - - public class NMEA0183 + public static byte Compute(string data) { - public static byte Compute(string data) - { - return Compute(data, 0, (uint)data.Length); - } - - public static byte Compute(string data, uint offset, uint length) - { - byte rt = 0; - var ends = offset + length; - for (int i = (int)offset; i < ends; i++) - rt ^= (byte)data[i]; - - return rt; - } + return Compute(data, 0, (uint)data.Length); } + public static byte Compute(string data, uint offset, uint length) + { + byte rt = 0; + var ends = offset + length; + for (int i = (int)offset; i < ends; i++) + rt ^= (byte)data[i]; + + return rt; + } } + diff --git a/Esiur/Security/Integrity/SHA256.cs b/Esiur/Security/Integrity/SHA256.cs index 3e2541e..887e1b3 100644 --- a/Esiur/Security/Integrity/SHA256.cs +++ b/Esiur/Security/Integrity/SHA256.cs @@ -3,35 +3,34 @@ using System; using System.Collections.Generic; using System.Text; -namespace Esiur.Security.Integrity +namespace Esiur.Security.Integrity; +public static class SHA256 { - public static class SHA256 + + static uint RROT(uint n, int d) { + return (n >> d) | (n << (32 - d)); + } - static uint RROT(uint n, int d) - { - return (n >> d) | (n << (32 - d)); - } + public static byte[] Compute(byte[] msg) + { + /* + Note 1: All variables are 32 bit unsigned integers and addition is calculated modulo 2^32 + Note 2: For each round, there is one round constant k[i] and one entry in the message schedule array w[i], 0 ≤ i ≤ 63 + Note 3: The compression function uses 8 working variables, a through h + Note 4: Big-endian convention is used when expressing the constants in this pseudocode, + and when parsing message block data from bytes to words, for example, + the first word of the input message "abc" after padding is 0x61626380 + */ - public static byte[] Compute(byte[] msg) - { - /* - Note 1: All variables are 32 bit unsigned integers and addition is calculated modulo 2^32 - Note 2: For each round, there is one round constant k[i] and one entry in the message schedule array w[i], 0 ≤ i ≤ 63 - Note 3: The compression function uses 8 working variables, a through h - Note 4: Big-endian convention is used when expressing the constants in this pseudocode, - and when parsing message block data from bytes to words, for example, - the first word of the input message "abc" after padding is 0x61626380 - */ + // Initialize hash values: + // (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19): - // Initialize hash values: - // (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19): + var hash = new uint[] { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 }; - var hash = new uint[] { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 }; - - // Initialize array of round constants: - // (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311): - var k = new uint[] { + // Initialize array of round constants: + // (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311): + var k = new uint[] { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, @@ -43,115 +42,114 @@ namespace Esiur.Security.Integrity - // Pre-processing: - // begin with the original message of length L bits - ulong L = (ulong)msg.Length * 8; + // Pre-processing: + // begin with the original message of length L bits + ulong L = (ulong)msg.Length * 8; - // append a single '1' bit - // append K '0' bits, where K is the minimum number >= 0 such that L + 1 + K + 64 is a multiple of 512 + // append a single '1' bit + // append K '0' bits, where K is the minimum number >= 0 such that L + 1 + K + 64 is a multiple of 512 - var K = 512 - ((L + 1 + 64) % 512); + var K = 512 - ((L + 1 + 64) % 512); - if (K == 512) - K = 0; + if (K == 512) + K = 0; - var paddingLength = (K + 1) / 8; - var paddingBytes = new byte[paddingLength]; - paddingBytes[0] = 0x80; + var paddingLength = (K + 1) / 8; + var paddingBytes = new byte[paddingLength]; + paddingBytes[0] = 0x80; - var data = new BinaryList().AddUInt8Array(msg).AddUInt8Array(paddingBytes).AddUInt64(L).ToArray(); + var data = new BinaryList().AddUInt8Array(msg).AddUInt8Array(paddingBytes).AddUInt64(L).ToArray(); - // append L as a 64-bit big-endian integer, making the total post-processed length a multiple of 512 bits + // append L as a 64-bit big-endian integer, making the total post-processed length a multiple of 512 bits - // Process the message in successive 512-bit chunks: - // break message into 512-bit chunks - // for each chunk + // Process the message in successive 512-bit chunks: + // break message into 512-bit chunks + // for each chunk - for (var chunk = 0; chunk < data.Length; chunk += 64) + for (var chunk = 0; chunk < data.Length; chunk += 64) + { + // create a 64-entry message schedule array w[0..63] of 32-bit words + // (The initial values in w[0..63] don't matter, so many implementations zero them here) + // copy chunk into first 16 words w[0..15] of the message schedule array + + var w = new uint[64]; + for (var i = 0; i < 16; i++) + w[i] = data.GetUInt32((uint)(chunk + (i * 4))); + + //for(var i = 16; i < 64; i++) + // w[i] = 0; + + // Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array: + // for i from 16 to 63 + // s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3) + // s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10) + // w[i] := w[i-16] + s0 + w[i-7] + s1 + + for (var i = 16; i < 64; i++) { - // create a 64-entry message schedule array w[0..63] of 32-bit words - // (The initial values in w[0..63] don't matter, so many implementations zero them here) - // copy chunk into first 16 words w[0..15] of the message schedule array - - var w = new uint[64]; - for (var i = 0; i < 16; i++) - w[i] = data.GetUInt32((uint)(chunk + (i * 4))); - - //for(var i = 16; i < 64; i++) - // w[i] = 0; - - // Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array: - // for i from 16 to 63 - // s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3) - // s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10) - // w[i] := w[i-16] + s0 + w[i-7] + s1 - - for (var i = 16; i < 64; i++) - { - var s0 = SHA256.RROT(w[i - 15], 7) ^ SHA256.RROT(w[i - 15], 18) ^ (w[i - 15] >> 3); - var s1 = SHA256.RROT(w[i - 2], 17) ^ SHA256.RROT(w[i - 2], 19) ^ (w[i - 2] >> 10); - w[i] = w[i - 16] + s0 + w[i - 7] + s1; - } - - // Initialize working variables to current hash value: - var a = hash[0]; - var b = hash[1]; - var c = hash[2]; - var d = hash[3]; - var e = hash[4]; - var f = hash[5]; - var g = hash[6]; - var h = hash[7]; - - - // Compression function main loop: - for (var i = 0; i < 64; i++) - { - var S1 = SHA256.RROT(e, 6) ^ SHA256.RROT(e, 11) ^ SHA256.RROT(e, 25); - var ch = (e & f) ^ ((~e) & g); - var temp1 = h + S1 + ch + k[i] + w[i]; - var S0 = SHA256.RROT(a, 2) ^ SHA256.RROT(a, 13) ^ SHA256.RROT(a, 22); - var maj = (a & b) ^ (a & c) ^ (b & c); - uint temp2 = S0 + maj; - - h = g; - g = f; - f = e; - e = (d + temp1) >> 0; - d = c; - c = b; - b = a; - a = (temp1 + temp2) >> 0; - } - - // Add the compressed chunk to the current hash value: - - hash[0] = (hash[0] + a) >> 0; - hash[1] = (hash[1] + b) >> 0; - hash[2] = (hash[2] + c) >> 0; - hash[3] = (hash[3] + d) >> 0; - hash[4] = (hash[4] + e) >> 0; - hash[5] = (hash[5] + f) >> 0; - hash[6] = (hash[6] + g) >> 0; - hash[7] = (hash[7] + h) >> 0; - - + var s0 = SHA256.RROT(w[i - 15], 7) ^ SHA256.RROT(w[i - 15], 18) ^ (w[i - 15] >> 3); + var s1 = SHA256.RROT(w[i - 2], 17) ^ SHA256.RROT(w[i - 2], 19) ^ (w[i - 2] >> 10); + w[i] = w[i - 16] + s0 + w[i - 7] + s1; } + // Initialize working variables to current hash value: + var a = hash[0]; + var b = hash[1]; + var c = hash[2]; + var d = hash[3]; + var e = hash[4]; + var f = hash[5]; + var g = hash[6]; + var h = hash[7]; + // Compression function main loop: + for (var i = 0; i < 64; i++) + { + var S1 = SHA256.RROT(e, 6) ^ SHA256.RROT(e, 11) ^ SHA256.RROT(e, 25); + var ch = (e & f) ^ ((~e) & g); + var temp1 = h + S1 + ch + k[i] + w[i]; + var S0 = SHA256.RROT(a, 2) ^ SHA256.RROT(a, 13) ^ SHA256.RROT(a, 22); + var maj = (a & b) ^ (a & c) ^ (b & c); + uint temp2 = S0 + maj; - // Produce the final hash value (big-endian): - //digest := hash := h0 append h1 append h2 append h3 append h4 append h5 append h6 append h7 + h = g; + g = f; + f = e; + e = (d + temp1) >> 0; + d = c; + c = b; + b = a; + a = (temp1 + temp2) >> 0; + } - var results = new BinaryList(); - for (var i = 0; i < 8; i++) - results.AddUInt32(hash[i]); + // Add the compressed chunk to the current hash value: + + hash[0] = (hash[0] + a) >> 0; + hash[1] = (hash[1] + b) >> 0; + hash[2] = (hash[2] + c) >> 0; + hash[3] = (hash[3] + d) >> 0; + hash[4] = (hash[4] + e) >> 0; + hash[5] = (hash[5] + f) >> 0; + hash[6] = (hash[6] + g) >> 0; + hash[7] = (hash[7] + h) >> 0; - return results.ToArray(); } + + + + + // Produce the final hash value (big-endian): + //digest := hash := h0 append h1 append h2 append h3 append h4 append h5 append h6 append h7 + + var results = new BinaryList(); + for (var i = 0; i < 8; i++) + results.AddUInt32(hash[i]); + + + return results.ToArray(); } } diff --git a/Esiur/Security/Membership/IDomain.cs b/Esiur/Security/Membership/IDomain.cs index c58d11b..d0ce488 100644 --- a/Esiur/Security/Membership/IDomain.cs +++ b/Esiur/Security/Membership/IDomain.cs @@ -30,11 +30,10 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Authority +namespace Esiur.Authority; + +public interface IDomain : IResource { - public interface IDomain : IResource - { - string Name { get; } - DomainCertificate Certificate { get; } - } + string Name { get; } + DomainCertificate Certificate { get; } } diff --git a/Esiur/Security/Membership/IMembership.cs b/Esiur/Security/Membership/IMembership.cs index 51fa0be..33d5597 100644 --- a/Esiur/Security/Membership/IMembership.cs +++ b/Esiur/Security/Membership/IMembership.cs @@ -33,16 +33,15 @@ using Esiur.Core; using Esiur.Security.Authority; using Esiur.Resource; -namespace Esiur.Security.Membership +namespace Esiur.Security.Membership; + +public interface IMembership { - public interface IMembership - { - AsyncReply UserExists(string username, string domain); - AsyncReply GetPassword(string username, string domain); - AsyncReply GetToken(ulong tokenIndex, string domain); - AsyncReply Login(Session session); - AsyncReply Logout(Session session); - bool GuestsAllowed { get; } - AsyncReply TokenExists(ulong tokenIndex, string domain); - } + AsyncReply UserExists(string username, string domain); + AsyncReply GetPassword(string username, string domain); + AsyncReply GetToken(ulong tokenIndex, string domain); + AsyncReply Login(Session session); + AsyncReply Logout(Session session); + bool GuestsAllowed { get; } + AsyncReply TokenExists(ulong tokenIndex, string domain); } diff --git a/Esiur/Security/Membership/IUser.cs b/Esiur/Security/Membership/IUser.cs index e354baf..ee41581 100644 --- a/Esiur/Security/Membership/IUser.cs +++ b/Esiur/Security/Membership/IUser.cs @@ -29,13 +29,12 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Membership +namespace Esiur.Security.Membership; + +public interface IUser { - public interface IUser + string Username { - string Username - { - get; - } + get; } } diff --git a/Esiur/Security/Permissions/ActionType.cs b/Esiur/Security/Permissions/ActionType.cs index 678fc0b..617e2a1 100644 --- a/Esiur/Security/Permissions/ActionType.cs +++ b/Esiur/Security/Permissions/ActionType.cs @@ -28,24 +28,23 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Permissions +namespace Esiur.Security.Permissions; + +public enum ActionType { - public enum ActionType - { - Attach, - Delete, - Execute, - GetProperty, - SetProperty, - CreateResource, - UpdateAttributes, - InquireAttributes, - AddParent, - RemoveParent, - AddChild, - RemoveChild, - Rename, - ReceiveEvent, - ViewTemplate - } + Attach, + Delete, + Execute, + GetProperty, + SetProperty, + CreateResource, + UpdateAttributes, + InquireAttributes, + AddParent, + RemoveParent, + AddChild, + RemoveChild, + Rename, + ReceiveEvent, + ViewTemplate } diff --git a/Esiur/Security/Permissions/IPermissionsManager.cs b/Esiur/Security/Permissions/IPermissionsManager.cs index fca2d65..7e2efde 100644 --- a/Esiur/Security/Permissions/IPermissionsManager.cs +++ b/Esiur/Security/Permissions/IPermissionsManager.cs @@ -34,23 +34,22 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Esiur.Security.Permissions +namespace Esiur.Security.Permissions; + +public interface IPermissionsManager { - public interface IPermissionsManager - { - /// - /// Check for permission. - /// - /// IResource. - /// Caller sessions. - /// Action type - /// Function, property or event to check for permission. - /// Permission inquirer object. - /// Allowed or denined. - Ruling Applicable(IResource resource, Session session, ActionType action, MemberTemplate member, object inquirer = null); + /// + /// Check for permission. + /// + /// IResource. + /// Caller sessions. + /// Action type + /// Function, property or event to check for permission. + /// Permission inquirer object. + /// Allowed or denined. + Ruling Applicable(IResource resource, Session session, ActionType action, MemberTemplate member, object inquirer = null); - bool Initialize(Structure settings, IResource resource); + bool Initialize(Structure settings, IResource resource); - Structure Settings { get; } - } + Structure Settings { get; } } diff --git a/Esiur/Security/Permissions/Ruling.cs b/Esiur/Security/Permissions/Ruling.cs index d87cf75..f0bd840 100644 --- a/Esiur/Security/Permissions/Ruling.cs +++ b/Esiur/Security/Permissions/Ruling.cs @@ -2,12 +2,11 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Security.Permissions +namespace Esiur.Security.Permissions; + +public enum Ruling { - public enum Ruling - { - Denied, - Allowed, - DontCare - } + Denied, + Allowed, + DontCare } diff --git a/Esiur/Security/Permissions/StorePermissionsManager.cs b/Esiur/Security/Permissions/StorePermissionsManager.cs index 9a29156..190661a 100644 --- a/Esiur/Security/Permissions/StorePermissionsManager.cs +++ b/Esiur/Security/Permissions/StorePermissionsManager.cs @@ -31,23 +31,22 @@ using Esiur.Resource; using Esiur.Resource.Template; using Esiur.Security.Authority; -namespace Esiur.Security.Permissions +namespace Esiur.Security.Permissions; + +public class StorePermissionsManager : IPermissionsManager { - public class StorePermissionsManager : IPermissionsManager + Structure settings; + + public Structure Settings => settings; + + public Ruling Applicable(IResource resource, Session session, ActionType action, MemberTemplate member, object inquirer = null) { - Structure settings; + return resource.Instance.Store.Instance.Applicable(session, action, member, inquirer); + } - public Structure Settings => settings; - - public Ruling Applicable(IResource resource, Session session, ActionType action, MemberTemplate member, object inquirer = null) - { - return resource.Instance.Store.Instance.Applicable(session, action, member, inquirer); - } - - public bool Initialize(Structure settings, IResource resource) - { - this.settings = settings; - return true; - } + public bool Initialize(Structure settings, IResource resource) + { + this.settings = settings; + return true; } } diff --git a/Esiur/Security/Permissions/UserPermissionsManager.cs b/Esiur/Security/Permissions/UserPermissionsManager.cs index e318bb0..3ddb23e 100644 --- a/Esiur/Security/Permissions/UserPermissionsManager.cs +++ b/Esiur/Security/Permissions/UserPermissionsManager.cs @@ -31,96 +31,95 @@ using Esiur.Resource; using Esiur.Resource.Template; using Esiur.Security.Authority; -namespace Esiur.Security.Permissions +namespace Esiur.Security.Permissions; + +public class UserPermissionsManager : IPermissionsManager { - public class UserPermissionsManager : IPermissionsManager + IResource resource; + Structure settings; + + public Structure Settings => settings; + + public Ruling Applicable(IResource resource, Session session, ActionType action, MemberTemplate member, object inquirer) { - IResource resource; - Structure settings; + Structure userPermissions = null; - public Structure Settings => settings; + if (settings.ContainsKey(session.RemoteAuthentication.FullName)) + userPermissions = settings[session.RemoteAuthentication.FullName] as Structure; + else if (settings.ContainsKey("public")) + userPermissions = settings["public"] as Structure; + else + return Ruling.Denied; - public Ruling Applicable(IResource resource, Session session, ActionType action, MemberTemplate member, object inquirer) + if (action == ActionType.Attach)// || action == ActionType.Delete) { - Structure userPermissions = null; - - if (settings.ContainsKey(session.RemoteAuthentication.FullName)) - userPermissions = settings[session.RemoteAuthentication.FullName] as Structure; - else if (settings.ContainsKey("public")) - userPermissions = settings["public"] as Structure; - else + if ((string)userPermissions["_attach"] != "yes") return Ruling.Denied; - - if (action == ActionType.Attach)// || action == ActionType.Delete) - { - if ((string)userPermissions["_attach"] != "yes") - return Ruling.Denied; - } - else if (action == ActionType.Delete) - { - if ((string)userPermissions["_delete"] != "yes") - return Ruling.Denied; - } - else if (action== ActionType.InquireAttributes) - { - if ((string)userPermissions["_get_attributes"] == "yes") - return Ruling.Denied; - } - else if (action == ActionType.UpdateAttributes) - { - if ((string)userPermissions["_set_attributes"] != "yes") - return Ruling.Denied; - } - else if (action == ActionType.AddChild) - { - if ((string)userPermissions["_add_child"] != "yes") - return Ruling.Denied; - } - else if (action == ActionType.RemoveChild) - { - if ((string)userPermissions["_remove_child"] != "yes") - return Ruling.Denied; - } - else if (action == ActionType.AddParent) - { - if ((string)userPermissions["_add_parent"] != "yes") - return Ruling.Denied; - } - else if (action == ActionType.RemoveParent) - { - if ((string)userPermissions["_remove_parent"] != "yes") - return Ruling.Denied; - } - else if (action == ActionType.Rename) - { - if ((string)userPermissions["_rename"] != "yes") - return Ruling.Denied; - } - else if (userPermissions.ContainsKey(member?.Name)) - { - Structure methodPermissions = userPermissions[member.Name] as Structure; - if ((string)methodPermissions[action.ToString()] != "yes") - return Ruling.Denied; - } - - return Ruling.DontCare; } - - public UserPermissionsManager() + else if (action == ActionType.Delete) { - + if ((string)userPermissions["_delete"] != "yes") + return Ruling.Denied; } - - public UserPermissionsManager(Structure settings) + else if (action == ActionType.InquireAttributes) { - this.settings = settings; + if ((string)userPermissions["_get_attributes"] == "yes") + return Ruling.Denied; + } + else if (action == ActionType.UpdateAttributes) + { + if ((string)userPermissions["_set_attributes"] != "yes") + return Ruling.Denied; + } + else if (action == ActionType.AddChild) + { + if ((string)userPermissions["_add_child"] != "yes") + return Ruling.Denied; + } + else if (action == ActionType.RemoveChild) + { + if ((string)userPermissions["_remove_child"] != "yes") + return Ruling.Denied; + } + else if (action == ActionType.AddParent) + { + if ((string)userPermissions["_add_parent"] != "yes") + return Ruling.Denied; + } + else if (action == ActionType.RemoveParent) + { + if ((string)userPermissions["_remove_parent"] != "yes") + return Ruling.Denied; + } + else if (action == ActionType.Rename) + { + if ((string)userPermissions["_rename"] != "yes") + return Ruling.Denied; + } + else if (userPermissions.ContainsKey(member?.Name)) + { + Structure methodPermissions = userPermissions[member.Name] as Structure; + if ((string)methodPermissions[action.ToString()] != "yes") + return Ruling.Denied; } - public bool Initialize(Structure settings, IResource resource) - { - this.resource = resource; - this.settings = settings; - return true; - } + return Ruling.DontCare; + } + + public UserPermissionsManager() + { + + } + + public UserPermissionsManager(Structure settings) + { + this.settings = settings; + } + + public bool Initialize(Structure settings, IResource resource) + { + this.resource = resource; + this.settings = settings; + return true; } } diff --git a/Esiur/Stores/MemoryStore.cs b/Esiur/Stores/MemoryStore.cs index 631775b..67f50e5 100644 --- a/Esiur/Stores/MemoryStore.cs +++ b/Esiur/Stores/MemoryStore.cs @@ -8,140 +8,139 @@ using Esiur.Core; using Esiur.Data; using Esiur.Resource.Template; -namespace Esiur.Stores +namespace Esiur.Stores; + +public class MemoryStore : IStore { - public class MemoryStore : IStore + public Instance Instance { get; set; } + + public event DestroyedEvent OnDestroy; + + KeyList resources = new KeyList(); + + public void Destroy() { - public Instance Instance { get; set; } + OnDestroy?.Invoke(this); + } - public event DestroyedEvent OnDestroy; + public string Link(IResource resource) + { + if (resource.Instance.Store == this) + return this.Instance.Name + "/" + resource.Instance.Id; - KeyList resources = new KeyList(); + return null; + } - public void Destroy() + public AsyncReply Get(string path) + { + foreach (var r in resources) + if (r.Value.Instance.Name == path) + return new AsyncReply(r.Value); + + + return new AsyncReply(null); + } + + public AsyncReply Put(IResource resource) + { + + resources.Add(resource.Instance.Id, resource);// new WeakReference(resource)); + resource.Instance.Variables["children"] = new AutoList(resource.Instance); + resource.Instance.Variables["parents"] = new AutoList(resource.Instance); + + return new AsyncReply(true); + } + + public AsyncReply Retrieve(uint iid) + { + if (resources.ContainsKey(iid)) { - OnDestroy?.Invoke(this); - } - - public string Link(IResource resource) - { - if (resource.Instance.Store == this) - return this.Instance.Name + "/" + resource.Instance.Id; - - return null; - } - - public AsyncReply Get(string path) - { - foreach (var r in resources) - if (r.Value.Instance.Name == path) - return new AsyncReply(r.Value); - - - return new AsyncReply(null); - } - - public AsyncReply Put(IResource resource) - { - - resources.Add(resource.Instance.Id, resource);// new WeakReference(resource)); - resource.Instance.Variables["children"] = new AutoList(resource.Instance); - resource.Instance.Variables["parents"] = new AutoList(resource.Instance); - - return new AsyncReply(true); - } - - public AsyncReply Retrieve(uint iid) - { - if (resources.ContainsKey(iid)) - { - if (resources.ContainsKey(iid))// .TryGetTarget(out r)) - return new AsyncReply(resources[iid]); - else - return new AsyncReply(null); - } + if (resources.ContainsKey(iid))// .TryGetTarget(out r)) + return new AsyncReply(resources[iid]); else return new AsyncReply(null); } + else + return new AsyncReply(null); + } - public AsyncReply Trigger(ResourceTrigger trigger) + public AsyncReply Trigger(ResourceTrigger trigger) + { + return new AsyncReply(true); + } + + public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + { + throw new NotImplementedException(); + } + + public AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate) + { + throw new NotImplementedException(); + } + + public bool Remove(IResource resource) + { + resources.Remove(resource.Instance.Id); + return true; + } + + public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + { + return true; + } + + public AsyncReply AddChild(IResource parent, IResource child) + { + if (parent.Instance.Store == this) { + (parent.Instance.Variables["children"] as AutoList).Add(child); return new AsyncReply(true); } + else + return new AsyncReply(false); + } - public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + public AsyncReply RemoveChild(IResource parent, IResource child) + { + throw new NotImplementedException(); + } + + public AsyncReply AddParent(IResource resource, IResource parent) + { + + if (resource.Instance.Store == this) { - throw new NotImplementedException(); + (resource.Instance.Variables["parents"] as AutoList).Add(parent); + return new AsyncReply(true); } + else + return new AsyncReply(false); + } - public AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate) - { - throw new NotImplementedException(); - } + public AsyncReply RemoveParent(IResource child, IResource parent) + { + throw new NotImplementedException(); + } - public bool Remove(IResource resource) - { - resources.Remove(resource.Instance.Id); - return true; - } + public AsyncBag Children(IResource resource, string name) where T : IResource + { + var children = (resource.Instance.Variables["children"] as AutoList); - public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) - { - return true; - } + if (name == null) + return new AsyncBag(children.Where(x => x is T).Select(x => (T)x).ToArray()); + else + return new AsyncBag(children.Where(x => x is T && x.Instance.Name == name).Select(x => (T)x).ToArray()); - public AsyncReply AddChild(IResource parent, IResource child) - { - if (parent.Instance.Store == this) - { - (parent.Instance.Variables["children"] as AutoList).Add(child); - return new AsyncReply(true); - } - else - return new AsyncReply(false); - } + } - public AsyncReply RemoveChild(IResource parent, IResource child) - { - throw new NotImplementedException(); - } + public AsyncBag Parents(IResource resource, string name) where T : IResource + { + var parents = (resource.Instance.Variables["parents"] as AutoList); - public AsyncReply AddParent(IResource resource, IResource parent) - { - - if (resource.Instance.Store == this) - { - (resource.Instance.Variables["parents"] as AutoList).Add(parent); - return new AsyncReply(true); - } - else - return new AsyncReply(false); - } - - public AsyncReply RemoveParent(IResource child, IResource parent) - { - throw new NotImplementedException(); - } - - public AsyncBag Children(IResource resource, string name) where T : IResource - { - var children = (resource.Instance.Variables["children"] as AutoList); - - if (name == null) - return new AsyncBag(children.Where(x=>x is T).Select(x=>(T)x).ToArray()); - else - return new AsyncBag(children.Where(x => x is T && x.Instance.Name == name).Select(x => (T)x).ToArray()); - - } - - public AsyncBag Parents(IResource resource, string name) where T : IResource - { - var parents = (resource.Instance.Variables["parents"] as AutoList); - - if (name == null) - return new AsyncBag(parents.Where(x => x is T).Select(x => (T)x).ToArray()); - else - return new AsyncBag(parents.Where(x => x is T && x.Instance.Name == name).Select(x => (T)x).ToArray()); - } + if (name == null) + return new AsyncBag(parents.Where(x => x is T).Select(x => (T)x).ToArray()); + else + return new AsyncBag(parents.Where(x => x is T && x.Instance.Name == name).Select(x => (T)x).ToArray()); } } diff --git a/Esiur/Stores/TemporaryStore.cs b/Esiur/Stores/TemporaryStore.cs index c11ba98..b3e74d1 100644 --- a/Esiur/Stores/TemporaryStore.cs +++ b/Esiur/Stores/TemporaryStore.cs @@ -8,112 +8,110 @@ using Esiur.Core; using Esiur.Data; using Esiur.Resource.Template; -namespace Esiur.Stores +namespace Esiur.Stores; +public class TemporaryStore : IStore { - public class TemporaryStore : IStore + public Instance Instance { get; set; } + + public event DestroyedEvent OnDestroy; + + Dictionary resources = new Dictionary(); + + public void Destroy() { - public Instance Instance { get; set; } + OnDestroy?.Invoke(this); - public event DestroyedEvent OnDestroy; + } - Dictionary resources = new Dictionary(); + public string Link(IResource resource) + { + if (resource.Instance.Store == this) + return this.Instance.Name + "/" + resource.Instance.Id; - public void Destroy() + return null; + } + + public AsyncReply Get(string path) + { + foreach (var r in resources) + if (r.Value.IsAlive && (r.Value.Target as IResource).Instance.Name == path) + return new AsyncReply(r.Value.Target as IResource); + + return new AsyncReply(null); + } + + public AsyncReply Put(IResource resource) + { + resources.Add(resource.Instance.Id, new WeakReference(resource));// new WeakReference(resource)); + return new AsyncReply(true); + } + + public AsyncReply Retrieve(uint iid) + { + if (resources.ContainsKey(iid)) { - OnDestroy?.Invoke(this); - - } - - public string Link(IResource resource) - { - if (resource.Instance.Store == this) - return this.Instance.Name + "/" + resource.Instance.Id; - - return null; - } - - public AsyncReply Get(string path) - { - foreach (var r in resources) - if (r.Value.IsAlive && (r.Value.Target as IResource).Instance.Name == path) - return new AsyncReply(r.Value.Target as IResource); - - return new AsyncReply(null); - } - - public AsyncReply Put(IResource resource) - { - resources.Add(resource.Instance.Id, new WeakReference( resource));// new WeakReference(resource)); - return new AsyncReply(true); - } - - public AsyncReply Retrieve(uint iid) - { - if (resources.ContainsKey(iid)) - { - if (resources.ContainsKey(iid) && resources[iid].IsAlive)// .TryGetTarget(out r)) - return new AsyncReply(resources[iid].Target as IResource); - else - return new AsyncReply(null); - } + if (resources.ContainsKey(iid) && resources[iid].IsAlive)// .TryGetTarget(out r)) + return new AsyncReply(resources[iid].Target as IResource); else return new AsyncReply(null); } + else + return new AsyncReply(null); + } - public AsyncReply Trigger(ResourceTrigger trigger) - { - return new AsyncReply(true); - } + public AsyncReply Trigger(ResourceTrigger trigger) + { + return new AsyncReply(true); + } - public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) - { - throw new NotImplementedException(); - } + public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + { + throw new NotImplementedException(); + } - public AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate) - { - throw new NotImplementedException(); - } + public AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate) + { + throw new NotImplementedException(); + } - public bool Remove(IResource resource) - { - resources.Remove(resource.Instance.Id); - return true; - } + public bool Remove(IResource resource) + { + resources.Remove(resource.Instance.Id); + return true; + } - public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) - { - return true; - } + public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + { + return true; + } - public AsyncReply AddChild(IResource parent, IResource child) - { - throw new NotImplementedException(); - } + public AsyncReply AddChild(IResource parent, IResource child) + { + throw new NotImplementedException(); + } - public AsyncReply RemoveChild(IResource parent, IResource child) - { - throw new NotImplementedException(); - } + public AsyncReply RemoveChild(IResource parent, IResource child) + { + throw new NotImplementedException(); + } - public AsyncReply AddParent(IResource child, IResource parent) - { - throw new NotImplementedException(); - } + public AsyncReply AddParent(IResource child, IResource parent) + { + throw new NotImplementedException(); + } - public AsyncReply RemoveParent(IResource child, IResource parent) - { - throw new NotImplementedException(); - } + public AsyncReply RemoveParent(IResource child, IResource parent) + { + throw new NotImplementedException(); + } - public AsyncBag Children(IResource resource, string name) where T : IResource - { - throw new NotImplementedException(); - } + public AsyncBag Children(IResource resource, string name) where T : IResource + { + throw new NotImplementedException(); + } - public AsyncBag Parents(IResource resource, string name) where T : IResource - { - throw new NotImplementedException(); - } + public AsyncBag Parents(IResource resource, string name) where T : IResource + { + throw new NotImplementedException(); } }