2
0
mirror of https://github.com/esiur/esiur-dotnet.git synced 2025-05-06 03:32:57 +00:00

.Net 6 Upgrade

This commit is contained in:
Ahmed Zamil 2021-12-01 12:17:45 +03:00
parent 1166e93ba9
commit 530df018ec
164 changed files with 21247 additions and 21425 deletions

View File

@ -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<bool> Trigger(ResourceTrigger trigger)
{
if (trigger == ResourceTrigger.Initialize)
Create();
return new AsyncReply<bool>(true);
}
public void Destroy()
{
OnDestroy?.Invoke(this);
}
}
protected virtual void Create()
{
}
public AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
if (trigger == ResourceTrigger.Initialize)
Create();
return new AsyncReply<bool>(true);
}
public void Destroy()
{
OnDestroy?.Invoke(this);
}
}

View File

@ -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<Type, Dictionary<object, WeakReference>> DB = new Dictionary<Type, Dictionary<object, WeakReference>>();
object DBLock = new object();
Dictionary<string, EntityTypeInfo> TypesByName = new Dictionary<string, EntityTypeInfo>();
internal Dictionary<Type, EntityTypeInfo> TypesByType = new Dictionary<Type, EntityTypeInfo>();
[Attribute]
public Func<DbContext> Getter { get; set; }
public AsyncReply<IResource> 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<Type, Dictionary<object, WeakReference>> DB = new Dictionary<Type, Dictionary<object, WeakReference>>();
object DBLock = new object();
// load navigation properties
var ent = db.Entry(res);
foreach (var rf in ent.References)
rf.Load();
Dictionary<string, EntityTypeInfo> TypesByName = new Dictionary<string, EntityTypeInfo>();
internal Dictionary<Type, EntityTypeInfo> TypesByType = new Dictionary<Type, EntityTypeInfo>();
[Attribute]
public Func<DbContext> Getter { get; set; }
public AsyncReply<IResource> 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<IResource>(res as IResource);
}
public AsyncReply<bool> Put(IResource resource)
{
if (resource == this)
return new AsyncReply<bool>(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<IResource>(res as IResource);
}
public AsyncReply<bool> Put(IResource resource)
{
if (resource == this)
return new AsyncReply<bool>(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<bool>(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<bool> AddChild(IResource parent, IResource child)
{
throw new NotImplementedException();
}
public AsyncReply<bool> RemoveChild(IResource parent, IResource child)
{
throw new NotImplementedException();
}
public AsyncReply<bool> AddParent(IResource child, IResource parent)
{
throw new NotImplementedException();
}
public AsyncReply<bool> RemoveParent(IResource child, IResource parent)
{
throw new NotImplementedException();
}
public AsyncBag<T> Children<T>(IResource resource, string name) where T : IResource
{
throw new NotImplementedException();
}
public AsyncBag<T> Parents<T>(IResource resource, string name) where T : IResource
{
throw new NotImplementedException();
}
public AsyncReply<KeyList<PropertyTemplate, PropertyValue[]>> GetRecord(IResource resource, DateTime fromDate, DateTime toDate)
{
throw new NotImplementedException();
}
internal DbContextOptions Options { get; set; }
public AsyncReply<bool> 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<bool>(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<object, WeakReference>());
}
}
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<bool> AddChild(IResource parent, IResource child)
{
throw new NotImplementedException();
}
public AsyncReply<bool> RemoveChild(IResource parent, IResource child)
{
throw new NotImplementedException();
}
public AsyncReply<bool> AddParent(IResource child, IResource parent)
{
throw new NotImplementedException();
}
public AsyncReply<bool> RemoveParent(IResource child, IResource parent)
{
throw new NotImplementedException();
}
public AsyncBag<T> Children<T>(IResource resource, string name) where T : IResource
{
throw new NotImplementedException();
}
public AsyncBag<T> Parents<T>(IResource resource, string name) where T : IResource
{
throw new NotImplementedException();
}
public AsyncReply<KeyList<PropertyTemplate, PropertyValue[]>> GetRecord(IResource resource, DateTime fromDate, DateTime toDate)
{
throw new NotImplementedException();
}
internal DbContextOptions Options { get; set; }
public AsyncReply<bool> 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<bool>(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<object, WeakReference>());
}
}
public void Destroy()
{
OnDestroy?.Invoke(this);
}
}

View File

@ -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<DbContext> Getter;
}
public string Name;
public IEntityType Type;
public PropertyInfo PrimaryKey;
// public Func<DbContext> Getter;
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<AssemblyName>Esiur.Stores.EntityCore</AssemblyName>
<Authors>Ahmed Kh. Zamil</Authors>
<Company>Esiur Foundation</Company>
@ -10,6 +10,7 @@
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageId>Esiur.Stores.EntityCore</PackageId>
<Version>1.2.5</Version>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
@ -21,7 +22,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.0" />
<PackageReference Include="System.Collections" Version="4.3.0" />
</ItemGroup>

View File

@ -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<Type, PropertyInfo> Cache { get; } = new Dictionary<Type, PropertyInfo>();
//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<IConventionSetPlugin, EsiurPlugin>();
}
public void Validate(IDbContextOptions options)
{
var internalServiceProvider = options.FindExtension<CoreOptionsExtension>()?.InternalServiceProvider;
if (internalServiceProvider != null)
{
var scope = internalServiceProvider.CreateScope();
var conventionPlugins = scope.ServiceProvider.GetService<IEnumerable<IConventionSetPlugin>>();
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<Type, PropertyInfo> Cache { get; } = new Dictionary<Type, PropertyInfo>();
//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<IConventionSetPlugin, EsiurPlugin>();
}
public void Validate(IDbContextOptions options)
{
var internalServiceProvider = options.FindExtension<CoreOptionsExtension>()?.InternalServiceProvider;
if (internalServiceProvider != null)
{
var scope = internalServiceProvider.CreateScope();
var conventionPlugins = scope.ServiceProvider.GetService<IEnumerable<IConventionSetPlugin>>();
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<string, string> 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<string, string> debugInfo)
{
}
}
public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other)
{
return true;
}
}
}

View File

@ -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<T>(this DbContext dbContext, object properties = null) where T:class,IResource
//{
// return dbContext.GetInfrastructure().CreateResource<T>(properties);
//}
public static T AddResource<T>(this DbSet<T> dbSet, T resource) where T : class, IResource
=> AddResourceAsync(dbSet, resource).Wait();
public static async AsyncReply<T> AddResourceAsync<T>(this DbSet<T> dbSet, T resource) where T : class, IResource
{
//public static T CreateResource<T>(this DbContext dbContext, object properties = null) where T:class,IResource
//{
// return dbContext.GetInfrastructure().CreateResource<T>(properties);
var store = dbSet.GetInfrastructure().GetService<IDbContextOptions>().FindExtension<EsiurExtensionOptions>().Store;
//}
public static T AddResource<T>(this DbSet<T> 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<T> AddResourceAsync<T>(this DbSet<T> dbSet, T resource) where T : class, IResource
//var db = dbSet.GetService<ICurrentDbContext>().Context;
//var resource = dbSet.GetInfrastructure().CreateResource<T>(properties);
//var resource = Warehouse.New<T>("", 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<IDbContextOptions>().FindExtension<EsiurExtensionOptions>().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<ICurrentDbContext>().Context;
//var resource = dbSet.GetInfrastructure().CreateResource<T>(properties);
//var resource = Warehouse.New<T>("", 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<T>("", 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<T> CreateResourceAsync<T>(this IServiceProvider serviceProvider, T properties = null) where T : class, IResource
//{
// var options = serviceProvider.GetService<IDbContextOptions>().FindExtension<EsiurExtensionOptions<T>>();
//await Warehouse.Put<T>("", null, null, null, null, properties);
var entity = dbSet.Add((T)res);
await entity.Context.SaveChangesAsync();
// var resource = await Warehouse.New<T>("", 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<T>(this IServiceProvider serviceProvider, object properties = null) where T : class, IResource
// => CreateResourceAsync<T>(serviceProvider, properties).Wait();
//public static async AsyncReply<T> CreateResourceAsync<T>(this IServiceProvider serviceProvider, T properties = null) where T : class, IResource
//{
// var options = serviceProvider.GetService<IDbContextOptions>().FindExtension<EsiurExtensionOptions<T>>();
public static DbContextOptionsBuilder UseEsiur(this DbContextOptionsBuilder optionsBuilder,
EntityStore store,
Func<DbContext> getter = null
// var resource = await Warehouse.New<T>("", options.Store, null, null, null, properties);
//IServiceCollection services = null
//string name = null,
//IResource parent = null,
//IPermissionsManager manager = null,
//Func<DbContext> dbContextProvider = null
)
// resource.Instance.Managers.AddRange(options.Store.Instance.Managers.ToArray());
// return resource;
//}
//public static T CreateResource<T>(this IServiceProvider serviceProvider, object properties = null) where T : class, IResource
// => CreateResourceAsync<T>(serviceProvider, properties).Wait();
public static DbContextOptionsBuilder UseEsiur(this DbContextOptionsBuilder optionsBuilder,
EntityStore store,
Func<DbContext> getter = null
//IServiceCollection services = null
//string name = null,
//IResource parent = null,
//IPermissionsManager manager = null,
//Func<DbContext> dbContextProvider = null
)
{
var extension = optionsBuilder.Options.FindExtension<EsiurExtensionOptions>();
if (extension == null)
{
var extension = optionsBuilder.Options.FindExtension<EsiurExtensionOptions>();
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<TContext> UseEsiur<TContext>(
// this DbContextOptionsBuilder<TContext> optionsBuilder,
// //DbContext context,
// string name = null,
// IResource parent = null,
// IPermissionsManager manager = null,
// Func<DbContext> dbContextProvider = null)
// where TContext : DbContext
//{
((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
// var extension = optionsBuilder.Options.FindExtension<EsiurExtensionOptions>();
// if (extension == null)
// {
// var store = Warehouse.New<EntityStore>(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<TContext> UseEsiur<TContext>(
// this DbContextOptionsBuilder<TContext> optionsBuilder,
// //DbContext context,
// string name = null,
// IResource parent = null,
// IPermissionsManager manager = null,
// Func<DbContext> dbContextProvider = null)
// where TContext : DbContext
//{
// var extension = optionsBuilder.Options.FindExtension<EsiurExtensionOptions>();
// if (extension == null)
// {
// var store = Warehouse.New<EntityStore>(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;
//}
}

View File

@ -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<EsiurExtensionOptions>();
conventionSet.ModelFinalizingConventions.Add(new EsiurProxyRewrite(
extension,
_conventionSetBuilderDependencies));
return conventionSet;
}
_options = options;
_conventionSetBuilderDependencies = conventionSetBuilderDependencies;
}
public ConventionSet ModifyConventions(ConventionSet conventionSet)
{
var extension = _options.FindExtension<EsiurExtensionOptions>();
conventionSet.ModelFinalizingConventions.Add(new EsiurProxyRewrite(
extension,
_conventionSetBuilderDependencies));
return conventionSet;
}
}

View File

@ -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<EsiurExtensionOptions>();
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<EsiurExtensionOptions>();
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<IConventionModelBuilder> 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<IConventionModelBuilder> 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<ParameterBinding>
{
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<ParameterBinding>
// {
// 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<ParameterBinding>
{
new DependencyInjectionParameterBinding(typeof(IDbContextOptions), typeof(IDbContextOptions)),
new EntityTypeParameterBinding(),
new ObjectArrayParameterBinding(new ParameterBinding[]{
new PropertyParameterBinding((IProperty)key) })
},
proxyType);
}
}

View File

@ -13,6 +13,7 @@
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Version>1.5.2</Version>
<PackageId>Esiur.Stores.MongoDB</PackageId>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>

File diff suppressed because it is too large Load Diff

View File

@ -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;
}
}

