2
0
mirror of https://github.com/esiur/esiur-dotnet.git synced 2025-06-26 13:03:13 +00:00
This commit is contained in:
2021-05-14 18:24:34 +03:00
parent 0af14009be
commit 5bf258673d
48 changed files with 1032 additions and 383 deletions

View File

@ -40,7 +40,7 @@ namespace Esiur.Stores.EntityCore
//internal object _PrimaryId;
public event DestroyedEvent OnDestroy;
public event PropertyChangedEventHandler PropertyChanged;
//public event PropertyChangedEventHandler PropertyChanged;
[NotMapped]
public Instance Instance { get; set; }
@ -66,7 +66,7 @@ namespace Esiur.Stores.EntityCore
public void Destroy()
{
//throw new NotImplementedException();
OnDestroy?.Invoke(this);
}

View File

@ -45,31 +45,25 @@ namespace Esiur.Stores.EntityCore
Dictionary<Type, Dictionary<object, WeakReference>> DB = new Dictionary<Type, Dictionary<object, WeakReference>>();
object DBLock = new object();
internal struct TypeInfo
{
public string Name;
public IEntityType Type;
public PropertyInfo PrimaryKey;
}
Dictionary<string, EntityTypeInfo> TypesByName = new Dictionary<string, EntityTypeInfo>();
internal Dictionary<Type, EntityTypeInfo> TypesByType = new Dictionary<Type, EntityTypeInfo>();
Dictionary<string, TypeInfo> TypesByName = new Dictionary<string, TypeInfo>();
internal Dictionary<Type, TypeInfo> TypesByType = new Dictionary<Type, TypeInfo>();
[Attribute]
public Func<DbContext> Getter { get; set; }
bool Loaded;
public AsyncReply<IResource> Get(string path)
{
var p = path.Split('/');
var ti = TypesByName[p[0]];
var id = Convert.ChangeType(p[1], ti.PrimaryKey.PropertyType);// Convert.ToInt32();
var id = Convert.ChangeType(p[1], ti.PrimaryKey.PropertyType);
var db = DbContextProvider();
// Get db
var db = Getter();
var res = db.Find(ti.Type.ClrType, id);
var ent = db.Entry(res);
// load navigation properties
var ent = db.Entry(res);
foreach (var rf in ent.References)
rf.Load();
@ -78,12 +72,11 @@ namespace Esiur.Stores.EntityCore
public AsyncReply<bool> Put(IResource resource)
{
if (resource is EntityStore)
if (resource == this)
return new AsyncReply<bool>(true);
var type = ResourceProxy.GetBaseType(resource);//.GetType().;
var type = ResourceProxy.GetBaseType(resource);
//var eid = (resource as EntityResource)._PrimaryId;// (int)resource.Instance.Variables["eid"];
var eid = TypesByType[type].PrimaryKey.GetValue(resource);
@ -112,11 +105,12 @@ namespace Esiur.Stores.EntityCore
}
}
[Attribute]
public Func<DbContext> DbContextProvider { get; set; }
[Attribute]
public DbContextOptionsBuilder Options { get; set; }
//public T CreateDB()
//{
//}
//DbContext dbContext;
//[Attribute]
@ -195,13 +189,17 @@ namespace Esiur.Stores.EntityCore
throw new NotImplementedException();
}
internal DbContextOptions Options { get; set; }
public AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
if (trigger == ResourceTrigger.Initialize)// SystemInitialized && DbContext != null)
{
if (DbContextProvider == null)
DbContextProvider = () => Activator.CreateInstance(Options.Options.ContextType, Options.Options) as DbContext;
if (Getter == null)
throw new Exception("Getter is not set for the store.");
// DbContextProvider = () => Activator.CreateInstance(Options.Options.ContextType, Options.Options) as DbContext;
ReloadModel();
}
@ -209,21 +207,23 @@ namespace Esiur.Stores.EntityCore
return new AsyncReply<bool>(true);
}
public void ReloadModel()
void ReloadModel()
{
TypesByName.Clear();
TypesByType.Clear();
var context = DbContextProvider();// Activator.CreateInstance(Options.Options.ContextType, Options.Options) as DbContext;
var context = Getter();
var types = context.Model.GetEntityTypes();
foreach (var t in types)
{
var ti = new TypeInfo()
var ti = new EntityTypeInfo()
{
Name = t.ClrType.Name,
PrimaryKey = t.FindPrimaryKey().Properties.FirstOrDefault()?.PropertyInfo,
Type = t
Type = t,
//Getter = getter
};
TypesByName.Add(t.ClrType.Name, ti);
@ -236,7 +236,7 @@ namespace Esiur.Stores.EntityCore
public void Destroy()
{
//throw new NotImplementedException();
OnDestroy?.Invoke(this);
}
}
}

View File

@ -0,0 +1,17 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace Esiur.Stores.EntityCore
{
struct EntityTypeInfo
{
public string Name;
public IEntityType Type;
public PropertyInfo PrimaryKey;
// public Func<DbContext> Getter;
}
}

View File

@ -9,10 +9,11 @@
<Product>Esiur Entity Framework Extension</Product>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageId>Esiur.Stores.EntityCore</PackageId>
<Version>1.0.2</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.6" />
<PackageReference Include="System.Collections" Version="4.3.0" />
</ItemGroup>

View File

