2
0
mirror of https://github.com/esiur/esiur-dotnet.git synced 2025-05-07 12:02:59 +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.ComponentModel;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace Esiur.Stores.EntityCore namespace Esiur.Stores.EntityCore;
public class EntityResource : IResource
{ {
//[NotMapped]
public class EntityResource : IResource //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 Microsoft.EntityFrameworkCore.Metadata;
using System.Reflection; 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>>(); // load navigation properties
object DBLock = new object(); var ent = db.Entry(res);
foreach (var rf in ent.References)
rf.Load();
Dictionary<string, EntityTypeInfo> TypesByName = new Dictionary<string, EntityTypeInfo>(); return new AsyncReply<IResource>(res as IResource);
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));
}
public AsyncReply<bool> Put(IResource resource)
{
if (resource == this)
return new AsyncReply<bool>(true); 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) if (!DB[type][id].IsAlive)
return null; return null;
return DB[type][id].Target as IResource; 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);
} }
} }
//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.Reflection;
using System.Text; using System.Text;
namespace Esiur.Stores.EntityCore namespace Esiur.Stores.EntityCore;
struct EntityTypeInfo
{ {
struct EntityTypeInfo public string Name;
{ public IEntityType Type;
public string Name; public PropertyInfo PrimaryKey;
public IEntityType Type; // public Func<DbContext> Getter;
public PropertyInfo PrimaryKey;
// public Func<DbContext> Getter;
}
} }

View File

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

View File

@ -36,79 +36,83 @@ using System.Reflection;
using Esiur.Proxy; using Esiur.Proxy;
using Microsoft.EntityFrameworkCore; 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 ExtensionInfo(IDbContextOptionsExtension extension)
//public void AddType(IEntityType type) : base(extension)
//{
// 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) private new EsiurExtensionOptions Extension
{ => (EsiurExtensionOptions)base.Extension;
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) public override bool IsDatabaseProvider => false;
{
_info = new ExtensionInfo(this);
_store = store;
}
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.Reflection;
using System.Text; 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 var store = dbSet.GetInfrastructure().GetService<IDbContextOptions>().FindExtension<EsiurExtensionOptions>().Store;
//{
// return dbContext.GetInfrastructure().CreateResource<T>(properties);
//}
public static T AddResource<T>(this DbSet<T> dbSet, T resource) where T : class, IResource var manager = store.Instance.Managers.FirstOrDefault();// > 0 ? store.Instance.Managers.First() : null;
=> AddResourceAsync(dbSet, resource).Wait();
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);
foreach (var p in ps)
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)
{ {
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)
{ {
if (mi is PropertyInfo)
var mi = resType.GetMember(p.Key, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
.FirstOrDefault();
if (mi != null)
{ {
if (mi is PropertyInfo) var pi = mi as PropertyInfo;
{ if (pi.CanWrite)
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)
{ {
try try
{ {
(mi as FieldInfo).SetValue(res, p.Value); pi.SetValue(res, p.Value);
} }
catch (Exception ex) 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 //await Warehouse.Put<T>("", null, null, null, null, properties);
//{ var entity = dbSet.Add((T)res);
// var options = serviceProvider.GetService<IDbContextOptions>().FindExtension<EsiurExtensionOptions<T>>(); 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 //public static async AsyncReply<T> CreateResourceAsync<T>(this IServiceProvider serviceProvider, T properties = null) where T : class, IResource
// => CreateResourceAsync<T>(serviceProvider, properties).Wait(); //{
// var options = serviceProvider.GetService<IDbContextOptions>().FindExtension<EsiurExtensionOptions<T>>();
public static DbContextOptionsBuilder UseEsiur(this DbContextOptionsBuilder optionsBuilder, // var resource = await Warehouse.New<T>("", options.Store, null, null, null, properties);
EntityStore store,
Func<DbContext> getter = null
//IServiceCollection services = null // resource.Instance.Managers.AddRange(options.Store.Instance.Managers.ToArray());
//string name = null,
//IResource parent = null, // return resource;
//IPermissionsManager manager = null, //}
//Func<DbContext> dbContextProvider = null
) //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 (store == null)
return optionsBuilder;
if (extension == null)
{
if (store == null)
return optionsBuilder;
store.Options = optionsBuilder.Options;
extension = new EsiurExtensionOptions(store);
}
((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
return optionsBuilder;
store.Options = optionsBuilder.Options;
extension = new EsiurExtensionOptions(store);
} }
//public static DbContextOptionsBuilder<TContext> UseEsiur<TContext>( ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
// this DbContextOptionsBuilder<TContext> optionsBuilder,
// //DbContext context,
// string name = null,
// IResource parent = null,
// IPermissionsManager manager = null,
// Func<DbContext> dbContextProvider = null)
// where TContext : DbContext
//{
return optionsBuilder;
// 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;
//}
} }
//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.Collections.Generic;
using System.Text; 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; _options = options;
private readonly ProviderConventionSetBuilderDependencies _conventionSetBuilderDependencies; _conventionSetBuilderDependencies = 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;
}
} }
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 Microsoft.EntityFrameworkCore.Metadata.Internal;
using Esiur.Data; 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 var id = properties.First();
= typeof(EsiurProxyRewrite).GetTypeInfo().GetDeclaredMethod(nameof(EsiurProxyRewrite.CreateInstance));
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, var cache = options.Store.GetById(entityType.ClrType, id);
// object[] constructorArguments, DbContext context, long id)
//{
// return CreateInstance(dbContextOptions, entityType,
// constructorArguments, context, id);
//}
public static object CreateInstance( if (cache != null)
IDbContextOptions dbContextOptions, return cache;
IEntityType entityType,
//object id
object[] properties
// ILazyLoader loader, if (Codec.ImplementsInterface(entityType.ClrType, typeof(IResource)))
// object[] constructorArguments,
//DbContext context,
)
{ {
var id = properties.First(); // check if the object exists
var obj = Warehouse.New(entityType.ClrType).Wait() as IResource;
var options = dbContextOptions.FindExtension<EsiurExtensionOptions>(); options.Store.TypesByType[entityType.ClrType].PrimaryKey.SetValue(obj, id);
var manager = options.Store.Instance.Managers.Count > 0 ? options.Store.Instance.Managers.First() : null; Warehouse.Put(id.ToString(), obj, options.Store, null, null, 0, manager).Wait();
return obj;
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);
} }
else
public void ProcessModelFinalizing(IConventionModelBuilder modelBuilder, IConventionContext<IConventionModelBuilder> context)
{ {
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; 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. binding = ((EntityType)entityType).ServiceOnlyConstructorBinding;
var binding = (InstantiationBinding)entityType[CoreAnnotationNames.ConstructorBinding]; if (binding != null)
#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
{ {
((EntityType)entityType).SetServiceOnlyConstructorBinding(
var key = entityType.FindPrimaryKey().Properties.First(); UpdateConstructorBindings(key, proxyType),
if (key == null) ConfigurationSource.Convention);
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));
} }
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> <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Version>1.5.2</Version> <Version>1.5.2</Version>
<PackageId>Esiur.Stores.MongoDB</PackageId> <PackageId>Esiur.Stores.MongoDB</PackageId>
<LangVersion>latest</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <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.Text;
using System.Threading.Tasks; 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; reply.Then(x =>
AsyncException exception = null;
object result;
public AsyncAwaiter(AsyncReply reply)
{ {
reply.Then(x => this.IsCompleted = true;
{ this.result = x;
this.IsCompleted = true; this.callback?.Invoke();
this.result = x; }).Error(x =>
this.callback?.Invoke();
}).Error(x =>
{
exception = x;
this.IsCompleted = true;
this.callback?.Invoke();
});
}
public object GetResult()
{ {
if (exception != null) exception = x;
throw exception; this.IsCompleted = true;
return result; this.callback?.Invoke();
} });
public bool IsCompleted { get; private set; }
public void OnCompleted(Action continuation)
{
if (IsCompleted)
continuation?.Invoke();
else
// Continue....
callback = continuation;
}
} }
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.Text;
using System.Threading.Tasks; 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; reply.Then(x =>
AsyncException exception = null;
T result;
public AsyncAwaiter(AsyncReply<T> reply)
{ {
reply.Then(x => this.IsCompleted = true;
{ this.result = (T)x;
this.IsCompleted = true; this.callback?.Invoke();
this.result = (T)x; }).Error(x =>
this.callback?.Invoke();
}).Error(x =>
{
exception = x;
this.IsCompleted = true;
this.callback?.Invoke();
});
}
public T GetResult()
{ {
if (exception != null) exception = x;
throw exception; this.IsCompleted = true;
return result; this.callback?.Invoke();
} });
public bool IsCompleted { get; private set; }
public void OnCompleted(Action continuation)
{
if (IsCompleted)
continuation?.Invoke();
else
// Continue....
callback = continuation;
}
} }
}
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.Text;
using System.Threading.Tasks; 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; public AsyncBag(object[] results)
bool sealedBag = false; : base(results)
{
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)
{
}
} }
} }

View File

@ -4,50 +4,48 @@ using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Threading.Tasks; 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; reply.Then(x =>
AsyncException exception = null;
object[] result;
public AsyncBagAwaiter(AsyncBag reply)
{ {
reply.Then(x => this.IsCompleted = true;
{ this.result = x;
this.IsCompleted = true; this.callback?.Invoke();
this.result = x; }).Error(x =>
this.callback?.Invoke();
}).Error(x =>
{
exception = x;
this.IsCompleted = true;
this.callback?.Invoke();
});
}
public object[] GetResult()
{ {
if (exception != null) exception = x;
throw exception; this.IsCompleted = true;
return result; this.callback?.Invoke();
} });
public bool IsCompleted { get; private set; }
public void OnCompleted(Action continuation)
{
if (IsCompleted)
continuation?.Invoke();
else
// Continue....
callback = continuation;
}
} }
}
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.Text;
using System.Threading.Tasks; 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; reply.Then(x =>
AsyncException exception = null;
T[] result;
public AsyncBagAwaiter(AsyncBag<T> reply)
{ {
reply.Then(x => this.IsCompleted = true;
{ this.result = x;
this.IsCompleted = true; this.callback?.Invoke();
this.result = x; }).Error(x =>
this.callback?.Invoke();
}).Error(x =>
{
exception = x;
this.IsCompleted = true;
this.callback?.Invoke();
});
}
public T[] GetResult()
{ {
if (exception != null) exception = x;
throw exception; this.IsCompleted = true;
return result; this.callback?.Invoke();
} });
public bool IsCompleted { get; private set; }
public void OnCompleted(Action continuation)
{
if (IsCompleted)
continuation?.Invoke();
else
// Continue....
callback = continuation;
}
} }
}
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.Text;
using System.Threading.Tasks; 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)
{ {
public AsyncBag<T> Then(Action<T[]> callback) base.Then(new Action<object>((o) => callback(((object[])o).Select(x => (T)x).ToArray())));
{ return this;
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 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.Collections.Generic;
using System.Text; 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; Type = ErrorType.Exception;
public readonly ExceptionCode Code; Code = 0;
}
public AsyncException(Exception exception) :base(exception.Message, exception) public override string StackTrace => InnerException != null && Type == ErrorType.Exception ? InnerException.StackTrace : base.StackTrace;
{
Type = ErrorType.Exception;
Code = 0;
}
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()
{
public override string ToString() return Code.ToString() + ": " + Message;
{
return Code.ToString() + ": " + Message;
}
} }
} }

View File