View File

@ -4,50 +4,48 @@ using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Core
namespace Esiur.Core;
public class AsyncAwaiter<T> : INotifyCompletion
{
public class AsyncAwaiter<T> : INotifyCompletion
Action callback = null;
AsyncException exception = null;
T result;
public AsyncAwaiter(AsyncReply<T> reply)
{
Action callback = null;
AsyncException exception = null;
T result;
public AsyncAwaiter(AsyncReply<T> 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;
}
}

View File

@ -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<AsyncReply> replies = new List<AsyncReply>();
List<object> results = new List<object>();
int count = 0;
bool sealedBag = false;
public Type ArrayType { get; set; }
public AsyncBag Then(Action<object[]> callback)
{
base.Then(new Action<object>(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<AsyncReply> replies = new List<AsyncReply>();
List<object> results = new List<object>();
}
int count = 0;
bool sealedBag = false;
public Type ArrayType { get; set; }
public AsyncBag Then(Action<object[]> callback)
{
base.Then(new Action<object>(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)
{
}
}

View File

@ -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;
}
}

View File

@ -4,50 +4,48 @@ using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Core
namespace Esiur.Core;
public class AsyncBagAwaiter<T> : INotifyCompletion
{
public class AsyncBagAwaiter<T> : INotifyCompletion
Action callback = null;
AsyncException exception = null;
T[] result;
public AsyncBagAwaiter(AsyncBag<T> reply)
{
Action callback = null;
AsyncException exception = null;
T[] result;
public AsyncBagAwaiter(AsyncBag<T> 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;
}
}

View File

@ -28,48 +28,47 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Core
namespace Esiur.Core;
public class AsyncBag<T> : AsyncBag
{
public class AsyncBag<T>: AsyncBag
{
public AsyncBag<T> Then(Action<T[]> callback)
{
base.Then(new Action<object>((o) => callback(((object[])o).Select(x=>(T)x).ToArray())));
return this;
}
public void Add(AsyncReply<T> reply)
{
base.Add(reply);
}
public void AddBag(AsyncBag<T> bag)
{
foreach (var r in bag.replies)
Add(r);
}
public new AsyncBagAwaiter<T> GetAwaiter()
{
return new AsyncBagAwaiter<T>(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<T> Then(Action<T[]> callback)
{
base.Then(new Action<object>((o) => callback(((object[])o).Select(x => (T)x).ToArray())));
return this;
}
}
public void Add(AsyncReply<T> reply)
{
base.Add(reply);
}
public void AddBag(AsyncBag<T> bag)
{
foreach (var r in bag.replies)
Add(r);
}
public new AsyncBagAwaiter<T> GetAwaiter()
{
return new AsyncBagAwaiter<T>(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())
{
}
}

View File

@ -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;
}
}

View File

@ -28,57 +28,56 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Core
namespace Esiur.Core;
public class AsyncQueue<T> : AsyncReply<T>
{
public class AsyncQueue<T> : AsyncReply<T>
List<AsyncReply<T>> list = new List<AsyncReply<T>>();
//Action<T> callback;
object queueLock = new object();
//public AsyncQueue<T> Then(Action<T> callback)
//{
// base.Then(new Action<object>(o => callback((T)o)));
//return this;
//}
public void Add(AsyncReply<T> reply)
{
List<AsyncReply<T>> list = new List<AsyncReply<T>>();
//Action<T> callback;
object queueLock = new object();
lock (queueLock)
list.Add(reply);
//public AsyncQueue<T> Then(Action<T> callback)
//{
// base.Then(new Action<object>(o => callback((T)o)));
resultReady = false;
reply.Then(processQueue);
}
//return this;
//}
public void Remove(AsyncReply<T> reply)
{
lock (queueLock)
list.Remove(reply);
processQueue(default(T));
}
public void Add(AsyncReply<T> 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<T> 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()
{
}
}
}

View File

@ -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<Action<object>> callbacks = new List<Action<object>>();
protected object result;
protected List<Action<AsyncException>> errorCallbacks = new List<Action<AsyncException>>();
protected List<Action<ProgressType, int, int>> progressCallbacks = new List<Action<ProgressType, int, int>>();
protected List<Action<object>> chunkCallbacks = new List<Action<object>>();
//List<AsyncAwaiter> awaiters = new List<AsyncAwaiter>();
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<Action<object>> callbacks = new List<Action<object>>();
protected object result;
protected List<Action<AsyncException>> errorCallbacks = new List<Action<AsyncException>>();
protected List<Action<ProgressType, int, int>> progressCallbacks = new List<Action<ProgressType, int, int>>();
protected List<Action<object>> chunkCallbacks = new List<Action<object>>();
//List<AsyncAwaiter> awaiters = new List<AsyncAwaiter>();
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<object> 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<AsyncException> callback)
{
// lock (callbacksLock)
// {
errorCallbacks.Add(callback);
if (exception != null)
callback(exception);
return this;
//}
}
public AsyncReply Progress(Action<ProgressType, int, int> callback)
{
//lock (callbacksLock)
//{
progressCallbacks.Add(callback);
return this;
//}
}
public AsyncReply Chunk(Action<object> 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<T> Then(Action<T> callback)
{
base.Then(new Action<object>(o => callback((T)o)));
return this;
}
public void Trigger(T result)
{
Trigger((object)result);
}
public Task<bool> MoveNext(CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public void Dispose()
{
}
public AsyncReply()
{
}
public new Task<T> Task
{
get
{
return base.Task.ContinueWith<T>((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<object> 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<AsyncException> callback)
{
// lock (callbacksLock)
// {
errorCallbacks.Add(callback);
if (exception != null)
callback(exception);
return this;
//}
}
public AsyncReply Progress(Action<ProgressType, int, int> callback)
{
//lock (callbacksLock)
//{
progressCallbacks.Add(callback);
return this;
//}
}
public AsyncReply Chunk(Action<object> 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<T> Then(Action<T> callback)
{
base.Then(new Action<object>(o => callback((T)o)));
return this;
}
public void Trigger(T result)
{
Trigger((object)result);
}
public Task<bool> MoveNext(CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public void Dispose()
{
}
public AsyncReply()
{
}
public new Task<T> Task
{
get
{
return base.Task.ContinueWith<T>((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)
{
}
*/
}

View File

@ -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<TStateMachine>(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<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine
{
awaiter.OnCompleted(stateMachine.MoveNext);
}
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
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<TStateMachine>(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<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine
{
awaiter.OnCompleted(stateMachine.MoveNext);
}
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine
{
awaiter.UnsafeOnCompleted(stateMachine.MoveNext);
}
public AsyncReply Task
{
get
{
return reply;
}
}
}

View File

@ -3,65 +3,65 @@ using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
namespace Esiur.Core
namespace Esiur.Core;
public class AsyncReplyBuilder<T>
{
public class AsyncReplyBuilder<T>
AsyncReply<T> reply;
AsyncReplyBuilder(AsyncReply<T> reply)
{
AsyncReply<T> reply;
AsyncReplyBuilder(AsyncReply<T> reply)
{
this.reply = reply;
}
public static AsyncReplyBuilder<T> Create()
{
return new AsyncReplyBuilder<T>(new AsyncReply<T>());
}
public void Start<TStateMachine>(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<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine
{
awaiter.OnCompleted(stateMachine.MoveNext);
}
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine
{
awaiter.UnsafeOnCompleted(stateMachine.MoveNext);
}
public AsyncReply<T> Task
{
get {
return reply;
}
}
this.reply = reply;
}
public static AsyncReplyBuilder<T> Create()
{
return new AsyncReplyBuilder<T>(new AsyncReply<T>());
}
public void Start<TStateMachine>(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<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine
{
awaiter.OnCompleted(stateMachine.MoveNext);
}
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine
{
awaiter.UnsafeOnCompleted(stateMachine.MoveNext);
}
public AsyncReply<T> Task
{
get
{
return reply;
}
}
}

View File

@ -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<T> : AsyncReply
{
[AsyncMethodBuilder(typeof(AsyncReplyBuilder<>))]
public class AsyncReply<T> : AsyncReply
public AsyncReply<T> Then(Action<T> callback)
{
base.Then((x) => callback((T)x));
return this;
}
public new AsyncReply<T> Progress(Action<ProgressType, int, int> callback)
{
base.Progress(callback);
return this;
}
public AsyncReply<T> Chunk(Action<T> callback)
{
chunkCallbacks.Add((x) => callback((T)x));
return this;
}
public AsyncReply(T result)
: base(result)
{
public AsyncReply<T> Then(Action<T> callback)
{
base.Then((x)=>callback((T)x));
return this;
}
public new AsyncReply<T> Progress(Action<ProgressType, int, int> callback)
{
base.Progress(callback);
return this;
}
public AsyncReply<T> Chunk(Action<T> callback)
{
chunkCallbacks.Add((x)=>callback((T)x));
return this;
}
public AsyncReply(T result)
: base(result)
{
}
public AsyncReply()
:base()
{
}
public new AsyncAwaiter<T> GetAwaiter()
{
return new AsyncAwaiter<T>(this);
}
public new T Wait()
{
return (T)base.Wait();
}
public new T Wait(int millisecondsTimeout)
{
return (T)base.Wait(millisecondsTimeout);
}
/*
protected new List<Action> callbacks = new List<Action>();
protected new object result;
protected new List<Action<AsyncException>> errorCallbacks = new List<Action<AsyncException>>();
protected new List<Action<ProgressType, int, int>> progressCallbacks = new List<Action<ProgressType, int, int>>();
protected new List<Action> chunkCallbacks = new List<Action>();
//List<AsyncAwaiter> awaiters = new List<AsyncAwaiter>();
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<T> Then(Action<T> 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<T> Error(Action<AsyncException> callback)
{
// lock (callbacksLock)
// {
errorCallbacks.Add(callback);
if (exception != null)
callback(exception);
return this;
//}
}
public IAsyncReply<T> Progress(Action<ProgressType, int, int> callback)
{
//lock (callbacksLock)
//{
progressCallbacks.Add(callback);
return this;
//}
}
public IAsyncReply<T> Chunk(Action<T> 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<T> GetAwaiter()
{
return new AsyncAwaiter<T>(this);
}
public AsyncReply()
{
// this.Debug = true;
Id = MaxId++;
}
public AsyncReply(T result)
{
// this.Debug = true;
resultReady = true;
this.result = result;
Id = MaxId++;
}
/*
public AsyncReply<T> Then(Action<T> callback)
{
base.Then(new Action<object>(o => callback((T)o)));
return this;
}
public void Trigger(T result)
{
Trigger((object)result);
}
public Task<bool> MoveNext(CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public void Dispose()
{
}
public AsyncReply()
{
}
public new Task<T> Task
{
get
{
return base.Task.ContinueWith<T>((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<T> GetAwaiter()
{
return new AsyncAwaiter<T>(this);
}
public new T Wait()
{
return (T)base.Wait();
}
public new T Wait(int millisecondsTimeout)
{
return (T)base.Wait(millisecondsTimeout);
}
/*
protected new List<Action> callbacks = new List<Action>();
protected new object result;
protected new List<Action<AsyncException>> errorCallbacks = new List<Action<AsyncException>>();
protected new List<Action<ProgressType, int, int>> progressCallbacks = new List<Action<ProgressType, int, int>>();
protected new List<Action> chunkCallbacks = new List<Action>();
//List<AsyncAwaiter> awaiters = new List<AsyncAwaiter>();
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<T> Then(Action<T> 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<T> Error(Action<AsyncException> callback)
{
// lock (callbacksLock)
// {
errorCallbacks.Add(callback);
if (exception != null)
callback(exception);
return this;
//}
}
public IAsyncReply<T> Progress(Action<ProgressType, int, int> callback)
{
//lock (callbacksLock)
//{
progressCallbacks.Add(callback);
return this;
//}
}
public IAsyncReply<T> Chunk(Action<T> 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<T> GetAwaiter()
{
return new AsyncAwaiter<T>(this);
}
public AsyncReply()
{
// this.Debug = true;
Id = MaxId++;
}
public AsyncReply(T result)
{
// this.Debug = true;
resultReady = true;
this.result = result;
Id = MaxId++;
}
/*
public AsyncReply<T> Then(Action<T> callback)
{
base.Then(new Action<object>(o => callback((T)o)));
return this;
}
public void Trigger(T result)
{
Trigger((object)result);
}
public Task<bool> MoveNext(CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public void Dispose()
{
}
public AsyncReply()
{
}
public new Task<T> Task
{
get
{
return base.Task.ContinueWith<T>((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();
*/
}

View File

@ -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<Action<object>> callbacks = new List<Action<object>>();
protected object result;
protected List<Action<AsyncException>> errorCallbacks = new List<Action<AsyncException>>();
protected List<Action<ProgressType, int, int>> progressCallbacks = new List<Action<ProgressType, int, int>>();
protected List<Action<object>> chunkCallbacks = new List<Action<object>>();
object callbacksLock = new object();
protected bool resultReady = false;
AsyncException exception;
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
public bool Ready
{
get { return resultReady; }
}
public object Result
{
get { return result; }
}
public AsyncReply Then(Action<object> callback)
{
callbacks.Add(callback);
protected List<Action<object>> callbacks = new List<Action<object>>();
protected object result;
if (resultReady)
callback(result);
protected List<Action<AsyncException>> errorCallbacks = new List<Action<AsyncException>>();
return this;
}
protected List<Action<ProgressType, int, int>> progressCallbacks = new List<Action<ProgressType, int, int>>();
public AsyncReply Error(Action<AsyncException> callback)
{
errorCallbacks.Add(callback);
protected List<Action<object>> chunkCallbacks = new List<Action<object>>();
object callbacksLock = new object();
protected bool resultReady = false;
AsyncException exception;
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
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<object> callback)
{
callbacks.Add(callback);
public AsyncReply Progress(Action<ProgressType, int, int> callback)
{
progressCallbacks.Add(callback);
return this;
}
if (resultReady)
callback(result);
public AsyncReply Chunk(Action<object> callback)
{
chunkCallbacks.Add(callback);
return this;
}
return this;
}
public void Trigger(object result)
{
public AsyncReply Error(Action<AsyncException> callback)
{
errorCallbacks.Add(callback);
if (exception != null)
{
callback(exception);
tcs.SetException(exception);
}
return this;
}
public AsyncReply Progress(Action<ProgressType, int, int> callback)
{
progressCallbacks.Add(callback);
return this;
}
public AsyncReply Chunk(Action<object> 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;
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -3,19 +3,18 @@ using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
namespace Esiur.Core
{
public interface IAsyncReply<out T>//IAsyncEnumerator<T>
{
IAsyncReply<T> Then(Action<T> callback);
IAsyncReply<T> Error(Action<AsyncException> callback);
IAsyncReply<T> Progress(Action<ProgressType, int, int> callback);
IAsyncReply<T> Chunk(Action<T> 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<out T>//IAsyncEnumerator<T>
{
IAsyncReply<T> Then(Action<T> callback);
IAsyncReply<T> Error(Action<AsyncException> callback);
IAsyncReply<T> Progress(Action<ProgressType, int, int> callback);
IAsyncReply<T> Chunk(Action<T> callback);
void Trigger(object result);
void TriggerError(Exception exception);
void TriggerProgress(ProgressType type, int value, int max);
void TriggerChunk(object value);
T Wait();
}

View File

@ -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();
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -30,285 +30,284 @@ using System.Collections;
using Esiur.Core;
using System.Reflection;
namespace Esiur.Data
namespace Esiur.Data;
public class AutoList<T, ST> : IEnumerable<T>, ICollection, ICollection<T>
{
public class AutoList<T, ST> : IEnumerable<T>, ICollection, ICollection<T>
private readonly object syncRoot = new object();
private List<T> list = new List<T>();
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<T> OrderBy<T, TK>(Func<T, TK> keySelector)
{
return list.OrderBy<T,TK>(keySelector);
}
*/
private readonly object syncRoot = new object();
private List<T> list = new List<T>();
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<T> OrderBy<T, TK>(Func<T, TK> keySelector)
{
return list.OrderBy<T,TK>(keySelector);
}
*/
public void Sort()
{
lock(syncRoot)
public void Sort()
{
lock (syncRoot)
list.Sort();
}
}
public void Sort(IComparer<T> comparer)
{
lock (syncRoot)
list.Sort(comparer);
}
public void Sort(IComparer<T> comparer)
{
lock (syncRoot)
list.Sort(comparer);
}
public void Sort(Comparison<T> comparison)
{
lock (syncRoot)
list.Sort(comparison);
}
public void Sort(Comparison<T> comparison)
{
lock (syncRoot)
list.Sort(comparison);
}
public IEnumerable<T> Where(Func<T, bool> predicate)
{
return list.Where(predicate);
}
public IEnumerable<T> Where(Func<T, bool> predicate)
{
return list.Where(predicate);
}
/// <summary>
/// Convert AutoList to array
/// </summary>
/// <returns>Array</returns>
public T[] ToArray()
{
// list.OrderBy()
return list.ToArray();
}
/// <summary>
/// Convert AutoList to array
/// </summary>
/// <returns>Array</returns>
public T[] ToArray()
{
// list.OrderBy()
return list.ToArray();
}
/// <summary>
/// Create a new instance of AutoList
/// </summary>
/// <param name="state">State object to be included when an event is raised.</param>
public AutoList(ST state)
{
State = state;
/// <summary>
/// Create a new instance of AutoList
/// </summary>
/// <param name="state">State object to be included when an event is raised.</param>
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
}
}
/// <summary>
/// Create a new instance of AutoList
/// </summary>
/// <param name="values">Populate the list with items</param>
/// <returns></returns>
public AutoList(ST state, T[] values)
{
State = state;
/// <summary>
/// Create a new instance of AutoList
/// </summary>
/// <param name="values">Populate the list with items</param>
/// <returns></returns>
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);
}
/// <summary>
/// Synchronization lock of the list
/// </summary>
public object SyncRoot
/// <summary>
/// Synchronization lock of the list
/// </summary>
public object SyncRoot
{
get
{
get
{
return syncRoot;
}
return syncRoot;
}
}
/// <summary>
/// First item in the list
/// </summary>
public T First()
/// <summary>
/// First item in the list
/// </summary>
public T First()
{
return list.First();
}
/// <summary>
/// Get an item at a specified index
/// </summary>
public T this[int index]
{
get
{
return list.First();
return list[index];
}
/// <summary>
/// Get an item at a specified index
/// </summary>
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);
}
}
/// <summary>
/// Add item to the list
/// </summary>
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);
}
/// <summary>
/// Add an array of items to the list
/// </summary>
public void AddRange(T[] values)
{
foreach (var v in values)
Add(v);
}
private void ItemDestroyed(object sender)
{
Remove((T)sender);
}
/// <summary>
/// Clear the list
/// </summary>
public void Clear()
{
if (removableList)
foreach (IDestructible v in list)
if (v != null)
v.OnDestroy -= ItemDestroyed;
lock (syncRoot)
list.Clear();
OnCleared?.Invoke(State);
}
/// <summary>
/// Remove an item from the list
/// <param name="value">Item to remove</param>
/// </summary>
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;
}
/// <summary>
/// Number of items in the list
/// </summary>
public int Count
{
get { return list.Count; }
}
public bool IsSynchronized => (list as ICollection).IsSynchronized;
public bool IsReadOnly => false;
/// <summary>
/// Check if an item exists in the list
/// </summary>
/// <param name="value">Item to check if exists</param>
public bool Contains(T value)
{
return list.Contains(value);
}
/// <summary>
/// Check if any item of the given array is in the list
/// </summary>
/// <param name="values">Array of items</param>
public bool ContainsAny(T[] values)
{
foreach (var v in values)
if (list.Contains(v))
return true;
return false;
}
/// <summary>
/// Check if any item of the given list is in the list
/// </summary>
/// <param name="values">List of items</param>
public bool ContainsAny(AutoList<T, ST> values)
{
foreach (var v in values)
if (list.Contains((T)v))
return true;
return false;
}
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)list).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<T>)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<T>.Remove(T item)
//{
// lock(syncRoot)
// return Remove(item);
//}
}
/// <summary>
/// Add item to the list
/// </summary>
public void Add(T value)
{
if (removableList)
if (value != null)
((IDestructible)value).OnDestroy += ItemDestroyed;
lock (syncRoot)
list.Add(value);
OnAdd?.Invoke(State, value);
}
/// <summary>
/// Add an array of items to the list
/// </summary>
public void AddRange(T[] values)
{
foreach (var v in values)
Add(v);
}
private void ItemDestroyed(object sender)
{
Remove((T)sender);
}
/// <summary>
/// Clear the list
/// </summary>
public void Clear()
{
if (removableList)
foreach (IDestructible v in list)
if (v != null)
v.OnDestroy -= ItemDestroyed;
lock (syncRoot)
list.Clear();
OnCleared?.Invoke(State);
}
/// <summary>
/// Remove an item from the list
/// <param name="value">Item to remove</param>
/// </summary>
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;
}
/// <summary>
/// Number of items in the list
/// </summary>
public int Count
{
get { return list.Count; }
}
public bool IsSynchronized => (list as ICollection).IsSynchronized;
public bool IsReadOnly => false;
/// <summary>
/// Check if an item exists in the list
/// </summary>
/// <param name="value">Item to check if exists</param>
public bool Contains(T value)
{
return list.Contains(value);
}
/// <summary>
/// Check if any item of the given array is in the list
/// </summary>
/// <param name="values">Array of items</param>
public bool ContainsAny(T[] values)
{
foreach (var v in values)
if (list.Contains(v))
return true;
return false;
}
/// <summary>
/// Check if any item of the given list is in the list
/// </summary>
/// <param name="values">List of items</param>
public bool ContainsAny(AutoList<T, ST> values)
{
foreach (var v in values)
if (list.Contains((T)v))
return true;
return false;
}
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)list).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<T>)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<T>.Remove(T item)
//{
// lock(syncRoot)
// return Remove(item);
//}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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;
}
}
}

View File

@ -2,10 +2,9 @@
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data
{
public interface IRecord
{
namespace Esiur.Data;
public interface IRecord
{
}
}

View File

@ -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);
}

View File

@ -33,212 +33,210 @@ using System.Linq;
using System.Linq.Expressions;
using Esiur.Core;
namespace Esiur.Data
namespace Esiur.Data;
public class KeyList<KT, T> : IEnumerable<KeyValuePair<KT, T>>
{
private readonly object syncRoot = new object();
private Dictionary<KT, T> dic;
public class KeyList<KT, T> : IEnumerable<KeyValuePair<KT, T>>
public delegate void Modified(KT key, T oldValue, T newValue, KeyList<KT, T> sender);
public delegate void Added(T value, KeyList<KT, T> sender);
public delegate void Removed(KT key, T value, KeyList<KT, T> sender);
public delegate void Cleared(KeyList<KT, T> 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<KT, T> dic;
public delegate void Modified(KT key, T oldValue, T newValue, KeyList<KT, T> sender);
public delegate void Added(T value, KeyList<KT, T> sender);
public delegate void Removed(KT key, T value, KeyList<KT, T> sender);
public delegate void Cleared(KeyList<KT, T> 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<KeyValuePair<KT, T>, 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<KT>();
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<KeyValuePair<KT, T>, object> keySelector)
set
{
dic = dic.OrderBy(keySelector).ToDictionary(x => x.Key, x => x.Value);
Add(key, value);
}
}
public T[] ToArray()
public IEnumerator<KeyValuePair<KT, T>> 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<KT, T>.KeyCollection Keys
{
get { return dic.Keys; }
}
public Dictionary<KT, T>.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<KT>();
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<KeyValuePair<KT, T>> 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<KT, T>.KeyCollection Keys
{
get { return dic.Keys; }
}
public Dictionary<KT, T>.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<KT, T>)(object)new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase);
else
dic = new Dictionary<KT, T>();
}
if (typeof(KT) == typeof(string))
dic = (Dictionary<KT, T>)(object)new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase);
else
dic = new Dictionary<KT, T>();
}
}
}