@ -34,6 +34,7 @@ using System.Linq;
using Microsoft.EntityFrameworkCore.Metadata;
using System.Reflection;
using Esiur.Proxy;
using Microsoft.EntityFrameworkCore;
namespace Esiur.Stores.EntityCore
{

View File

@ -23,6 +23,9 @@ SOFTWARE.
*/
using Esiur.Core;
using Esiur.Data;
using Esiur.Misc;
using Esiur.Proxy;
using Esiur.Resource;
using Esiur.Security.Permissions;
using Microsoft.EntityFrameworkCore;
@ -31,6 +34,7 @@ using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Esiur.Stores.EntityCore
@ -43,49 +47,108 @@ namespace Esiur.Stores.EntityCore
//}
public static T AddResource<T>(this DbSet<T> dbSet, object properties = null) where T : class, IResource
=> AddResourceAsync(dbSet, properties).Wait();
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, object properties = null) where T : class, IResource
public static async AsyncReply<T> AddResourceAsync<T>(this DbSet<T> dbSet, T resource) where T : class, IResource
{
var store = dbSet.GetInfrastructure().GetService<IDbContextOptions>().FindExtension<EsiurExtensionOptions>().Store;
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 resource = await Warehouse.New<T>("", null, null, null, null, properties);
var entity = dbSet.Add(resource);
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 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
{
(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(resource, id.ToString(), store, null, null, 0, manager);
await Warehouse.Put(id.ToString(), res, store, null, null, 0, manager);
return resource;
}
public static async AsyncReply<T> CreateResourceAsync<T>(this IServiceProvider serviceProvider, object properties = null) where T : class, IResource
{
var options = serviceProvider.GetService<IDbContextOptions>().FindExtension<EsiurExtensionOptions>();
//public static async AsyncReply<T> CreateResourceAsync<T>(this IServiceProvider serviceProvider, T properties = null) where T : class, IResource
//{
// var options = serviceProvider.GetService<IDbContextOptions>().FindExtension<EsiurExtensionOptions<T>>();
var resource = await Warehouse.New<T>("", options.Store, null, null, null, properties);
// var resource = await Warehouse.New<T>("", options.Store, null, null, null, properties);
resource.Instance.Managers.AddRange(options.Store.Instance.Managers.ToArray());
// resource.Instance.Managers.AddRange(options.Store.Instance.Managers.ToArray());
return resource;
}
// return resource;
//}
public static T CreateResource<T>(this IServiceProvider serviceProvider, object properties = null) where T : class, IResource
=> CreateResourceAsync<T>(serviceProvider, properties).Wait();
//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,
//DbContext context,
string name = null,
IResource parent = null,
IPermissionsManager manager = null,
Func<DbContext> dbContextProvider = null
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>();
@ -93,10 +156,9 @@ namespace Esiur.Stores.EntityCore
if (extension == null)
{
var store = Warehouse.New<EntityStore>(name, null, parent, manager, new { Options = optionsBuilder, DbContextProvider = dbContextProvider }).Wait();
//var store = Warehouse.New<EntityStore>(name, null, parent, manager, new { Options = optionsBuilder, DbContextProvider = dbContextProvider }).Wait();
store.Options = optionsBuilder.Options;
extension = new EsiurExtensionOptions(store);
//store.Options = optionsBuilder;
//store.DbContext = context;
}
((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
@ -105,34 +167,34 @@ namespace Esiur.Stores.EntityCore
}
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
{
//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>();
// 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;
}
// 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);
// ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
return optionsBuilder;
// return optionsBuilder;
}
//}
}
}

View File

@ -79,7 +79,7 @@ namespace Esiur.Stores.EntityCore
var obj = Warehouse.New(entityType.ClrType).Wait() as EntityResource;//, "", options.Store, null, manager);
//obj._PrimaryId = id;
options.Store.TypesByType[entityType.ClrType].PrimaryKey.SetValue(obj, id);
Warehouse.Put(obj, id.ToString(), options.Store, null, null, 0, manager).Wait();
Warehouse.Put(id.ToString(), obj, options.Store, null, null, 0, manager).Wait();
// obj.Instance.IntVal = id;//.Variables.Add("eid", id);

View File

@ -11,7 +11,7 @@
<PackageProjectUrl>http://www.esiur.com</PackageProjectUrl>
<RepositoryUrl>https://github.com/esiur/esiur-dotnet/</RepositoryUrl>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Version>1.4.0</Version>
<Version>1.4.1</Version>
<PackageId>Esiur.Stores.MongoDB</PackageId>
</PropertyGroup>

View File

@ -192,7 +192,7 @@ namespace Esiur.Core
// }
}
public void Trigger(object result)
public AsyncReply Trigger(object result)
{
lock (asyncLock)
{
@ -202,7 +202,7 @@ namespace Esiur.Core
Console.WriteLine($"AsyncReply: {Id} Trigger");
if (resultReady)
return;
return this;
this.result = result;
@ -219,14 +219,16 @@ namespace Esiur.Core
Console.WriteLine($"AsyncReply: {Id} Trigger ended");
}
return this;
}
public void TriggerError(Exception exception)
public AsyncReply TriggerError(Exception exception)
{
//timeout?.Dispose();
if (resultReady)
return;
return this;
if (exception is AsyncException)
this.exception = exception as AsyncException;
@ -242,9 +244,10 @@ namespace Esiur.Core
mutex?.Set();
return this;
}
public void TriggerProgress(ProgressType type, int value, int max)
public AsyncReply TriggerProgress(ProgressType type, int value, int max)
{
//timeout?.Dispose();
@ -254,10 +257,12 @@ namespace Esiur.Core
cb(type, value, max);
//}
return this;
}
public void TriggerChunk(object value)
public AsyncReply TriggerChunk(object value)
{
//timeout?.Dispose();
@ -269,6 +274,8 @@ namespace Esiur.Core
cb(value);
//}
return this;
}
public AsyncAwaiter GetAwaiter()

View File

@ -36,6 +36,10 @@ namespace Esiur.Core
SetPropertyDenied,
ReadOnlyProperty,
GeneralFailure,
AddToStoreFailed
AddToStoreFailed,
NotAttached,
AlreadyListened,
AlreadyUnlistened,
NotListenable
}
}

View File