@ -28,57 +28,56 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; 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>>(); lock (queueLock)
//Action<T> callback; list.Add(reply);
object queueLock = new object();
//public AsyncQueue<T> Then(Action<T> callback) resultReady = false;
//{ reply.Then(processQueue);
// base.Then(new Action<object>(o => callback((T)o))); }
//return this; public void Remove(AsyncReply<T> reply)
//} {
lock (queueLock)
list.Remove(reply);
processQueue(default(T));
}
public void Add(AsyncReply<T> reply) void processQueue(T o)
{ {
lock (queueLock) lock (queueLock)
list.Add(reply); 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; resultReady = (list.Count == 0);
reply.Then(processQueue); }
}
public void Remove(AsyncReply<T> reply) public AsyncQueue()
{ {
lock (queueLock)
list.Remove(reply);
processQueue(default(T));
}
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.Runtime.CompilerServices;
using System.Diagnostics; using System.Diagnostics;
namespace Esiur.Core namespace Esiur.Core;
[AsyncMethodBuilder(typeof(AsyncReplyBuilder))]
public class AsyncReply
{ {
[AsyncMethodBuilder(typeof(AsyncReplyBuilder))] public bool Debug = false;
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>>();
//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; get { return resultReady; }
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)
{
}
*/
} }
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.Runtime.CompilerServices;
using System.Text; using System.Text;
namespace Esiur.Core namespace Esiur.Core;
public class AsyncReplyBuilder
{ {
public class AsyncReplyBuilder AsyncReply reply;
AsyncReplyBuilder(AsyncReply reply)
{ {
AsyncReply reply; this.reply = 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;
}
}
} }
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.Runtime.CompilerServices;
using System.Text; 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; this.reply = 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;
}
}
} }
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.Runtime.CompilerServices;
using System.Diagnostics; 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.Text;
using System.Threading.Tasks; 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>>(); if (resultReady)
protected object result; 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>>(); if (exception != null)
object callbacksLock = new object();
protected bool resultReady = false;
AsyncException exception;
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
public bool Ready
{ {
get { return resultReady; } callback(exception);
tcs.SetException(exception);
} }
public object Result return this;
{ }
get { return result; }
}
public AsyncReply Then(Action<object> callback) public AsyncReply Progress(Action<ProgressType, int, int> callback)
{ {
callbacks.Add(callback); progressCallbacks.Add(callback);
return this;
}
if (resultReady) public AsyncReply Chunk(Action<object> callback)
callback(result); {
chunkCallbacks.Add(callback);
return this;
}
return this; public void Trigger(object result)
} {
public AsyncReply Error(Action<AsyncException> callback) lock (callbacksLock)
{
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)
{ {
if (resultReady) if (resultReady)
return; 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; 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.Collections.Generic;
using System.Text; 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.Collections.Generic;
using System.Text; using System.Text;
namespace Esiur.Core namespace Esiur.Core;
public enum ExceptionCode : ushort
{ {
public enum ExceptionCode : ushort HostNotReachable,
{ AccessDenied,
HostNotReachable, UserOrTokenNotFound,
AccessDenied, ChallengeFailed,
UserOrTokenNotFound, ResourceNotFound,
ChallengeFailed, AttachDenied,
ResourceNotFound, InvalidMethod,
AttachDenied, InvokeDenied,
InvalidMethod, CreateDenied,
InvokeDenied, AddParentDenied,
CreateDenied, AddChildDenied,
AddParentDenied, ViewAttributeDenied,
AddChildDenied, UpdateAttributeDenied,
ViewAttributeDenied, StoreNotFound,
UpdateAttributeDenied, ParentNotFound,
StoreNotFound, ChildNotFound,
ParentNotFound, ResourceIsNotStore,
ChildNotFound, DeleteDenied,
ResourceIsNotStore, DeleteFailed,
DeleteDenied, UpdateAttributeFailed,
DeleteFailed, GetAttributesFailed,
UpdateAttributeFailed, ClearAttributesFailed,
GetAttributesFailed, TemplateNotFound,
ClearAttributesFailed, RenameDenied,
TemplateNotFound, ClassNotFound,
RenameDenied, MethodNotFound,
ClassNotFound, PropertyNotFound,
MethodNotFound, SetPropertyDenied,
PropertyNotFound, ReadOnlyProperty,
SetPropertyDenied, GeneralFailure,
ReadOnlyProperty, AddToStoreFailed,
GeneralFailure, NotAttached,
AddToStoreFailed, AlreadyListened,
NotAttached, AlreadyUnlistened,
AlreadyListened, NotListenable
AlreadyUnlistened,
NotListenable
}
} }

View File

@ -2,13 +2,12 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
namespace Esiur.Core namespace Esiur.Core;
public enum ExceptionLevel
{ {
public enum ExceptionLevel Code = 0x1,
{ Message = 0x2,
Code = 0x1, Source = 0x4,
Message = 0x2, Trace = 0x8
Source = 0x4,
Trace = 0x8
}
} }

View File

@ -3,19 +3,18 @@ using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text; using System.Text;
namespace Esiur.Core 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);
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.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Esiur.Core namespace Esiur.Core;
{
public delegate void DestroyedEvent(object sender);
public interface IDestructible public delegate void DestroyedEvent(object sender);
{
event DestroyedEvent OnDestroy; public interface IDestructible
void Destroy(); {
} event DestroyedEvent OnDestroy;
void Destroy();
} }

View File

@ -29,12 +29,11 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Esiur.Core namespace Esiur.Core;
public enum LogType
{ {
public enum LogType Debug,
{ Warning,
Debug, Error,
Warning,
Error,
}
} }

View File

@ -2,11 +2,10 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; 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 Esiur.Core;
using System.Reflection; 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(); public void Sort()
private List<T> list = new List<T>(); {
lock (syncRoot)
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)
list.Sort(); list.Sort();
} }
public void Sort(IComparer<T> comparer) public void Sort(IComparer<T> comparer)
{ {
lock (syncRoot) lock (syncRoot)
list.Sort(comparer); list.Sort(comparer);
} }
public void Sort(Comparison<T> comparison) public void Sort(Comparison<T> comparison)
{ {
lock (syncRoot) lock (syncRoot)
list.Sort(comparison); list.Sort(comparison);
} }
public IEnumerable<T> Where(Func<T, bool> predicate) public IEnumerable<T> Where(Func<T, bool> predicate)
{ {
return list.Where(predicate); return list.Where(predicate);
} }
/// <summary> /// <summary>
/// Convert AutoList to array /// Convert AutoList to array
/// </summary> /// </summary>
/// <returns>Array</returns> /// <returns>Array</returns>
public T[] ToArray() public T[] ToArray()
{ {
// list.OrderBy() // list.OrderBy()
return list.ToArray(); return list.ToArray();
} }
/// <summary> /// <summary>
/// Create a new instance of AutoList /// Create a new instance of AutoList
/// </summary> /// </summary>
/// <param name="state">State object to be included when an event is raised.</param> /// <param name="state">State object to be included when an event is raised.</param>
public AutoList(ST state) public AutoList(ST state)
{ {
State = state; State = state;
#if NETSTANDARD #if NETSTANDARD
removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())); removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo()));
#else #else
removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T))); removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T)));
#endif #endif
} }
/// <summary> /// <summary>
/// Create a new instance of AutoList /// Create a new instance of AutoList
/// </summary> /// </summary>
/// <param name="values">Populate the list with items</param> /// <param name="values">Populate the list with items</param>
/// <returns></returns> /// <returns></returns>
public AutoList(ST state, T[] values) public AutoList(ST state, T[] values)
{ {
State = state; State = state;
#if NETSTANDARD #if NETSTANDARD
removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())); removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo()));
#else #else
removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T))); removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T)));
#endif #endif
AddRange(values); AddRange(values);
} }
/// <summary> /// <summary>
/// Synchronization lock of the list /// Synchronization lock of the list
/// </summary> /// </summary>
public object SyncRoot public object SyncRoot
{
get
{ {
get return syncRoot;
{
return syncRoot;
}
} }
}
/// <summary> /// <summary>
/// First item in the list /// First item in the list
/// </summary> /// </summary>
public T First() 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];
} }
set
/// <summary>
/// Get an item at a specified index
/// </summary>
public T this[int index]
{ {
get var oldValue = list[index];
{
return list[index];
}
set
{
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 (removableList)
{
if (oldValue != null)
((IDestructible)oldValue).OnDestroy -= ItemDestroyed;
if (value != null) if (value != null)
((IDestructible)value).OnDestroy += ItemDestroyed; ((IDestructible)value).OnDestroy += ItemDestroyed;
}
lock (syncRoot) 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.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Esiur.Data namespace Esiur.Data;
public enum DataType : byte
{ {
public enum DataType : byte Void = 0x0,
{ //Variant,
Void = 0x0, Bool,
//Variant, Int8,
Bool, UInt8,
Int8, Char,
UInt8, Int16,
Char, UInt16,
Int16, Int32,
UInt16, UInt32,
Int32, Int64,
UInt32, UInt64,
Int64, Float32,
UInt64, Float64,
Float32, Decimal,
Float64, DateTime,
Decimal, Resource,
DateTime, DistributedResource,
Resource, ResourceLink,
DistributedResource, String,
ResourceLink, Structure,
String, Record,
Structure, //Stream,
Record, //Array = 0x80,
//Stream, VarArray = 0x80,
//Array = 0x80, BoolArray,
VarArray = 0x80, Int8Array,
BoolArray, UInt8Array,
Int8Array, CharArray,
UInt8Array, Int16Array,
CharArray, UInt16Array,
Int16Array, Int32Array,
UInt16Array, UInt32Array,
Int32Array, Int64Array,
UInt32Array, UInt64Array,
Int64Array, Float32Array,
UInt64Array, Float64Array,
Float32Array, DecimalArray,
Float64Array, DateTimeArray,
DecimalArray, ResourceArray,
DateTimeArray, DistributedResourceArray,
ResourceArray, ResourceLinkArray,
DistributedResourceArray, StringArray,
ResourceLinkArray, StructureArray,
StringArray, RecordArray,
StructureArray, NotModified = 0x7f,
RecordArray, Unspecified = 0xff,
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:
case DataType.Void: return 0;
case DataType.NotModified: case DataType.Bool:
return 0; case DataType.UInt8:
case DataType.Bool: case DataType.Int8:
case DataType.UInt8: return 1;
case DataType.Int8: case DataType.Char:
return 1; case DataType.UInt16:
case DataType.Char: case DataType.Int16:
case DataType.UInt16: return 2;
case DataType.Int16: case DataType.Int32:
return 2; case DataType.UInt32:
case DataType.Int32: case DataType.Float32:
case DataType.UInt32: case DataType.Resource:
case DataType.Float32: return 4;
case DataType.Resource: case DataType.Int64:
return 4; case DataType.UInt64:
case DataType.Int64: case DataType.Float64:
case DataType.UInt64: case DataType.DateTime:
case DataType.Float64: return 8;
case DataType.DateTime: case DataType.DistributedResource:
return 8; return 4;
case DataType.DistributedResource:
return 4;
default: default:
return -1; return -1;
}
} }
} }
} }

View File

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

View File