View File

@ -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
{
}
}

View File

@ -2,34 +2,33 @@
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data
{
public class PropertyValue
{
/// <summary>
/// Get or set the value.
/// </summary>
public object Value { get; set; }
/// <summary>
/// Get or set date of modification or occurrence.
/// </summary>
public DateTime Date { get; set; }
/// <summary>
/// Get or set property age.
/// </summary>
public ulong Age { get; set; }
namespace Esiur.Data;
/// <summary>
/// Create an instance of PropertyValue.
/// </summary>
/// <param name="value">Value.</param>
/// <param name="age">Age.</param>
/// <param name="date">Date.</param>
public PropertyValue(object value, ulong age, DateTime date)
{
Value = value;
Age = age;
Date = date;
}
public class PropertyValue
{
/// <summary>
/// Get or set the value.
/// </summary>
public object Value { get; set; }
/// <summary>
/// Get or set date of modification or occurrence.
/// </summary>
public DateTime Date { get; set; }
/// <summary>
/// Get or set property age.
/// </summary>
public ulong Age { get; set; }
/// <summary>
/// Create an instance of PropertyValue.
/// </summary>
/// <param name="value">Value.</param>
/// <param name="age">Age.</param>
/// <param name="date">Date.</param>
public PropertyValue(object value, ulong age, DateTime date)
{
Value = value;
Age = age;
Date = date;
}
}

View File

@ -2,10 +2,8 @@
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data
namespace Esiur.Data;
public class Record : KeyList<string, object>, IRecord
{
public class Record: KeyList<string, object>, IRecord
{
}
}

View File

@ -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
}

View File

@ -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,
}