@ -1,4 +1,5 @@
using Esiur.Resource;
using Esiur.Net.IIP;
using Esiur.Resource;
/*
Copyright (c) 2017-2021 Ahmed Kh. Zamil
@ -53,7 +54,14 @@ namespace Esiur.Data
foreach (var pt in resource.Instance.Template.Properties)
{
var rt = pt.Info.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);
}

View File

@ -110,6 +110,10 @@ namespace Esiur.Data
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

View File

@ -1,22 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>netstandard2.0</TargetFramework>
<Description>Distributed Resources Platform</Description>
<Copyright>Ahmed Kh. Zamil</Copyright>
<PackageLicenseUrl>https://github.com/Esiur/Esiur-dotnet/blob/master/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>http://www.esiur.com</PackageProjectUrl>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>1.5.1</Version>
<Version>1.6.1</Version>
<RepositoryUrl>https://github.com/esiur/esiur-dotnet</RepositoryUrl>
<Authors>Ahmed Kh. Zamil</Authors>
<AssemblyVersion>1.3.1.0</AssemblyVersion>
<AssemblyVersion>1.6.0</AssemblyVersion>
<Company>Esiur Foundation</Company>
<FileVersion>1.3.1.0</FileVersion>
<FileVersion>1.6.0</FileVersion>
<AssemblyName>Esiur</AssemblyName>
<RootNamespace>Esiur</RootNamespace>
<PackageId>Esiur</PackageId>
<Product>Esiur</Product>
<LangVersion>9.0</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@ -55,6 +56,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="3.9.0" />
<PackageReference Include="System.Diagnostics.StackTrace" Version="4.3.0" />
<PackageReference Include="System.Dynamic.Runtime" Version="4.3.0" />
<PackageReference Include="System.Interactive.Async" Version="5.0.0" />
@ -62,8 +64,12 @@
<PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" />
<PackageReference Include="System.Net.Security" Version="4.3.2" />
<PackageReference Include="System.Reflection.Emit" Version="4.7.0" />
<PackageReference Include="System.Text.Json" Version="5.0.1" />
<PackageReference Include="System.Text.Json" Version="5.0.2" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.2" PrivateAssets="all" />
</ItemGroup>
</Project>

View File

@ -69,7 +69,7 @@ namespace Esiur.Misc
}catch (Exception ex)
{
Console.WriteLine(ex.ToString());
return "";
return "{}";
}
}
@ -433,9 +433,9 @@ namespace Esiur.Misc
public static byte[] GenerateBytes(int Length)
public static byte[] GenerateBytes(int length)
{
var b = new byte[Length];
var b = new byte[length];
rand.NextBytes(b);
return b;
}

View File

@ -50,7 +50,7 @@ namespace Esiur.Net.DataLink
public void Destroy()
{
OnDestroy?.Invoke(this);
}
}
}

View File

@ -65,7 +65,7 @@ namespace Esiur.Net.DataLink
public void Destroy()
{
throw new NotImplementedException();
OnDestroy?.Invoke(this);
}
public AsyncReply<bool> Trigger(ResourceTrigger trigger)

View File

@ -69,7 +69,7 @@ namespace Esiur.Net.DataLink
public void Destroy()
{
throw new NotImplementedException();
OnDestroy?.Invoke(this);
}
/*

View File

@ -76,7 +76,7 @@ namespace Esiur.Net.HTTP
public void Destroy()
{
throw new NotImplementedException();
OnDestroy?.Invoke(this);
}
}
}

View File

@ -112,7 +112,7 @@ namespace Esiur.Net.HTTP
private void IipConnection_OnReady(DistributedConnection sender)
{
Warehouse.Put(sender, sender.RemoteUsername, null, sender.Server);
Warehouse.Put(sender.RemoteUsername, sender, null, sender.Server).Wait();
}
public override AsyncReply<bool> Trigger(ResourceTrigger trigger)

View File

@ -197,11 +197,20 @@ namespace Esiur.Net.IIP
if (socket.State == SocketState.Established &&
session.LocalAuthentication.Type == AuthenticationType.Client)
{
Declare();
}
}
private void Declare()
{
var dmn = DC.ToBytes(session.LocalAuthentication.Domain);// domain);
if (session.LocalAuthentication.Method == AuthenticationMethod.Credentials)
{
// declare (Credentials -> No Auth, No Enctypt)
var un = DC.ToBytes(session.LocalAuthentication.Username);
var dmn = DC.ToBytes(session.LocalAuthentication.Domain);// domain);
SendParams()
.AddUInt8(0x60)
@ -212,8 +221,27 @@ namespace Esiur.Net.IIP
.AddUInt8Array(un)
.Done();//, dmn, localNonce, (byte)un.Length, un);
}
}
else if (session.LocalAuthentication.Method == AuthenticationMethod.Token)
{
SendParams()
.AddUInt8(0x70)
.AddUInt8((byte)dmn.Length)
.AddUInt8Array(dmn)
.AddUInt8Array(localNonce)
.AddUInt64(session.LocalAuthentication.TokenIndex)
.Done();//, dmn, localNonce, token
}
else if (session.LocalAuthentication.Method == AuthenticationMethod.None)
{
SendParams()
.AddUInt8(0x40)
.AddUInt8((byte)dmn.Length)
.AddUInt8Array(dmn)
.Done();//, dmn, localNonce, token
}
}
/// <summary>
/// Create a new distributed connection.
@ -451,12 +479,21 @@ namespace Esiur.Net.IIP
IIPRequestInvokeFunctionNamedArguments(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content);
break;
case IIPPacket.IIPPacketAction.GetProperty:
IIPRequestGetProperty(packet.CallbackId, packet.ResourceId, packet.MethodIndex);
//case IIPPacket.IIPPacketAction.GetProperty:
// IIPRequestGetProperty(packet.CallbackId, packet.ResourceId, packet.MethodIndex);
// break;
//case IIPPacket.IIPPacketAction.GetPropertyIfModified:
// IIPRequestGetPropertyIfModifiedSince(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.ResourceAge);
// break;
case IIPPacket.IIPPacketAction.Listen:
IIPRequestListen(packet.CallbackId, packet.ResourceId, packet.MethodIndex);
break;
case IIPPacket.IIPPacketAction.GetPropertyIfModified:
IIPRequestGetPropertyIfModifiedSince(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.ResourceAge);
case IIPPacket.IIPPacketAction.Unlisten:
IIPRequestUnlisten(packet.CallbackId, packet.ResourceId, packet.MethodIndex);
break;
case IIPPacket.IIPPacketAction.SetProperty:
IIPRequestSetProperty(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content);
break;
@ -531,14 +568,17 @@ namespace Esiur.Net.IIP
IIPReplyInvoke(packet.CallbackId, packet.Content);
break;
case IIPPacket.IIPPacketAction.GetProperty:
IIPReply(packet.CallbackId, packet.Content);
break;
//case IIPPacket.IIPPacketAction.GetProperty:
// IIPReply(packet.CallbackId, packet.Content);
// break;
case IIPPacket.IIPPacketAction.GetPropertyIfModified:
IIPReply(packet.CallbackId, packet.Content);
break;
case IIPPacket.IIPPacketAction.SetProperty:
//case IIPPacket.IIPPacketAction.GetPropertyIfModified:
// IIPReply(packet.CallbackId, packet.Content);
// break;
case IIPPacketAction.Listen:
case IIPPacketAction.Unlisten:
case IIPPacketAction.SetProperty:
IIPReply(packet.CallbackId);
break;
@ -753,24 +793,34 @@ namespace Esiur.Net.IIP
session.Id = new byte[32];
r.NextBytes(session.Id);
//SendParams((byte)0x28, session.Id);
SendParams()
.AddUInt8(0x28)
SendParams().AddUInt8(0x28)
.AddUInt8Array(session.Id)
.Done();
ready = true;
Warehouse.Put(this, this.LocalUsername, null, Server).Then(x =>
if (this.Instance == null)
{
Warehouse.Put(this.RemoteUsername, this, null, Server).Then(x =>
{
ready = true;
openReply?.Trigger(true);
OnReady?.Invoke(this);
Server?.Membership.Login(session);
loginDate = DateTime.Now;
}).Error(x=>
}).Error(x =>
{
openReply?.TriggerError(x);
});
}
else
{
ready = true;
openReply?.Trigger(true);
OnReady?.Invoke(this);
Server?.Membership.Login(session);
}
//Global.Log("auth", LogType.Warning, "U:" + RemoteUsername + " IP:" + Socket.RemoteEndPoint.Address.ToString() + " S:AUTH");
@ -841,13 +891,21 @@ namespace Esiur.Net.IIP
ready = true;
// put it in the warehouse
Warehouse.Put(this, this.LocalUsername, null, Server).Then(x =>
if (this.Instance == null)
{
Warehouse.Put(this.LocalUsername, this, null, Server).Then(x =>
{
openReply?.Trigger(true);
OnReady?.Invoke(this);
}).Error(x=> openReply?.TriggerError(x));
}).Error(x => openReply?.TriggerError(x));
}
else
{
openReply?.Trigger(true);
OnReady?.Invoke(this);
}
}
}
else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Error)
@ -957,28 +1015,7 @@ namespace Esiur.Net.IIP
}
protected void NetworkClose()
{
// clean up
ready = false;
readyToEstablish = false;
foreach (var x in requests.Values)
x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed"));
foreach (var x in resourceRequests.Values)
x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed"));
foreach (var x in templateRequests.Values)
x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed"));
requests.Clear();
resourceRequests.Clear();
templateRequests.Clear();
foreach (var x in resources.Values)
x.Suspend();
}
public AsyncReply<bool> Connect(AuthenticationMethod method = AuthenticationMethod.Certificate, Sockets.ISocket socket = null, string hostname = null, ushort port = 0, string username = null, ulong tokenIndex = 0, byte[] passwordOrToken = null, string domain = null)
{
@ -1128,32 +1165,38 @@ namespace Esiur.Net.IIP
protected override void Connected()
{
if (session.LocalAuthentication.Type == AuthenticationType.Client)
{
// declare (Credentials -> No Auth, No Enctypt)
var un = DC.ToBytes(session.LocalAuthentication.Username);
var dmn = DC.ToBytes(session.LocalAuthentication.Domain);// domain);
SendParams()
.AddUInt8(0x60)
.AddUInt8((byte)dmn.Length)
.AddUInt8Array(dmn)
.AddUInt8Array(localNonce)
.AddUInt8((byte)un.Length)
.AddUInt8Array(un)
.Done();
}
Declare();
}
protected override void Disconencted()
{
if (ready)
{
Server?.Membership.Logout(session);
Warehouse.Remove(this);
ready = false;
// clean up
readyToEstablish = false;
foreach (var x in requests.Values)
x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed"));
foreach (var x in resourceRequests.Values)
x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed"));
foreach (var x in templateRequests.Values)
x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed"));
requests.Clear();
resourceRequests.Clear();
templateRequests.Clear();
foreach (var x in resources.Values)
x.Suspend();
UnsubscribeAll();
}
Warehouse.Remove(this);
if (ready)
Server?.Membership.Logout(session);
ready = false;
}
/*

View File

@ -36,6 +36,7 @@ using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography.X509Certificates;
namespace Esiur.Net.IIP
{
@ -54,7 +55,9 @@ namespace Esiur.Net.IIP
volatile uint callbackCounter = 0;
List<IResource> subscriptions = new List<IResource>();
//List<IResource> subscriptions = new List<IResource>();
Dictionary<IResource, List<byte>> subscriptions = new Dictionary<IResource, List<byte>>();// new List<IResource>();
object subscriptionsLock = new object();
AsyncQueue<DistributedResourceQueueItem> queue = new AsyncQueue<DistributedResourceQueueItem>();
@ -108,13 +111,40 @@ namespace Esiur.Net.IIP
internal SendList SendEvent(IIPPacket.IIPPacketEvent evt)
{
//var bl = new BinaryList((byte)(evt));
//bl.AddRange(args);
//Send(bl.ToArray());
return (SendList)SendParams().AddUInt8((byte)(evt));
}
internal AsyncReply SendListenRequest(uint instanceId, byte index)
{
var reply = new AsyncReply<object>();
var c = callbackCounter++;
requests.Add(c, reply);
SendParams().AddUInt8((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.Listen))
.AddUInt32(c)
.AddUInt32(instanceId)
.AddUInt8(index)
.Done();
return reply;
}
internal AsyncReply SendUnlistenRequest(uint instanceId, byte index)
{
var reply = new AsyncReply<object>();
var c = callbackCounter++;
requests.Add(c, reply);
SendParams().AddUInt8((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.Unlisten))
.AddUInt32(c)
.AddUInt32(instanceId)
.AddUInt8(index)
.Done();
return reply;
}
internal AsyncReply<object> SendInvokeByArrayArguments(uint instanceId, byte index, object[] parameters)
{
var pb = Codec.ComposeVarArray(parameters, this, true);
@ -593,6 +623,7 @@ namespace Esiur.Net.IIP
var r = res as IResource;
// unsubscribe
Unsubscribe(r);
Subscribe(r);
//r.Instance.ResourceEventOccurred -= Instance_EventOccurred;
//r.Instance.CustomResourceEventOccurred -= Instance_CustomEventOccurred;
@ -610,7 +641,6 @@ namespace Esiur.Net.IIP
//r.Instance.ResourceModified += Instance_PropertyModified;
//r.Instance.ResourceDestroyed += Instance_ResourceDestroyed;
Subscribe(r);
//r.Instance.Children.OnAdd += Children_OnAdd;
//r.Instance.Children.OnRemoved += Children_OnRemoved;
@ -770,7 +800,7 @@ namespace Esiur.Net.IIP
// create the resource
var resource = Activator.CreateInstance(type, args) as IResource;
Warehouse.Put(resource, name, store as IStore, parent).Then(ok =>
Warehouse.Put( name, resource, store as IStore, parent).Then(ok =>
{
SendReply(IIPPacket.IIPPacketAction.CreateResource, callback)
.AddUInt32(resource.Instance.Id)
@ -1126,7 +1156,7 @@ namespace Esiur.Net.IIP
if (Server?.EntryPoint != null)
Server.EntryPoint.Query(resourceLink, this).Then(queryCallback);
else
Warehouse.Query(resourceLink).Then(x => queryCallback(x));
Warehouse.Query(resourceLink).Then(queryCallback);
}
void IIPRequestResourceAttribute(uint callback, uint resourceId)
@ -1469,53 +1499,161 @@ namespace Esiur.Net.IIP
});
}
void IIPRequestGetProperty(uint callback, uint resourceId, byte index)
void IIPRequestListen(uint callback, uint resourceId, byte index)
{
Warehouse.GetById(resourceId).Then((r) =>
{
if (r != null)
{
var pt = r.Instance.Template.GetFunctionTemplateByIndex(index);
if (pt != null)
var et = r.Instance.Template.GetEventTemplateByIndex(index);
if (et != null)
{
if (r is DistributedResource)
{
SendReply(IIPPacket.IIPPacketAction.GetProperty, callback)
.AddUInt8Array(Codec.Compose((r as DistributedResource)._Get(pt.Index), this))
.Done();
(r as DistributedResource).Listen(et).Then(x =>
{
SendReply(IIPPacket.IIPPacketAction.Listen, callback).Done();
}).Error(x => SendError(ErrorType.Exception, callback, (ushort)ExceptionCode.GeneralFailure));
}
else
{
#if NETSTANDARD
var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name);
#else
var pi = r.GetType().GetProperty(pt.Name);
#endif
lock(subscriptionsLock)
{
if (!subscriptions.ContainsKey(r))
{
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.NotAttached);
return;
}
if (pi != null)
if (subscriptions[r].Contains(index))
{
SendReply(IIPPacket.IIPPacketAction.GetProperty, callback)
.AddUInt8Array(Codec.Compose(pi.GetValue(r), this))
.Done();
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AlreadyListened);
return;
}
else
{
// pt found, pi not found, this should never happen
subscriptions[r].Add(index);
SendReply(IIPPacket.IIPPacketAction.Listen, callback).Done();
}
}
}
else
{
// pt not found
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound);
}
}
else
{
// resource not found
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound);
}
});
}
void IIPRequestUnlisten(uint callback, uint resourceId, byte index)
{
Warehouse.GetById(resourceId).Then((r) =>
{
if (r != null)
{
var et = r.Instance.Template.GetEventTemplateByIndex(index);
if (et != null)
{
if (r is DistributedResource)
{
(r as DistributedResource).Unlisten(et).Then(x =>
{
SendReply(IIPPacket.IIPPacketAction.Unlisten, callback).Done();
}).Error(x => SendError(ErrorType.Exception, callback, (ushort)ExceptionCode.GeneralFailure));
}
else
{
lock (subscriptionsLock)
{
if (!subscriptions.ContainsKey(r))
{
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.NotAttached);
return;
}
if (!subscriptions[r].Contains(index))
{
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AlreadyUnlistened);
return;
}
subscriptions[r].Remove(index);
SendReply(IIPPacket.IIPPacketAction.Unlisten, callback).Done();
}
}
}
else
{
// pt not found
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound);
}
}
else
{
// resource not found
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound);
}
});
}
// void IIPRequestGetProperty(uint callback, uint resourceId, byte index)
// {
// Warehouse.GetById(resourceId).Then((r) =>
// {
// if (r != null)
// {
// var pt = r.Instance.Template.GetPropertyTemplateByIndex(index);
// if (pt != null)
// {
// if (r is DistributedResource)
// {
// SendReply(IIPPacket.IIPPacketAction.GetProperty, callback)
// .AddUInt8Array(Codec.Compose((r as DistributedResource)._Get(pt.Index), this))
// .Done();
// }
// else
// {
//#if NETSTANDARD
// var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name);
//#else
// var pi = r.GetType().GetProperty(pt.Name);
//#endif
// if (pi != null)
// {
// SendReply(IIPPacket.IIPPacketAction.GetProperty, callback)
// .AddUInt8Array(Codec.Compose(pi.GetValue(r), this))
// .Done();
// }
// else
// {
// // pt found, pi not found, this should never happen
// }
// }
// }
// else
// {
// // pt not found
// }
// }
// else
// {
// // resource not found
// }
// });
// }
void IIPRequestInquireResourceHistory(uint callback, uint resourceId, DateTime fromDate, DateTime toDate)
{
Warehouse.GetById(resourceId).Then((r) =>
@ -1552,51 +1690,51 @@ namespace Esiur.Net.IIP
});
}
void IIPRequestGetPropertyIfModifiedSince(uint callback, uint resourceId, byte index, ulong age)
{
Warehouse.GetById(resourceId).Then((r) =>
{
if (r != null)
{
var pt = r.Instance.Template.GetFunctionTemplateByIndex(index);
if (pt != null)
{
if (r.Instance.GetAge(index) > age)
{
#if NETSTANDARD
var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name);
#else
var pi = r.GetType().GetProperty(pt.Name);
#endif
if (pi != null)
{
SendReply(IIPPacket.IIPPacketAction.GetPropertyIfModified, callback)
.AddUInt8Array(Codec.Compose(pi.GetValue(r), this))
.Done();
}
else
{
// pt found, pi not found, this should never happen
}
}
else
{
SendReply(IIPPacket.IIPPacketAction.GetPropertyIfModified, callback)
.AddUInt8((byte)DataType.NotModified)
.Done();
}
}
else
{
// pt not found
}
}
else
{
// resource not found
}
});
}
// void IIPRequestGetPropertyIfModifiedSince(uint callback, uint resourceId, byte index, ulong age)
// {
// Warehouse.GetById(resourceId).Then((r) =>
// {
// if (r != null)
// {
// var pt = r.Instance.Template.GetFunctionTemplateByIndex(index);
// if (pt != null)
// {
// if (r.Instance.GetAge(index) > age)
// {
//#if NETSTANDARD
// var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name);
//#else
// var pi = r.GetType().GetProperty(pt.Name);
//#endif
// if (pi != null)
// {
// SendReply(IIPPacket.IIPPacketAction.GetPropertyIfModified, callback)
// .AddUInt8Array(Codec.Compose(pi.GetValue(r), this))
// .Done();
// }
// else
// {
// // pt found, pi not found, this should never happen
// }
// }
// else
// {
// SendReply(IIPPacket.IIPPacketAction.GetPropertyIfModified, callback)
// .AddUInt8((byte)DataType.NotModified)
// .Done();
// }
// }
// else
// {
// // pt not found
// }
// }
// else
// {
// // resource not found
// }
// });
// }
void IIPRequestSetProperty(uint callback, uint resourceId, byte index, byte[] content)
{
@ -1973,7 +2111,7 @@ namespace Esiur.Net.IIP
// ClassId, ResourceAge, ResourceLink, Content
if (resource == null)
{
Warehouse.Put(dr, id.ToString(), this, null, tmp).Then((ok) =>
Warehouse.Put(id.ToString(), dr, this, null, tmp).Then((ok) =>
{
Codec.ParsePropertyValueArray((byte[])rt[3], this).Then((ar) =>
{
@ -2242,7 +2380,7 @@ namespace Esiur.Net.IIP
resource.Instance.ResourceModified += Instance_PropertyModified;
resource.Instance.ResourceDestroyed += Instance_ResourceDestroyed;
subscriptions.Add(resource);
subscriptions.Add(resource, new List<byte>());
}
}
@ -2265,7 +2403,7 @@ namespace Esiur.Net.IIP
{
lock(subscriptionsLock)
{
foreach(var resource in subscriptions)
foreach(var resource in subscriptions.Keys)
{
resource.Instance.ResourceEventOccurred -= Instance_EventOccurred;
resource.Instance.CustomResourceEventOccurred -= Instance_CustomEventOccurred;
@ -2313,12 +2451,26 @@ namespace Esiur.Net.IIP
if (et == null)
return;
if (et.Listenable)
{
lock (subscriptionsLock)
{
// check the client requested listen
if (!subscriptions.ContainsKey(resource))
return;
if (!subscriptions[resource].Contains(et.Index))
return;
}
}
if (!receivers(this.session))
return;
if (resource.Instance.Applicable(this.session, ActionType.ReceiveEvent, et, issuer) == Ruling.Denied)
return;
// compose the packet
SendEvent(IIPPacket.IIPPacketEvent.EventOccurred)
.AddUInt32(resource.Instance.Id)
@ -2334,6 +2486,18 @@ namespace Esiur.Net.IIP
if (et == null)
return;
if (et.Listenable)
{
lock (subscriptionsLock)
{
// check the client requested listen
if (!subscriptions.ContainsKey(resource))
return;
if (!subscriptions[resource].Contains(et.Index))
return;
}
}
if (resource.Instance.Applicable(this.session, ActionType.ReceiveEvent, et, null) == Ruling.Denied)
return;

View File

@ -232,6 +232,7 @@ namespace Esiur.Net.IIP
return connection.SendInvokeByNamedArguments(instanceId, index, namedArgs);
}
public AsyncReply<object> _InvokeByArrayArguments(byte index, object[] args)
{
if (destroyed)
@ -248,13 +249,51 @@ namespace Esiur.Net.IIP
}
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 (attached && ft != null)
{
if (args.Length == 1)
{

View File

@ -32,7 +32,7 @@ namespace Esiur.Net.IIP
{
public class DistributedSession : NetworkSession
{
Source Source { get; }
Authentication Authentication;
public Source Source { get; set; }
public Authentication Authentication { get; set; }
}
}

View File

@ -30,6 +30,7 @@ using System.Text;
using Esiur.Misc;
using Esiur.Data;
using System.Net;
using System.Text.Json.Serialization;
namespace Esiur.Net.Packets
{
@ -291,6 +292,10 @@ namespace Esiur.Net.Packets
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( ));

View File

@ -110,10 +110,10 @@ namespace Esiur.Net.Packets
// Request Invoke
InvokeFunctionArrayArguments = 0x10,
GetProperty,
GetPropertyIfModified,
SetProperty,
InvokeFunctionNamedArguments,
Listen,
Unlisten,
SetProperty,
// Request Attribute
GetAllAttributes = 0x18,
@ -543,7 +543,8 @@ namespace Esiur.Net.Packets
offset += cl;
}
else if (Action == IIPPacketAction.GetProperty)
else if (Action == IIPPacketAction.Listen
|| Action == IIPPacketAction.Unlisten)// .GetProperty)
{
if (NotEnough(offset, ends, 5))
return -dataLengthNeeded;
@ -554,20 +555,20 @@ namespace Esiur.Net.Packets
MethodIndex = data[offset++];
}
else if (Action == IIPPacketAction.GetPropertyIfModified)
{
if (NotEnough(offset, ends, 9))
return -dataLengthNeeded;
//else if (Action == IIPPacketAction.GetPropertyIfModified)
//{
// if (NotEnough(offset, ends, 9))
// return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
// ResourceId = data.GetUInt32(offset);
// offset += 4;
MethodIndex = data[offset++];
// MethodIndex = data[offset++];
ResourceAge = data.GetUInt64(offset);
offset += 8;
// ResourceAge = data.GetUInt64(offset);
// offset += 8;
}
//}
else if (Action == IIPPacketAction.SetProperty)
{
if (NotEnough(offset, ends, 6))
@ -707,9 +708,9 @@ namespace Esiur.Net.Packets
offset += cl;
}
else if (Action == IIPPacketAction.InvokeFunctionArrayArguments
|| Action == IIPPacketAction.InvokeFunctionNamedArguments
|| Action == IIPPacketAction.GetProperty
|| Action == IIPPacketAction.GetPropertyIfModified)
|| Action == IIPPacketAction.InvokeFunctionNamedArguments)
//|| Action == IIPPacketAction.GetProperty
//|| Action == IIPPacketAction.GetPropertyIfModified)
{
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded;
@ -740,7 +741,9 @@ namespace Esiur.Net.Packets
offset += (uint)size;
}
}
else if (Action == IIPPacketAction.SetProperty)
else if (Action == IIPPacketAction.SetProperty
|| Action == IIPPacketAction.Listen
|| Action == IIPPacketAction.Unlisten)
{
// nothing to do
}

View File

@ -329,7 +329,7 @@ namespace Esiur.Net.Packets
}
*/
PosixTime Timeval;
//PosixTime Timeval;
public byte[] Header;
public byte[] Preamble;
//public byte[] Payload;