@ -2,11 +2,10 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; 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 System.Linq.Expressions;
using Esiur.Core; 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(); get
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 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)) if (dic.ContainsKey(key))
{ {
var v = dic[key]; var oldValue = dic[key];
Remove(key); if (removableList)
return v; 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 else
return default(T); return default(T);
} }
set
public void Sort(Func<KeyValuePair<KT, T>, object> keySelector)
{ {
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]; return dic.Values;
dic.Values.CopyTo(a, 0);
return a;
} }
}
public void Add(KT key, T value) public void Remove(KT key)
{ {
lock (syncRoot) if (!dic.ContainsKey(key))
{ return;
if (removableList)
if (value != null)
((IDestructible)value).OnDestroy += ItemDestroyed;
if (dic.ContainsKey(key)) var value = dic[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);
if (OnAdd != null) if (removableList)
OnAdd(value, this); if (value != null)
} ((IDestructible)value).OnDestroy -= ItemDestroyed;
}
}
private void ItemDestroyed(object sender) lock (syncRoot)
{ dic.Remove(key);
RemoveValue((T)sender);
}
public void RemoveValue(T value) if (OnRemoved != null)
{ OnRemoved(key, value, this);
var toRemove = new List<KT>(); }
foreach (var kv in dic)
if (kv.Value.Equals(value))
toRemove.Add(kv.Key);
foreach (var k in toRemove) public object Owner
Remove(k); {
} get;
set;
}
public T this[KT key] public int Count
{ {
get get { return dic.Count; }
{ }
if (dic.ContainsKey(key)) public bool Contains(KT Key)
return dic[key]; {
else return dic.ContainsKey(Key);
return default(T); }
} public bool ContainsKey(KT Key)
set {
{ return dic.ContainsKey(Key);
Add(key, value); }
} public bool ContainsValue(T Value)
} {
return dic.ContainsValue(Value);
}
public IEnumerator<KeyValuePair<KT, T>> GetEnumerator()
{
return dic.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return dic.GetEnumerator();
}
public void Clear() public KeyList(object owner = null)
{ {
if (removableList) #if NETSTANDARD
foreach (IDestructible v in dic.Values) removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo()));
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()));
#else #else
removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T))); removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T)));
#endif #endif
this.Owner = owner; this.Owner = owner;
if (typeof(KT) == typeof(string)) if (typeof(KT) == typeof(string))
dic = (Dictionary<KT, T>)(object)new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase); dic = (Dictionary<KT, T>)(object)new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase);
else else
dic = new Dictionary<KT, T>(); dic = new Dictionary<KT, T>();
}
} }
} }

View File

@ -28,10 +28,8 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; 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.Collections.Generic;
using System.Text; using System.Text;
namespace Esiur.Data 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; }
/// <summary> public class PropertyValue
/// Create an instance of PropertyValue. {
/// </summary> /// <summary>
/// <param name="value">Value.</param> /// Get or set the value.
/// <param name="age">Age.</param> /// </summary>
/// <param name="date">Date.</param> public object Value { get; set; }
public PropertyValue(object value, ulong age, DateTime date) /// <summary>
{ /// Get or set date of modification or occurrence.
Value = value; /// </summary>
Age = age; public DateTime Date { get; set; }
Date = date; /// <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.Collections.Generic;
using System.Text; 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.Collections.Generic;
using System.Text; using System.Text;
namespace Esiur.Data namespace Esiur.Data;
public enum RecordComparisonResult : byte
{ {
public enum RecordComparisonResult : byte Null,
{ Record,
Null, RecordSameType,
Record, Same
RecordSameType,
Same
}
} }

View File

@ -2,12 +2,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
namespace Esiur.Data namespace Esiur.Data;
public enum ResourceArrayType
{ {
public enum ResourceArrayType Dynamic = 0x0,
{ Static = 0x10,
Dynamic = 0x0, Wrapper = 0x20,
Static = 0x10,
Wrapper = 0x20,
}
} }

View File

@ -2,13 +2,12 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
namespace Esiur.Data namespace Esiur.Data;
public enum ResourceComparisonResult
{ {
public enum ResourceComparisonResult Null, // null
{ Distributed, // resource is distributed
Null, // null Local, // resource is local
Distributed, // resource is distributed Same, // Same as previous
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 Copyright (c) 2017-2021 Ahmed Kh. Zamil
@ -24,76 +23,77 @@ SOFTWARE.
*/ */
using Esiur.Net.IIP;
using Esiur.Resource;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; 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( return (IResource)JsonSerializer.Deserialize(ref reader, typeof(IResource), options);
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();
}
} }
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)) var rt = pt.PropertyInfo.GetValue(resource, null);
{ if (rt is DistributedPropertyContext)
writer.WriteStringValue("NaN"); continue;
}
writer.WritePropertyName(options.PropertyNamingPolicy?.ConvertName(pt.Name) ?? pt.Name);
if (rt is IResource)
JsonSerializer.Serialize(writer, (IResource)rt, options);
else else
{ JsonSerializer.Serialize(writer, rt, options);
writer.WriteNumberValue(value);
}
} }
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 Esiur.Core;
using System.Reflection; 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(); public void Sort(IComparer<T> comparer)
private List<T> list = new List<T>(); {
list.Sort(comparer);
}
public delegate void Modified(ST sender, int index, T oldValue, T newValue); public void Sort(Comparison<T> comparison)
public delegate void Added(ST sender, T value); {
public delegate void Removed(ST sender, int index, T value); list.Sort(comparison);
public delegate void Cleared(ST sender); }
public IEnumerable<T> Where(Func<T, bool> predicate)
{
return list.Where(predicate);
}
public event Modified OnModified; /// <summary>
public event Removed OnRemoved; /// Convert AutoList to array
public event Cleared OnCleared; /// </summary>
public event Added OnAdd; /// <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(); return syncRoot;
}
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);
} }
} }
/// <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.Reflection;
using System.Linq; 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)
{ {
allowMultiple = AllowMultipleValues;
//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>>(); 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); if (!allowMultiple)
public event Modified OnModified;
public StringKeyList(bool AllowMultipleValues = false)
{ {
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) 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 (kv.Key.ToLower() == key)
{ {
if (OnModified != null)
OnModified(Key, null);
m_Variables.Remove(kv); m_Variables.Remove(kv);
return true; break;
} }
} }
return false;
} }
public int Count m_Variables.Add(new KeyValuePair<string, string>(Key, Value));
{ }
get { return m_Variables.Count; }
} public string this[string Key]
{
public bool ContainsKey(string Key) get
{ {
var key = Key.ToLower(); var key = Key.ToLower();
foreach (var kv in m_Variables) foreach (var kv in m_Variables)
if (kv.Key.ToLower() == key) if (kv.Key.ToLower() == key)
return true; return kv.Value;
return false;
}
/* return null;
public bool ContainsKey(string Key) }
set
{ {
//return m_Variables.ContainsKey(Key); var key = Key.ToLower();
return m_keys.Contains(Key.ToLower());
}
*/
public bool ContainsValue(string Value) var toRemove = m_Variables.Where(x => x.Key.ToLower() == key).ToArray();
{
var value = Value.ToLower();
foreach (var kv in m_Variables)
if (kv.Value.ToLower() == value)
return true;
return false;
}
//internal KeyList() foreach (var item in toRemove)
//{ m_Variables.Remove(item);
// m_Session = Session;
// m_Server = Server;
//} 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.Reflection;
using System.Dynamic; 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.Collections.Generic;
using System.Text; using System.Text;
namespace Esiur.Data namespace Esiur.Data;
public enum StructureComparisonResult : byte
{ {
public enum StructureComparisonResult : byte Null,
{ Structure,
Null, StructureSameKeys,
Structure, StructureSameTypes,
StructureSameKeys, Same
StructureSameTypes,
Same
}
} }

View File

@ -4,20 +4,20 @@
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<Description>Distributed Resources Platform</Description> <Description>Distributed Resources Platform</Description>
<Copyright>Ahmed Kh. Zamil</Copyright> <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> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>1.8.8</Version> <Version>2.0.0-alpha</Version>
<RepositoryUrl>https://github.com/esiur/esiur-dotnet</RepositoryUrl> <RepositoryUrl>https://github.com/esiur/esiur-dotnet</RepositoryUrl>
<Authors>Ahmed Kh. Zamil</Authors> <Authors>Ahmed Kh. Zamil</Authors>
<AssemblyVersion>1.8.8.0</AssemblyVersion> <AssemblyVersion>2.0.0.0</AssemblyVersion>
<Company>Esiur Foundation</Company> <Company>Esiur Foundation</Company>
<FileVersion>1.8.8.0</FileVersion> <FileVersion>2.0.0.0</FileVersion>
<AssemblyName>Esiur</AssemblyName> <AssemblyName>Esiur</AssemblyName>
<RootNamespace>Esiur</RootNamespace> <RootNamespace>Esiur</RootNamespace>
<PackageId>Esiur</PackageId> <PackageId>Esiur</PackageId>
<Product>Esiur</Product> <Product>Esiur</Product>
<LangVersion>9.0</LangVersion> <LangVersion>latest</LangVersion>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@ -79,10 +79,13 @@
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" /> <None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
<!-- Package the Newtonsoft.Json dependency alongside the generator assembly --> <!-- 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="$(PkgSystem_Text_Json)\lib\netstandard2.0\*.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
<None Include="Tools/*" Pack="true" PackagePath="tools/" /> <None Include="Tools/*" Pack="true" PackagePath="tools/" />
</ItemGroup>
<ItemGroup>
<None Include="LICENSE" Pack="true" PackagePath="">
</None>
</ItemGroup> </ItemGroup>
</Project> </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 Esiur.Resource;
using System.Text.Json.Serialization; 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>(); try
// 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 return JsonSerializer.Serialize(resource, Global.SerializeOptions);
{
return JsonSerializer.Serialize(resource, Global.SerializeOptions);
}catch (Exception ex)
{
Console.WriteLine(ex.ToString());
return "{}";
}
} }
catch (Exception ex)
public static JsonSerializerOptions SerializeOptions = new JsonSerializerOptions
{ {
ReferenceHandler = ReferenceHandler.Preserve, Console.WriteLine(ex.ToString());
WriteIndented = true, return "{}";
Converters = }
}
public static JsonSerializerOptions SerializeOptions = new JsonSerializerOptions
{
ReferenceHandler = ReferenceHandler.Preserve,
WriteIndented = true,
Converters =
{ {
new ResourceJsonConverter(), new ResourceJsonConverter(),
new DoubleJsonConverter() 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); //FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
// string version = fvi.FileVersion; // string version = fvi.FileVersion;
/* /*
public static char GetDirectorySeparator() public static char GetDirectorySeparator()
{ {
return System.IO.Path.DirectorySeparatorChar; 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 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.Net.Packets;
using Esiur.Resource; 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 public event DestroyedEvent OnDestroy;
{
get;
set;
}
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()
{
public void Destroy() OnDestroy?.Invoke(this);
{
OnDestroy?.Invoke(this);
}
} }
} }

View File

@ -32,91 +32,89 @@ using System.Runtime.InteropServices;
using Esiur.Net.Packets; using Esiur.Net.Packets;
using Esiur.Resource; 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>(); get;
List<PacketFilter> filters = new List<PacketFilter>(); set;
}
public Instance Instance
[Storable] {
public string Mode get;
set;
}
public List<PacketSource> Sources
{
get
{ {
get; return sources;
set;
} }
}
public Instance Instance public event DestroyedEvent OnDestroy;
{
get;
set;
}
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); if (f.Execute(Packet))
}
public AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
if (trigger == ResourceTrigger.Initialize)
{ {
/* break;
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;
}
} }
} }
} }

View File

@ -30,66 +30,64 @@ using System.Text;
using Esiur.Core; using Esiur.Core;
using Esiur.Resource; 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); get;
public abstract event NewPacket OnNewPacket; set;
public event DestroyedEvent OnDestroy; }
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; return "Raw";
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;
} }
} }
*/
public abstract byte[] Address
{
get;
}
public abstract string DeviceId
{
get;
}
} }

