mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2025-06-27 05:23:13 +00:00
ResourceTemplate 2.0
This commit is contained in:
15
Esiur/Resource/ImportAttribute.cs
Normal file
15
Esiur/Resource/ImportAttribute.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Esiur.Resource
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ImportAttribute:Attribute
|
||||
{
|
||||
public ImportAttribute(string url)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -185,8 +185,8 @@ namespace Esiur.Resource
|
||||
var at = template.GetAttributeTemplate(kv.Key);
|
||||
|
||||
if (at != null)
|
||||
if (at.Info.CanWrite)
|
||||
at.Info.SetValue(res, DC.CastConvert(kv.Value, at.Info.PropertyType));
|
||||
if (at.PropertyInfo.CanWrite)
|
||||
at.PropertyInfo.SetValue(res, DC.CastConvert(kv.Value, at.PropertyInfo.PropertyType));
|
||||
|
||||
}
|
||||
}
|
||||
@ -354,17 +354,17 @@ namespace Esiur.Resource
|
||||
#endif
|
||||
*/
|
||||
|
||||
if (pt.Info.PropertyType == typeof(DistributedPropertyContext))
|
||||
if (pt.PropertyInfo.PropertyType == typeof(DistributedPropertyContext))
|
||||
return false;
|
||||
|
||||
|
||||
if (pt.Info.CanWrite)
|
||||
if (pt.PropertyInfo.CanWrite)
|
||||
{
|
||||
try
|
||||
{
|
||||
loading = true;
|
||||
|
||||
pt.Info.SetValue(res, DC.CastConvert(value, pt.Info.PropertyType));
|
||||
pt.PropertyInfo.SetValue(res, DC.CastConvert(value, pt.PropertyInfo.PropertyType));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -453,7 +453,7 @@ namespace Esiur.Resource
|
||||
|
||||
if (resource.TryGetTarget(out res))
|
||||
{
|
||||
var rt = pt.Info.GetValue(res, null);
|
||||
var rt = pt.PropertyInfo.GetValue(res, null);
|
||||
props.Add(new PropertyValue(rt, ages[pt.Index], modificationDates[pt.Index]));
|
||||
}
|
||||
}
|
||||
@ -628,7 +628,7 @@ namespace Esiur.Resource
|
||||
|
||||
var pt = template.GetPropertyTemplateByName(name);
|
||||
|
||||
if (pt != null && pt.Info != null)
|
||||
if (pt != null && pt.PropertyInfo != null)
|
||||
{
|
||||
/*
|
||||
#if NETSTANDARD
|
||||
@ -649,7 +649,7 @@ namespace Esiur.Resource
|
||||
|
||||
IResource res;
|
||||
if (resource.TryGetTarget(out res))
|
||||
value = pt.Info.GetValue(res, null);
|
||||
value = pt.PropertyInfo.GetValue(res, null);
|
||||
else
|
||||
{
|
||||
value = null;
|
||||
@ -900,28 +900,30 @@ namespace Esiur.Resource
|
||||
//if (evt.EventHandlerType != typeof(ResourceEventHanlder))
|
||||
// continue;
|
||||
|
||||
if (evt.Info == null)
|
||||
if (evt.EventInfo == null)
|
||||
continue;
|
||||
|
||||
if (evt.Info.EventHandlerType == typeof(ResourceEventHanlder))
|
||||
var eventGenericType = evt.EventInfo.EventHandlerType.GetGenericTypeDefinition();
|
||||
|
||||
if (eventGenericType == typeof(ResourceEventHanlder<>))
|
||||
{
|
||||
|
||||
// var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true);
|
||||
// if (ca.Length == 0)
|
||||
// continue;
|
||||
|
||||
ResourceEventHanlder proxyDelegate = (args) => EmitResourceEvent(evt.Name, args);
|
||||
evt.Info.AddEventHandler(resource, proxyDelegate);
|
||||
|
||||
ResourceEventHanlder<object> proxyDelegate = (args) => EmitResourceEvent(evt.Name, args);
|
||||
evt.EventInfo.AddEventHandler(resource, proxyDelegate);
|
||||
|
||||
}
|
||||
else if (evt.Info.EventHandlerType == typeof(CustomResourceEventHanlder))
|
||||
else if (eventGenericType == typeof(CustomResourceEventHanlder<>))
|
||||
{
|
||||
//var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true);
|
||||
//if (ca.Length == 0)
|
||||
// continue;
|
||||
|
||||
CustomResourceEventHanlder proxyDelegate = (issuer, receivers, args) => EmitCustomResourceEvent(issuer, receivers, evt.Name, args);
|
||||
evt.Info.AddEventHandler(resource, proxyDelegate);
|
||||
CustomResourceEventHanlder<object> proxyDelegate = (issuer, receivers, args) => EmitCustomResourceEvent(issuer, receivers, evt.Name, args);
|
||||
evt.EventInfo.AddEventHandler(resource, proxyDelegate);
|
||||
}
|
||||
|
||||
|
||||
|
@ -33,12 +33,14 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Esiur.Resource
|
||||
{
|
||||
public delegate void ResourceEventHanlder(object args);
|
||||
public delegate R DCovariant<out R>();
|
||||
|
||||
public delegate void ResourceEventHanlder<in T>(T argument);
|
||||
// public delegate void CustomUsersEventHanlder(string[] usernames, params object[] args);
|
||||
//public delegate void CustomReceiversEventHanlder(DistributedConnection[] connections, params object[] args);
|
||||
//public delegate void CustomInquirerEventHanlder(object inquirer, params object[] args);
|
||||
|
||||
public delegate void CustomResourceEventHanlder(object issuer, Func<Session, bool> receivers, object args);// object issuer, Session[] receivers, params object[] args);
|
||||
public delegate void CustomResourceEventHanlder<T>(object issuer, Func<Session, bool> receivers, T argument);// object issuer, Session[] receivers, params object[] args);
|
||||
|
||||
// public delegate void CustomReceiversEventHanlder(string[] usernames, DistributedConnection[] connections, params object[] args);
|
||||
|
||||
|
49
Esiur/Resource/Template/ArgumentTemplate.cs
Normal file
49
Esiur/Resource/Template/ArgumentTemplate.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using Esiur.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Esiur.Resource.Template
|
||||
{
|
||||
public class ArgumentTemplate
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public TemplateDataType Type { get; set; }
|
||||
|
||||
public ParameterInfo ParameterInfo { get; set; }
|
||||
|
||||
public static (uint, ArgumentTemplate) Parse(byte[] data, uint offset)
|
||||
{
|
||||
var cs = (uint)data[offset++];
|
||||
var name = DC.GetString(data, offset, cs);
|
||||
offset += cs;
|
||||
var (size, type) = TemplateDataType.Parse(data, offset);
|
||||
|
||||
return (cs + 1 + size, new ArgumentTemplate(name, type));
|
||||
}
|
||||
|
||||
public ArgumentTemplate()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ArgumentTemplate(string name, TemplateDataType type)
|
||||
{
|
||||
Name = name;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public byte[] Compose()
|
||||
{
|
||||
var name = DC.ToBytes(Name);
|
||||
|
||||
return new BinaryList()
|
||||
.AddUInt8((byte)name.Length)
|
||||
.AddUInt8Array(name)
|
||||
.AddUInt8Array(Type.Compose())
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ namespace Esiur.Resource.Template
|
||||
{
|
||||
public class AttributeTemplate : MemberTemplate
|
||||
{
|
||||
public PropertyInfo Info
|
||||
public PropertyInfo PropertyInfo
|
||||
{
|
||||
get;
|
||||
set;
|
||||
|
@ -18,7 +18,9 @@ namespace Esiur.Resource.Template
|
||||
|
||||
public bool Listenable { get; set; }
|
||||
|
||||
public EventInfo Info { get; set; }
|
||||
public EventInfo EventInfo { get; set; }
|
||||
|
||||
public TemplateDataType ArgumentType { get; set; }
|
||||
|
||||
public override byte[] Compose()
|
||||
{
|
||||
@ -26,12 +28,12 @@ namespace Esiur.Resource.Template
|
||||
|
||||
if (Expansion != null)
|
||||
{
|
||||
|
||||
var exp = DC.ToBytes(Expansion);
|
||||
return new BinaryList()
|
||||
.AddUInt8(Listenable ? (byte) 0x58 : (byte) 0x50)
|
||||
.AddUInt8((byte)name.Length)
|
||||
.AddUInt8Array(name)
|
||||
.AddUInt8Array(ArgumentType.Compose())
|
||||
.AddInt32(exp.Length)
|
||||
.AddUInt8Array(exp)
|
||||
.ToArray();
|
||||
@ -41,15 +43,17 @@ namespace Esiur.Resource.Template
|
||||
.AddUInt8(Listenable ? (byte) 0x48 : (byte) 0x40)
|
||||
.AddUInt8((byte)name.Length)
|
||||
.AddUInt8Array(name)
|
||||
.AddUInt8Array(ArgumentType.Compose())
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
|
||||
public EventTemplate(ResourceTemplate template, byte index, string name, string expansion = null, bool listenable=false)
|
||||
public EventTemplate(ResourceTemplate template, byte index, string name, TemplateDataType argumentType, string expansion = null, bool listenable=false)
|
||||
:base(template, MemberType.Property, index, name)
|
||||
{
|
||||
this.Expansion = expansion;
|
||||
this.Listenable = listenable;
|
||||
this.ArgumentType = argumentType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -16,7 +17,17 @@ namespace Esiur.Resource.Template
|
||||
set;
|
||||
}
|
||||
|
||||
public bool IsVoid
|
||||
//public bool IsVoid
|
||||
//{
|
||||
// get;
|
||||
// set;
|
||||
//}
|
||||
|
||||
public TemplateDataType ReturnType { get; set; }
|
||||
|
||||
public ArgumentTemplate[] Arguments { get; set; }
|
||||
|
||||
public MethodInfo MethodInfo
|
||||
{
|
||||
get;
|
||||
set;
|
||||
@ -25,30 +36,40 @@ namespace Esiur.Resource.Template
|
||||
|
||||
public override byte[] Compose()
|
||||
{
|
||||
|
||||
var name = base.Compose();
|
||||
|
||||
var bl = new BinaryList()
|
||||
//.AddUInt8(Expansion != null ? (byte)0x10 : (byte)0)
|
||||
.AddUInt8((byte)name.Length)
|
||||
.AddUInt8Array(name)
|
||||
.AddUInt8Array(ReturnType.Compose())
|
||||
.AddUInt8((byte)Arguments.Length);
|
||||
|
||||
for (var i = 0; i < Arguments.Length; i++)
|
||||
bl.AddUInt8Array(Arguments[i].Compose());
|
||||
|
||||
|
||||
if (Expansion != null)
|
||||
{
|
||||
var exp = DC.ToBytes(Expansion);
|
||||
return new BinaryList().AddUInt8((byte)(0x10 | (IsVoid ? 0x8 : 0x0)))
|
||||
.AddUInt8((byte)name.Length)
|
||||
.AddUInt8Array(name)
|
||||
.AddInt32(exp.Length)
|
||||
.AddUInt8Array(exp)
|
||||
.ToArray();
|
||||
bl.AddInt32(exp.Length)
|
||||
.AddUInt8Array(exp);
|
||||
bl.InsertUInt8(0, 0x10);
|
||||
}
|
||||
else
|
||||
return new BinaryList().AddUInt8((byte)(IsVoid ? 0x8 : 0x0))
|
||||
.AddUInt8((byte)name.Length)
|
||||
.AddUInt8Array(name)
|
||||
.ToArray();
|
||||
bl.InsertUInt8(0, 0x0);
|
||||
|
||||
return bl.ToArray();
|
||||
}
|
||||
|
||||
|
||||
public FunctionTemplate(ResourceTemplate template, byte index, string name,bool isVoid, string expansion = null)
|
||||
:base(template, MemberType.Property, index, name)
|
||||
public FunctionTemplate(ResourceTemplate template, byte index, string name, ArgumentTemplate[] arguments, TemplateDataType returnType, string expansion = null)
|
||||
: base(template, MemberType.Property, index, name)
|
||||
{
|
||||
this.IsVoid = isVoid;
|
||||
//this.IsVoid = isVoid;
|
||||
this.Arguments = arguments;
|
||||
this.ReturnType = returnType;
|
||||
this.Expansion = expansion;
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ namespace Esiur.Resource.Template
|
||||
{
|
||||
public class PropertyTemplate : MemberTemplate
|
||||
{
|
||||
public enum PropertyPermission:byte
|
||||
public enum PropertyPermission : byte
|
||||
{
|
||||
Read = 1,
|
||||
Write,
|
||||
@ -18,12 +18,15 @@ namespace Esiur.Resource.Template
|
||||
}
|
||||
|
||||
|
||||
public PropertyInfo Info
|
||||
public PropertyInfo PropertyInfo
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public TemplateDataType ValueType { get; set; }
|
||||
|
||||
|
||||
/*
|
||||
public bool Serilize
|
||||
{
|
||||
@ -32,12 +35,13 @@ namespace Esiur.Resource.Template
|
||||
*/
|
||||
//bool ReadOnly;
|
||||
//IIPTypes::DataType ReturnType;
|
||||
public PropertyPermission Permission {
|
||||
public PropertyPermission Permission
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public bool Recordable
|
||||
{
|
||||
get;
|
||||
@ -84,6 +88,7 @@ namespace Esiur.Resource.Template
|
||||
.AddUInt8((byte)(0x38 | pv))
|
||||
.AddUInt8((byte)name.Length)
|
||||
.AddUInt8Array(name)
|
||||
.AddUInt8Array(ValueType.Compose())
|
||||
.AddInt32(wexp.Length)
|
||||
.AddUInt8Array(wexp)
|
||||
.AddInt32(rexp.Length)
|
||||
@ -97,6 +102,7 @@ namespace Esiur.Resource.Template
|
||||
.AddUInt8((byte)(0x30 | pv))
|
||||
.AddUInt8((byte)name.Length)
|
||||
.AddUInt8Array(name)
|
||||
.AddUInt8Array(ValueType.Compose())
|
||||
.AddInt32(wexp.Length)
|
||||
.AddUInt8Array(wexp)
|
||||
.ToArray();
|
||||
@ -108,25 +114,30 @@ namespace Esiur.Resource.Template
|
||||
.AddUInt8((byte)(0x28 | pv))
|
||||
.AddUInt8((byte)name.Length)
|
||||
.AddUInt8Array(name)
|
||||
.AddUInt8Array(ValueType.Compose())
|
||||
.AddInt32(rexp.Length)
|
||||
.AddUInt8Array(rexp)
|
||||
.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new BinaryList()
|
||||
.AddUInt8((byte)(0x20 | pv))
|
||||
.AddUInt8((byte)name.Length)
|
||||
.AddUInt8Array(name)
|
||||
.AddUInt8Array(ValueType.Compose())
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public PropertyTemplate(ResourceTemplate template, byte index, string name, string read = null, string write = null, bool recordable = false)
|
||||
:base(template, MemberType.Property, index, name)
|
||||
public PropertyTemplate(ResourceTemplate template, byte index, string name, TemplateDataType valueType, string read = null, string write = null, bool recordable = false)
|
||||
: base(template, MemberType.Property, index, name)
|
||||
{
|
||||
this.Recordable = recordable;
|
||||
//this.Storage = storage;
|
||||
this.ReadExpansion = read;
|
||||
this.WriteExpansion = write;
|
||||
this.ValueType = valueType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ namespace Esiur.Resource.Template
|
||||
{
|
||||
public class ResourceTemplate
|
||||
{
|
||||
|
||||
Guid classId;
|
||||
string className;
|
||||
List<MemberTemplate> members = new List<MemberTemplate>();
|
||||
@ -31,6 +32,8 @@ namespace Esiur.Resource.Template
|
||||
get { return content; }
|
||||
}
|
||||
|
||||
public Type RuntimeType { get; set; }
|
||||
|
||||
public MemberTemplate GetMemberTemplate(MemberInfo member)
|
||||
{
|
||||
if (member is MethodInfo)
|
||||
@ -135,20 +138,137 @@ namespace Esiur.Resource.Template
|
||||
}
|
||||
|
||||
|
||||
public static Guid GetTypeGuid(Type type) => GetTypeGuid(type.FullName);
|
||||
|
||||
public static Guid GetTypeGuid(string typeName)
|
||||
{
|
||||
var tn = Encoding.UTF8.GetBytes(typeName);
|
||||
var hash = SHA256.Create().ComputeHash(tn).Clip(0, 16);
|
||||
|
||||
return new Guid(hash);
|
||||
}
|
||||
|
||||
static Type GetElementType(Type type) => type switch
|
||||
{
|
||||
{ IsArray: true } => type.GetElementType(),
|
||||
{ IsEnum: true } => type.GetEnumUnderlyingType(),
|
||||
(_) => type
|
||||
};
|
||||
|
||||
|
||||
|
||||
public static ResourceTemplate[] GetRuntimeTypes(ResourceTemplate template)
|
||||
{
|
||||
|
||||
var list = new List<ResourceTemplate>();
|
||||
|
||||
list.Add(template);
|
||||
|
||||
Action<ResourceTemplate, List<ResourceTemplate>> getRuntimeTypes = null;
|
||||
|
||||
getRuntimeTypes = (ResourceTemplate tmp, List<ResourceTemplate> bag) =>
|
||||
{
|
||||
if (template.RuntimeType == null)
|
||||
return;
|
||||
|
||||
// functions
|
||||
foreach (var f in tmp.functions)
|
||||
{
|
||||
var frtt = Warehouse.GetTemplate(GetElementType(f.MethodInfo.ReturnType));
|
||||
if (frtt != null)
|
||||
{
|
||||
if (!bag.Contains(frtt))
|
||||
{
|
||||
list.Add(frtt);
|
||||
getRuntimeTypes(frtt, bag);
|
||||
}
|
||||
}
|
||||
|
||||
var args = f.MethodInfo.GetParameters();
|
||||
|
||||
for(var i = 0; i < args.Length - 1; i++)
|
||||
{
|
||||
var fpt = Warehouse.GetTemplate(GetElementType(args[i].ParameterType));
|
||||
if (fpt != null)
|
||||
{
|
||||
if (!bag.Contains(fpt))
|
||||
{
|
||||
bag.Add(fpt);
|
||||
getRuntimeTypes(fpt, bag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// skip DistributedConnection argument
|
||||
if (args.Length > 0)
|
||||
{
|
||||
var last = args.Last();
|
||||
if (last.ParameterType != typeof(DistributedConnection))
|
||||
{
|
||||
var fpt = Warehouse.GetTemplate(GetElementType(last.ParameterType));
|
||||
if (fpt != null)
|
||||
{
|
||||
if (!bag.Contains(fpt))
|
||||
{
|
||||
bag.Add(fpt);
|
||||
getRuntimeTypes(fpt, bag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// properties
|
||||
foreach (var p in tmp.properties)
|
||||
{
|
||||
var pt = Warehouse.GetTemplate(GetElementType(p.PropertyInfo.PropertyType));
|
||||
if (pt != null)
|
||||
{
|
||||
if (!bag.Contains(pt))
|
||||
{
|
||||
bag.Add(pt);
|
||||
getRuntimeTypes(pt, bag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// events
|
||||
foreach (var e in tmp.events)
|
||||
{
|
||||
var et = Warehouse.GetTemplate(GetElementType(e.EventInfo.EventHandlerType.GenericTypeArguments[0]));
|
||||
|
||||
if (et != null)
|
||||
{
|
||||
if (!bag.Contains(et))
|
||||
{
|
||||
bag.Add(et);
|
||||
getRuntimeTypes(et, bag);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
getRuntimeTypes(template, list);
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
public ResourceTemplate(Type type)
|
||||
{
|
||||
if (!Codec.ImplementsInterface(type, typeof(IResource)))
|
||||
throw new Exception("Type is not a resource.");
|
||||
|
||||
type = ResourceProxy.GetBaseType(type);
|
||||
|
||||
// set guid
|
||||
RuntimeType = type;
|
||||
|
||||
var typeName = Encoding.UTF8.GetBytes(type.FullName);
|
||||
var hash = SHA256.Create().ComputeHash(typeName).Clip(0, 16);
|
||||
|
||||
classId = new Guid(hash);
|
||||
className = type.FullName;
|
||||
|
||||
//Console.WriteLine($"Creating {className}");
|
||||
|
||||
// set guid
|
||||
classId = GetTypeGuid(className);
|
||||
|
||||
#if NETSTANDARD
|
||||
PropertyInfo[] propsInfo = type.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly);
|
||||
EventInfo[] eventsInfo = type.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly);
|
||||
@ -175,8 +295,9 @@ namespace Esiur.Resource.Template
|
||||
{
|
||||
var annotationAttr = pi.GetCustomAttribute<AnnotationAttribute>(true);
|
||||
var storageAttr = pi.GetCustomAttribute<StorageAttribute>(true);
|
||||
|
||||
var pt = new PropertyTemplate(this, i++, pi.Name, TemplateDataType.FromType(pi.PropertyType));
|
||||
|
||||
var pt = new PropertyTemplate(this, i++, pi.Name);
|
||||
if (storageAttr != null)
|
||||
pt.Recordable = storageAttr.Mode == StorageMode.Recordable;
|
||||
|
||||
@ -185,7 +306,7 @@ namespace Esiur.Resource.Template
|
||||
else
|
||||
pt.ReadExpansion = pi.PropertyType.Name;
|
||||
|
||||
pt.Info = pi;
|
||||
pt.PropertyInfo = pi;
|
||||
//pt.Serilize = publicAttr.Serialize;
|
||||
properties.Add(pt);
|
||||
}
|
||||
@ -195,7 +316,7 @@ namespace Esiur.Resource.Template
|
||||
if (attributeAttr != null)
|
||||
{
|
||||
var at = new AttributeTemplate(this, 0, pi.Name);
|
||||
at.Info = pi;
|
||||
at.PropertyInfo = pi;
|
||||
attributes.Add(at);
|
||||
}
|
||||
}
|
||||
@ -211,8 +332,9 @@ namespace Esiur.Resource.Template
|
||||
var annotationAttr = ei.GetCustomAttribute<AnnotationAttribute>(true);
|
||||
var listenableAttr = ei.GetCustomAttribute<ListenableAttribute>(true);
|
||||
|
||||
var et = new EventTemplate(this, i++, ei.Name);
|
||||
et.Info = ei;
|
||||
var argType = ei.EventHandlerType.GenericTypeArguments[0];
|
||||
var et = new EventTemplate(this, i++, ei.Name, TemplateDataType.FromType(argType));
|
||||
et.EventInfo = ei;
|
||||
|
||||
if (annotationAttr != null)
|
||||
et.Expansion = annotationAttr.Annotation;
|
||||
@ -232,12 +354,32 @@ namespace Esiur.Resource.Template
|
||||
{
|
||||
var annotationAttr = mi.GetCustomAttribute<AnnotationAttribute>(true);
|
||||
|
||||
var ft = new FunctionTemplate(this, i++, mi.Name, mi.ReturnType == typeof(void));
|
||||
var returnType = TemplateDataType.FromType(mi.ReturnType);
|
||||
|
||||
var args = mi.GetParameters();
|
||||
|
||||
if (args.Length > 0)
|
||||
{
|
||||
if (args.Last().ParameterType == typeof(DistributedConnection))
|
||||
args = args.Take(args.Count() - 1).ToArray();
|
||||
}
|
||||
|
||||
var arguments = args.Select(x => new ArgumentTemplate()
|
||||
{
|
||||
Name = x.Name,
|
||||
Type = TemplateDataType.FromType(x.ParameterType),
|
||||
ParameterInfo = x
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
var ft = new FunctionTemplate(this, i++, mi.Name, arguments, returnType);// mi.ReturnType == typeof(void));
|
||||
|
||||
if (annotationAttr != null)
|
||||
ft.Expansion = annotationAttr.Annotation;
|
||||
else
|
||||
ft.Expansion = "(" + String.Join(",", mi.GetParameters().Where(x => x.ParameterType != typeof(DistributedConnection)).Select(x => "[" + x.ParameterType.Name + "] " + x.Name)) + ") -> " + mi.ReturnType.Name;
|
||||
|
||||
ft.MethodInfo = mi;
|
||||
functions.Add(ft);
|
||||
}
|
||||
}
|
||||
@ -253,8 +395,9 @@ namespace Esiur.Resource.Template
|
||||
{
|
||||
var annotationAttr = pi.GetCustomAttribute<AnnotationAttribute>(true);
|
||||
var storageAttr = pi.GetCustomAttribute<StorageAttribute>(true);
|
||||
var valueType = TemplateDataType.FromType(pi.PropertyType);
|
||||
|
||||
var pt = new PropertyTemplate(this, i++, pi.Name);//, rp.ReadExpansion, rp.WriteExpansion, rp.Storage);
|
||||
var pt = new PropertyTemplate(this, i++, pi.Name, valueType);//, rp.ReadExpansion, rp.WriteExpansion, rp.Storage);
|
||||
if (storageAttr != null)
|
||||
pt.Recordable = storageAttr.Mode == StorageMode.Recordable;
|
||||
|
||||
@ -263,7 +406,7 @@ namespace Esiur.Resource.Template
|
||||
else
|
||||
pt.ReadExpansion = pi.PropertyType.Name;
|
||||
|
||||
pt.Info = pi;
|
||||
pt.PropertyInfo = pi;
|
||||
//pt.Serilize = publicAttr.Serialize;
|
||||
properties.Add(pt);
|
||||
}
|
||||
@ -273,7 +416,7 @@ namespace Esiur.Resource.Template
|
||||
if (attributeAttr != null)
|
||||
{
|
||||
var at = new AttributeTemplate(this, 0, pi.Name);
|
||||
at.Info = pi;
|
||||
at.PropertyInfo = pi;
|
||||
attributes.Add(at);
|
||||
}
|
||||
}
|
||||
@ -289,8 +432,10 @@ namespace Esiur.Resource.Template
|
||||
var annotationAttr = ei.GetCustomAttribute<AnnotationAttribute>(true);
|
||||
var listenableAttr = ei.GetCustomAttribute<ListenableAttribute>(true);
|
||||
|
||||
var et = new EventTemplate(this, i++, ei.Name);
|
||||
et.Info = ei;
|
||||
var argType = ei.EventHandlerType.GenericTypeArguments[0];
|
||||
|
||||
var et = new EventTemplate(this, i++, ei.Name, TemplateDataType.FromType(argType));
|
||||
et.EventInfo = ei;
|
||||
|
||||
if (annotationAttr != null)
|
||||
et.Expansion = annotationAttr.Annotation;
|
||||
@ -309,13 +454,32 @@ namespace Esiur.Resource.Template
|
||||
if (publicAttr != null)
|
||||
{
|
||||
var annotationAttr = mi.GetCustomAttribute<AnnotationAttribute>(true);
|
||||
var returnType = TemplateDataType.FromType(mi.ReturnType);
|
||||
|
||||
var ft = new FunctionTemplate(this, i++, mi.Name, mi.ReturnType == typeof(void));
|
||||
var args = mi.GetParameters();
|
||||
|
||||
if (args.Length > 0)
|
||||
{
|
||||
if (args.Last().ParameterType == typeof(DistributedConnection))
|
||||
args = args.Take(args.Count() - 1).ToArray();
|
||||
}
|
||||
|
||||
var arguments = args.Select(x => new ArgumentTemplate()
|
||||
{
|
||||
Name = x.Name,
|
||||
Type = TemplateDataType.FromType(x.ParameterType),
|
||||
ParameterInfo = x
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
var ft = new FunctionTemplate(this, i++, mi.Name, arguments, returnType);// mi.ReturnType == typeof(void));
|
||||
|
||||
if (annotationAttr != null)
|
||||
ft.Expansion = annotationAttr.Annotation;
|
||||
else
|
||||
ft.Expansion = "(" + String.Join(",", mi.GetParameters().Where(x=>x.ParameterType != typeof(DistributedConnection)).Select(x=> "[" + x.ParameterType.Name + "] " + x.Name)) + ") -> " + mi.ReturnType.Name;
|
||||
|
||||
ft.MethodInfo = mi;
|
||||
functions.Add(ft);
|
||||
}
|
||||
}
|
||||
@ -391,11 +555,27 @@ namespace Esiur.Resource.Template
|
||||
if (type == 0) // function
|
||||
{
|
||||
string expansion = null;
|
||||
var hasExpansion = ((data[offset] & 0x10) == 0x10);
|
||||
var isVoid = ((data[offset++] & 0x08) == 0x08);
|
||||
var hasExpansion = ((data[offset++] & 0x10) == 0x10);
|
||||
|
||||
var name = data.GetString(offset + 1, data[offset]);
|
||||
offset += (uint)data[offset] + 1;
|
||||
|
||||
|
||||
// return type
|
||||
var (rts, returnType) = TemplateDataType.Parse(data, offset);
|
||||
offset += rts;
|
||||
|
||||
// arguments count
|
||||
var argsCount = data[offset++];
|
||||
List<ArgumentTemplate> arguments = new();
|
||||
|
||||
for (var a = 0; a < argsCount; a++)
|
||||
{
|
||||
var (cs, argType) = ArgumentTemplate.Parse(data, offset);
|
||||
arguments.Add(argType);
|
||||
offset += cs;
|
||||
}
|
||||
|
||||
// arguments
|
||||
if (hasExpansion) // expansion ?
|
||||
{
|
||||
var cs = data.GetUInt32(offset);
|
||||
@ -404,7 +584,7 @@ namespace Esiur.Resource.Template
|
||||
offset += cs;
|
||||
}
|
||||
|
||||
var ft = new FunctionTemplate(od, functionIndex++, name, isVoid, expansion);
|
||||
var ft = new FunctionTemplate(od, functionIndex++, name, arguments.ToArray(), returnType, expansion);
|
||||
|
||||
od.functions.Add(ft);
|
||||
}
|
||||
@ -421,6 +601,10 @@ namespace Esiur.Resource.Template
|
||||
|
||||
offset += (uint)data[offset] + 1;
|
||||
|
||||
var (dts, valueType) = TemplateDataType.Parse(data, offset);
|
||||
|
||||
offset += dts;
|
||||
|
||||
if (hasReadExpansion) // expansion ?
|
||||
{
|
||||
var cs = data.GetUInt32(offset);
|
||||
@ -437,7 +621,7 @@ namespace Esiur.Resource.Template
|
||||
offset += cs;
|
||||
}
|
||||
|
||||
var pt = new PropertyTemplate(od, propertyIndex++, name, readExpansion, writeExpansion, recordable);
|
||||
var pt = new PropertyTemplate(od, propertyIndex++, name, valueType, readExpansion, writeExpansion, recordable);
|
||||
|
||||
od.properties.Add(pt);
|
||||
}
|
||||
@ -451,6 +635,10 @@ namespace Esiur.Resource.Template
|
||||
var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, (int)data[offset]);
|
||||
offset += (uint)data[offset] + 1;
|
||||
|
||||
var (dts, argType) = TemplateDataType.Parse(data, offset);
|
||||
|
||||
offset += dts;
|
||||
|
||||
if (hasExpansion) // expansion ?
|
||||
{
|
||||
var cs = data.GetUInt32(offset);
|
||||
@ -459,7 +647,7 @@ namespace Esiur.Resource.Template
|
||||
offset += cs;
|
||||
}
|
||||
|
||||
var et = new EventTemplate(od, eventIndex++, name, expansion, listenable);
|
||||
var et = new EventTemplate(od, eventIndex++, name, argType, expansion, listenable);
|
||||
|
||||
od.events.Add(et);
|
||||
|
||||
|
118
Esiur/Resource/Template/TemplateDataType.cs
Normal file
118
Esiur/Resource/Template/TemplateDataType.cs
Normal file
@ -0,0 +1,118 @@
|
||||
using Esiur.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Text;
|
||||
|
||||
namespace Esiur.Resource.Template
|
||||
{
|
||||
public struct TemplateDataType
|
||||
{
|
||||
public DataType Type { get; set; }
|
||||
//public string TypeName { get; set; }
|
||||
public ResourceTemplate TypeTemplate => TypeGuid == null ? null : Warehouse.GetTemplate((Guid)TypeGuid);
|
||||
|
||||
public Guid? TypeGuid { get; set; }
|
||||
//public TemplateDataType(DataType type, string typeName)
|
||||
//{
|
||||
// Type = type;
|
||||
// TypeName = typeName;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
public static TemplateDataType FromType(Type type)
|
||||
{
|
||||
|
||||
var t = type switch
|
||||
{
|
||||
{ IsArray: true } => type.GetElementType(),
|
||||
{ IsEnum: true } => type.GetEnumUnderlyingType(),
|
||||
(_) => type
|
||||
};
|
||||
|
||||
DataType dt = t switch
|
||||
{
|
||||
_ when t == typeof(bool) => DataType.Bool,
|
||||
_ when t == typeof(char) => DataType.Char,
|
||||
_ when t == typeof(byte) => DataType.UInt8,
|
||||
_ when t == typeof(sbyte) => DataType.Int8,
|
||||
_ when t == typeof(short) => DataType.Int16,
|
||||
_ when t == typeof(ushort) => DataType.UInt16,
|
||||
_ when t == typeof(int) => DataType.Int32,
|
||||
_ when t == typeof(uint) => DataType.UInt32,
|
||||
_ when t == typeof(long) => DataType.Int64,
|
||||
_ when t == typeof(ulong) => DataType.UInt64,
|
||||
_ when t == typeof(float) => DataType.Float32,
|
||||
_ when t == typeof(double) => DataType.Float64,
|
||||
_ when t == typeof(decimal) => DataType.Decimal,
|
||||
_ when t == typeof(string) => DataType.String,
|
||||
_ when t == typeof(DateTime) => DataType.DateTime,
|
||||
_ when t == typeof(IResource) => DataType.Void, // Dynamic resource (unspecified type)
|
||||
_ when typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject) => DataType.Structure,
|
||||
_ when Codec.ImplementsInterface(t, typeof(IResource)) => DataType.Resource,
|
||||
_ => DataType.Void
|
||||
};
|
||||
|
||||
|
||||
//string tn = dt switch
|
||||
//{
|
||||
// DataType.Resource => t.FullName,
|
||||
// DataType.Structure when t != typeof(Structure) => t.FullName,
|
||||
// _ => null
|
||||
//};
|
||||
|
||||
Guid? typeGuid = null;
|
||||
|
||||
if (dt == DataType.Resource)
|
||||
typeGuid = ResourceTemplate.GetTypeGuid(t);
|
||||
|
||||
if (type.IsArray)
|
||||
dt = (DataType)((byte)dt | 0x80);
|
||||
|
||||
return new TemplateDataType()
|
||||
{
|
||||
Type = dt,
|
||||
TypeGuid = typeGuid
|
||||
};
|
||||
}
|
||||
|
||||
public byte[] Compose()
|
||||
{
|
||||
if (Type == DataType.Resource ||
|
||||
Type == DataType.ResourceArray)//||
|
||||
//Type == DataType.DistributedResource ||
|
||||
//Type == DataType.DistributedResourceArray ||
|
||||
//Type == DataType.Structure ||
|
||||
//Type == DataType.StructureArray)
|
||||
{
|
||||
var guid = DC.ToBytes((Guid)TypeGuid);
|
||||
return new BinaryList()
|
||||
.AddUInt8((byte)Type)
|
||||
.AddUInt8Array(guid).ToArray();
|
||||
}
|
||||
else
|
||||
return new byte[] { (byte)Type };
|
||||
}
|
||||
|
||||
public override string ToString() => Type.ToString() + TypeTemplate != null ? "<" + TypeTemplate.ClassName + ">" : "";
|
||||
|
||||
|
||||
public static (uint, TemplateDataType) Parse(byte[] data, uint offset)
|
||||
{
|
||||
var type = (DataType)data[offset++];
|
||||
if (type == DataType.Resource ||
|
||||
type == DataType.ResourceArray)//||
|
||||
// type == DataType.DistributedResource ||
|
||||
// type == DataType.DistributedResourceArray)// ||
|
||||
// type == DataType.Structure ||
|
||||
// type == DataType.StructureArray)
|
||||
{
|
||||
var guid = DC.GetGuid(data, offset);
|
||||
return (17, new TemplateDataType() { Type = type, TypeGuid = guid });
|
||||
}
|
||||
else
|
||||
return (1, new TemplateDataType() { Type = type });
|
||||
}
|
||||
}
|
||||
}
|
@ -113,6 +113,22 @@ namespace Esiur.Resource
|
||||
return new AsyncReply<IResource>(null);
|
||||
}
|
||||
|
||||
static void LoadGenerated()
|
||||
{
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
var generatedType = assembly.GetType("Esiur.Generated");
|
||||
if (generatedType != null)
|
||||
{
|
||||
var types = (Type[])generatedType.GetProperty("Types").GetValue(null);
|
||||
foreach (var t in types)
|
||||
{
|
||||
PutTemplate(new ResourceTemplate(t));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open the warehouse.
|
||||
/// This function issues the initialize trigger to all stores and resources.
|
||||
@ -123,6 +139,10 @@ namespace Esiur.Resource
|
||||
if (warehouseIsOpen)
|
||||
return false;
|
||||
|
||||
// Load generated models
|
||||
LoadGenerated();
|
||||
|
||||
|
||||
warehouseIsOpen = true;
|
||||
|
||||
var resSnap = resources.Select(x =>
|
||||
@ -380,7 +400,8 @@ namespace Esiur.Resource
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns>Resource instance.</returns>
|
||||
public static async AsyncReply<IResource> Get(string path, object attributes = null, IResource parent = null, IPermissionsManager manager = null)
|
||||
public static async AsyncReply<T> Get<T>(string path, object attributes = null, IResource parent = null, IPermissionsManager manager = null)
|
||||
where T: IResource
|
||||
{
|
||||
//var rt = new AsyncReply<IResource>();
|
||||
|
||||
@ -404,9 +425,9 @@ namespace Esiur.Resource
|
||||
//await Put(store, url[2], null, parent, null, 0, manager, attributes);
|
||||
|
||||
if (url[3].Length > 0 && url[3] != "")
|
||||
return await store.Get(url[3]);
|
||||
return (T)await store.Get(url[3]);
|
||||
else
|
||||
return store;
|
||||
return (T)store;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -471,9 +492,9 @@ namespace Esiur.Resource
|
||||
var res = await Query(path);
|
||||
|
||||
if (res.Length == 0)
|
||||
return null;
|
||||
return default(T);
|
||||
else
|
||||
return res.First();
|
||||
return (T)res.First();
|
||||
|
||||
}
|
||||
|
||||
@ -503,7 +524,7 @@ namespace Esiur.Resource
|
||||
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)));
|
||||
parent = await Warehouse.Get<IResource>(string.Join("/", path.Take(path.Length - 1)));
|
||||
|
||||
if (parent == null)
|
||||
throw new Exception("Can't find parent");
|
||||
@ -518,27 +539,28 @@ namespace Esiur.Resource
|
||||
|
||||
if (store == null)
|
||||
{
|
||||
// assign parent as a store
|
||||
if (parent is IStore)
|
||||
{
|
||||
store = (IStore)parent;
|
||||
List<WeakReference<IResource>> list;
|
||||
if (stores.TryGetValue(store, out list))
|
||||
lock (((ICollection)list).SyncRoot)
|
||||
list.Add(resourceReference);
|
||||
//stores[store].Add(resourceReference);
|
||||
}
|
||||
// assign parent's store as a store
|
||||
else if (parent != null)
|
||||
if (parent != null)
|
||||
{
|
||||
store = parent.Instance.Store;
|
||||
// assign parent as a store
|
||||
if (parent is IStore)
|
||||
{
|
||||
store = (IStore)parent;
|
||||
List<WeakReference<IResource>> list;
|
||||
if (stores.TryGetValue(store, out list))
|
||||
lock (((ICollection)list).SyncRoot)
|
||||
list.Add(resourceReference);
|
||||
//stores[store].Add(resourceReference);
|
||||
}
|
||||
else
|
||||
{
|
||||
store = parent.Instance.Store;
|
||||
|
||||
List<WeakReference<IResource>> list;
|
||||
if (stores.TryGetValue(store, out list))
|
||||
lock (((ICollection)list).SyncRoot)
|
||||
list.Add(resourceReference);
|
||||
|
||||
//stores[store].Add(resourceReference);
|
||||
List<WeakReference<IResource>> list;
|
||||
if (stores.TryGetValue(store, out list))
|
||||
lock (((ICollection)list).SyncRoot)
|
||||
list.Add(resourceReference);
|
||||
}
|
||||
}
|
||||
// assign self as a store (root store)
|
||||
else if (resource is IStore)
|
||||
@ -722,9 +744,16 @@ namespace Esiur.Resource
|
||||
/// <returns>Resource template.</returns>
|
||||
public static ResourceTemplate GetTemplate(Type type)
|
||||
{
|
||||
|
||||
if (!Codec.ImplementsInterface(type, typeof(IResource)))
|
||||
return null;
|
||||
|
||||
var baseType = ResourceProxy.GetBaseType(type);
|
||||
|
||||
if (baseType == typeof(IResource) )
|
||||
return null;
|
||||
|
||||
|
||||
// loaded ?
|
||||
foreach (var t in templates.Values)
|
||||
if (t.ClassName == baseType.FullName)
|
||||
@ -741,10 +770,10 @@ namespace Esiur.Resource
|
||||
/// </summary>
|
||||
/// <param name="classId">Class Id.</param>
|
||||
/// <returns>Resource template.</returns>
|
||||
public static AsyncReply<ResourceTemplate> GetTemplate(Guid classId)
|
||||
public static ResourceTemplate GetTemplate(Guid classId)
|
||||
{
|
||||
if (templates.ContainsKey(classId))
|
||||
return new AsyncReply<ResourceTemplate>(templates[classId]);
|
||||
return templates[classId];
|
||||
return null;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user