View File

@ -165,7 +165,7 @@ namespace Esiur.Net.Sockets
{
ssl.BeginWrite(kv.Value, 0, kv.Value.Length, SendCallback, kv.Key);
}
catch (Exception ex)
catch //(Exception ex)
{
asyncSending = false;
try
@ -179,7 +179,7 @@ namespace Esiur.Net.Sockets
Close();
}
}
catch (Exception ex2)
catch //(Exception ex2)
{
//state = SocketState.Closed;// .Terminated;
Close();
@ -439,7 +439,7 @@ namespace Esiur.Net.Sockets
ssl.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReceiveCallback, this);
}
catch (Exception ex)
catch //(Exception ex)
{
if (state != SocketState.Closed && !sock.Connected)
{

View File

@ -126,7 +126,7 @@ namespace Esiur.Net.Sockets
return;
}
}
catch (Exception ex)
catch //(Exception ex)
{
if (socket.state != SocketState.Closed && !socket.sock.Connected)
{
@ -500,7 +500,7 @@ namespace Esiur.Net.Sockets
socket.Close();
}
}
catch (Exception ex2)
catch //(Exception ex2)
{
socket.Close();
//socket.state = SocketState.Closed;// .Terminated;

View File

@ -118,6 +118,7 @@ namespace Esiur.Net.Sockets
public void Send(byte[] message)
{
lock (sendLock)
{
if (held)
@ -131,9 +132,8 @@ namespace Esiur.Net.Sockets
pkt_send.Message = message;
if (pkt_send.Compose())
sock.Send(pkt_send.Data);
sock?.Send(pkt_send.Data);
}
}
@ -229,8 +229,6 @@ namespace Esiur.Net.Sockets
if (pkt_send.Compose())
sock.Send(pkt_send.Data);
}
}