View File

@ -38,400 +38,399 @@ using Esiur.Misc;
using System.Security.Cryptography; using System.Security.Cryptography;
using Esiur.Core; 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)
{ {
if (WSMode)
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) // now parse WS protocol
WebsocketPacket ws = new WebsocketPacket();
var pSize = ws.Parse(data, 0, (uint)data.Length);
if (pSize > 0)
{ {
// now parse WS protocol WSRequest = ws;
WebsocketPacket ws = new WebsocketPacket(); return 0;
var pSize = ws.Parse(data, 0, (uint)data.Length);
if (pSize > 0)
{
WSRequest = ws;
return 0;
}
else
{
return pSize;
}
} }
else else
{ {
var rp = new HTTPRequestPacket(); return pSize;
var pSize = rp.Parse(data, 0, (uint)data.Length);
if (pSize > 0)
{
Request = rp;
return 0;
}
else
{
return pSize;
}
} }
} }
else
public void Flush()
{ {
// close the connection var rp = new HTTPRequestPacket();
if (Request.Headers["connection"].ToLower() != "keep-alive" & IsConnected) var pSize = rp.Parse(data, 0, (uint)data.Length);
Close(); 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"; Close();
string ret = Request.Headers["Sec-WebSocket-Key"] + magicString; }
// Compute the SHA1 hash finally { }
SHA1 sha = SHA1.Create(); }
byte[] sha1Hash = sha.ComputeHash(Encoding.UTF8.GetBytes(ret)); finally
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; public void CreateNewSession()
Response.Text = "Switching Protocols"; {
WSMode = true; 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 true;
} }
return false;
}
public HTTPServer Parent var fileEditTime = File.GetLastWriteTime(filename).ToUniversalTime();
{ if (Request.Headers.ContainsKey("if-modified-since"))
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
{ {
try 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 finally
{ {
} }
}
return false;
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
} }
} }
}
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.Core;
using Esiur.Resource; using Esiur.Resource;
namespace Esiur.Net.HTTP namespace Esiur.Net.HTTP;
public abstract class HTTPFilter : IResource
{ {
public Instance Instance
public abstract class HTTPFilter : IResource
{ {
public Instance Instance get;
{ set;
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);
}
} }
}
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 System.Security.Cryptography.X509Certificates;
using Esiur.Resource; 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>(); get;
HTTPFilter[] filters = new HTTPFilter[0]; 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; Cookie += "; expires=" + Expires.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss") + " GMT";
set;
} }
if (Domain != null)
[Attribute]
public virtual string IP
{ {
get; Cookie += "; domain=" + Domain;
set;
} }
if (Path != null)
[Attribute]
public virtual ushort Port
{ {
get; Cookie += "; path=" + Path;
set;
} }
if (HttpOnly)
//[Attribute]
//public virtual uint Timeout
//{
// get;
// set;
//}
//[Attribute]
//public virtual uint Clock
//{
// get;
// set;
//}
[Attribute]
public virtual uint MaxPost
{ {
get; Cookie += "; HttpOnly";
set;
} }
return Cookie;
}
[Attribute] protected override void ClientDisconnected(HTTPConnection connection)
public virtual bool SSL {
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; if (c.Session == session)
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)
{ {
Cookie += "; expires=" + Expires.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss") + " GMT"; session.Refresh();
}
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();
return; return;
} }
foreach (var resource in filters)
{
resource.ClientConnected(connection);
}
} }
foreach (Instance instance in Instance.Children)
/*
public int LocalPort
{
get
{
return cServer.LocalPort;
}
}
*/
/*
public HTTPServer(int Port)
{ {
cServer = new TServer(); var f = (HTTPFilter)instance.Resource;
cServer.LocalPort = Port; f.SessionExpired((HTTPSession)session);
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);
}*/ base.SessionEnded((HTTPSession)session);
//Sessions.Remove(Session.ID);
//~HTTPServer() //Session.Dispose();
//{
// cServer.StopServer();
//}
} }
} */
/*
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.Misc;
using Esiur.Core; 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); get { return variables; }
public delegate void SessionEndedEvent(HTTPSession session); }
private string id; public HTTPSession()
private Timer timer; {
private int timeout; variables = new KeyList<string, object>();
DateTime creation; variables.OnModified += new KeyList<string, object>.Modified(VariablesModified);
DateTime lastAction; 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; if (this.timeout != 0)
public event SessionModifiedEvent OnModify;
public event DestroyedEvent OnDestroy;
public KeyList<string, object> Variables
{ {
get { return variables; } this.timeout = timeout;
} timer = new Timer(OnSessionEndTimerCallback, null, TimeSpan.FromSeconds(timeout), TimeSpan.FromSeconds(0));
public HTTPSession()
{
variables = new KeyList<string, object>();
variables.OnModified += new KeyList<string, object>.Modified(VariablesModified);
creation = DateTime.Now; 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.Collections.Generic;
using System.Text; 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] if (sender.Request.URL != "iip")
EntryPoint EntryPoint { get; set; } 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") EntryPoint.Query(sender.Request.Query["l"], null).Then(x =>
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 =>
{
}); });
}
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.Net.Sockets;
using Esiur.Core; using Esiur.Core;
namespace Esiur.Net.HTTP namespace Esiur.Net.HTTP;
public class IIPoWS : HTTPFilter
{ {
public class IIPoWS: HTTPFilter [Attribute]
public DistributedServer Server
{ {
[Attribute] get;
public DistributedServer Server set;
}
public override AsyncReply<bool> Execute(HTTPConnection sender)
{
if (sender.IsWebsocketRequest())
{ {
get; if (Server == null)
set; return new AsyncReply<bool>(false);
}
public override AsyncReply<bool> Execute(HTTPConnection sender) var tcpSocket = sender.Unassign();
{
if (sender.IsWebsocketRequest()) if (tcpSocket == null)
{ return new AsyncReply<bool>(false);
if (Server == 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) var iipConnection = new DistributedConnection();
return new AsyncReply<bool>(false);
var httpServer = sender.Parent; Server.Add(iipConnection);
var wsSocket = new WSocket(tcpSocket); iipConnection.Assign(wsSocket);
httpServer.Remove(sender); 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>(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.Collections.Generic;
using System.Text; 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; } this.Value = value;
public DistributedConnection Connection { get; private set; } this.Connection = connection;
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);
} }
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;
using Esiur.Resource.Template; 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)] /// <summary>
public class DistributedResource : DynamicObject, IResource /// 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> var props = new PropertyValue[properties.Length];
/// Raised when the distributed resource is destroyed.
/// </summary>
public event DestroyedEvent OnDestroy;
public event Instance.ResourceModifiedEvent OnModified;
uint instanceId;
DistributedConnection connection;
bool attached = false; for (byte i = 0; i < properties.Length; i++)
bool destroyed = false; props[i] = new PropertyValue(properties[i], Instance.GetAge(i), Instance.GetModificationDate(i));
bool suspended = false;
//Structure properties = new Structure(); return props;
}
string link; internal bool _Attach(PropertyValue[] properties)
//ulong age; {
//ulong[] ages; if (attached)
protected object[] properties; return false;
internal List<DistributedResource> parents = new List<DistributedResource>(); else
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; } suspended = false;
}
/// <summary> this.properties = new object[properties.Length];
/// 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.events = new DistributedResourceEvent[Instance.Template.Events.Length];
for (byte i = 0; i < properties.Length; i++) 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; Instance.SetAge(i, properties[i].Age);
Instance.SetModificationDate(i, properties[i].Date);
this.properties = new object[properties.Length]; this.properties[i] = properties[i].Value;
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;
} }
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); if (args.Length == 1)
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) // Detect anonymous types
var type = args[0].GetType();
if (Codec.IsAnonymous(type))
{ {
// Detect anonymous types var namedArgs = new Structure();
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 pi = type.GetTypeInfo().GetProperties();
foreach (var p in pi)
namedArgs[p.Name] = p.GetValue(args[0]);
result = _InvokeByNamedArguments(ft.Index, namedArgs);
} }
else else
{ {
result = _InvokeByArrayArguments(ft.Index, args); result = _InvokeByArrayArguments(ft.Index, args);
} }
return true;
} }
else else
{ {
result = null; result = _InvokeByArrayArguments(ft.Index, args);
return false;
} }
return true;
} }
else
/// <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; 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; return false;
var pt = Instance.Template.GetPropertyTemplateByName(binder.Name); result = events[et.Index];
if (pt != null) return true;
{
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;
}
} }
}
internal void _UpdatePropertyByIndex(byte index, object value) internal void _UpdatePropertyByIndex(byte index, object value)
{ {
var pt = Instance.Template.GetPropertyTemplateByIndex(index); var pt = Instance.Template.GetPropertyTemplateByIndex(index);
properties[index] = value; properties[index] = value;
Instance.EmitModification(pt, value); Instance.EmitModification(pt, value);
} }
/// <summary> /// <summary>
/// Set property value. /// Set property value.
/// </summary> /// </summary>
/// <param name="index">Zero-based property index.</param> /// <param name="index">Zero-based property index.</param>
/// <param name="value">Value</param> /// <param name="value">Value</param>
/// <returns>Indicator when the property is set.</returns> /// <returns>Indicator when the property is set.</returns>
protected internal AsyncReply<object> _Set(byte index, object value) protected internal AsyncReply<object> _Set(byte index, object value)
{ {
if (index >= properties.Length) if (index >= properties.Length)
return null; return null;
var reply = new AsyncReply<object>(); var reply = new AsyncReply<object>();
var parameters = Codec.Compose(value, connection); var parameters = Codec.Compose(value, connection);
connection.SendRequest(Packets.IIPPacket.IIPPacketAction.SetProperty) connection.SendRequest(Packets.IIPPacket.IIPPacketAction.SetProperty)
.AddUInt32(instanceId) .AddUInt32(instanceId)
.AddUInt8(index) .AddUInt8(index)
.AddUInt8Array(parameters) .AddUInt8Array(parameters)
.Done() .Done()
.Then((res) => .Then((res) =>
{ {
// not really needed, server will always send property modified, // not really needed, server will always send property modified,
// this only happens if the programmer forgot to emit in property setter // this only happens if the programmer forgot to emit in property setter
properties[index] = value; 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) _Set(pt.Index, value);
throw new Exception("Trying to access destroyed object"); return true;
}
if (suspended) else
throw new Exception("Trying to access suspended object"); {
var et = Instance.Template.GetEventTemplateByName(binder.Name);
if (!attached) if (et == null)
return false; return false;
var pt = Instance.Template.GetPropertyTemplateByName(binder.Name); events[et.Index] = (DistributedResourceEvent)value;
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;
}
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 | public async void InvokeMethod(byte index, object[] arguments, DistributedConnection sender)
BindingFlags.Instance | BindingFlags.InvokeMethod); {
if (mi != null) // 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);
var res = await invokeMethod(mi, arguments, sender); sender.SendParams((byte)0x80, instanceId, index, rt);
object rt = Codec.Compose(res); }
sender.SendParams((byte)0x80, instanceId, index, rt); catch(Exception ex)
} {
catch(Exception ex) var msg = ex.InnerException != null ? ex.InnerException.Message : ex.Message;
{ sender.SendParams((byte)0x8E, instanceId, index, Codec.Compose(msg));
var msg = ex.InnerException != null ? ex.InnerException.Message : ex.Message;
sender.SendParams((byte)0x8E, instanceId, index, Codec.Compose(msg));
}
} }
} }
*/ }
*/
/// <summary> /// <summary>
/// Resource interface. /// Resource interface.
/// </summary> /// </summary>
public Instance Instance public Instance Instance
{ {
get; get;
set; set;
} }
/// <summary> /// <summary>
/// Create a new instance of distributed resource. /// Create a new instance of distributed resource.
/// </summary> /// </summary>
public DistributedResource() public DistributedResource()
{ {
//stack = new DistributedResourceStack(this); //stack = new DistributedResourceStack(this);
//this.Instance.ResourceModified += this.OnModified; //this.Instance.ResourceModified += this.OnModified;
} }
/// <summary> /// <summary>
/// Resource interface. /// Resource interface.
/// </summary> /// </summary>
/// <param name="trigger"></param> /// <param name="trigger"></param>
/// <returns></returns> /// <returns></returns>
public AsyncReply<bool> Trigger(ResourceTrigger trigger) public AsyncReply<bool> Trigger(ResourceTrigger trigger)
{ {
if (trigger == ResourceTrigger.Initialize) if (trigger == ResourceTrigger.Initialize)
this.Instance.ResourceModified += this.OnModified; this.Instance.ResourceModified += this.OnModified;
// do nothing. // do nothing.
return new AsyncReply<bool>(true); return new AsyncReply<bool>(true);
}
} }
} }