View File

@ -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
}

View File

@ -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<IResource>
{
class ResourceJsonConverter : JsonConverter<IResource>
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<double>
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<double>
{
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);
}
}
}

View File

@ -30,245 +30,244 @@ using System.Collections;
using Esiur.Core;
using System.Reflection;
namespace Esiur.Data
namespace Esiur.Data;
public class ResourceList<T, ST> : IEnumerable<T>, ICollection, ICollection<T>
{
public class ResourceList<T, ST> : IEnumerable<T>, ICollection, ICollection<T>
private readonly object syncRoot = new object();
private List<T> list = new List<T>();
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<T> list = new List<T>();
public void Sort(IComparer<T> 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<T> comparison)
{
list.Sort(comparison);
}
public IEnumerable<T> Where(Func<T, bool> predicate)
{
return list.Where(predicate);
}
public event Modified OnModified;
public event Removed OnRemoved;
public event Cleared OnCleared;
public event Added OnAdd;
/// <summary>
/// Convert AutoList to array
/// </summary>
/// <returns>Array</returns>
public T[] ToArray()
{
// list.OrderBy()
return list.ToArray();
}
ST state;
/// <summary>
/// Create a new instance of AutoList
/// </summary>
/// <param name="state">State object to be included when an event is raised.</param>
public ResourceList(ST state)
{
this.state = state;
}
public void Sort()
/// <summary>
/// Create a new instance of AutoList
/// </summary>
/// <param name="values">Populate the list with items</param>
/// <returns></returns>
public ResourceList(ST state, T[] values)
{
this.state = state;
AddRange(values);
}
/// <summary>
/// Synchronization lock of the list
/// </summary>
public object SyncRoot
{
get
{
list.Sort();
}
public void Sort(IComparer<T> comparer)
{
list.Sort(comparer);
}
public void Sort(Comparison<T> comparison)
{
list.Sort(comparison);
}
public IEnumerable<T> Where(Func<T, bool> predicate)
{
return list.Where(predicate);
}
/// <summary>
/// Convert AutoList to array
/// </summary>
/// <returns>Array</returns>
public T[] ToArray()
{
// list.OrderBy()
return list.ToArray();
}
/// <summary>
/// Create a new instance of AutoList
/// </summary>
/// <param name="state">State object to be included when an event is raised.</param>
public ResourceList(ST state)
{
this.state = state;
}
/// <summary>
/// Create a new instance of AutoList
/// </summary>
/// <param name="values">Populate the list with items</param>
/// <returns></returns>
public ResourceList(ST state, T[] values)
{
this.state = state;
AddRange(values);
}
/// <summary>
/// Synchronization lock of the list
/// </summary>
public object SyncRoot
{
get
{
return syncRoot;
}
}
/// <summary>
/// First item in the list
/// </summary>
public T First()
{
return list.First();
}
/// <summary>
/// Get an item at a specified index
/// </summary>
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);
}
}
/// <summary>
/// Add item to the list
/// </summary>
public void Add(T value)
{
lock (syncRoot)
list.Add(value);
OnAdd?.Invoke(state, value);
}
/// <summary>
/// Add an array of items to the list
/// </summary>
public void AddRange(T[] values)
{
foreach (var v in values)
Add(v);
}
private void ItemDestroyed(object sender)
{
Remove((T)sender);
}
/// <summary>
/// Clear the list
/// </summary>
public void Clear()
{
lock (syncRoot)
list.Clear();
OnCleared?.Invoke(state);
}
/// <summary>
/// Remove an item from the list
/// <param name="value">Item to remove</param>
/// </summary>
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);
}
/// <summary>
/// Number of items in the list
/// </summary>
public int Count
{
get { return list.Count; }
}
public bool IsSynchronized => (list as ICollection).IsSynchronized;
public bool IsReadOnly => throw new NotImplementedException();
/// <summary>
/// Check if an item exists in the list
/// </summary>
/// <param name="value">Item to check if exists</param>
public bool Contains(T value)
{
return list.Contains(value);
}
/// <summary>
/// Check if any item of the given array is in the list
/// </summary>
/// <param name="values">Array of items</param>
public bool ContainsAny(T[] values)
{
foreach (var v in values)
if (list.Contains(v))
return true;
return false;
}
/// <summary>
/// Check if any item of the given list is in the list
/// </summary>
/// <param name="values">List of items</param>
public bool ContainsAny(AutoList<T, ST> values)
{
foreach (var v in values)
if (list.Contains((T)v))
return true;
return false;
}
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)list).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<T>)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<T>.Remove(T item)
{
return list.Remove(item);
return syncRoot;
}
}
/// <summary>
/// First item in the list
/// </summary>
public T First()
{
return list.First();
}
/// <summary>
/// Get an item at a specified index
/// </summary>
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);
}
}
/// <summary>
/// Add item to the list
/// </summary>
public void Add(T value)
{
lock (syncRoot)
list.Add(value);
OnAdd?.Invoke(state, value);
}
/// <summary>
/// Add an array of items to the list
/// </summary>
public void AddRange(T[] values)
{
foreach (var v in values)
Add(v);
}
private void ItemDestroyed(object sender)
{
Remove((T)sender);
}
/// <summary>
/// Clear the list
/// </summary>
public void Clear()
{
lock (syncRoot)
list.Clear();
OnCleared?.Invoke(state);
}
/// <summary>
/// Remove an item from the list
/// <param name="value">Item to remove</param>
/// </summary>
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);
}
/// <summary>
/// Number of items in the list
/// </summary>
public int Count
{
get { return list.Count; }
}
public bool IsSynchronized => (list as ICollection).IsSynchronized;
public bool IsReadOnly => throw new NotImplementedException();
/// <summary>
/// Check if an item exists in the list
/// </summary>
/// <param name="value">Item to check if exists</param>
public bool Contains(T value)
{
return list.Contains(value);
}
/// <summary>
/// Check if any item of the given array is in the list
/// </summary>
/// <param name="values">Array of items</param>
public bool ContainsAny(T[] values)
{
foreach (var v in values)
if (list.Contains(v))
return true;
return false;
}
/// <summary>
/// Check if any item of the given list is in the list
/// </summary>
/// <param name="values">List of items</param>
public bool ContainsAny(AutoList<T, ST> values)
{
foreach (var v in values)
if (list.Contains((T)v))
return true;
return false;
}
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)list).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<T>)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<T>.Remove(T item)
{
return list.Remove(item);
}
}