View File

@ -60,7 +60,7 @@ namespace Esiur.Net.TCP
public void Destroy()
{
throw new NotImplementedException();
OnDestroy?.Invoke(this);
}
}
}

View File

@ -51,7 +51,7 @@ namespace Esiur.Net.UDP
public void Destroy()
{
throw new NotImplementedException();
OnDestroy?.Invoke(this);
}
}
}

View File

@ -0,0 +1,20 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Proxy
{
public struct GenerationInfo
{
public string Name { get; set; }
public bool ImplementInterface { get; set; }
public bool ImplementTrigger { get; set; }
public IFieldSymbol[] Fields { get; set; }
public ITypeSymbol ClassSymbol { get; set; }
public ClassDeclarationSyntax ClassDeclaration { get; set; }
}
}

View File

@ -0,0 +1,71 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Linq;
namespace Esiur.Proxy
{
[Generator]
public class ResourceGenerator : ISourceGenerator
{
public void Initialize(GeneratorInitializationContext context)
{
// Register receiver
context.RegisterForSyntaxNotifications(() => new ResourceGeneratorReceiver());
}
public void Execute(GeneratorExecutionContext context)
{
if (!(context.SyntaxContextReceiver is ResourceGeneratorReceiver receiver))
return;
//#if DEBUG
// if (!Debugger.IsAttached)
// {
// Debugger.Launch();
// }
//#endif
//var toImplement = receiver.Classes.Where(x => x.Fields.Length > 0);
foreach (var ci in receiver.Classes)
{
var code = @$"using Esiur.Resource;
using Esiur.Core;
namespace { ci.ClassSymbol.ContainingNamespace.ToDisplayString() } {{
";
if (ci.ImplementInterface)
code += $"public partial class {ci.Name} {{";
else
{
code += @$"public partial class {ci.Name} : IResource {{
public Instance Instance {{ get; set; }}
public event DestroyedEvent OnDestroy;
public virtual void Destroy() {{ OnDestroy?.Invoke(this); }}
";
if (!ci.ImplementTrigger)
code += "public AsyncReply<bool> Trigger(ResourceTrigger trigger) => new AsyncReply<bool>(true);";
}
foreach (var f in ci.Fields)
{
var fn = f.Name;
var pn = fn.Substring(0, 1).ToUpper() + fn.Substring(1);
code += $@"[Public] public {f.Type} {pn} {{ get => {fn}; set {{ {fn} = value; Instance.Modified(); }} }}";
}
code += "}}";
//System.IO.File.WriteAllText("C:\\www\\class.cs", code);
context.AddSource(ci.Name + "_esiur.cs", code);
}
}
}
}

View File

@ -0,0 +1,61 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace Esiur.Proxy
{
public class ResourceGeneratorReceiver : ISyntaxContextReceiver
{
public List<GenerationInfo> Classes { get; } = new();
public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
{
if (context.Node is ClassDeclarationSyntax)
{
var cds = context.Node as ClassDeclarationSyntax;
var cls = context.SemanticModel.GetDeclaredSymbol(cds) as ITypeSymbol;
if (cls.GetAttributes().Any(a => a.AttributeClass.ToDisplayString() == "Esiur.Resource.ResourceAttribute"))
{
//if (!Debugger.IsAttached)
//{
// Debugger.Launch();
//}
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();
// get fields
Classes.Add(new GenerationInfo()
{
Name = cls.Name,
ClassDeclaration = cds,
ClassSymbol = cls,
Fields = fields,
ImplementInterface = cls.Interfaces.Any(x => x.ToDisplayString() == "Esiur.Resource.IResource"),
ImplementTrigger = hasTrigger
});
return;
}
}
}
}
}

View File

@ -12,7 +12,6 @@ namespace Esiur.Proxy
{
static Dictionary<Type, Type> cache = new Dictionary<Type, Type>();
#if NETSTANDARD
static MethodInfo modifyMethod = typeof(Instance).GetTypeInfo().GetMethod("Modified");
static MethodInfo instanceGet = typeof(IResource).GetTypeInfo().GetProperty("Instance").GetGetMethod();
@ -34,14 +33,14 @@ namespace Esiur.Proxy
else
return type;
if (type.FullName.Contains("Esiur.Proxy.T"))
#if NETSTANDARD
return type.GetTypeInfo().BaseType;
#else
return type.BaseType;
#endif
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)
@ -50,6 +49,13 @@ namespace Esiur.Proxy
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 NETSTANDARD
var typeInfo = type.GetTypeInfo();

View File

@ -41,7 +41,6 @@ namespace Esiur.Resource
{
AsyncReply<bool> Trigger(ResourceTrigger trigger);
Instance Instance
{
get;

View File

@ -0,0 +1,42 @@
/*
Copyright (c) 2021 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.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource
{
[AttributeUsage(AttributeTargets.Event)]
public class ListenableAttribute : System.Attribute
{
public ListenableAttribute()
{
}
}
}

View File

@ -4,7 +4,7 @@ using System.Text;
namespace Esiur.Resource
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Event | AttributeTargets.Class)]
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Event | AttributeTargets.Class)]
public class PublicAttribute : Attribute
{

View File

@ -47,6 +47,7 @@ namespace Esiur.Resource
return new AsyncReply<bool>(true);
}
protected virtual bool Create()
{
return true;

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Resource
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class ResourceAttribute : Attribute
{
public ResourceAttribute()
{
}
}
}

View File

@ -16,6 +16,8 @@ namespace Esiur.Resource.Template
set;
}
public bool Listenable { get; set; }
public EventInfo Info { get; set; }
public override byte[] Compose()
@ -24,9 +26,10 @@ namespace Esiur.Resource.Template
if (Expansion != null)
{
var exp = DC.ToBytes(Expansion);
return new BinaryList()
.AddUInt8(0x50)
.AddUInt8(Listenable ? (byte) 0x58 : (byte) 0x50)
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddInt32(exp.Length)
@ -35,17 +38,18 @@ namespace Esiur.Resource.Template
}
else
return new BinaryList()
.AddUInt8(0x40)
.AddUInt8(Listenable ? (byte) 0x48 : (byte) 0x40)
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.ToArray();
}
public EventTemplate(ResourceTemplate template, byte index, string name, string expansion = null)
public EventTemplate(ResourceTemplate template, byte index, string name, string expansion = null, bool listenable=false)
:base(template, MemberType.Property, index, name)
{
this.Expansion = expansion;
this.Listenable = listenable;
}
}
}

View File

@ -176,7 +176,7 @@ namespace Esiur.Resource.Template
var annotationAttr = pi.GetCustomAttribute<AnnotationAttribute>(true);
var storageAttr = pi.GetCustomAttribute<StorageAttribute>(true);
var pt = new PropertyTemplate(this, i++, pi.Name);//, rp.ReadExpansion, rp.WriteExpansion, rp.Storage);
var pt = new PropertyTemplate(this, i++, pi.Name);
if (storageAttr != null)
pt.Recordable = storageAttr.Mode == StorageMode.Recordable;
@ -209,6 +209,7 @@ namespace Esiur.Resource.Template
if (privateAttr == null)
{
var annotationAttr = ei.GetCustomAttribute<AnnotationAttribute>(true);
var listenableAttr = ei.GetCustomAttribute<ListenableAttribute>(true);
var et = new EventTemplate(this, i++, ei.Name);
et.Info = ei;
@ -216,6 +217,9 @@ namespace Esiur.Resource.Template
if (annotationAttr != null)
et.Expansion = annotationAttr.Annotation;
if (listenableAttr != null)
et.Listenable = true;
events.Add(et);
}
}
@ -283,6 +287,7 @@ namespace Esiur.Resource.Template
if (publicAttr != null)
{
var annotationAttr = ei.GetCustomAttribute<AnnotationAttribute>(true);
var listenableAttr = ei.GetCustomAttribute<ListenableAttribute>(true);
var et = new EventTemplate(this, i++, ei.Name);
et.Info = ei;
@ -290,6 +295,9 @@ namespace Esiur.Resource.Template
if (annotationAttr != null)
et.Expansion = annotationAttr.Annotation;
if (listenableAttr != null)
et.Listenable = true;
events.Add(et);
}
}
@ -340,6 +348,7 @@ namespace Esiur.Resource.Template
b.AddUInt8Array(et.Compose());
content = b.ToArray();
}
public static ResourceTemplate Parse(byte[] data)
@ -436,7 +445,8 @@ namespace Esiur.Resource.Template
{
string expansion = null;
var hasExpansion = ((data[offset++] & 0x10) == 0x10);
var hasExpansion = ((data[offset] & 0x10) == 0x10);
var listenable = ((data[offset++] & 0x8) == 0x8);
var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, (int)data[offset]);
offset += (uint)data[offset] + 1;
@ -449,7 +459,7 @@ namespace Esiur.Resource.Template
offset += cs;
}
var et = new EventTemplate(od, eventIndex++, name, expansion);
var et = new EventTemplate(od, eventIndex++, name, expansion, listenable);
od.events.Add(et);

View File

@ -57,11 +57,12 @@ namespace Esiur.Resource
static bool warehouseIsOpen = false;
public delegate void StoreConnectedEvent(IStore store, string name);
public delegate void StoreDisconnectedEvent(IStore store);
public delegate void StoreEvent(IStore store);//, string name);
// public delegate void StoreDisconnectedEvent(IStore store);
public static event StoreConnectedEvent StoreConnected;
public static event StoreDisconnectedEvent StoreDisconnected;
public static event StoreEvent StoreConnected;
//public static event StoreEvent StoreOpen;
public static event StoreEvent StoreDisconnected;
public delegate AsyncReply<IStore> ProtocolInstance(string name, object properties);
@ -476,18 +477,43 @@ namespace Esiur.Resource
}
//public static async AsyncReply<T> Push<T>(string path, T resource) where T : IResource
//{
// await Put(path, resource);
// return resource;
//}
/// <summary>
/// Put a resource in the warehouse.
/// </summary>
/// <param name="resource">Resource instance.</param>
/// <param name="name">Resource name.</param>
/// <param name="resource">Resource instance.</param>
/// <param name="store">IStore that manages the resource. Can be null if the resource is a store.</param>
/// <param name="parent">Parent resource. if not presented the store becomes the parent for the resource.</param>
public static async AsyncReply<bool> Put(IResource resource, string name, IStore store = null, IResource parent = null, ResourceTemplate customTemplate = null, ulong age = 0, IPermissionsManager manager = null, object attributes = null)
public static async AsyncReply<T> Put<T>(string name, T resource, IStore store = null, IResource parent = null, ResourceTemplate customTemplate = null, ulong age = 0, IPermissionsManager manager = null, object attributes = null) where T:IResource
{
if (resource.Instance != null)
throw new Exception("Resource has a store.");
var path = name.TrimStart('/').Split('/');
if (path.Length > 1)
{
if (parent != null)
throw new Exception("Parent can't be set when using path in instance name");
parent = await Warehouse.Get(string.Join("/", path.Take(path.Length - 1)));
if (parent == null)
throw new Exception("Can't find parent");
store = store ?? parent.Instance.Store;
}
var instanceName = path.Last();
var resourceReference = new WeakReference<IResource>(resource);
if (store == null)
@ -523,7 +549,7 @@ namespace Esiur.Resource
throw new Exception("Can't find a store for the resource.");
}
resource.Instance = new Instance(resourceCounter++, name, resource, store, customTemplate, age);
resource.Instance = new Instance(resourceCounter++, instanceName, resource, store, customTemplate, age);
if (attributes != null)
resource.Instance.SetAttributes(Structure.FromObject(attributes));
@ -537,12 +563,15 @@ namespace Esiur.Resource
try
{
if (resource is IStore)
stores.TryAdd(resource as IStore, new List<WeakReference<IResource>>());
if (!await store.Put(resource))
return false;
throw new Exception("Store failed to put the resource");
//return default(T);
if (parent != null)
@ -565,14 +594,21 @@ namespace Esiur.Resource
}
if (resource is IStore)
StoreConnected?.Invoke(resource as IStore, name);
StoreConnected?.Invoke(resource as IStore);
}
catch (Exception ex)
{
Warehouse.Remove(resource);
throw ex;
}
return true;
return resource;
}
public static async AsyncReply<IResource> New(Type type, string name = null, IStore store = null, IResource parent = null, IPermissionsManager manager = null, object attributes = null, object properties = null)
{
type = ResourceProxy.GetProxy(type);
@ -618,7 +654,9 @@ namespace Esiur.Resource
{
var pi = type.GetProperty(p.Key, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
if (pi != null && pi.CanWrite)
if (pi != null)
{
if (pi.CanWrite)
{
try
{
@ -630,12 +668,30 @@ namespace Esiur.Resource
}
}
}
else
{
var fi = type.GetField(p.Key, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
if (fi != null)
{
try
{
fi.SetValue(res, p.Value);
}
catch (Exception ex)
{
Global.Log(ex);
}
}
}
}
}
if (store != null || parent != null || res is IStore)
{
if (!await Put(res, name, store, parent, null, 0, manager, attributes))
return null;
//if (!await Put(name, res, store, parent, null, 0, manager, attributes))
// return null;
await Put(name, res, store, parent, null, 0, manager, attributes);
}
return res;

View File

@ -35,11 +35,11 @@ using Esiur.Resource;
namespace Esiur.Security.Membership
{
public interface IMembership : IResource
public interface IMembership
{
AsyncReply<bool> UserExists(string username, string domain);
AsyncReply<byte[]> GetPassword(string username, string domain);
AsyncReply<byte[]> GetToken(ulong TokenIndex, string domain);
AsyncReply<byte[]> GetToken(ulong tokenIndex, string domain);
AsyncReply<bool> Login(Session session);
AsyncReply<bool> Logout(Session session);

View File

@ -46,6 +46,7 @@ namespace Esiur.Security.Permissions
public bool Initialize(Structure settings, IResource resource)
{
this.settings = settings;
return true;
}
}

View File

@ -20,7 +20,7 @@ namespace Esiur.Stores
public void Destroy()
{
OnDestroy?.Invoke(this);
}
public string Link(IResource resource)
@ -41,14 +41,14 @@ namespace Esiur.Stores
return new AsyncReply<IResource>(null);
}
public async AsyncReply<bool> Put(IResource resource)
public AsyncReply<bool> Put(IResource resource)
{
resources.Add(resource.Instance.Id, resource);// new WeakReference<IResource>(resource));
resource.Instance.Variables["children"] = new AutoList<IResource, Instance>(resource.Instance);
resource.Instance.Variables["parents"] = new AutoList<IResource, Instance>(resource.Instance);
return true;
return new AsyncReply<bool>(true);
}
public AsyncReply<IResource> Retrieve(uint iid)

View File

@ -20,6 +20,7 @@ namespace Esiur.Stores
public void Destroy()
{
OnDestroy?.Invoke(this);
}
@ -31,19 +32,19 @@ namespace Esiur.Stores
return null;
}
public async AsyncReply<IResource> Get(string path)
public AsyncReply<IResource> Get(string path)
{
foreach (var r in resources)
if (r.Value.IsAlive && (r.Value.Target as IResource).Instance.Name == path)
return r.Value.Target as IResource;
return new AsyncReply<IResource>(r.Value.Target as IResource);
return null;
return new AsyncReply<IResource>(null);
}
public async AsyncReply<bool> Put(IResource resource)
public AsyncReply<bool> Put(IResource resource)
{
resources.Add(resource.Instance.Id, new WeakReference( resource));// new WeakReference<IResource>(resource));
return true;
return new AsyncReply<bool>(true);
}
public AsyncReply<IResource> Retrieve(uint iid)