View File

@ -28,7 +28,6 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Esiur.Net.IIP namespace Esiur.Net.IIP;
{
public delegate void DistributedResourceEvent(DistributedResource sender, object argument); public delegate void DistributedResourceEvent(DistributedResource sender, object argument);
}

View File

@ -28,46 +28,44 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; 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; DistributedResourceQueueItemType type;
byte index; byte index;
object value; object value;
DistributedResource resource; DistributedResource resource;
public DistributedResourceQueueItem(DistributedResource resource, DistributedResourceQueueItemType type, object value, byte index) public DistributedResourceQueueItem(DistributedResource resource, DistributedResourceQueueItemType type, object value, byte index)
{ {
this.resource = resource; this.resource = resource;
this.index = index; this.index = index;
this.type = type; this.type = type;
this.value = value; this.value = value;
} }
public DistributedResource Resource public DistributedResource Resource
{ {
get { return resource; } get { return resource; }
} }
public DistributedResourceQueueItemType Type public DistributedResourceQueueItemType Type
{ {
get { return type; } get { return type; }
} }
public byte Index public byte Index
{ {
get { return index; } get { return index; }
} }
public object Value public object Value
{ {
get { return value; } get { return value; }
}
} }
} }

View File

@ -35,143 +35,141 @@ using System.Net;
using Esiur.Resource; using Esiur.Resource;
using Esiur.Security.Membership; 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] get;
public string IP set;
{
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);
}
} }
[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.Net.Sockets;
using Esiur.Security.Authority; 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;
using Esiur.Resource.Template; using Esiur.Resource.Template;
namespace Esiur.Net.IIP namespace Esiur.Net.IIP;
{
public abstract class EntryPoint : Esiur.Resource.Resource
{
public abstract AsyncReply<IResource[]> Query(string path, DistributedConnection sender); public abstract class EntryPoint : Esiur.Resource.Resource
protected abstract override bool Create(); {
}
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.Collections.Generic;
using System.Text; using System.Text;
namespace Esiur.Net namespace Esiur.Net;
{
public interface INetworkReceiver<T>
{
void NetworkClose(T sender);
void NetworkReceive(T sender, NetworkBuffer buffer);
//void NetworkError(T sender);
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.Data;
using Esiur.Misc; 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; public bool Protected
//bool trim; {
get
object syncLock = new object();
//public object SyncLock
//{
// get { return syncLock; }
//}
public NetworkBuffer()
{ {
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; rt = data;
} data = new byte[0];
}
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;
} }
else 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) //Console.WriteLine("P STATE:" + data.Length + " " + neededDataLength);
return false;
if (data.Length < neededDataLength)
return false;
return true; if (data.Length >= neededDataLength)
}
}
public byte[] Read()
{
lock (syncLock)
{
if (data.Length == 0)
return null;
byte[] rt = null;
if (neededDataLength == 0)
{ {
//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; rt = data;
data = new byte[0]; data = new byte[0];
//}
neededDataLength = 0;
return rt;
} }
else else
{ {
//Console.WriteLine("P STATE:" + data.Length + " " + neededDataLength); return null;
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 rt; return rt;
}
} }
} }
} }

View File