View File

@ -31,190 +31,189 @@ using System.Text;
using System.Reflection;
using System.Linq;
namespace Esiur.Data
namespace Esiur.Data;
public class StringKeyList : IEnumerable<KeyValuePair<string, string>>
{
public class StringKeyList : IEnumerable<KeyValuePair<string, string>>
//private List<string> m_keys = new List<string>();
//private List<string> m_values = new List<string>();
private List<KeyValuePair<string, string>> m_Variables = new List<KeyValuePair<string, string>>();
private bool allowMultiple;
public delegate void Modified(string Key, string NewValue);
public event Modified OnModified;
public StringKeyList(bool AllowMultipleValues = false)
{
//private List<string> m_keys = new List<string>();
//private List<string> m_values = new List<string>();
allowMultiple = AllowMultipleValues;
}
private List<KeyValuePair<string, string>> m_Variables = new List<KeyValuePair<string, string>>();
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<string, string>(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<string, string>(Key, value));
OnModified?.Invoke(Key, value);
}
}
IEnumerator<KeyValuePair<string, string>> IEnumerable<KeyValuePair<string, string>>.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<string, string>.ValueCollection Values
public string[] Values
{
get
{
//return m_Variables.Values;
return m_values.ToArray();
}
}
*/
public List<string> GetValues(string Key)
{
var key = Key.ToLower();
List<string> values = new List<string>();
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<string, string>(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<string, string>(Key, value));
OnModified?.Invoke(Key, value);
}
}
IEnumerator<KeyValuePair<string, string>> IEnumerable<KeyValuePair<string, string>>.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<string, string>.ValueCollection Values
public string[] Values
{
get
{
//return m_Variables.Values;
return m_values.ToArray();
}
}
*/
public List<string> GetValues(string Key)
{
var key = Key.ToLower();
List<string> values = new List<string>();
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;
//}
}

View File

@ -34,148 +34,147 @@ using Esiur.Core;
using System.Reflection;
using System.Dynamic;
namespace Esiur.Data
namespace Esiur.Data;
public class Structure : IEnumerable<KeyValuePair<string, object>>
{
public class Structure : IEnumerable<KeyValuePair<string, object>>
public struct StructureMetadata
{
public string[] Keys;
public DataType[] Types;
}
private Dictionary<string, object> dic = new Dictionary<string, object>(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<string, object> dic = new Dictionary<string, object>(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<T>(Structure source) where T : Structure
{
var rt = Activator.CreateInstance<T>();
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<KeyValuePair<string, object>> GetEnumerator()
{
return dic.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return dic.GetEnumerator();
}
public int Length
{
get { return dic.Count; }
}
public KeyValuePair<string, object> 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<T>(Structure source) where T : Structure
{
var rt = Activator.CreateInstance<T>();
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<KeyValuePair<string, object>> GetEnumerator()
{
return dic.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return dic.GetEnumerator();
}
public int Length
{
get { return dic.Count; }
}
public KeyValuePair<string, object> 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);
}
}
}

View File

@ -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
}