@ -36,332 +36,330 @@ using Esiur.Data;
using Esiur.Net.Sockets; using Esiur.Net.Sockets;
using Esiur.Resource; 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; // remove references
// private bool connected; //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 ISocket Socket
//public delegate void ConnectionClosedEvent(NetworkConnection sender); {
public delegate void NetworkConnectionEvent(NetworkConnection connection); get
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()
{ {
// 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.OnClose -= Socket_OnClose;
//sock.OnConnect -= Socket_OnConnect; //sock.OnConnect -= Socket_OnConnect;
//sock.OnReceive -= Socket_OnReceive; //sock.OnReceive -= Socket_OnReceive;
sock?.Destroy(); sock.Receiver = null;
//Receiver = null;
Close(); var rt = sock;
sock = null; sock = null;
OnClose = null; return rt;
OnConnect = null;
//OnDataReceived = null;
OnDestroy?.Invoke(this);
OnDestroy = null;
} }
else
return null;
}
public ISocket Socket //protected virtual void DataReceived(NetworkBuffer data)
{ //{
get // if (OnDataReceived != null)
{ // {
return sock; // try
} // {
} // OnDataReceived?.Invoke(this, data);
// }
// catch (Exception ex)
// {
// Global.Log("NetworkConenction:DataReceived", LogType.Error, ex.ToString());
// }
// }
//}
public virtual void Assign(ISocket socket) public void Close()
{ {
lastAction = DateTime.Now; //if (!connected)
sock = socket; // return;
sock.Receiver = this;
//socket.OnReceive += Socket_OnReceive;
//socket.OnClose += Socket_OnClose;
//socket.OnConnect += Socket_OnConnect;
}
//private void Socket_OnConnect() try
//{
// 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) if (sock != null)
{ sock.Close();
// connected = false; }
//sock.OnClose -= Socket_OnClose; catch (Exception ex)
//sock.OnConnect -= Socket_OnConnect; {
//sock.OnReceive -= Socket_OnReceive; Global.Log("NetworkConenction:Close", LogType.Error, ex.ToString());
sock.Receiver = null;
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 else
return null; return null;
} }
}
//protected virtual void DataReceived(NetworkBuffer data) public IPEndPoint LocalEndPoint
//{ {
// if (OnDataReceived != null) get
// {
// try
// {
// OnDataReceived?.Invoke(this, data);
// }
// catch (Exception ex)
// {
// Global.Log("NetworkConenction:DataReceived", LogType.Error, ex.ToString());
// }
// }
//}
public void Close()
{ {
//if (!connected) if (sock != null)
// return; 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) if (sock != null)
sock.Close(); sock.Close();
}
catch (Exception ex)
{
Global.Log("NetworkConenction:Close", LogType.Error, ex.ToString());
} while (connected)
//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)
{ {
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) //Receiver?.NetworkReceive(this, buffer);
while (buffer.Available > 0 && !buffer.Protected) 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.Threading.Tasks;
using System.Diagnostics; 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; List<TConnection> ToBeClosed = null;
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);
private Timer timer; lock (Connections.SyncRoot)
//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)
{ {
List<TConnection> ToBeClosed = null; foreach (TConnection c in Connections)
lock (Connections.SyncRoot)
{ {
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>();
if (ToBeClosed == null) ToBeClosed.Add(c);
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) //Console.WriteLine("Term: " + ToBeClosed.Count + " " + this.listener.LocalEndPoint.ToString());
return; 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)); try
}
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 var s = listener.Accept();
if (s == null)
{ {
var s = listener.Accept(); Console.Write("sock == null");
return;
}
if (s == null) var c = new TConnection();
{
Console.Write("sock == null");
return;
}
var c = new TConnection();
//c.OnClose += ClientDisconnectedEventReceiver; //c.OnClose += ClientDisconnectedEventReceiver;
c.Assign(s); c.Assign(s);
Add(c); Add(c);
//Connections.Add(c); //Connections.Add(c);
try try
{ {
//ClientConnected(c); //ClientConnected(c);
ClientConnected(c); ClientConnected(c);
//NetworkConnect(c); //NetworkConnect(c);
} }
catch catch
{ {
// something wrong with the child. // something wrong with the child.
} }
s.Begin(); s.Begin();
// Accept more // Accept more
//listener.Accept().Then(NewConnection); //listener.Accept().Then(NewConnection);
} }
catch (Exception ex) 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)
{ {
port = listener.LocalEndPoint.Port; Console.WriteLine(ex);
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);
//}
} }
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);
//}
} }
finally
public virtual void Remove(TConnection connection)
{ {
//connection.OnDataReceived -= OnDataReceived; Console.WriteLine("Server@{0} is down", port);
//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;
} }
} }
}
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.Misc;
using Esiur.Core; 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); get { return variables; }
public delegate void SessionEndedEvent(NetworkSession session); }
private string id; public NetworkSession()
private Timer timer; {
private int timeout; variables = new KeyList<string, object>();
DateTime creation; variables.OnModified += new KeyList<string, object>.Modified(VariablesModified);
DateTime lastAction; 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; if (this.timeout != 0)
public event SessionModifiedEvent OnModify;
public event DestroyedEvent OnDestroy;
public KeyList<string, object> Variables
{ {
get { return variables; } this.timeout = timeout;
} timer = new Timer(OnSessionEndTimerCallback, null, TimeSpan.FromSeconds(timeout), TimeSpan.FromSeconds(0));
public NetworkSession()
{
variables = new KeyList<string, object>();
variables.OnModified += new KeyList<string, object>.Modified(VariablesModified);
creation = DateTime.Now; 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.Net;
using System.Text.Json.Serialization; 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, case "get":
POST, return HTTPMethod.GET;
HEAD, case "post":
PUT, return HTTPMethod.POST;
DELETE, case "head":
OPTIONS, return HTTPMethod.HEAD;
TRACE, case "put":
CONNECT, return HTTPMethod.PUT;
UNKNOWN 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 override string ToString()
public HTTPMethod Method; {
public StringKeyList Headers; 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; uint headerSize = 0;
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;
for (uint i = offset; i < ends - 3; i++)
private HTTPMethod getMethod(string method)
{ {
switch (method.ToLower()) if (data[i] == '\r' && data[i + 1] == '\n'
&& data[i + 2] == '\r' && data[i + 3] == '\n')
{ {
case "get": sLines = Encoding.ASCII.GetString(data, (int)offset, (int)(i - offset)).Split(new string[] { "\r\n" },
return HTTPMethod.GET; StringSplitOptions.None);
case "post":
return HTTPMethod.POST; headerSize = i + 4;
case "head": break;
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 override string ToString() if (headerSize == 0)
{ return -1;
return "HTTPRequestPacket"
+ "\n\tVersion: " + Version
+ "\n\tMethod: " + Method
+ "\n\tURL: " + URL
+ "\n\tMessage: " + (Message != null ? Message.Length.ToString() : "NULL");
}
public override long Parse(byte[] data, uint offset, uint ends) Cookies = new StringKeyList();
{ PostForms = new KeyList<string, object>();
string[] sMethod = null; Query = new StringKeyList();
string[] sLines = null; Headers = new StringKeyList();
uint headerSize = 0;
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' if (sMethod[1].StartsWith("http://"))
&& data[i + 2] == '\r' && data[i + 3] == '\n')
{ {
sLines = Encoding.ASCII.GetString(data, (int)offset,(int)( i - offset)).Split(new string[] { "\r\n" }, sMethod[1] = sMethod[1].Substring(sMethod[1].IndexOf("/", 7));
StringSplitOptions.None);
headerSize = i + 4;
break;
} }
} }
if (headerSize == 0) URL = sMethod[1].Trim();
return -1;
Cookies = new StringKeyList(); if (URL.IndexOf("?", 0) != -1)
PostForms = new KeyList<string, object>();
Query = new StringKeyList();
Headers = new StringKeyList();
sMethod = sLines[0].Split(' ');
Method = getMethod(sMethod[0].Trim());
if (sMethod.Length == 3)
{ {
sMethod[1] = WebUtility.UrlDecode(sMethod[1]); Filename = URL.Split(new char[] { '?' }, 2)[0];
if (sMethod[1].Length >= 7) }
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(); // Query String
if (URL.IndexOf("?", 0) != -1)
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 else
{ {
Filename = URL; if (!(Query.ContainsKey(WebUtility.UrlDecode(S))))
}
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 (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('='); string key = WebUtility.HtmlDecode(
splitCookie[0] = splitCookie[0].Trim(); WebUtility.UrlDecode(PostVars[J].Split(new char[] { '=' }, 2)[0]));
splitCookie[1] = splitCookie[1].Trim(); if (PostForms.Contains(key))
if (!(Cookies.ContainsKey(splitCookie[0].Trim()))) PostForms[key] = WebUtility.HtmlDecode(
Cookies.Add(splitCookie[0], splitCookie[1]); 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 else
{ if (PostForms.Contains("unknown"))
if (!(Cookies.ContainsKey(cookie.Trim()))) PostForms["unknown"] = PostForms["unknown"]
{ + "&" + WebUtility.HtmlDecode(WebUtility.UrlDecode(PostVars[J]));
Cookies.Add(cookie.Trim(), String.Empty); 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 string[] sc = Encoding.UTF8.GetString(data, (int)headerSize, (int)postSize).Split(
if (URL.IndexOf("?", 0) != -1) 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('&'); return 0;
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);
}
}
}
} }
// 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 System.Text;
using Esiur.Misc; using Esiur.Misc;
using Esiur.Data; 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, this.Name = name;
AllDontCalculateLength, this.Value = value;
SpecifiedHeadersOnly, this.Path = null;
DataOnly this.Expires = DateTime.MinValue;
this.HttpOnly = false;
this.Domain = null;
} }
public enum ResponseCode : int public HTTPCookie(string name, string value, DateTime expires)
{ {
Switching= 101, this.Name = name;
OK = 200, this.Value = value;
Created = 201, this.Expires = expires;
Accepted = 202, this.HttpOnly = false;
NoContent = 204, this.Domain = null;
MovedPermanently = 301, this.Path = null;
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)
{
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() public override string ToString()
{ {
return "HTTPResponsePacket" //Set-Cookie: ckGeneric=CookieBody; expires=Sun, 30-Dec-2001 21:00:00 GMT; domain=.com.au; path=/
+ "\n\tVersion: " + Version //Set-Cookie: SessionID=another; expires=Fri, 29 Jun 2006 20:47:11 UTC; path=/
//+ "\n\tMethod: " + Method var cookie = Name + "=" + Value;
//+ "\n\tURL: " + URL
+ "\n\tMessage: " + (Message != null ? Message.Length.ToString() : "NULL"); 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 (Message != null)
msg.AddRange(Message);
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;
} }
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 (data[i] == '\r' && data[i + 1] == '\n'
&& data[i + 2] == '\r' && data[i + 3] == '\n')
if (options != ComposeOptions.DataOnly)
{ {
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) headerSize = i + 4;
{ break;
if (Message != null)
msg.AddRange(Message);
} }
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; if (sLines[i] == String.Empty)
string[] sLines = null;
uint headerSize = 0;
for (uint i = offset; i < ends - 3; i++)
{ {
if (data[i] == '\r' && data[i + 1] == '\n' // Invalid header
&& data[i + 2] == '\r' && data[i + 3] == '\n') return 0;
{
sLines = Encoding.ASCII.GetString(data, (int)offset, (int)(i - offset)).Split(new string[] { "\r\n" },
StringSplitOptions.None);
headerSize = i + 4;
break;
}
} }
if (headerSize == 0) if (sLines[i].IndexOf(':') == -1)
return -1;
//Cookies = new DStringDictionary();
//Headers = new DStringDictionary(true);
sMethod = sLines[0].Split(' ');
if (sMethod.Length == 3)
{ {
Version = sMethod[0].Trim(); // Invalid header
Number = (ResponseCode)(Convert.ToInt32(sMethod[1].Trim())); return 0;
Text = sMethod[2];
} }
// 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 string[] splitCookie = cookie[0].Split('=');
return 0; HTTPCookie c = new HTTPCookie(splitCookie[0], splitCookie[1]);
}
if (sLines[i].IndexOf(':') == -1) for (int j = 1; j < cookie.Length; j++)
{
// 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)
{ {
string[] splitCookie = cookie[0].Split('='); splitCookie = cookie[j].Split('=');
HTTPCookie c = new HTTPCookie(splitCookie[0], splitCookie[1]); switch (splitCookie[0].ToLower())
for (int j = 1; j < cookie.Length; j++)
{ {
splitCookie = cookie[j].Split('='); case "domain":
switch (splitCookie[0].ToLower()) c.Domain = splitCookie[1];
{ break;
case "domain": case "path":
c.Domain = splitCookie[1]; c.Path = splitCookie[1];
break; break;
case "path": case "httponly":
c.Path = splitCookie[1]; c.HttpOnly = true;
break; break;
case "httponly": case "expires":
c.HttpOnly = true; // Wed, 13-Jan-2021 22:23:01 GMT
break; c.Expires = DateTime.Parse(splitCookie[1]);
case "expires": break;
// 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)
{ {
return 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;
} }
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.Text;
using System.Threading.Tasks; 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, dataLengthNeeded = needed - (ends - offset);
Declare, return true;
Acknowledge,
Error,
} }
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 Action = (IIPAuthPacketAction)(data[offset++] & 0x3f);
AuthenticateHash,
if (Action == IIPAuthPacketAction.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)
{ {
dataLengthNeeded = needed - (ends - offset); if (NotEnough(offset, ends, 32))
return true; 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 else if (Action == IIPAuthPacketAction.NewConnection)
return false; {
} if (NotEnough(offset, ends, 2))
return -dataLengthNeeded;
public override string ToString() var length = data.GetUInt16(offset);
{
return Command.ToString() + " " + Action.ToString();
}
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)) if (NotEnough(offset, ends, 1))
return -dataLengthNeeded; 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 (LocalMethod == AuthenticationMethod.None)
if (Action == IIPAuthPacketAction.AuthenticateHash)
{ {
if (NotEnough(offset, ends, 32)) if (NotEnough(offset, ends, 33))
return -dataLengthNeeded; 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]; RemoteNonce = data.Clip(offset, 32);
//Buffer.BlockCopy(data, (int)offset, hash, 0, 32);
//Hash = hash;
offset += 32; offset += 32;
}
else if (Action == IIPAuthPacketAction.NewConnection)
{
if (NotEnough(offset, ends, 2))
return -dataLengthNeeded;
var length = data.GetUInt16(offset); var length = data[offset++];
offset += 2;
if (NotEnough(offset, ends, length)) if (NotEnough(offset, ends, length))
return -dataLengthNeeded; 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); offset += length;
//SourceInfo = sourceInfo; }
}
else if (RemoteMethod == AuthenticationMethod.Token)
{
if (LocalMethod == AuthenticationMethod.None)
{
if (NotEnough(offset, ends, 37))
return -dataLengthNeeded;
RemoteNonce = data.Clip(offset, 32);
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)) if (NotEnough(offset, ends, 32))
return -dataLengthNeeded; return -dataLengthNeeded;
SessionId = data.Clip(offset, 32); RemoteNonce = data.Clip(offset, 32);
//Buffer.BlockCopy(data, (int)offset, sessionId, 0, 32);
//SessionId = sessionId;
offset += 32; offset += 32;
} }
} }
else if (Command == IIPAuthPacketCommand.Declare)
if (encrypt)
{ {
RemoteMethod = (AuthenticationMethod)((data[offset] >> 4) & 0x3); if (NotEnough(offset, ends, 2))
LocalMethod = (AuthenticationMethod)((data[offset] >> 2) & 0x3);
var encrypt = ((data[offset++] & 0x2) == 0x2);
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded; return -dataLengthNeeded;
var domainLength = data[offset++]; var keyLength = data.GetUInt16(offset);
if (NotEnough(offset, ends, domainLength))
return -dataLengthNeeded;
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; offset += 2;
if (NotEnough(offset, ends, cl)) if (NotEnough(offset, ends, keyLength))
return -dataLengthNeeded; return -dataLengthNeeded;
ErrorMessage = data.GetString(offset, cl); //var key = new byte[keyLength];
offset += cl; //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.Collections.Generic;
using System.Text; using System.Text;
namespace Esiur.Net.Packets namespace Esiur.Net.Packets;
{
struct IIPPacketAttachInfo
{
public string Link;
public ulong Age;
public byte[] Content;
public Guid ClassId;
public IIPPacketAttachInfo(Guid classId, ulong age, string link, byte[] content) struct IIPPacketAttachInfo
{ {
ClassId = classId; public string Link;
Age = age; public ulong Age;
Content = content; public byte[] Content;
Link = link; 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 System.Net.NetworkInformation;
using Esiur.Data; 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; return;
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);
} }
if (dest != null)
/*
public static Array Resize(Array array, int newSize)
{ {
Type myType = Type.GetType(array.GetType().FullName.TrimEnd('[', ']')); I = dest.Length;
Array nA = Array.CreateInstance(myType, newSize); Array.Resize(ref dest, dest.Length + src.Length);
Array.Copy(array, nA, (newSize > array.Length ? array.Length : newSize)); //dest = (byte[])Resize(dest, dest.Length + src.Length);
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);
} }
else
public static ushort GetInteger(byte B1, byte B2)
{ {
return BitConverter.ToUInt16(new byte[] { B2, B1 }, 0); dest = new byte[src.Length];
//return System.Convert.ToUInt16("&h" + GetHex(B1) + GetHex(B2));
} }
Array.Copy(src, 0, dest, I, 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;
}
} }
public class PosixTime /*
public static Array Resize(Array array, int newSize)
{ {
ulong seconds; Type myType = Type.GetType(array.GetType().FullName.TrimEnd('[', ']'));
ulong microseconds; 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; Array.Resize(ref data, data.Length + 1);
microseconds = Microseconds; //data = (byte[])Resize(data, data.Length + 1);
Padding = true;
} }
int count = data.Length;
public override string ToString() ///* 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 public class PosixTime
{ {
IP = 0x0021, // Internet Protocol version 4 [RFC1332] ulong seconds;
SDTP = 0x0049, // Serial Data Transport Protocol (PPP-SDTP) [RFC1963] ulong microseconds;
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 PosixTime(ulong Seconds, ulong Microseconds)
{ {
IP = 0x800, // IPv4 seconds = Seconds;
ARP = 0x806, // Address Resolution Protocol microseconds = Microseconds;
IPv6 = 0x86DD, // IPv6 }
FrameRelayARP = 0x0808, // Frame Relay ARP [RFC1701]
VINESLoopback = 0x0BAE, // VINES Loopback [RFC1701] public override string ToString()
VINESEcho = 0x0BAF, // VINES ECHO [RFC1701] {
TransEtherBridging = 0x6558, // TransEther Bridging [RFC1701] return seconds + "." + microseconds;
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] public class Packet
IPAutonomousSystems = 0x876C, // IP Autonomous Systems [RFC1701] {
SecureData = 0x876D, // Secure Data [RFC1701] //public EtherServer2.EthernetSource Source;
PPP = 0x880B, // PPP [IANA]
MPLS = 0x8847, // MPLS [RFC5332] public PacketSource Source;
MPLS_UpstreamAssignedLabel = 0x8848, // MPLS with upstream-assigned label [RFC5332]
PPPoEDiscoveryStage = 0x8863, // PPPoE Discovery Stage [RFC2516] public DateTime Timestamp;
PPPoESessionStage = 0x8864, // PPPoE Session Stage [RFC2516]
} 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 TZSPPacket tp = (TZSPPacket)root;
Packet root = packet.RootPacket; if (tp.Protocol == TZSPPacket.TZSPEncapsulatedProtocol.Ethernet)
if (root is TZSPPacket)
{ {
EthernetPacket ep = (EthernetPacket)tp.SubPacket;
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;
srcMAC = ep.SourceMAC; srcMAC = ep.SourceMAC;
dstMAC = ep.DestinationMAC; 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; srcMAC = wp.SA;
dstMAC = wp.DA; dstMAC = wp.DA;
} }
@ -278,92 +259,109 @@ namespace Esiur.Net.Packets
srcMAC = null; srcMAC = null;
dstMAC = 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) EthernetPacket ep = (EthernetPacket)tp.SubPacket;
{
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;
srcMAC = DC.GetPhysicalAddress(ep.SourceMAC, 0).ToString(); srcMAC = DC.GetPhysicalAddress(ep.SourceMAC, 0).ToString();
dstMAC = DC.GetPhysicalAddress(ep.DestinationMAC, 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(); srcMAC = DC.GetPhysicalAddress(wp.SA, 0).ToString();
dstMAC = DC.GetPhysicalAddress(wp.DA, 0).ToString(); dstMAC = DC.GetPhysicalAddress(wp.DA, 0).ToString();
} }
} }
*/ else if (root is EthernetPacket)
//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 EthernetPacket ep = (EthernetPacket)root;
{ srcMAC = DC.GetPhysicalAddress(ep.SourceMAC, 0).ToString();
Packet root = this; dstMAC = DC.GetPhysicalAddress(ep.DestinationMAC, 0).ToString();
while (root.ParentPacket != null)
root = root.ParentPacket;
return root;
}
} }
else if (root is W802_11Packet)
public Packet LeafPacket
{ {
get W802_11Packet wp = (W802_11Packet)root;
{ srcMAC = DC.GetPhysicalAddress(wp.SA, 0).ToString();
Packet leaf = this; dstMAC = DC.GetPhysicalAddress(wp.DA, 0).ToString();
while (leaf.SubPacket != null) }
leaf = leaf.SubPacket; }
return leaf; */
}
//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 *************************************/ /************************************ EOF *************************************/

View File

@ -29,189 +29,187 @@ using System.Text;
using Esiur.Misc; using Esiur.Misc;
using Esiur.Data; 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 pkt.Add((byte)((Mask ? 0x80 : 0x0) | 127));
pkt.AddRange(DC.ToBytes((UInt64)Message.LongCount()));
TextFrame = 0x1, // %x1 denotes a text frame }
else if (Message.Length > 125)
BinaryFrame = 0x2, // %x2 denotes a binary frame // 2 bytes
{
// %x3-7 are reserved for further non-control frames pkt.Add((byte)((Mask ? 0x80 : 0x0) | 126));
pkt.AddRange(DC.ToBytes((UInt16)Message.Length));
ConnectionClose = 0x8, // %x8 denotes a connection close }
else
Ping = 0x9, // %x9 denotes a ping {
pkt.Add((byte)((Mask ? 0x80 : 0x0) | Message.Length));
Pong = 0xA, // %xA denotes a pong
//* %xB-F are reserved for further control frames
} }
if (Mask)
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" pkt.AddRange(MaskKey);
+ "\n\tFIN: " + FIN
+ "\n\tOpcode: " + Opcode
+ "\n\tPayload: " + PayloadLength
+ "\n\tMaskKey: " + MaskKey
+ "\n\tMessage: " + (Message != null ? Message.Length.ToString() : "NULL");
} }
public override bool Compose() pkt.AddRange(Message);
{
var pkt = new List<byte>();
pkt.Add((byte)((FIN ? 0x80 : 0x0) |
(RSV1 ? 0x40 : 0x0) |
(RSV2 ? 0x20 : 0x0) |
(RSV3 ? 0x10 : 0x0) |
(byte)Opcode));
// calculate length Data = pkt.ToArray();
if (Message.Length > UInt16.MaxValue)
// 4 bytes 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)); //Console.WriteLine("stage 1 " + needed);
pkt.AddRange(DC.ToBytes((UInt64)Message.LongCount())); return length - needed;
}
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));
} }
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) if (Mask)
needed += 4;
if (PayloadLength == 126)
{ {
pkt.AddRange(MaskKey); needed += 2;
}
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);
if (length < needed) 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; return length - needed;
} }
uint oOffset = offset; PayloadLength = data.GetInt64(offset);
FIN = ((data[offset] & 0x80) == 0x80); offset += 8;
RSV1 = ((data[offset] & 0x40) == 0x40); }
RSV2 = ((data[offset] & 0x20) == 0x20);
RSV3 = ((data[offset] & 0x10) == 0x10); /*
Opcode = (WSOpcode)(data[offset++] & 0xF); if (Mask)
Mask = ((data[offset] & 0x80) == 0x80); {
PayloadLength = (long)(data[offset++] & 0x7F); 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) if (Mask)
needed += 4;
if (PayloadLength == 126)
{ {
needed += 2; MaskKey = new byte[4];
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[0] = data[offset++]; MaskKey[0] = data[offset++];
MaskKey[1] = data[offset++]; MaskKey[1] = data[offset++];
MaskKey[2] = data[offset++]; MaskKey[2] = data[offset++];
MaskKey[3] = data[offset++]; MaskKey[3] = data[offset++];
//MaskKey = DC.GetUInt32(data, offset); Message = DC.Clip(data, offset, (uint)PayloadLength);
//offset += 4;
}
*/
needed += PayloadLength; //var aMask = BitConverter.GetBytes(MaskKey);
if (length < needed) for (int i = 0; i < Message.Length; i++)
{ Message[i] = (byte)(Message[i] ^ MaskKey[i % 4]);
//Console.WriteLine("stage 4");
return length - needed;
} }
else else
{ Message = DC.Clip(data, offset, (uint)PayloadLength);
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);
return (offset - oOffset) + (int)PayloadLength; return (offset - oOffset) + (int)PayloadLength;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Console.WriteLine(offset + "::" + DC.ToHex(data));
throw ex;
} }
} }
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.Collections.Generic;
using System.Text; 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; this.reply = reply;
AsyncReply<object[]> reply; this.connection = connection;
}
public SendList(NetworkConnection connection, AsyncReply<object[]> reply) public override AsyncReply<object[]> Done()
{ {
this.reply = reply; connection.Send(this.ToArray());
this.connection = connection; 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.Resource;
using Esiur.Core; 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); SocketState State { get; }
//public delegate void ISocketConnectEvent();
//public delegate void ISocketCloseEvent();
public interface ISocket : IDestructible //event ISocketReceiveEvent OnReceive;
{ //event ISocketConnectEvent OnConnect;
SocketState State { get; } //event ISocketCloseEvent OnClose;
//event ISocketReceiveEvent OnReceive; INetworkReceiver<ISocket> Receiver { get; set; }
//event ISocketConnectEvent OnConnect;
//event ISocketCloseEvent OnClose;
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); IPEndPoint RemoteEndPoint { get; }
void Send(byte[] message, int offset, int length); IPEndPoint LocalEndPoint { get; }
void Close();
AsyncReply<bool> Connect(string hostname, ushort port);
bool Begin();
AsyncReply<bool> BeginAsync();
//ISocket Accept();
AsyncReply<ISocket> AcceptAsync();
ISocket Accept();
IPEndPoint RemoteEndPoint { get; } void Hold();
IPEndPoint LocalEndPoint { get; }
void Hold(); void Unhold();
void Unhold();
}
} }