View File

@ -4,20 +4,20 @@
<TargetFramework>netstandard2.0</TargetFramework>
<Description>Distributed Resources Platform</Description>
<Copyright>Ahmed Kh. Zamil</Copyright>
<PackageLicenseUrl>https://github.com/Esiur/Esiur-dotnet/blob/master/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>http://www.esiur.com</PackageProjectUrl>
<PackageProjectUrl>http://www.esiur.com</PackageProjectUrl>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>1.8.8</Version>
<Version>2.0.0-alpha</Version>
<RepositoryUrl>https://github.com/esiur/esiur-dotnet</RepositoryUrl>
<Authors>Ahmed Kh. Zamil</Authors>
<AssemblyVersion>1.8.8.0</AssemblyVersion>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
<Company>Esiur Foundation</Company>
<FileVersion>1.8.8.0</FileVersion>
<FileVersion>2.0.0.0</FileVersion>
<AssemblyName>Esiur</AssemblyName>
<RootNamespace>Esiur</RootNamespace>
<PackageId>Esiur</PackageId>
<Product>Esiur</Product>
<LangVersion>9.0</LangVersion>
<LangVersion>latest</LangVersion>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@ -79,10 +79,13 @@
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
<!-- Package the Newtonsoft.Json dependency alongside the generator assembly -->
<None Include="$(PkgSystem_Text_Json)\lib\netstandard2.0\*.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
<None Include="Tools/*" Pack="true" PackagePath="tools/" />
</ItemGroup>
<ItemGroup>
<None Include="LICENSE" Pack="true" PackagePath="">
</None>
</ItemGroup>
</Project>

21
Esiur/LICENSE Normal file
View File

@ -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.

View File

@ -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<string, object> variables = new KeyList<string, object>();
// 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<string, long> Counters = new KeyList<string, long>();
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<string, object> variables = new KeyList<string, object>();
// 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<string, long> Counters = new KeyList<string, long>();
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<string, object> 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<byte[]>(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;
}
}
*/
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<string, object> 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<byte[]>(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(
//}
}

View File

@ -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<bool> Trigger(ResourceTrigger trigger);
public abstract AsyncReply<bool> 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);
}
}

View File

@ -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<PacketSource> sources = new List<PacketSource>();
List<PacketFilter> filters = new List<PacketFilter>();
[Storable]
public string Mode
{
List<PacketSource> sources = new List<PacketSource>();
List<PacketFilter> filters = new List<PacketFilter>();
get;
set;
}
[Storable]
public string Mode
public Instance Instance
{
get;
set;
}
public List<PacketSource> Sources
{
get
{
get;
set;
return sources;
}
}
public Instance Instance
{
get;
set;
}
public event DestroyedEvent OnDestroy;
public List<PacketSource> Sources
public void Destroy()
{
OnDestroy?.Invoke(this);
}
public AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
if (trigger == ResourceTrigger.Initialize)
{
get
/*
foreach (var resource in Instance.Children<IResource>())
{
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<bool>(true);
}
public void Destroy()
void PacketReceived(Packet Packet)
{
foreach (var f in filters)
{
OnDestroy?.Invoke(this);
}
public AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
if (trigger == ResourceTrigger.Initialize)
if (f.Execute(Packet))
{
/*
foreach (var resource in Instance.Children<IResource>())
{
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<bool>( true);
}
void PacketReceived(Packet Packet)
{
foreach (var f in filters)
{
if (f.Execute(Packet))
{
break;
}
break;
}
}
}

View File

@ -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<bool> 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<bool> 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;
}
}

View File

@ -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<string, object> Variables { get; } = new KeyList<string, object>();
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<string, object> Variables { get; } = new KeyList<string, object>();
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(
"<html><body>POST method content is larger than "
+ Server.MaxPost
+ " bytes.</body></html>");
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 "<html><head><title>500 Internal Server Error</title></head><br>\r\n"
+ "<body><br>\r\n"
+ "<b>500</b> Internal Server Error<br>" + msg + "\r\n"
+ "</body><br>\r\n"
+ "</html><br>\r\n";
}
public async AsyncReply<bool> 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(
"<html><body>POST method content is larger than "
+ Server.MaxPost
+ " bytes.</body></html>");
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 "<html><head><title>500 Internal Server Error</title></head><br>\r\n"
+ "<body><br>\r\n"
+ "<b>500</b> Internal Server Error<br>" + msg + "\r\n"
+ "</body><br>\r\n"
+ "</html><br>\r\n";
}
public async AsyncReply<bool> 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;
}
}
}
protected override void Connected()
{
// do nothing
}
protected override void Disconencted()
{
// do nothing
}
}

View File

@ -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<bool> Trigger(ResourceTrigger trigger);
/*
public virtual void SessionModified(HTTPSession session, string key, object oldValue, object newValue)
{
}
public virtual void SessionExpired(HTTPSession session)
{
}
*/
public abstract AsyncReply<bool> 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;
}
}
public event DestroyedEvent OnDestroy;
public abstract AsyncReply<bool> Trigger(ResourceTrigger trigger);
/*
public virtual void SessionModified(HTTPSession session, string key, object oldValue, object newValue)
{
}
public virtual void SessionExpired(HTTPSession session)
{
}
*/
public abstract AsyncReply<bool> 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);
}
}

View File

@ -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<HTTPConnection>, IResource
{
public class HTTPServer : NetworkServer<HTTPConnection>, IResource
Dictionary<string, HTTPSession> sessions = new Dictionary<string, HTTPSession>();
HTTPFilter[] filters = new HTTPFilter[0];
public Instance Instance
{
Dictionary<string, HTTPSession> sessions= new Dictionary<string, HTTPSession>();
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<bool> 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<HTTPFilter>();
}
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();
}
}
*/
/*
public int TTL
{
get
{
return Timeout;// mTimeout;
}
}
*/
public async AsyncReply<bool> 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<HTTPFilter>();
}
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();
//}
}

View File

@ -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 //<T> where T : TClient
{
public class HTTPSession : IDestructible //<T> 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<string, object> variables;
public event SessionEndedEvent OnEnd;
public event SessionModifiedEvent OnModify;
public event DestroyedEvent OnDestroy;
public KeyList<string, object> 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<string, object>();
variables.OnModified += new KeyList<string, object>.Modified(VariablesModified);
creation = DateTime.Now;
}
private KeyList<string, object> 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<string, object> Variables
if (this.timeout != 0)
{
get { return variables; }
}
public HTTPSession()
{
variables = new KeyList<string, object>();
variables.OnModified += new KeyList<string, object>.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<string, object> 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; }
}
}
}
private void OnSessionEndTimerCallback(object o)
{
OnEnd?.Invoke(this);
}
void VariablesModified(string key, object oldValue, object newValue, KeyList<string, object> 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; }
}
}

View File

@ -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<bool> Execute(HTTPConnection sender)
{
[Attribute]
EntryPoint EntryPoint { get; set; }
if (sender.Request.URL != "iip")
return new AsyncReply<bool>(false);
public override AsyncReply<bool> 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<bool>(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<bool>(true);
});
}
public override AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
return new AsyncReply<bool>(true);
}
return new AsyncReply<bool>(true);
}
public override AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
return new AsyncReply<bool>(true);
}
}

View File