View File

@ -37,519 +37,518 @@ using Esiur.Resource;
using System.Threading.Tasks; using System.Threading.Tasks;
using Esiur.Data; 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; state = SocketState.Connecting;
byte[] receiveBuffer; await sock.ConnectAsync(hostname, port);
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; try
X509Certificate2 cert;
bool server;
string hostname;
public async AsyncReply<bool> Connect(string hostname, ushort port)
{ {
var rt = new AsyncReply<bool>(); await BeginAsync();
state = SocketState.Established;
this.hostname = hostname; //OnConnect?.Invoke();
this.server = false; Receiver?.NetworkConnect(this);
}
state = SocketState.Connecting; catch (Exception ex)
await sock.ConnectAsync(hostname, port); {
state = SocketState.Closed;// .Terminated;
Close();
try Global.Log(ex);
{
await BeginAsync();
state = SocketState.Established;
//OnConnect?.Invoke();
Receiver?.NetworkConnect(this);
}
catch (Exception ex)
{
state = SocketState.Closed;// .Terminated;
Close();
Global.Log(ex);
}
return true;
} }
//private void DataSent(Task task) return true;
//{ }
// try
// {
// if (sendBufferQueue.Count > 0) //private void DataSent(Task task)
// { //{
// byte[] data = sendBufferQueue.Dequeue(); // try
// 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();
// }
// 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) private void SendCallback(IAsyncResult ar)
{ {
if (ar != null) 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)
{ {
try try
{ {
if (state != SocketState.Established) ssl.EndWrite(ar);
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);
if (ar.AsyncState != null)
((AsyncReply<bool>)ar.AsyncState).Trigger(true);
} }
catch //(Exception ex) catch
{ {
if (state != SocketState.Closed && !sock.Connected) if (state != SocketState.Closed && !sock.Connected)
{ {
//state = SocketState.Terminated; //state = SocketState.Closed;//.Terminated;
Close(); Close();
} }
//Global.Log("SSLSocket", LogType.Error, ex.ToString());
} }
} }
public bool Trigger(ResourceTrigger trigger) lock (sendLock)
{
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); if (sendBufferQueue.Count > 0)
lock (sendLock)
{ {
if (!sock.Connected) var kv = sendBufferQueue.Dequeue();
return new AsyncReply<bool>(false);
var rt = new AsyncReply<bool>(); try
if (asyncSending || held)
{ {
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 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); //state = SocketState.Closed;// .Terminated;
asyncSending = false;
//state = SocketState.Terminated;
Close(); Close();
} }
//Global.Log("TCPSocket", LogType.Error, ex.ToString());
} }
return rt;
} }
} else
public ISocket Accept()
{
try
{ {
return new SSLSocket(sock.Accept(), cert, true); asyncSending = false;
}
catch
{
state = SocketState.Closed;// .Terminated;
return null;
} }
} }
} }
}
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.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Esiur.Net.Sockets namespace Esiur.Net.Sockets;
public enum SocketState
{ {
public enum SocketState Initial,
{ Listening,
Initial, Connecting,
Listening, Established,
Connecting, Closed,
Established, //Terminated
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 Esiur.Data;
using System.Globalization; 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(); get { return (IPEndPoint)sock.LocalEndPoint; }
WebsocketPacket pkt_send = new WebsocketPacket(); }
ISocket sock; public IPEndPoint RemoteEndPoint
NetworkBuffer receiveNetworkBuffer = new NetworkBuffer(); {
NetworkBuffer sendNetworkBuffer = new NetworkBuffer(); get { return sock.RemoteEndPoint; }
}
object sendLock = new object();
bool held;
//public event ISocketReceiveEvent OnReceive; public SocketState State
//public event ISocketConnectEvent OnConnect; {
//public event ISocketCloseEvent OnClose; get
public event DestroyedEvent OnDestroy;
long totalSent, totalReceived;
bool processing = false;
public IPEndPoint LocalEndPoint
{ {
get { return (IPEndPoint)sock.LocalEndPoint; } return sock.State;
}
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);
} }
} }
}
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.Misc;
using Esiur.Data; 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;
{
return variables;
}
}
protected override void Connected()
{
// do nothing
}
protected override void DataReceived(NetworkBuffer buffer)
{
Server?.Execute(this, buffer);
}
protected override void Disconencted()
{
// do nothing
} }
} }
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.Core;
using Esiur.Resource; 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) public virtual bool Connected(TCPConnection sender)
{ {
return false; return false;
} }
public virtual bool Disconnected(TCPConnection sender) public virtual bool Disconnected(TCPConnection sender)
{ {
return false; 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() public void Destroy()
{ {
OnDestroy?.Invoke(this); OnDestroy?.Invoke(this);
}
} }
} }