@ -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<bool> Execute(HTTPConnection sender)
{
if (sender.IsWebsocketRequest())
{
get;
set;
}
if (Server == null)
return new AsyncReply<bool>(false);
public override AsyncReply<bool> Execute(HTTPConnection sender)
{
var tcpSocket = sender.Unassign();
if (sender.IsWebsocketRequest())
{
if (Server == null)
return new AsyncReply<bool>(false);
if (tcpSocket == null)
return new AsyncReply<bool>(false);
var tcpSocket = sender.Unassign();
var httpServer = sender.Parent;
var wsSocket = new WSocket(tcpSocket);
httpServer.Remove(sender);
if (tcpSocket == null)
return new AsyncReply<bool>(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<bool>(true);
}
return new AsyncReply<bool>( 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<bool> Trigger(ResourceTrigger trigger)
{
return new AsyncReply<bool>(true);
}
return new AsyncReply<bool>(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<bool> Trigger(ResourceTrigger trigger)
{
return new AsyncReply<bool>(true);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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<DistributedConnection, object> Method { get; private set; }
public DistributedPropertyContext(DistributedConnection connection, object value)
{
public object Value { get; private set; }
public DistributedConnection Connection { get; private set; }
public Func<DistributedConnection, object> Method { get; private set; }
public DistributedPropertyContext(DistributedConnection connection, object value)
{
this.Value = value;
this.Connection = connection;
}
public DistributedPropertyContext(Func<DistributedConnection, object> method)
{
this.Method = method;
}
public static implicit operator DistributedPropertyContext(Func<DistributedConnection, object> method)
=> new DistributedPropertyContext(method);
this.Value = value;
this.Connection = connection;
}
public DistributedPropertyContext(Func<DistributedConnection, object> method)
{
this.Method = method;
}
public static implicit operator DistributedPropertyContext(Func<DistributedConnection, object> method)
=> new DistributedPropertyContext(method);
}

View File

@ -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
/// <summary>
/// Raised when the distributed resource is destroyed.
/// </summary>
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<DistributedResource> parents = new List<DistributedResource>();
internal List<DistributedResource> children = new List<DistributedResource>();
DistributedResourceEvent[] events;
/// <summary>
/// Resource template for the remotely located resource.
/// </summary>
//public ResourceTemplate Template
//{
// get { return template; }
//}
/// <summary>
/// Connection responsible for the distributed resource.
/// </summary>
public DistributedConnection Connection
{
get { return connection; }
}
/// <summary>
/// Resource link
/// </summary>
public string Link
{
get { return link; }
}
/// <summary>
/// Instance Id given by the other end.
/// </summary>
public uint Id
{
get { return instanceId; }
}
/// <summary>
/// IDestructible interface.
/// </summary>
public void Destroy()
{
destroyed = true;
attached = false;
connection.SendDetachRequest(instanceId);
OnDestroy?.Invoke(this);
}
/// <summary>
/// Suspend resource
/// </summary>
internal void Suspend()
{
suspended = true;
attached = false;
}
/// <summary>
/// Resource is attached when all its properties are received.
/// </summary>
internal bool Attached => attached;
internal bool Suspended => suspended;
// public DistributedResourceStack Stack
//{
// get { return stack; }
//}
/// <summary>
/// Create a new distributed resource.
/// </summary>
/// <param name="connection">Connection responsible for the distributed resource.</param>
/// <param name="template">Resource template.</param>
/// <param name="instanceId">Instance Id given by the other end.</param>
/// <param name="age">Resource age.</param>
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;
}
/// <summary>
/// Export all properties with ResourceProperty attributed as bytes array.
/// </summary>
/// <returns></returns>
internal PropertyValue[] _Serialize()
{
/// <summary>
/// Raised when the distributed resource is destroyed.
/// </summary>
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<DistributedResource> parents = new List<DistributedResource>();
internal List<DistributedResource> children = new List<DistributedResource>();
DistributedResourceEvent[] events;
/// <summary>
/// Resource template for the remotely located resource.
/// </summary>
//public ResourceTemplate Template
//{
// get { return template; }
//}
/// <summary>
/// Connection responsible for the distributed resource.
/// </summary>
public DistributedConnection Connection
internal bool _Attach(PropertyValue[] properties)
{
if (attached)
return false;
else
{
get { return connection; }
}
suspended = false;
/// <summary>
/// Resource link
/// </summary>
public string Link
{
get { return link; }
}
/// <summary>
/// Instance Id given by the other end.
/// </summary>
public uint Id
{
get { return instanceId; }
}
/// <summary>
/// IDestructible interface.
/// </summary>
public void Destroy()
{
destroyed = true;
attached = false;
connection.SendDetachRequest(instanceId);
OnDestroy?.Invoke(this);
}
/// <summary>
/// Suspend resource
/// </summary>
internal void Suspend()
{
suspended = true;
attached = false;
}
/// <summary>
/// Resource is attached when all its properties are received.
/// </summary>
internal bool Attached => attached;
internal bool Suspended => suspended;
// public DistributedResourceStack Stack
//{
// get { return stack; }
//}
/// <summary>
/// Create a new distributed resource.
/// </summary>
/// <param name="connection">Connection responsible for the distributed resource.</param>
/// <param name="template">Resource template.</param>
/// <param name="instanceId">Instance Id given by the other end.</param>
/// <param name="age">Resource age.</param>
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;
}
/// <summary>
/// Export all properties with ResourceProperty attributed as bytes array.
/// </summary>
/// <returns></returns>
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<object> _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<object> _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<object>();
if (attached && ft != null)
{
var et = Instance.Template.GetEventTemplateByIndex(index);
events[index]?.Invoke(this, args);
Instance.EmitResourceEvent(et.Name, args);
}
public AsyncReply<object> _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<object> _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<object>();
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;
}
/// <summary>
/// Get a property value.
/// </summary>
/// <param name="index">Zero-based property index.</param>
/// <returns>Value</returns>
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)
/// <summary>
/// Get a property value.
/// </summary>
/// <param name="index">Zero-based property index.</param>
/// <returns>Value</returns>
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);
}
/// <summary>
/// Set property value.
/// </summary>
/// <param name="index">Zero-based property index.</param>
/// <param name="value">Value</param>
/// <returns>Indicator when the property is set.</returns>
protected internal AsyncReply<object> _Set(byte index, object value)
{
if (index >= properties.Length)
return null;
/// <summary>
/// Set property value.
/// </summary>
/// <param name="index">Zero-based property index.</param>
/// <param name="value">Value</param>
/// <returns>Indicator when the property is set.</returns>
protected internal AsyncReply<object> _Set(byte index, object value)
{
if (index >= properties.Length)
return null;
var reply = new AsyncReply<object>();
var reply = new AsyncReply<object>();
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));
}
}
*/
}
*/
/// <summary>
/// Resource interface.
/// </summary>
public Instance Instance
{
get;
set;
}
/// <summary>
/// Resource interface.
/// </summary>
public Instance Instance
{
get;
set;
}
/// <summary>
/// Create a new instance of distributed resource.
/// </summary>
public DistributedResource()
{
//stack = new DistributedResourceStack(this);
//this.Instance.ResourceModified += this.OnModified;
/// <summary>
/// Create a new instance of distributed resource.
/// </summary>
public DistributedResource()
{
//stack = new DistributedResourceStack(this);
//this.Instance.ResourceModified += this.OnModified;
}
}
/// <summary>
/// Resource interface.
/// </summary>
/// <param name="trigger"></param>
/// <returns></returns>
public AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
/// <summary>
/// Resource interface.
/// </summary>
/// <param name="trigger"></param>
/// <returns></returns>
public AsyncReply<bool> 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<bool>(true);
}
// do nothing.
return new AsyncReply<bool>(true);
}
}

View File

@ -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);

View File

@ -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; }
}
}

View File

@ -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<DistributedConnection>, IResource
{
public class DistributedServer : NetworkServer<DistributedConnection>, 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<bool> 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<bool>(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<bool> 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<bool>(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);
}
}

View File

@ -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; }
}

View File

@ -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<IResource[]> Query(string path, DistributedConnection sender);
protected abstract override bool Create();
}
public abstract class EntryPoint : Esiur.Resource.Resource
{
public abstract AsyncReply<IResource[]> Query(string path, DistributedConnection sender);
protected abstract override bool Create();
}

View File

@ -2,14 +2,13 @@
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net
{
public interface INetworkReceiver<T>
{
void NetworkClose(T sender);
void NetworkReceive(T sender, NetworkBuffer buffer);
//void NetworkError(T sender);
namespace Esiur.Net;
void NetworkConnect(T sender);
}
public interface INetworkReceiver<T>
{
void NetworkClose(T sender);
void NetworkReceive(T sender, NetworkBuffer buffer);
//void NetworkError(T sender);
void NetworkConnect(T sender);
}

View File

@ -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;
}
}
}

View File

@ -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<ISocket>// <TS>: IResource where TS : NetworkSession
{
public abstract class NetworkConnection: IDestructible, INetworkReceiver<ISocket>// <TS>: 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<NetworkConnection> 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<NetworkConnection> 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<bool> SendAsync(byte[] message, int offset, int length)
{
try
{
lastAction = DateTime.Now;
return sock.SendAsync(message, offset, length);
}
catch
{
return new AsyncReply<bool>(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<bool> SendAsync(byte[] message, int offset, int length)
{
try
{
lastAction = DateTime.Now;
return sock.SendAsync(message, offset, length);
}
catch
{
return new AsyncReply<bool>(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();
//}
}
}
//{
// Receiver?.NetworkError(this);
//throw new NotImplementedException();
//}
//public void NetworkConnect(ISocket sender)
//{
// Receiver?.NetworkConnect(this);
//throw new NotImplementedException();
//}
}

View File

@ -33,279 +33,277 @@ using Esiur.Resource;
using System.Threading.Tasks;
using System.Diagnostics;
namespace Esiur.Net
namespace Esiur.Net;
public abstract class NetworkServer<TConnection> : IDestructible where TConnection : NetworkConnection, new()
{
//private bool isRunning;
private Sockets.ISocket listener;
public AutoList<TConnection, NetworkServer<TConnection>> Connections { get; internal set; }
public abstract class NetworkServer<TConnection> : 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<string, TSession> Sessions = new KeyList<string, TSession>();
public event DestroyedEvent OnDestroy;
//public AutoList<TConnection, NetworkServer<TConnection>> Connections => connections;
private void MinuteThread(object state)
{
//private bool isRunning;
private Sockets.ISocket listener;
public AutoList<TConnection, NetworkServer<TConnection>> 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<TConnection> ToBeClosed = null;
private Timer timer;
//public KeyList<string, TSession> Sessions = new KeyList<string, TSession>();
public event DestroyedEvent OnDestroy;
//public AutoList<TConnection, NetworkServer<TConnection>> Connections => connections;
private void MinuteThread(object state)
lock (Connections.SyncRoot)
{
List<TConnection> 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<TConnection>();
ToBeClosed.Add(c);
}
if (ToBeClosed == null)
ToBeClosed = new List<TConnection>();
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<TConnection, NetworkServer<TConnection>>(this);
Connections = new AutoList<TConnection, NetworkServer<TConnection>>(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);
}
}
}
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;
}
}

View File

@ -35,96 +35,94 @@ using Esiur.Data;
using Esiur.Misc;
using Esiur.Core;
namespace Esiur.Net
namespace Esiur.Net;
public class NetworkSession : IDestructible //<T> where T : TClient
{
public class NetworkSession:IDestructible //<T> 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<string, object> variables;
public event SessionEndedEvent OnEnd;
public event SessionModifiedEvent OnModify;
public event DestroyedEvent OnDestroy;
public KeyList<string, object> 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<string, object>();
variables.OnModified += new KeyList<string, object>.Modified(VariablesModified);
creation = DateTime.Now;
}
private KeyList<string, object> 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<string, object> Variables
if (this.timeout != 0)
{
get { return variables; }
}
public NetworkSession()
{
variables = new KeyList<string, object>();
variables.OnModified += new KeyList<string, object>.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<string, object> 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; }
}
}
}
private void OnSessionEndTimerCallback(object o)
{
OnEnd?.Invoke(this);
}
void VariablesModified(string key, object oldValue, object newValue, KeyList<string, object> 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; }
}
}

View File

@ -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<string, object> 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<string, object> 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<string, object>();
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<string, object>();
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;
}
}

View File

@ -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<HTTPCookie> Cookies = new List<HTTPCookie>();
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<HTTPCookie> Cookies = new List<HTTPCookie>();
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<byte> msg = new List<byte>();
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<byte> msg = new List<byte>();
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;
}
}
}

View File

@ -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;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
}
}

View File

@ -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 *************************************/

View File

@ -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<byte>();
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<byte>();
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;
}
}
}

View File

@ -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<object[]> reply;
public SendList(NetworkConnection connection, AsyncReply<object[]> reply)
{
NetworkConnection connection;
AsyncReply<object[]> reply;
this.reply = reply;
this.connection = connection;
}
public SendList(NetworkConnection connection, AsyncReply<object[]> reply)
{
this.reply = reply;
this.connection = connection;
}
public override AsyncReply<object[]> Done()
{
connection.Send(this.ToArray());
return reply;
}
public override AsyncReply<object[]> Done()
{
connection.Send(this.ToArray());
return reply;
}
}

View File

@ -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<ISocket> Receiver { get; set; }
INetworkReceiver<ISocket> Receiver { get; set; }
AsyncReply<bool> SendAsync(byte[] message, int offset, int length);
AsyncReply<bool> SendAsync(byte[] message, int offset, int length);
void Send(byte[] message);
void Send(byte[] message, int offset, int length);
void Close();
AsyncReply<bool> Connect(string hostname, ushort port);
bool Begin();
AsyncReply<bool> BeginAsync();
//ISocket Accept();
AsyncReply<ISocket> AcceptAsync();
ISocket Accept();
void Send(byte[] message);
void Send(byte[] message, int offset, int length);
void Close();
AsyncReply<bool> Connect(string hostname, ushort port);
bool Begin();
AsyncReply<bool> BeginAsync();
//ISocket Accept();
AsyncReply<ISocket> AcceptAsync();
ISocket Accept();
IPEndPoint RemoteEndPoint { get; }
IPEndPoint LocalEndPoint { get; }
IPEndPoint RemoteEndPoint { get; }
IPEndPoint LocalEndPoint { get; }
void Hold();
void Hold();
void Unhold();
}
void Unhold();
}

View File

@ -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<ISocket> Receiver { get; set; }
Socket sock;
byte[] receiveBuffer;
bool held;
//ArraySegment<byte> receiveBufferSegment;
NetworkBuffer receiveNetworkBuffer = new NetworkBuffer();
readonly object sendLock = new object();
Queue<KeyValuePair<AsyncReply<bool>, byte[]>> sendBufferQueue = new Queue<KeyValuePair<AsyncReply<bool>, byte[]>>();// Queue<byte[]>();
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<bool> Connect(string hostname, ushort port)
{
var rt = new AsyncReply<bool>();
public INetworkReceiver<ISocket> Receiver { get; set; }
this.hostname = hostname;
this.server = false;
Socket sock;
byte[] receiveBuffer;
bool held;
//ArraySegment<byte> receiveBufferSegment;
NetworkBuffer receiveNetworkBuffer = new NetworkBuffer();
readonly object sendLock = new object();
Queue<KeyValuePair<AsyncReply<bool>, byte[]>> sendBufferQueue = new Queue<KeyValuePair<AsyncReply<bool>, byte[]>>();// Queue<byte[]>();
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<bool> Connect(string hostname, ushort port)
try
{
var rt = new AsyncReply<bool>();
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<bool>)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<AsyncReply<bool>, 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<int> 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<bool> 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<bool>)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<ISocket> 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<bool> 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<bool>(false);
var kv = sendBufferQueue.Dequeue();
var rt = new AsyncReply<bool>();
if (asyncSending || held)
try
{
sendBufferQueue.Enqueue(new KeyValuePair<AsyncReply<bool>, 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;
}
}
}
}
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<AsyncReply<bool>, 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<int> 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<bool> 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<ISocket> 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<bool> SendAsync(byte[] message, int offset, int length)
{
var msg = message.Clip((uint)offset, (uint)length);
lock (sendLock)
{
if (!sock.Connected)
return new AsyncReply<bool>(false);
var rt = new AsyncReply<bool>();
if (asyncSending || held)
{
sendBufferQueue.Enqueue(new KeyValuePair<AsyncReply<bool>, 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;
}
}
}

View File

@ -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
}

File diff suppressed because it is too large Load Diff

View File

@ -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<ISocket>
{
public class WSocket : ISocket, INetworkReceiver<ISocket>
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<ISocket> 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<bool> 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<ISocket> 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<bool> SendAsync(byte[] message, int offset, int length)
{
throw new NotImplementedException();
}
public ISocket Accept()
{
throw new NotImplementedException();
}
public AsyncReply<bool> 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;
}
}
}
public INetworkReceiver<ISocket> 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<bool> 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<ISocket> 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<bool> SendAsync(byte[] message, int offset, int length)
{
throw new NotImplementedException();
}
public ISocket Accept()
{
throw new NotImplementedException();
}
public AsyncReply<bool> 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);
}
}

View File

@ -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<string, object> variables = new KeyList<string, object>();
private KeyList<string, object> variables = new KeyList<string, object>();
public TCPServer Server { get; internal set; }
public TCPServer Server { get; internal set; }
public KeyList<string, object> Variables
public KeyList<string, object> 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
}
}

View File

@ -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<bool> Trigger(ResourceTrigger trigger);
public abstract AsyncReply<bool> 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);
}
}

View File

@ -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<TCPConnection>, IResource
{
public class TCPServer : NetworkServer<TCPConnection>, 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<bool> 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<TCPFilter>().Then(x => filters = x);
}
return new AsyncReply<bool>(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<bool> 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<TCPFilter>().Then(x => filters = x);
}
return new AsyncReply<bool>(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);
}
}
}
}

View File

@ -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
{
}
}

View File

@ -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<bool> Trigger(ResourceTrigger trigger);
public abstract bool Execute(byte[] data, IPEndPoint sender);
public void Destroy()
{
OnDestroy?.Invoke(this);
}
get;
set;
}
}
public event DestroyedEvent OnDestroy;
public abstract AsyncReply<bool> Trigger(ResourceTrigger trigger);
public abstract bool Execute(byte[] data, IPEndPoint sender);
public void Destroy()
{
OnDestroy?.Invoke(this);
}
}

View File

@ -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<bool> 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<UDPFilter>();
}
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<bool> 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<UDPFilter>();
}
return true;
}
}

View File

@ -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<string, TypeTemplate[]> cache = new();
// private List<string> 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<string, TypeTemplate[]> cache = new();
// private List<string> 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<DistributedConnection>(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<DistributedConnection>(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<bool> Trigger(ResourceTrigger trigger) => new AsyncReply<bool>(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<bool> Trigger(ResourceTrigger trigger) => new AsyncReply<bool>(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");
}
}
}

View File

@ -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<IFieldSymbol> Fields { get; set; }
public ITypeSymbol ClassSymbol { get; set; }
public bool HasTrigger { get; set; }
public List<IFieldSymbol> Fields { get; set; }
public ITypeSymbol ClassSymbol { get; set; }
public ClassDeclarationSyntax ClassDeclaration { get; set; }
public ClassDeclarationSyntax ClassDeclaration { get; set; }
}
}

View File

@ -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; }
}

View File

@ -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<string, ResourceGeneratorClassInfo> Classes { get; } = new();
public List<string> Imports { get; } = new();
public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
{
public Dictionary<string, ResourceGeneratorClassInfo> Classes { get; } = new();
public List<string> 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;
}
}
}
}

View File

@ -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<Type, Type> cache = new Dictionary<Type, Type>();
static Dictionary<Type, Type> cache = new Dictionary<Type, Type>();
#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<ResourceAttribute>(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<ResourceAttribute>(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<PublicAttribute>(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<PublicAttribute>(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<T>()
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<T>()
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
*/
}
}

View File

@ -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<DistributedConnection>(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<DistributedConnection>(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();
}
}

Some files were not shown because too many files have changed in this diff Show More