View File

@ -34,123 +34,121 @@ using Esiur.Core;
using System.Net; using System.Net;
using Esiur.Resource; 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; filter.Disconnected(connection);
set;
} }
[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; filter.Connected(connection);
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)
{
}
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.Text;
using System.Threading.Tasks; 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.Core;
using Esiur.Resource; 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;
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);
}
} }
}
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.Resource;
using Esiur.Core; 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; get;
public set;
}*/ }
public class UDPServer : IResource
[Attribute]
string IP
{ {
Thread receiver; get;
UdpClient udp; set;
UDPFilter[] filters = new UDPFilter[0]; }
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; byte[] b = udp.Receive(ref ep);
set;
}
[Attribute] foreach (var child in filters)
string IP
{
get;
set;
}
[Attribute]
ushort Port
{
get;
set;
}
private void Receiving()
{
IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);
while (true)
{ {
byte[] b = udp.Receive(ref ep); var f = child as UDPFilter;
foreach (var child in filters) try
{ {
var f = child as UDPFilter; if (f.Execute(b, ep))
try
{ {
if (f.Execute(b, ep)) break;
{
break;
}
}
catch (Exception ex)
{
Global.Log("UDPServer", LogType.Error, ex.ToString());
//Console.WriteLine(ex.ToString());
} }
} }
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);
{
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; 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 System.IO;
using Esiur.Core; 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(); if (!(context.SyntaxContextReceiver is ResourceGeneratorReceiver receiver))
// private List<string> inProgress = new(); 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());
}
//File.WriteAllLines("C:\\gen\\ref.log", context.Compilation.ReferencedAssemblyNames.Select(x => x.ToString()));
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));
}
if (cache.Contains(path))
void GenerateModel(GeneratorExecutionContext context, TypeTemplate[] templates)
{
foreach (var tmp in templates)
{ {
if (tmp.Type == TemplateType.Resource) GenerateModel(context, cache[path]);
{ continue;
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 // 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[] { " + try
string.Join(",", templates.Where(x => x.Type == TemplateType.Resource).Select(x => $"typeof({x.ClassName})")) {
+ " }; \r\n public static Type[] Records { get; } = new Type[] { " + var con = Warehouse.Get<DistributedConnection>(url[1] + "://" + url[2]).Wait(20000);
string.Join(",", templates.Where(x => x.Type == TemplateType.Record).Select(x => $"typeof({x.ClassName})")) 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);
} }
//#if DEBUG
public void Execute(GeneratorExecutionContext context)
//#endif
//var toImplement = receiver.Classes.Where(x => x.Fields.Length > 0);
foreach (var ci in receiver.Classes.Values)
{ {
try
if (!(context.SyntaxContextReceiver is ResourceGeneratorReceiver receiver))
return;
//if (receiver.Imports.Count > 0 && !Debugger.IsAttached)
//{
// Debugger.Launch();
//}
foreach (var path in receiver.Imports)
{ {
if (!TemplateGenerator.urlRegex.IsMatch(path))
continue;
var code = @$"using Esiur.Resource;
//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;
using Esiur.Core; using Esiur.Core;
namespace { ci.ClassSymbol.ContainingNamespace.ToDisplayString() } {{ namespace { ci.ClassSymbol.ContainingNamespace.ToDisplayString() } {{
"; ";
if (ci.HasInterface) if (ci.HasInterface)
code += $"public partial class {ci.Name} {{"; code += $"public partial class {ci.Name} {{";
else else
{ {
code += @$"public partial class {ci.Name} : IResource {{ code += @$"public partial class {ci.Name} : IResource {{
public Instance Instance {{ get; set; }} public Instance Instance {{ get; set; }}
public event DestroyedEvent OnDestroy; public event DestroyedEvent OnDestroy;
public virtual void Destroy() {{ OnDestroy?.Invoke(this); }} public virtual void Destroy() {{ OnDestroy?.Invoke(this); }}
"; ";
if (!ci.HasTrigger) if (!ci.HasTrigger)
code += "public AsyncReply<bool> Trigger(ResourceTrigger trigger) => new AsyncReply<bool>(true);\r\n"; 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);
} }
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.Collections.Generic;
using System.Text; 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 bool HasTrigger { get; set; }
public List<IFieldSymbol> Fields { get; set; } public List<IFieldSymbol> Fields { get; set; }
public ITypeSymbol ClassSymbol { 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.Collections.Generic;
using System.Text; 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.Linq;
using System.Text; 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(); if (context.Node is ClassDeclarationSyntax)
public List<string> Imports { get; } = new ();
public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
{ {
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; // Debugger.Launch();
var cls = context.SemanticModel.GetDeclaredSymbol(cds) as ITypeSymbol;
var attrs = cls.GetAttributes();
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(); // append fields
var c = Classes[fullName];
var url = import.ConstructorArguments.First().Value.ToString(); c.Fields.AddRange(fields);
if (!c.HasInterface)
if (!Imports.Contains(url)) c.HasInterface = cls.Interfaces.Any(x => x.ToDisplayString() == "Esiur.Resource.IResource");
Imports.Add(url); 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) return;
.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;
}
} }
} }
} }
} }

View File

@ -7,72 +7,71 @@ using System.Reflection;
using System.Reflection.Emit; using System.Reflection.Emit;
using System.Text; 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 #if NETSTANDARD
static MethodInfo modifyMethod = typeof(Instance).GetTypeInfo().GetMethod("Modified"); static MethodInfo modifyMethod = typeof(Instance).GetTypeInfo().GetMethod("Modified");
static MethodInfo instanceGet = typeof(IResource).GetTypeInfo().GetProperty("Instance").GetGetMethod(); static MethodInfo instanceGet = typeof(IResource).GetTypeInfo().GetProperty("Instance").GetGetMethod();
#else #else
static MethodInfo modifyMethod = typeof(Instance).GetMethod("Modified"); static MethodInfo modifyMethod = typeof(Instance).GetMethod("Modified");
static MethodInfo instanceGet = typeof(IResource).GetProperty("Instance").GetGetMethod(); static MethodInfo instanceGet = typeof(IResource).GetProperty("Instance").GetGetMethod();
#endif #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) cache.Add(type, type);
return type.GetTypeInfo().BaseType; return type;
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)
{
cache.Add(type, type);
return type;
}
if (!Codec.ImplementsInterface(type, typeof(IResource)))
{
cache.Add(type, type);
return type;
}
#if NETSTANDARD #if NETSTANDARD
var typeInfo = type.GetTypeInfo(); var typeInfo = type.GetTypeInfo();
if (typeInfo.IsSealed || typeInfo.IsAbstract) if (typeInfo.IsSealed || typeInfo.IsAbstract)
throw new Exception("Sealed/Abastract classes can't be proxied."); throw new Exception("Sealed/Abastract classes can't be proxied.");
var props = from p in typeInfo.GetProperties(BindingFlags.Instance | BindingFlags.Public) var props = from p in typeInfo.GetProperties(BindingFlags.Instance | BindingFlags.Public)
where p.CanWrite && p.SetMethod.IsVirtual && !p.SetMethod.IsFinal && where p.CanWrite && p.SetMethod.IsVirtual && !p.SetMethod.IsFinal &&
p.GetCustomAttribute<PublicAttribute>(false) != null p.GetCustomAttribute<PublicAttribute>(false) != null
select p; select p;
#else #else
if (type.IsSealed) if (type.IsSealed)
@ -84,172 +83,171 @@ namespace Esiur.Proxy
select p; select p;
#endif #endif
var assemblyName = new AssemblyName("Esiur.Proxy.T." + type.Assembly.GetName().Name);// type.Namespace); var assemblyName = new AssemblyName("Esiur.Proxy.T." + type.Assembly.GetName().Name);// type.Namespace);
assemblyName.Version = type.Assembly.GetName().Version; assemblyName.Version = type.Assembly.GetName().Version;
assemblyName.CultureInfo = type.Assembly.GetName().CultureInfo; assemblyName.CultureInfo = type.Assembly.GetName().CultureInfo;
//assemblyName.SetPublicKeyToken(null); //assemblyName.SetPublicKeyToken(null);
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name);
var typeName = "Esiur.Proxy.T." + type.FullName;// Assembly.CreateQualifiedName(assemblyName.FullName, "Esiur.Proxy.T." + type.FullName); var typeName = "Esiur.Proxy.T." + type.FullName;// Assembly.CreateQualifiedName(assemblyName.FullName, "Esiur.Proxy.T." + type.FullName);
var typeBuilder = moduleBuilder.DefineType(typeName, var typeBuilder = moduleBuilder.DefineType(typeName,
TypeAttributes.Public | TypeAttributes.Class, type); TypeAttributes.Public | TypeAttributes.Class, type);
foreach (PropertyInfo propertyInfo in props) foreach (PropertyInfo propertyInfo in props)
CreateProperty(propertyInfo, typeBuilder, type); CreateProperty(propertyInfo, typeBuilder, type);
#if NETSTANDARD #if NETSTANDARD
var t = typeBuilder.CreateTypeInfo().AsType(); var t = typeBuilder.CreateTypeInfo().AsType();
cache.Add(type, t); cache.Add(type, t);
return t; return t;
#else #else
var t = typeBuilder.CreateType(); var t = typeBuilder.CreateType();
cache.Add(type, t); cache.Add(type, t);
return t; return t;
#endif #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 Esiur.Net.IIP;
using System.Diagnostics; 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 ptTypeName = GetTypeName(p.ValueType, templates);
rt.AppendLine($"public {ptTypeName} {p.Name} {{ get; set; }}");
var nameSpace = string.Join(".", cls.Take(cls.Length - 1)); rt.AppendLine();
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();
} }
static string GetTypeName(TemplateDataType templateDataType, TypeTemplate[] templates) rt.AppendLine("\r\n}\r\n}");
{
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();
}
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