2
0
mirror of https://github.com/esiur/esiur-dotnet.git synced 2026-01-27 01:20:39 +00:00

IDynamicResource Added

This commit is contained in:
2026-01-21 09:06:35 +03:00
parent 63ba506338
commit f8d7630c21
18 changed files with 698 additions and 839 deletions

View File

@@ -1586,7 +1586,7 @@ public static class DataDeserializer
var pvs = new List<PropertyValue>(); var pvs = new List<PropertyValue>();
for (var i = 0; i < ar.Length; i += 3) for (var i = 0; i < ar.Length; i += 3)
pvs.Add(new PropertyValue(ar[2], Convert.ToUInt64(ar[0]), (DateTime?)ar[1])); pvs.Add(new PropertyValue(ar[i + 2], Convert.ToUInt64(ar[i]), (DateTime?)ar[i+1]));
rt.Trigger(pvs.ToArray()); rt.Trigger(pvs.ToArray());

View File

@@ -0,0 +1,20 @@
using Esiur.Core;
using Esiur.Resource.Template;
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data
{
public interface IDynamicResource
{
public PropertyValue[] SerializeResource();
public Map<byte, PropertyValue> SerializeResourceAfter(ulong age);
public object GetResourceProperty(byte index);
public AsyncReply SetResourcePropertyAsync(byte index, object value);
public void SetResourceProperty(byte index, object value);
public TypeTemplate ResourceTemplate { get; }
}
}

View File

@@ -68,7 +68,7 @@ partial class DistributedConnection
object subscriptionsLock = new object(); object subscriptionsLock = new object();
AsyncQueue<DistributedResourceQueueItem> queue = new (); AsyncQueue<DistributedResourceQueueItem> queue = new();
@@ -450,7 +450,7 @@ partial class DistributedConnection
var (valueOffset, valueSize, args) = var (valueOffset, valueSize, args) =
DataDeserializer.LimitedCountListParser(dataType.Data, dataType.Offset, dataType.ContentLength, Instance.Warehouse, 2); DataDeserializer.LimitedCountListParser(dataType.Data, dataType.Offset, dataType.ContentLength, Instance.Warehouse, 2);
var rid =Convert.ToUInt32(args[0]); var rid = Convert.ToUInt32(args[0]);
var index = (byte)args[1]; var index = (byte)args[1];
Fetch(rid, null).Then(r => Fetch(rid, null).Then(r =>
@@ -559,26 +559,13 @@ partial class DistributedConnection
// unsubscribe // unsubscribe
Unsubscribe(r); Unsubscribe(r);
if (r is DistributedResource dr) // reply ok
{ SendReply(IIPPacketReply.Completed, callback,
// reply ok r.Instance.Template.ClassId,
SendReply(IIPPacketReply.Completed, callback, r.Instance.Age,
r.Instance.Template.ClassId, r.Instance.Link,
r.Instance.Age, r.Instance.Hops,
r.Instance.Link, r.Instance.Serialize());
r.Instance.Hops,
dr._Serialize());
}
else
{
// reply ok
SendReply(IIPPacketReply.Completed, callback,
r.Instance.Template.ClassId,
r.Instance.Age,
r.Instance.Link,
r.Instance.Hops,
r.Instance.Serialize());
}
// subscribe // subscribe
Subscribe(r); Subscribe(r);
@@ -618,26 +605,15 @@ partial class DistributedConnection
// unsubscribe // unsubscribe
Unsubscribe(r); Unsubscribe(r);
if (r is DistributedResource dr)
{ // reply ok
// reply ok SendReply(IIPPacketReply.Completed, callback,
SendReply(IIPPacketReply.Completed, callback, r.Instance.Template.ClassId,
r.Instance.Template.ClassId, r.Instance.Age,
r.Instance.Age, r.Instance.Link,
r.Instance.Link, r.Instance.Hops,
r.Instance.Hops, r.Instance.SerializeAfter(age));
dr._SerializeAfter(age));
}
else
{
// reply ok
SendReply(IIPPacketReply.Completed, callback,
r.Instance.Template.ClassId,
r.Instance.Age,
r.Instance.Link,
r.Instance.Hops,
r.Instance.SerializeAfter(age));
}
// subscribe // subscribe
Subscribe(r); Subscribe(r);
@@ -1612,7 +1588,7 @@ partial class DistributedConnection
} }
if (r is DistributedResource) if (r is IDynamicResource)
{ {
var (_, parsed) = Codec.ParseAsync(data, offset, this, null); var (_, parsed) = Codec.ParseAsync(data, offset, this, null);
if (parsed is AsyncReply) if (parsed is AsyncReply)
@@ -1620,7 +1596,7 @@ partial class DistributedConnection
(parsed as AsyncReply).Then((value) => (parsed as AsyncReply).Then((value) =>
{ {
// propagation // propagation
(r as DistributedResource)._Set(index, value).Then((x) => (r as IDynamicResource).SetResourcePropertyAsync(index, value).Then((x) =>
{ {
SendReply(IIPPacketReply.Completed, callback); SendReply(IIPPacketReply.Completed, callback);
}).Error(x => }).Error(x =>
@@ -1912,7 +1888,7 @@ partial class DistributedConnection
{ {
template = Instance.Warehouse.GetTemplateByClassId(classId, TemplateType.Resource); template = Instance.Warehouse.GetTemplateByClassId(classId, TemplateType.Resource);
if (template?.DefinedType != null && template.IsWrapper) if (template?.DefinedType != null && template.IsWrapper)
dr = Activator.CreateInstance(template.DefinedType, this, id,Convert.ToUInt64( args[1]), (string)args[2]) as DistributedResource; dr = Activator.CreateInstance(template.DefinedType, this, id, Convert.ToUInt64(args[1]), (string)args[2]) as DistributedResource;
else else
dr = new DistributedResource(this, id, Convert.ToUInt64(args[1]), (string)args[2]); dr = new DistributedResource(this, id, Convert.ToUInt64(args[1]), (string)args[2]);
} }
@@ -1955,7 +1931,9 @@ partial class DistributedConnection
// ClassId, ResourceAge, ResourceLink, Content // ClassId, ResourceAge, ResourceLink, Content
if (resource == null) if (resource == null)
{ {
Instance.Warehouse.Put(this.Instance.Link + "/" + id.ToString(), dr, tmp) dr.ResourceTemplate = tmp;
Instance.Warehouse.Put(this.Instance.Link + "/" + id.ToString(), dr)
.Then(initResource) .Then(initResource)
.Error(ex => reply.TriggerError(ex)); .Error(ex => reply.TriggerError(ex));
} }
@@ -1973,7 +1951,7 @@ partial class DistributedConnection
{ {
if (resource == null) if (resource == null)
{ {
Instance.Warehouse.Put(this.Instance.Link + "/" + id.ToString(), dr, template) Instance.Warehouse.Put(this.Instance.Link + "/" + id.ToString(), dr)
.Then(initResource).Error((ex) => reply.TriggerError(ex)); .Then(initResource).Error((ex) => reply.TriggerError(ex));
} }
else else

View File

@@ -46,7 +46,7 @@ using Esiur.Net.Packets;
namespace Esiur.Net.IIP; namespace Esiur.Net.IIP;
//[System.Runtime.InteropServices.ComVisible(true)] //[System.Runtime.InteropServices.ComVisible(true)]
public class DistributedResource : DynamicObject, IResource, INotifyPropertyChanged public class DistributedResource : DynamicObject, IResource, INotifyPropertyChanged, IDynamicResource
{ {
/// <summary> /// <summary>
@@ -57,6 +57,7 @@ public class DistributedResource : DynamicObject, IResource, INotifyPropertyChan
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
uint instanceId; uint instanceId;
TypeTemplate template;
DistributedConnection connection; DistributedConnection connection;
@@ -67,7 +68,7 @@ public class DistributedResource : DynamicObject, IResource, INotifyPropertyChan
//Structure properties = new Structure(); //Structure properties = new Structure();
string link; string link;
//ulong age; ulong age;
protected object[] properties; protected object[] properties;
internal List<DistributedResource> parents = new List<DistributedResource>(); internal List<DistributedResource> parents = new List<DistributedResource>();
@@ -77,17 +78,6 @@ public class DistributedResource : DynamicObject, IResource, INotifyPropertyChan
/// <summary>
/// Resource template for the remotely located resource.
/// </summary>
//public ResourceTemplate Template
//{
// get { return template; }
//}
/// <summary> /// <summary>
/// Connection responsible for the distributed resource. /// Connection responsible for the distributed resource.
/// </summary> /// </summary>
@@ -160,45 +150,9 @@ public class DistributedResource : DynamicObject, IResource, INotifyPropertyChan
this.link = link; this.link = link;
this.connection = connection; this.connection = connection;
this.instanceId = instanceId; this.instanceId = instanceId;
this.age = age;
//this.Instance.Template = template;
//this.Instance.Age = age;
//this.template = template;
//this.age = age;
} }
/// <summary>
/// Export properties as byte array.
/// </summary>
/// <returns></returns>
internal PropertyValue[] _Serialize()
{
var props = new PropertyValue[properties.Length];
for (byte i = 0; i < properties.Length; i++)
props[i] = new PropertyValue(properties[i],
Instance.GetAge(i),
Instance.GetModificationDate(i));
return props;
}
internal Map<byte, PropertyValue> _SerializeAfter(ulong age = 0)
{
var rt = new Map<byte, PropertyValue>();
for (byte i = 0; i < properties.Length; i++)
if (Instance.GetAge(i) > age)
rt.Add(i, new PropertyValue(properties[i],
Instance.GetAge(i),
Instance.GetModificationDate(i)));
return rt;
}
internal bool _Attach(PropertyValue[] properties) internal bool _Attach(PropertyValue[] properties)
{ {
if (attached) if (attached)
@@ -357,17 +311,14 @@ public class DistributedResource : DynamicObject, IResource, INotifyPropertyChan
} }
} }
/// <summary> ///// <summary>
/// Get a property value. ///// Get a property value.
/// </summary> ///// </summary>
/// <param name="index">Zero-based property index.</param> ///// <param name="index">Zero-based property index.</param>
/// <returns>Value</returns> ///// <returns>Value</returns>
protected internal object _Get(byte index) //protected internal object _Get(byte index)
{ //{
if (index >= properties.Length) //}
return null;
return properties[index];
}
public bool TryGetPropertyValue(byte index, out object value) public bool TryGetPropertyValue(byte index, out object value)
{ {
@@ -427,65 +378,19 @@ public class DistributedResource : DynamicObject, IResource, INotifyPropertyChan
/// <param name="index">Zero-based property index.</param> /// <param name="index">Zero-based property index.</param>
/// <param name="value">Value</param> /// <param name="value">Value</param>
/// <returns>Indicator when the property is set.</returns> /// <returns>Indicator when the property is set.</returns>
protected object _SetSync(byte index, object value) //protected object _SetSync(byte index, object value)
{ //{
//Console.WriteLine("Setting..." + index + " " + value); //}
if (destroyed) ///// <summary>
throw new Exception("Trying to access a destroyed object."); ///// Set property value.
///// </summary>
if (suspended) ///// <param name="index">Zero-based property index.</param>
throw new Exception("Trying to access a suspended object."); ///// <param name="value">Value</param>
///// <returns>Indicator when the property is set.</returns>
if (!attached) //protected internal AsyncReply<object> _Set(byte index, object value)
return null; //{
//}
if (index >= properties.Length)
return null;
// Don't set the same current value
if (properties[index] == value)
return value;
var rt = _Set(index, value).Wait();
//Console.WriteLine("Done Setting");
return rt;
}
/// <summary>
/// Set property value.
/// </summary>
/// <param name="index">Zero-based property index.</param>
/// <param name="value">Value</param>
/// <returns>Indicator when the property is set.</returns>
protected internal AsyncReply<object> _Set(byte index, object value)
{
if (destroyed)
throw new Exception("Trying to access a destroyed object.");
if (suspended)
throw new Exception("Trying to access a suspended object.");
if (!attached)
return null;
if (index >= properties.Length)
return null;
var reply = new AsyncReply<object>();
connection.SendSetProperty(instanceId, index, value)
.Then((res) =>
{
// not really needed, server will always send property modified,
// this only happens if the programmer forgot to emit in property setter
properties[index] = value;
reply.Trigger(null);
});
return reply;
}
public override bool TrySetMember(SetMemberBinder binder, object value) public override bool TrySetMember(SetMemberBinder binder, object value)
{ {
@@ -502,7 +407,7 @@ public class DistributedResource : DynamicObject, IResource, INotifyPropertyChan
if (pt != null) if (pt != null)
{ {
_Set(pt.Index, value); SetResourceProperty(pt.Index, value);
return true; return true;
} }
else else
@@ -518,33 +423,6 @@ public class DistributedResource : DynamicObject, IResource, INotifyPropertyChan
} }
/*
public async void InvokeMethod(byte index, object[] arguments, DistributedConnection sender)
{
// get function parameters
Type t = this.GetType();
MethodInfo mi = t.GetMethod(GetFunctionName(index), BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.Instance | BindingFlags.InvokeMethod);
if (mi != null)
{
try
{
var res = await invokeMethod(mi, arguments, sender);
object rt = Codec.Compose(res);
sender.SendParams((byte)0x80, instanceId, index, rt);
}
catch(Exception ex)
{
var msg = ex.InnerException != null ? ex.InnerException.Message : ex.Message;
sender.SendParams((byte)0x8E, instanceId, index, Codec.Compose(msg));
}
}
}
*/
/// <summary> /// <summary>
/// Resource interface. /// Resource interface.
@@ -555,6 +433,18 @@ public class DistributedResource : DynamicObject, IResource, INotifyPropertyChan
set; set;
} }
public TypeTemplate ResourceTemplate
{
get
{
return template;
}
internal set
{
template = value;
}
}
/// <summary> /// <summary>
/// Create a new instance of distributed resource. /// Create a new instance of distributed resource.
/// </summary> /// </summary>
@@ -587,6 +477,82 @@ public class DistributedResource : DynamicObject, IResource, INotifyPropertyChan
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
} }
public PropertyValue[] SerializeResource()
{
var props = new PropertyValue[properties.Length];
for (byte i = 0; i < properties.Length; i++)
props[i] = new PropertyValue(properties[i],
Instance.GetAge(i),
Instance.GetModificationDate(i));
return props;
}
public Map<byte, PropertyValue> SerializeResourceAfter(ulong age = 0)
{
var rt = new Map<byte, PropertyValue>();
for (byte i = 0; i < properties.Length; i++)
if (Instance.GetAge(i) > age)
rt.Add(i, new PropertyValue(properties[i],
Instance.GetAge(i),
Instance.GetModificationDate(i)));
return rt;
}
public object GetResourceProperty(byte index)
{
if (index >= properties.Length)
return null;
return properties[index];
}
public AsyncReply SetResourcePropertyAsync(byte index, object value)
{
if (destroyed)
throw new Exception("Trying to access a destroyed object.");
if (suspended)
throw new Exception("Trying to access a suspended object.");
if (!attached)
throw new Exception("Resource is not attached.");
if (index >= properties.Length)
throw new Exception("Property index not found."); ;
var reply = new AsyncReply<object>();
connection.SendSetProperty(instanceId, index, value)
.Then((res) =>
{
// not really needed, server will always send property modified,
// this only happens if the programmer forgot to emit in property setter
properties[index] = value;
reply.Trigger(null);
});
return reply;
}
public void SetResourceProperty(byte index, object value)
{
// Don't set the same current value
if (properties[index] == value)
return;
SetResourcePropertyAsync(index, value).Wait();
return;
}
~DistributedResource() ~DistributedResource()
{ {
Destroy(); Destroy();

View File

@@ -74,9 +74,13 @@ public static class TemplateGenerator
rt.AppendLine("using System;\r\nusing Esiur.Resource;\r\nusing Esiur.Core;\r\nusing Esiur.Data;\r\nusing Esiur.Net.IIP;"); rt.AppendLine("using System;\r\nusing Esiur.Resource;\r\nusing Esiur.Core;\r\nusing Esiur.Data;\r\nusing Esiur.Net.IIP;");
rt.AppendLine($"namespace {nameSpace} {{"); rt.AppendLine($"namespace {nameSpace} {{");
if (template.Annotation != null) if (template.Annotations != null)
rt.AppendLine($"[Annotation({ToLiteral(template.Annotation)})]"); {
foreach (var ann in template.Annotations)
{
rt.AppendLine($"[Annotation({ToLiteral(ann.Key)}, {ToLiteral(ann.Value)})]");
}
}
rt.AppendLine($"[ClassId(\"{template.ClassId.Data.ToHex(0, 16, null)}\")]"); rt.AppendLine($"[ClassId(\"{template.ClassId.Data.ToHex(0, 16, null)}\")]");
rt.AppendLine($"[Export] public class {className} : IRecord {{"); rt.AppendLine($"[Export] public class {className} : IRecord {{");
@@ -85,8 +89,17 @@ public static class TemplateGenerator
foreach (var p in template.Properties) foreach (var p in template.Properties)
{ {
var ptTypeName = GetTypeName(p.ValueType, templates); var ptTypeName = GetTypeName(p.ValueType, templates);
if (p.ReadAnnotation != null)
rt.AppendLine($"[Annotation({ToLiteral(p.ReadAnnotation)})]");
if (p.Annotations != null)
{
foreach (var ann in p.Annotations)
{
rt.AppendLine($"[Annotation({ToLiteral(ann.Key)}, {ToLiteral(ann.Value)})]");
}
}
rt.AppendLine($"public {ptTypeName} {p.Name} {{ get; set; }}"); rt.AppendLine($"public {ptTypeName} {p.Name} {{ get; set; }}");
rt.AppendLine(); rt.AppendLine();
} }
@@ -108,8 +121,13 @@ public static class TemplateGenerator
rt.AppendLine("using System;\r\nusing Esiur.Resource;\r\nusing Esiur.Core;\r\nusing Esiur.Data;\r\nusing Esiur.Net.IIP;"); rt.AppendLine("using System;\r\nusing Esiur.Resource;\r\nusing Esiur.Core;\r\nusing Esiur.Data;\r\nusing Esiur.Net.IIP;");
rt.AppendLine($"namespace {nameSpace} {{"); rt.AppendLine($"namespace {nameSpace} {{");
if (template.Annotation != null) if (template.Annotations != null)
rt.AppendLine($"[Annotation({ToLiteral(template.Annotation)})]"); {
foreach (var ann in template.Annotations)
{
rt.AppendLine($"[Annotation({ToLiteral(ann.Key)}, {ToLiteral(ann.Value)})]");
}
}
rt.AppendLine($"[ClassId(\"{template.ClassId.Data.ToHex(0, 16, null)}\")]"); rt.AppendLine($"[ClassId(\"{template.ClassId.Data.ToHex(0, 16, null)}\")]");
rt.AppendLine($"[Export] public enum {className} {{"); rt.AppendLine($"[Export] public enum {className} {{");
@@ -275,8 +293,13 @@ public static class TemplateGenerator
rt.AppendLine($"namespace {nameSpace} {{"); rt.AppendLine($"namespace {nameSpace} {{");
if (template.Annotation != null) if (template.Annotations != null)
rt.AppendLine($"[Annotation({ToLiteral(template.Annotation)})]"); {
foreach (var ann in template.Annotations)
{
rt.AppendLine($"[Annotation({ToLiteral(ann.Key)}, {ToLiteral(ann.Value)})]");
}
}
rt.AppendLine($"[ClassId(\"{template.ClassId.Data.ToHex(0, 16, null)}\")]"); rt.AppendLine($"[ClassId(\"{template.ClassId.Data.ToHex(0, 16, null)}\")]");
@@ -371,8 +394,13 @@ public static class TemplateGenerator
if (p.Inherited) if (p.Inherited)
continue; continue;
if (p.ReadAnnotation != null) if (p.Annotations != null)
rt.AppendLine($"[Annotation({ToLiteral(p.ReadAnnotation)})]"); {
foreach (var ann in p.Annotations)
{
rt.AppendLine($"[Annotation({ToLiteral(ann.Key)}, {ToLiteral(ann.Value)})]");
}
}
var ptTypeName = GetTypeName(p.ValueType, templates); var ptTypeName = GetTypeName(p.ValueType, templates);
rt.AppendLine($"[Export] public {ptTypeName} {p.Name} {{"); rt.AppendLine($"[Export] public {ptTypeName} {p.Name} {{");
@@ -389,8 +417,11 @@ public static class TemplateGenerator
if (c.Inherited) if (c.Inherited)
continue; continue;
if (c.Annotation != null) if (c.Annotations != null)
rt.AppendLine($"[Annotation({ToLiteral(c.Annotation)})]"); {
foreach (var ann in c.Annotations)
rt.AppendLine($"[Annotation({ToLiteral(ann.Key)}, {ToLiteral(ann.Value)})]");
}
var ctTypeName = GetTypeName(c.ValueType, templates); var ctTypeName = GetTypeName(c.ValueType, templates);
rt.AppendLine($"[Export] public const {ctTypeName} {c.Name} = {c.Value};"); rt.AppendLine($"[Export] public const {ctTypeName} {c.Name} = {c.Value};");
@@ -410,8 +441,13 @@ public static class TemplateGenerator
var etTypeName = GetTypeName(e.ArgumentType, templates); var etTypeName = GetTypeName(e.ArgumentType, templates);
rt.AppendLine($"case {e.Index}: {e.Name}?.Invoke(({etTypeName})args); break;"); rt.AppendLine($"case {e.Index}: {e.Name}?.Invoke(({etTypeName})args); break;");
if (e.Annotation != null)
eventsList.AppendLine($"[Annotation({ToLiteral(e.Annotation)})]"); if (e.Annotations != null)
{
foreach (var ann in e.Annotations)
rt.AppendLine($"[Annotation({ToLiteral(ann.Key)}, {ToLiteral(ann.Value)})]");
}
eventsList.AppendLine($"[Export] public event ResourceEventHandler<{etTypeName}> {e.Name};"); eventsList.AppendLine($"[Export] public event ResourceEventHandler<{etTypeName}> {e.Name};");
} }

View File

@@ -4,7 +4,7 @@ using System.Text;
namespace Esiur.Resource; namespace Esiur.Resource;
[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Event, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Event | AttributeTargets.Parameter, AllowMultiple = true)]
public class AnnotationAttribute : Attribute public class AnnotationAttribute : Attribute
{ {
@@ -13,7 +13,7 @@ public class AnnotationAttribute : Attribute
public AnnotationAttribute(string annotation) public AnnotationAttribute(string annotation)
{ {
Key = null; Key = "";
Value = annotation; Value = annotation;
} }
public AnnotationAttribute(string key, string value) public AnnotationAttribute(string key, string value)

View File

@@ -116,58 +116,6 @@ public class Instance
} }
return rt; return rt;
/*
var st = new Structure();
if (attributes == null)
{
var clone = this.attributes.Keys.ToList();
clone.Add("managers");
attributes = clone.ToArray();// this.attributes.Keys.ToList().Add("managers");
}
foreach (var attr in attributes)
{
if (attr == "name")
st["name"] = this.name;
else if (attr == "managers")
{
var mngrs = new List<Structure>();
foreach (var manager in this.managers)
mngrs.Add(new Structure()
{
["type"] = manager.GetType().FullName + "," + manager.GetType().GetTypeInfo().Assembly.GetName().Name,
["settings"] = manager.Settings
});
st["managers"] = mngrs.ToArray();
}
else if (attr == "parents")
{
//st["parents"] = parents.ToArray();
}
else if (attr == "children")
{
//st["children"] = children.ToArray();
}
else if (attr == "childrenCount")
{
//st["childrenCount"] = children.Count;
}
else if (attr == "type")
{
st["type"] = resource.GetType().FullName;
}
else
st[attr] = this.attributes[attr];
}
return st;
*/
} }
public bool SetAttributes(Map<string, object> attributes, bool clearAttributes = false) public bool SetAttributes(Map<string, object> attributes, bool clearAttributes = false)
@@ -454,17 +402,21 @@ public class Instance
/// <returns></returns> /// <returns></returns>
public PropertyValue[] Serialize() public PropertyValue[] Serialize()
{ {
IResource res;
if (!resource.TryGetTarget(out res))
throw new Exception("Resource no longer available.");
if (res is IDynamicResource dynamicResource)
return dynamicResource.SerializeResource();
var props = new List<PropertyValue>(); var props = new List<PropertyValue>();
foreach (var pt in template.Properties) foreach (var pt in template.Properties)
{ {
IResource res; var rt = pt.PropertyInfo.GetValue(res, null);
props.Add(new PropertyValue(rt, ages[pt.Index], modificationDates[pt.Index]));
if (resource.TryGetTarget(out res))
{
var rt = pt.PropertyInfo.GetValue(res, null);
props.Add(new PropertyValue(rt, ages[pt.Index], modificationDates[pt.Index]));
}
} }
return props.ToArray(); return props.ToArray();
@@ -476,93 +428,31 @@ public class Instance
/// <returns></returns> /// <returns></returns>
public Map<byte, PropertyValue> SerializeAfter(ulong age = 0) public Map<byte, PropertyValue> SerializeAfter(ulong age = 0)
{ {
IResource res;
if (!resource.TryGetTarget(out res))
throw new Exception("Resource no longer available.");
if (res is IDynamicResource dynamicResource)
return dynamicResource.SerializeResourceAfter(age);
var props = new Map<byte, PropertyValue>(); var props = new Map<byte, PropertyValue>();
foreach (var pt in template.Properties) foreach (var pt in template.Properties)
{ {
IResource res; if (res.Instance.GetAge(pt.Index) > age)
if (resource.TryGetTarget(out res))
{ {
if (res.Instance.GetAge(pt.Index) > age) var rt = pt.PropertyInfo.GetValue(res, null);
{ props.Add(pt.Index,
var rt = pt.PropertyInfo.GetValue(res, null); new PropertyValue(rt,
props.Add(pt.Index, ages[pt.Index],
new PropertyValue(rt, modificationDates[pt.Index]));
ages[pt.Index],
modificationDates[pt.Index]));
}
} }
} }
return props; return props;
} }
/*
public bool Deserialize(byte[] data, uint offset, uint length)
{
var props = Codec.ParseValues(data, offset, length);
Deserialize(props);
return true;
}
*/
/*
public byte[] Serialize(bool includeLength = false, DistributedConnection sender = null)
{
//var bl = new BinaryList();
List<object> props = new List<object>();
foreach (var pt in template.Properties)
{
var pi = resource.GetType().GetProperty(pt.Name);
var rt = pi.GetValue(resource, null);
// this is a cool hack to let the property know the sender
if (rt is Func<DistributedConnection, object>)
rt = (rt as Func<DistributedConnection, object>)(sender);
props.Add(rt);
}
if (includeLength)
{
return Codec.Compose(props.ToArray(), false);
}
else
{
var rt = Codec.Compose(props.ToArray(), false);
return DC.Clip(rt, 4, (uint)(rt.Length - 4));
}
}
public byte[] StorageSerialize()
{
var props = new List<object>();
foreach(var pt in template.Properties)
{
if (!pt.Storable)
continue;
var pi = resource.GetType().GetProperty(pt.Name);
if (!pi.CanWrite)
continue;
var rt = pi.GetValue(resource, null);
props.Add(rt);
}
return Codec.Compose(props.ToArray(), false);
}
*/
/// <summary> /// <summary>
/// If True, the instance can be stored to disk. /// If True, the instance can be stored to disk.
@@ -619,7 +509,7 @@ public class Instance
return; return;
object value; object value;
if (GetPropertyValue(propertyName, out value)) if (TryGetPropertyValue(propertyName, out value))
{ {
var pt = template.GetPropertyTemplateByName(propertyName); var pt = template.GetPropertyTemplateByName(propertyName);
EmitModification(pt, value); EmitModification(pt, value);
@@ -675,66 +565,37 @@ public class Instance
/// <param name="name">Property name</param> /// <param name="name">Property name</param>
/// <param name="value">Output value</param> /// <param name="value">Output value</param>
/// <returns>True, if the resource has the property.</returns> /// <returns>True, if the resource has the property.</returns>
public bool GetPropertyValue(string name, out object value) public bool TryGetPropertyValue(string name, out object value)
{ {
/*
#if NETSTANDARD
PropertyInfo pi = resource.GetType().GetTypeInfo().GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
#else
PropertyInfo pi = resource.GetType().GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
#endif
*/
var pt = template.GetPropertyTemplateByName(name); var pt = template.GetPropertyTemplateByName(name);
if (pt != null && pt.PropertyInfo != null) IResource res;
if (resource.TryGetTarget(out res))
{ {
/* if (res is IDynamicResource dynamicResource)
#if NETSTANDARD
object[] ca = pi.GetCustomAttributes(typeof(ResourceProperty), false).ToArray();
#else
object[] ca = pi.GetCustomAttributes(typeof(ResourceProperty), false);
#endif
if (ca.Length > 0)
{ {
value = pi.GetValue(resource, null); value = dynamicResource.GetResourceProperty(pt.Index);
//if (value is Func<IManager, object>)
// value = (value as Func<IManager, object>)(sender);
return true; return true;
} }
*/ else if (pt != null && pt.PropertyInfo != null)
IResource res;
if (resource.TryGetTarget(out res))
value = pt.PropertyInfo.GetValue(res, null);
else
{ {
value = null; value = pt.PropertyInfo.GetValue(res, null);
return false; return true;
} }
return true;
} }
value = null; value = null;
return false; return false;
} }
public object GetPropertyValueOrDefault(string name, object defaultValue = null)
/*
public bool Inherit
{ {
get { return inherit; } object value;
}*/ if (TryGetPropertyValue(name, out value))
return value;
/// <summary> else
/// List of parents. return defaultValue;
/// </summary> }
//public AutoList<IResource, Instance> Parents => parents;
/// <summary> /// <summary>
/// Store responsible for creating and keeping the resource. /// Store responsible for creating and keeping the resource.
@@ -746,11 +607,6 @@ public class Instance
public bool IsDestroyed { get; private set; } public bool IsDestroyed { get; private set; }
/// <summary>
/// List of children.
/// </summary>
// public AutoList<IResource, Instance> Children => children;
/// <summary> /// <summary>
/// The unique and permanent link to the resource. /// The unique and permanent link to the resource.
/// </summary> /// </summary>
@@ -793,35 +649,6 @@ public class Instance
return new AsyncBag<T>(default(T[])); return new AsyncBag<T>(default(T[]));
} }
/*
{
get
{
if (this.store != null)
return this.store.Link(this.resource);
else
{
var l = new List<string>();
//l.Add(name);
var p = this.resource; // parents.First();
while (true)
{
l.Insert(0, p.Instance.name);
if (p.Instance.parents.Count == 0)
break;
p = p.Instance.parents.First();
}
return String.Join("/", l.ToArray());
}
}
}
*
*/
/// <summary> /// <summary>
/// Instance name. /// Instance name.
@@ -913,7 +740,7 @@ public class Instance
/// <param name="name">Name of the instance.</param> /// <param name="name">Name of the instance.</param>
/// <param name="resource">Resource to manage.</param> /// <param name="resource">Resource to manage.</param>
/// <param name="store">Store responsible for the resource.</param> /// <param name="store">Store responsible for the resource.</param>
public Instance(Warehouse warehouse, uint id, string name, IResource resource, IStore store, TypeTemplate customTemplate = null, ulong age = 0) public Instance(Warehouse warehouse, uint id, string name, IResource resource, IStore store, ulong age = 0)
{ {
this.Warehouse = warehouse; this.Warehouse = warehouse;
this.store = store; this.store = store;
@@ -933,10 +760,14 @@ public class Instance
resource.OnDestroy += Resource_OnDestroy; resource.OnDestroy += Resource_OnDestroy;
if (customTemplate != null) if (resource is IDynamicResource dynamicResource)
this.template = customTemplate; {
this.template = dynamicResource.ResourceTemplate;
}
else else
{
this.template = Warehouse.GetTemplateByType(resource.GetType()); this.template = Warehouse.GetTemplateByType(resource.GetType());
}
// set ages // set ages
for (byte i = 0; i < template.Properties.Length; i++) for (byte i = 0; i < template.Properties.Length; i++)
@@ -1020,34 +851,6 @@ public class Instance
} }
} }
//IQueryable<IResource> Children => store.GetChildren(this);
/*
* private void Children_OnRemoved(Instance parent, IResource value)
{
value.Instance.parents.Remove(resource);
}
private void Children_OnAdd(Instance parent, IResource value)
{
if (!value.Instance.parents.Contains(resource))
value.Instance.parents.Add(resource);
}
private void Parents_OnRemoved(Instance parent, IResource value)
{
value.Instance.children.Remove(resource);
}
private void Parents_OnAdd(Instance parent, IResource value)
{
if (!value.Instance.children.Contains(resource))
value.Instance.children.Add(resource);
}
*/
private void Resource_OnDestroy(object sender) private void Resource_OnDestroy(object sender)
{ {
IsDestroyed = true; IsDestroyed = true;

View File

@@ -30,20 +30,30 @@ public class ArgumentTemplate
offset += cs; offset += cs;
var (size, type) = TRU.Parse(data, offset); var (size, type) = TRU.Parse(data, offset);
offset += size;
Map<string, string> annotations = null; Map<string, string> annotations = null;
if (hasAnnotations) if (hasAnnotations)
{ {
var acs = data.GetUInt32(offset, Endian.Little); //var acs = data.GetUInt32(offset, Endian.Little);
offset += 2; //offset += 2;
var (l, a) = Codec.ParseSync(data, offset, null); var (l, a) = Codec.ParseSync(data, offset, null);
// for saftey, Map<string, string> might change in the future // for saftey, Map<string, string> might change in the future
if (a is Map<string, string> ann) if (a is Map<string, string> ann)
annotations = ann; annotations = ann;
cs += l;
} }
return (cs + 2 + size, new ArgumentTemplate(name, index, type, optional, annotations)); return (cs + 2 + size, new ArgumentTemplate()
{
Name = name,
Index = index,
Type = type,
Optional = optional,
Annotations = annotations
});
} }
public ArgumentTemplate() public ArgumentTemplate()
@@ -51,15 +61,7 @@ public class ArgumentTemplate
} }
public ArgumentTemplate(string name, int index, TRU type, bool optional, Map<string, string> annotations)
{
Name = name;
Index = index;
Type = type;
Optional = optional;
Annotations = annotations;
}
public override string ToString() public override string ToString()
{ {
if (Optional) if (Optional)
@@ -90,10 +92,8 @@ public class ArgumentTemplate
.AddUInt8((byte)name.Length) .AddUInt8((byte)name.Length)
.AddUInt8Array(name) .AddUInt8Array(name)
.AddUInt8Array(Type.Compose()) .AddUInt8Array(Type.Compose())
.AddUInt32((ushort)exp.Length)
.AddUInt8Array(exp) .AddUInt8Array(exp)
.ToArray(); .ToArray();
} }
} }
} }

View File

@@ -10,6 +10,7 @@ namespace Esiur.Resource.Template;
public class AttributeTemplate : MemberTemplate public class AttributeTemplate : MemberTemplate
{ {
public PropertyInfo PropertyInfo public PropertyInfo PropertyInfo
{ {
get; get;
@@ -17,16 +18,14 @@ public class AttributeTemplate : MemberTemplate
} }
public AttributeTemplate(TypeTemplate template, byte index, string name, bool inherited)
: base(template, index, name, inherited)
{
}
public static AttributeTemplate MakeAttributeTemplate(Type type, PropertyInfo pi, byte index = 0, string customName = null, TypeTemplate typeTemplate = null) public static AttributeTemplate MakeAttributeTemplate(Type type, PropertyInfo pi, byte index = 0, string customName = null, TypeTemplate typeTemplate = null)
{ {
var at = new AttributeTemplate(typeTemplate, index, customName, pi.DeclaringType != type); return new AttributeTemplate()
at.PropertyInfo = pi; {
return at; Index = index,
Inherited = pi.DeclaringType != type,
Name = customName,
PropertyInfo = pi
};
} }
} }

View File

@@ -9,33 +9,59 @@ namespace Esiur.Resource.Template;
public class ConstantTemplate : MemberTemplate public class ConstantTemplate : MemberTemplate
{ {
public readonly object Value; public object Value { get; set; }
public Map<string, string> Annotations; public Map<string, string> Annotations { get; set; }
public readonly TRU ValueType; public TRU ValueType { get; set; }
public FieldInfo FieldInfo { get; set; } public FieldInfo FieldInfo { get; set; }
public ConstantTemplate(TypeTemplate template, byte index, string name, bool inherited, TRU valueType, object value, Map<string, string> annotations)
: base(template, index, name, inherited) public static (uint, ConstantTemplate) Parse(byte[] data, uint offset, byte index, bool inherited)
{ {
Annotations = annotations; var oOffset = offset;
ValueType = valueType;
Value = value; var hasAnnotation = ((data[offset++] & 0x10) == 0x10);
//try
//{ var name = data.GetString(offset + 1, data[offset]);
// Codec.Compose(value, null); offset += (uint)data[offset] + 1;
// Value = value;
//} var (dts, valueType) = TRU.Parse(data, offset);
//catch
//{ offset += dts;
// throw new Exception($"Constant `{template.ClassName}.{name}` can't be serialized.");
//} (dts, var value) = Codec.ParseSync(data, offset, Warehouse.Default);
offset += dts;
Map<string, string> annotations = null;
// arguments
if (hasAnnotation) // Annotation ?
{
var (len, anns) = Codec.ParseSync(data, offset, null);
if (anns is Map<string, string> map)
annotations = map;
offset += len;
}
return (offset - oOffset, new ConstantTemplate()
{
Index = index,
Name = name,
Inherited = inherited,
ValueType = valueType,
Value = value,
Annotations = annotations
});
} }
public override byte[] Compose() public byte[] Compose()
{ {
var name = base.Compose(); var name = DC.ToBytes(Name);
var hdr = Inherited ? (byte)0x80 : (byte)0; var hdr = Inherited ? (byte)0x80 : (byte)0;
@@ -93,10 +119,17 @@ public class ConstantTemplate : MemberTemplate
} }
var ct = new ConstantTemplate(typeTemplate, index, customName ?? ci.Name, ci.DeclaringType != type, valueType, value, annotations);
ct.FieldInfo = ci;
return ct; return new ConstantTemplate()
{
Name = customName,
Index = index,
Inherited = ci.DeclaringType != type,
ValueType = valueType,
Value = value,
FieldInfo = ci,
Annotations = annotations,
};
} }

View File

@@ -12,6 +12,7 @@ namespace Esiur.Resource.Template;
public class EventTemplate : MemberTemplate public class EventTemplate : MemberTemplate
{ {
public Map<string, string> Annotations public Map<string, string> Annotations
{ {
get; get;
@@ -29,9 +30,48 @@ public class EventTemplate : MemberTemplate
public TRU ArgumentType { get; set; } public TRU ArgumentType { get; set; }
public override byte[] Compose()
public static (uint, EventTemplate) Parse(byte[] data, uint offset, byte index, bool inherited)
{ {
var name = base.Compose(); var oOffset = offset;
var hasAnnotation = ((data[offset] & 0x10) == 0x10);
var subscribable = ((data[offset++] & 0x8) == 0x8);
var name = data.GetString(offset + 1, data[offset]);
offset += (uint)data[offset] + 1;
var (dts, argType) = TRU.Parse(data, offset);
offset += dts;
// Annotation ?
Map<string, string> annotations = null;
if (hasAnnotation)
{
var (len, anns) = Codec.ParseSync(data, offset, null);
if (anns is Map<string, string> map)
annotations = map;
offset += len;
}
return (offset - oOffset, new EventTemplate()
{
Index = index,
Name = name,
Inherited = inherited,
ArgumentType = argType,
Subscribable = subscribable,
Annotations = annotations
});
}
public byte[] Compose()
{
var name = Name.ToBytes();
var hdr = Inherited ? (byte)0x80 : (byte)0; var hdr = Inherited ? (byte)0x80 : (byte)0;
@@ -62,13 +102,13 @@ public class EventTemplate : MemberTemplate
.ToArray(); .ToArray();
} }
public EventTemplate(TypeTemplate template, byte index, string name, bool inherited, TRU argumentType, Map<string, string> annotations = null, bool subscribable = false) //public EventTemplate(TypeTemplate template, byte index, string name, bool inherited, TRU argumentType, Map<string, string> annotations = null, bool subscribable = false)
: base(template, index, name, inherited) // : base(template, index, name, inherited)
{ //{
this.Annotations = annotations; // this.Annotations = annotations;
this.Subscribable = subscribable; // this.Subscribable = subscribable;
this.ArgumentType = argumentType; // this.ArgumentType = argumentType;
} //}
public static EventTemplate MakeEventTemplate(Type type, EventInfo ei, byte index = 0, string customName = null, TypeTemplate typeTemplate = null) public static EventTemplate MakeEventTemplate(Type type, EventInfo ei, byte index = 0, string customName = null, TypeTemplate typeTemplate = null)
{ {
@@ -121,21 +161,26 @@ public class EventTemplate : MemberTemplate
evtType.SetNull(nullableAttrFlags); evtType.SetNull(nullableAttrFlags);
} }
var et = new EventTemplate(typeTemplate, index, customName ?? ei.Name, ei.DeclaringType != type, evtType); Map<string, string> annotations = null;
et.EventInfo = ei;
if (annotationAttrs != null && annotationAttrs.Count() > 0) if (annotationAttrs != null && annotationAttrs.Count() > 0)
{ {
et.Annotations = new Map<string, string>(); annotations = new Map<string, string>();
foreach (var attr in annotationAttrs) foreach (var attr in annotationAttrs)
et.Annotations.Add(attr.Key, attr.Value); annotations.Add(attr.Key, attr.Value);
} }
if (subscribableAttr != null)
et.Subscribable = true;
return et; return new EventTemplate()
{
Name = customName ?? ei.Name,
ArgumentType = evtType,
Index = index,
Inherited = ei.DeclaringType != type,
Annotations = annotations,
EventInfo = ei,
Subscribable = subscribableAttr != null
};
} }
} }

View File

@@ -10,6 +10,7 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Esiur.Resource.Template; namespace Esiur.Resource.Template;
public class FunctionTemplate : MemberTemplate public class FunctionTemplate : MemberTemplate
{ {
@@ -38,10 +39,61 @@ public class FunctionTemplate : MemberTemplate
} }
public override byte[] Compose() public static (uint, FunctionTemplate) Parse(byte[] data, uint offset, byte index, bool inherited)
{ {
var name = base.Compose(); var oOffset = offset;
var isStatic = ((data[offset] & 0x4) == 0x4);
var hasAnnotation = ((data[offset++] & 0x10) == 0x10);
var name = data.GetString(offset + 1, data[offset]);
offset += (uint)data[offset] + 1;
// return type
var (rts, returnType) = TRU.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, a);
arguments.Add(argType);
offset += cs;
}
Map<string, string> annotations = null;
// arguments
if (hasAnnotation) // Annotation ?
{
var (len, anns) = Codec.ParseSync(data, offset, null);
if (anns is Map<string, string> map)
annotations = map;
offset += len;
}
return (offset - oOffset, new FunctionTemplate()
{
Index = index,
Name = name,
Arguments = arguments.ToArray(),
IsStatic = isStatic,
Inherited = inherited,
Annotations = annotations,
ReturnType = returnType,
});
}
public byte[] Compose()
{
var name = DC.ToBytes(Name);
var bl = new BinaryList() var bl = new BinaryList()
.AddUInt8((byte)name.Length) .AddUInt8((byte)name.Length)
@@ -56,8 +108,7 @@ public class FunctionTemplate : MemberTemplate
if (Annotations != null) if (Annotations != null)
{ {
var exp = Codec.Compose(Annotations, null, null);// DC.ToBytes(Annotation); var exp = Codec.Compose(Annotations, null, null);// DC.ToBytes(Annotation);
bl.AddInt32(exp.Length) bl.AddUInt8Array(exp);
.AddUInt8Array(exp);
bl.InsertUInt8(0, (byte)((Inherited ? (byte)0x90 : (byte)0x10) | (IsStatic ? 0x4 : 0))); bl.InsertUInt8(0, (byte)((Inherited ? (byte)0x90 : (byte)0x10) | (IsStatic ? 0x4 : 0)));
} }
else else
@@ -66,14 +117,14 @@ public class FunctionTemplate : MemberTemplate
return bl.ToArray(); return bl.ToArray();
} }
public FunctionTemplate(TypeTemplate template, byte index, string name, bool inherited, bool isStatic, ArgumentTemplate[] arguments, TRU returnType, Map<string, string> annotations = null) //public FunctionTemplate(TypeTemplate template, byte index, string name, bool inherited, bool isStatic, ArgumentTemplate[] arguments, TRU returnType, Map<string, string> annotations = null)
: base(template, index, name, inherited) // : base(template, index, name, inherited)
{ //{
this.Arguments = arguments; // this.Arguments = arguments;
this.ReturnType = returnType; // this.ReturnType = returnType;
this.Annotations = annotations; // this.Annotations = annotations;
this.IsStatic = isStatic; // this.IsStatic = isStatic;
} //}
@@ -99,7 +150,10 @@ public class FunctionTemplate : MemberTemplate
} }
else else
{ {
rtType = TRU.FromType(mi.ReturnType); if (mi.ReturnType == typeof(Task))
rtType = TRU.FromType(null);
else
rtType = TRU.FromType(mi.ReturnType);
} }
if (rtType == null) if (rtType == null)
@@ -162,7 +216,7 @@ public class FunctionTemplate : MemberTemplate
if (args.Length > 0) if (args.Length > 0)
{ {
if (args.Last().ParameterType == typeof(DistributedConnection) if (args.Last().ParameterType == typeof(DistributedConnection)
|| args.Last().ParameterType == typeof(InvocationContext)) || args.Last().ParameterType == typeof(InvocationContext))
args = args.Take(args.Count() - 1).ToArray(); args = args.Take(args.Count() - 1).ToArray();
} }
@@ -219,32 +273,35 @@ public class FunctionTemplate : MemberTemplate
}) })
.ToArray(); .ToArray();
var fn = customName ?? mi.Name; Map<string, string> annotations = null;
var ft = new FunctionTemplate(typeTemplate, index, fn, mi.DeclaringType != type,
mi.IsStatic,
arguments, rtType);
if (annotationAttrs != null && annotationAttrs.Count() > 0) if (annotationAttrs != null && annotationAttrs.Count() > 0)
{ {
ft.Annotations = new Map<string, string>(); annotations = new Map<string, string>();
foreach (var attr in annotationAttrs) foreach (var attr in annotationAttrs)
ft.Annotations.Add(attr.Key, attr.Value); annotations.Add(attr.Key, attr.Value);
} }
else else
{ {
ft.Annotations = new Map<string, string>(); annotations = new Map<string, string>();
ft.Annotations.Add(null, "(" + String.Join(",", annotations.Add("", "(" + String.Join(",",
mi.GetParameters().Where(x => x.ParameterType != typeof(DistributedConnection)) mi.GetParameters().Where(x => x.ParameterType != typeof(DistributedConnection))
.Select(x => "[" + x.ParameterType.Name + "] " + x.Name)) + ") -> " + mi.ReturnType.Name); .Select(x => "[" + x.ParameterType.Name + "] " + x.Name)) + ") -> " + mi.ReturnType.Name);
} }
ft.MethodInfo = mi; return new FunctionTemplate()
// functions.Add(ft); {
Name = customName ?? mi.Name,
Index = index,
Inherited = mi.DeclaringType != type,
IsStatic = mi.IsStatic,
ReturnType = rtType,
Arguments = arguments,
MethodInfo = mi,
Annotations = annotations
};
return ft;
} }
public override string ToString() public override string ToString()

View File

@@ -40,19 +40,19 @@ public class MemberData
return rt; return rt;
} }
public string? GetAnnotation() //public string? GetAnnotation()
{ //{
string? rt = null; // string? rt = null;
var md = this; // var md = this;
while (md != null) // while (md != null)
{ // {
var annotationAttr = md.Info.GetCustomAttribute<AnnotationAttribute>(); // var annotationAttr = md.Info.GetCustomAttribute<AnnotationAttribute>();
if (annotationAttr != null) // if (annotationAttr != null)
rt = annotationAttr.Annotation; // rt = annotationAttr.Annotation;
md = md.Child; // md = md.Child;
} // }
return rt; // return rt;
} //}
} }

View File

@@ -9,24 +9,24 @@ namespace Esiur.Resource.Template;
public class MemberTemplate public class MemberTemplate
{ {
public readonly byte Index; public byte Index { get; set; }
public readonly string Name; public string Name { get; set; }
public readonly bool Inherited; public bool Inherited { get; set; }
public readonly TypeTemplate Template; public TypeTemplate Template { get; set; }
public MemberTemplate(TypeTemplate template, byte index, string name, bool inherited) //public MemberTemplate()
{ //{
Template = template; // Template = template;
Index = index; // Index = index;
Name = name; // Name = name;
Inherited = inherited; // Inherited = inherited;
} //}
public string Fullname => Template.ClassName + "." + Name; public string Fullname => Template.ClassName + "." + Name;
public virtual byte[] Compose() //public virtual byte[] Compose()
{ //{
return DC.ToBytes(Name); // return DC.ToBytes(Name);
} //}
} }

View File

@@ -9,8 +9,11 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Esiur.Resource.Template; namespace Esiur.Resource.Template;
public class PropertyTemplate : MemberTemplate public class PropertyTemplate : MemberTemplate
{ {
public Map<string, string> Annotations { get; set; }
public enum PropertyPermission : byte public enum PropertyPermission : byte
{ {
Read = 1, Read = 1,
@@ -42,7 +45,7 @@ public class PropertyTemplate : MemberTemplate
set; set;
} }
public bool IsNullable { get; set; } //public bool IsNullable { get; set; }
public bool Recordable public bool Recordable
{ {
@@ -57,17 +60,17 @@ public class PropertyTemplate : MemberTemplate
set; set;
}*/ }*/
public string ReadAnnotation //public string ReadAnnotation
{ //{
get; // get;
set; // set;
} //}
public string WriteAnnotation //public string WriteAnnotation
{ //{
get; // get;
set; // set;
} //}
/* /*
public bool Storable public bool Storable
@@ -81,50 +84,105 @@ public class PropertyTemplate : MemberTemplate
return $"{Name}: {ValueType}"; return $"{Name}: {ValueType}";
} }
public override byte[] Compose() public static (uint, PropertyTemplate) Parse(byte[] data, uint offset, byte index, bool inherited)
{ {
var name = base.Compose(); var oOffset = offset;
var hasAnnotation = ((data[offset] & 0x8) == 0x8);
var recordable = ((data[offset] & 1) == 1);
var permission = (PropertyTemplate.PropertyPermission)((data[offset++] >> 1) & 0x3);
var name = data.GetString(offset + 1, data[offset]);
offset += (uint)data[offset] + 1;
var (dts, valueType) = TRU.Parse(data, offset);
offset += dts;
Map<string, string> annotations = null;
// arguments
if (hasAnnotation) // Annotation ?
{
var (len, anns) = Codec.ParseSync(data, offset, null);
if (anns is Map<string, string> map)
annotations = map;
offset += len;
}
return (offset - oOffset, new PropertyTemplate()
{
Index = index,
Name = name,
Inherited = inherited,
Permission = permission,
Recordable = recordable,
ValueType = valueType,
Annotations = annotations
});
}
public byte[] Compose()
{
var name = DC.ToBytes(Name);
var pv = ((byte)(Permission) << 1) | (Recordable ? 1 : 0); var pv = ((byte)(Permission) << 1) | (Recordable ? 1 : 0);
if (Inherited) if (Inherited)
pv |= 0x80; pv |= 0x80;
if (WriteAnnotation != null && ReadAnnotation != null) //if (WriteAnnotation != null && ReadAnnotation != null)
//{
// var rexp = DC.ToBytes(ReadAnnotation);
// var wexp = DC.ToBytes(WriteAnnotation);
// return new BinaryList()
// .AddUInt8((byte)(0x38 | pv))
// .AddUInt8((byte)name.Length)
// .AddUInt8Array(name)
// .AddUInt8Array(ValueType.Compose())
// .AddInt32(wexp.Length)
// .AddUInt8Array(wexp)
// .AddInt32(rexp.Length)
// .AddUInt8Array(rexp)
// .ToArray();
//}
//else if (WriteAnnotation != null)
//{
// var wexp = DC.ToBytes(WriteAnnotation);
// return new BinaryList()
// .AddUInt8((byte)(0x30 | pv))
// .AddUInt8((byte)name.Length)
// .AddUInt8Array(name)
// .AddUInt8Array(ValueType.Compose())
// .AddInt32(wexp.Length)
// .AddUInt8Array(wexp)
// .ToArray();
//}
//else if (ReadAnnotation != null)
//{
// var rexp = DC.ToBytes(ReadAnnotation);
// return new BinaryList()
// .AddUInt8((byte)(0x28 | pv))
// .AddUInt8((byte)name.Length)
// .AddUInt8Array(name)
// .AddUInt8Array(ValueType.Compose())
// .AddInt32(rexp.Length)
// .AddUInt8Array(rexp)
// .ToArray();
//}
if (Annotations != null)
{ {
var rexp = DC.ToBytes(ReadAnnotation); var rexp = Codec.Compose(Annotations, null, null);
var wexp = DC.ToBytes(WriteAnnotation);
return new BinaryList()
.AddUInt8((byte)(0x38 | pv))
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddUInt8Array(ValueType.Compose())
.AddInt32(wexp.Length)
.AddUInt8Array(wexp)
.AddInt32(rexp.Length)
.AddUInt8Array(rexp)
.ToArray();
}
else if (WriteAnnotation != null)
{
var wexp = DC.ToBytes(WriteAnnotation);
return new BinaryList()
.AddUInt8((byte)(0x30 | pv))
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddUInt8Array(ValueType.Compose())
.AddInt32(wexp.Length)
.AddUInt8Array(wexp)
.ToArray();
}
else if (ReadAnnotation != null)
{
var rexp = DC.ToBytes(ReadAnnotation);
return new BinaryList() return new BinaryList()
.AddUInt8((byte)(0x28 | pv)) .AddUInt8((byte)(0x28 | pv))
.AddUInt8((byte)name.Length) .AddUInt8((byte)name.Length)
.AddUInt8Array(name) .AddUInt8Array(name)
.AddUInt8Array(ValueType.Compose()) .AddUInt8Array(ValueType.Compose())
.AddInt32(rexp.Length)
.AddUInt8Array(rexp) .AddUInt8Array(rexp)
.ToArray(); .ToArray();
} }
@@ -139,17 +197,17 @@ public class PropertyTemplate : MemberTemplate
} }
} }
public PropertyTemplate(TypeTemplate template, byte index, string name, bool inherited, //public PropertyTemplate(TypeTemplate template, byte index, string name, bool inherited,
TRU valueType, string readAnnotation = null, string writeAnnotation = null, bool recordable = false) // TRU valueType, string readAnnotation = null, string writeAnnotation = null, bool recordable = false)
: base(template, index, name, inherited) // : base(template, index, name, inherited)
{ //{
this.Recordable = recordable; // this.Recordable = recordable;
//this.Storage = storage; // //this.Storage = storage;
if (readAnnotation != null) // if (readAnnotation != null)
this.ReadAnnotation = readAnnotation; // this.ReadAnnotation = readAnnotation;
this.WriteAnnotation = writeAnnotation; // this.WriteAnnotation = writeAnnotation;
this.ValueType = valueType; // this.ValueType = valueType;
} //}
public static PropertyTemplate MakePropertyTemplate(Type type, PropertyInfo pi, byte index = 0, string customName = null, TypeTemplate typeTemplate = null) public static PropertyTemplate MakePropertyTemplate(Type type, PropertyInfo pi, byte index = 0, string customName = null, TypeTemplate typeTemplate = null)
{ {
@@ -162,7 +220,7 @@ public class PropertyTemplate : MemberTemplate
if (propType == null) if (propType == null)
throw new Exception($"Unsupported type `{pi.PropertyType}` in property `{type.Name}.{pi.Name}`"); throw new Exception($"Unsupported type `{pi.PropertyType}` in property `{type.Name}.{pi.Name}`");
var annotationAttr = pi.GetCustomAttribute<AnnotationAttribute>(true); var annotationAttrs = pi.GetCustomAttributes<AnnotationAttribute>(true);
var storageAttr = pi.GetCustomAttribute<StorageAttribute>(true); var storageAttr = pi.GetCustomAttribute<StorageAttribute>(true);
//var nullabilityContext = new NullabilityInfoContext(); //var nullabilityContext = new NullabilityInfoContext();
@@ -196,19 +254,46 @@ public class PropertyTemplate : MemberTemplate
propType.SetNull(nullableAttrFlags); propType.SetNull(nullableAttrFlags);
} }
var pt = new PropertyTemplate(typeTemplate, index, customName ?? pi.Name, pi.DeclaringType != type, propType);
if (storageAttr != null) Map<string, string> annotations = null;
pt.Recordable = storageAttr.Mode == StorageMode.Recordable;
if (annotationAttr != null) if (annotationAttrs != null && annotationAttrs.Count() > 0)
pt.ReadAnnotation = annotationAttr.Annotation; {
annotations = new Map<string, string>();
foreach (var attr in annotationAttrs)
annotations.Add(attr.Key, attr.Value);
}
else else
pt.ReadAnnotation = GetTypeAnnotationName(pi.PropertyType); {
annotations = new Map<string, string>();
annotations.Add("", GetTypeAnnotationName(pi.PropertyType));
}
pt.PropertyInfo = pi; return new PropertyTemplate()
{
Name = customName ?? pi.Name,
Index = index,
Inherited = pi.DeclaringType != type,
ValueType = propType,
PropertyInfo = pi,
Recordable = storageAttr == null ? false : storageAttr.Mode == StorageMode.Recordable,
Permission = (pi.CanWrite && pi.CanRead) ? PropertyPermission.ReadWrite : (pi.CanWrite ? PropertyPermission.Write : PropertyPermission.Read),
Annotations = annotations,
};
return pt; //var pt = new PropertyTemplate(typeTemplate, index, customName ?? pi.Name, pi.DeclaringType != type, propType);
//if (storageAttr != null)
// pt.Recordable = storageAttr.Mode == StorageMode.Recordable;
//if (annotationAttr != null)
// pt.ReadAnnotation = annotationAttr.Annotation;
//else
// pt.ReadAnnotation = GetTypeAnnotationName(pi.PropertyType);
//pt.PropertyInfo = pi;
//return pt;
} }

View File

@@ -7,5 +7,6 @@ public enum TemplateType : byte
{ {
Resource, Resource,
Record, Record,
Enum Enum,
Function
} }

View File

@@ -25,10 +25,9 @@ public class TypeTemplate
protected UUID classId; protected UUID classId;
protected UUID? parentId; protected UUID? parentId;
public string Annotation { get; set; } public Map<string, string> Annotations { get; set; }
string className; string className;
List<MemberTemplate> members = new List<MemberTemplate>();
List<FunctionTemplate> functions = new List<FunctionTemplate>(); List<FunctionTemplate> functions = new List<FunctionTemplate>();
List<EventTemplate> events = new List<EventTemplate>(); List<EventTemplate> events = new List<EventTemplate>();
List<PropertyTemplate> properties = new List<PropertyTemplate>(); List<PropertyTemplate> properties = new List<PropertyTemplate>();
@@ -137,10 +136,10 @@ public class TypeTemplate
get { return className; } get { return className; }
} }
public MemberTemplate[] Methods //public MemberTemplate[] Methods
{ //{
get { return members.ToArray(); } // get { return members.ToArray(); }
} //}
public FunctionTemplate[] Functions public FunctionTemplate[] Functions
{ {
@@ -383,34 +382,12 @@ public class TypeTemplate
public static ConstantTemplate MakeConstantTemplate(Type type, FieldInfo ci, ExportAttribute exportAttr, byte index = 0, TypeTemplate typeTemplate = null)
{
var annotationAttr = ci.GetCustomAttribute<AnnotationAttribute>(true);
var valueType = TRU.FromType(ci.FieldType);
if (valueType == null)
throw new Exception($"Unsupported type `{ci.FieldType}` in constant `{type.Name}.{ci.Name}`");
var value = ci.GetValue(null);
if (typeTemplate.Type == TemplateType.Enum)
value = Convert.ChangeType(value, ci.FieldType.GetEnumUnderlyingType());
var ct = new ConstantTemplate(typeTemplate, index, exportAttr?.Name ?? ci.Name, ci.DeclaringType != type, valueType, value, annotationAttr?.Annotation);
return ct;
}
public bool IsWrapper { get; private set; } public bool IsWrapper { get; private set; }
public TypeTemplate(Type type, Warehouse warehouse = null) public TypeTemplate(Type type, Warehouse warehouse = null)
{ {
//if (!type.IsPublic)
// throw new Exception("Not public");
if (Codec.ImplementsInterface(type, typeof(IResource))) if (Codec.ImplementsInterface(type, typeof(IResource)))
templateType = TemplateType.Resource; templateType = TemplateType.Resource;
else if (Codec.ImplementsInterface(type, typeof(IRecord))) else if (Codec.ImplementsInterface(type, typeof(IRecord)))
@@ -422,12 +399,6 @@ public class TypeTemplate
IsWrapper = Codec.InheritsClass(type, typeof(DistributedResource)); IsWrapper = Codec.InheritsClass(type, typeof(DistributedResource));
//if (isRecord && isResource)
// throw new Exception("Type can't have both IResource and IRecord interfaces");
//if (!(isResource || isRecord))
// throw new Exception("Type is neither a resource nor a record.");
type = ResourceProxy.GetBaseType(type); type = ResourceProxy.GetBaseType(type);
DefinedType = type; DefinedType = type;
@@ -440,17 +411,6 @@ public class TypeTemplate
if (warehouse != null) if (warehouse != null)
warehouse.PutTemplate(this); warehouse.PutTemplate(this);
//PropertyInfo[] propsInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
//EventInfo[] eventsInfo = type.GetEvents(BindingFlags.Public | BindingFlags.Instance);
//MethodInfo[] methodsInfo = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
//FieldInfo[] constantsInfo = type.GetFields(BindingFlags.Public | BindingFlags.Static);
//bool classIsPublic = type.IsEnum || (type.GetCustomAttribute<PublicAttribute>() != null);
var hierarchy = GetHierarchy(type); var hierarchy = GetHierarchy(type);
if (hierarchy.ContainsKey(MemberTypes.Field)) if (hierarchy.ContainsKey(MemberTypes.Field))
@@ -505,19 +465,6 @@ public class TypeTemplate
.MakeAttributeTemplate(type, attr, 0, attrAttr?.Name ?? attr.Name, this)); .MakeAttributeTemplate(type, attr, 0, attrAttr?.Name ?? attr.Name, this));
} }
// append signals)
for (var i = 0; i < events.Count; i++)
members.Add(events[i]);
// append slots
for (var i = 0; i < functions.Count; i++)
members.Add(functions[i]);
// append properties
for (var i = 0; i < properties.Count; i++)
members.Add(properties[i]);
// append constants
for (var i = 0; i < constants.Count; i++)
members.Add(constants[i]);
// bake it binarily // bake it binarily
var b = new BinaryList(); var b = new BinaryList();
@@ -526,8 +473,10 @@ public class TypeTemplate
var hasParent = HasParent(type); var hasParent = HasParent(type);
var classAnnotation = type.GetCustomAttribute<AnnotationAttribute>(false); var classAnnotations = type.GetCustomAttributes<AnnotationAttribute>(false);
var hasClassAnnotation = classAnnotation != null && classAnnotation.Annotation != null;
var hasClassAnnotation = (classAnnotations != null) && (classAnnotations.Count() > 0);
var classNameBytes = DC.ToBytes(className); var classNameBytes = DC.ToBytes(className);
@@ -546,15 +495,19 @@ public class TypeTemplate
if (hasClassAnnotation) if (hasClassAnnotation)
{ {
var classAnnotationBytes = DC.ToBytes(classAnnotation.Annotation); Annotations = new Map<string, string>();
b.AddUInt16((ushort)classAnnotationBytes.Length)
.AddUInt8Array(classAnnotationBytes); foreach (var ann in classAnnotations)
Annotations.Add(ann.Key, ann.Value);
var classAnnotationBytes = Codec.Compose (Annotations, null, null);
b.AddUInt8Array(classAnnotationBytes);
Annotation = classAnnotation.Annotation;
} }
b.AddInt32(version) b.AddInt32(version)
.AddUInt16((ushort)members.Count); .AddUInt16((ushort)(functions.Count + properties.Count + events.Count + constants.Count));
foreach (var ft in functions) foreach (var ft in functions)
b.AddUInt8Array(ft.Compose()); b.AddUInt8Array(ft.Compose());
@@ -758,9 +711,11 @@ public class TypeTemplate
if (hasClassAnnotation) if (hasClassAnnotation)
{ {
var len = data.GetUInt16(offset, Endian.Little); var (len, anns) = Codec.ParseSync(data, offset, null);
offset += 2;
od.Annotation = data.GetString(offset, len); if (anns is Map<string, string> annotations)
od.Annotations = annotations;
offset += len; offset += len;
} }
@@ -781,151 +736,32 @@ public class TypeTemplate
if (type == 0) // function if (type == 0) // function
{ {
string annotation = null; var (len, ft) = FunctionTemplate.Parse(data, offset, functionIndex++, inherited);
var isStatic = ((data[offset] & 0x4) == 0x4); offset += len;
var hasAnnotation = ((data[offset++] & 0x10) == 0x10);
var name = data.GetString(offset + 1, data[offset]);
offset += (uint)data[offset] + 1;
// return type
var (rts, returnType) = TRU.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, a);
arguments.Add(argType);
offset += cs;
}
// arguments
if (hasAnnotation) // Annotation ?
{
var cs = data.GetUInt32(offset, Endian.Little);
offset += 4;
annotation = data.GetString(offset, cs);
offset += cs;
}
var ft = new FunctionTemplate(od, functionIndex++, name, inherited, isStatic, arguments.ToArray(), returnType, annotation);
od.functions.Add(ft); od.functions.Add(ft);
} }
else if (type == 1) // property else if (type == 1) // property
{ {
var (len, pt) = PropertyTemplate.Parse(data, offset, propertyIndex++, inherited);
string readAnnotation = null, writeAnnotation = null; offset += len;
var hasReadAnnotation = ((data[offset] & 0x8) == 0x8);
var hasWriteAnnotation = ((data[offset] & 0x10) == 0x10);
var recordable = ((data[offset] & 1) == 1);
var permission = (PropertyTemplate.PropertyPermission)((data[offset++] >> 1) & 0x3);
var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]);
offset += (uint)data[offset] + 1;
var (dts, valueType) = TRU.Parse(data, offset);
offset += dts;
if (hasReadAnnotation) // annotation ?
{
var cs = data.GetUInt32(offset, Endian.Little);
offset += 4;
readAnnotation = data.GetString(offset, cs);
offset += cs;
}
if (hasWriteAnnotation) // annotation ?
{
var cs = data.GetUInt32(offset, Endian.Little);
offset += 4;
writeAnnotation = data.GetString(offset, cs);
offset += cs;
}
var pt = new PropertyTemplate(od, propertyIndex++, name, inherited, valueType, readAnnotation, writeAnnotation, recordable);
od.properties.Add(pt); od.properties.Add(pt);
} }
else if (type == 2) // Event else if (type == 2) // Event
{ {
var (len, et) = EventTemplate.Parse(data, offset, propertyIndex++, inherited);
string annotation = null; offset += len;
var hasAnnotation = ((data[offset] & 0x10) == 0x10);
var listenable = ((data[offset++] & 0x8) == 0x8);
var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, (int)data[offset]);
offset += (uint)data[offset] + 1;
var (dts, argType) = TRU.Parse(data, offset);
offset += dts;
if (hasAnnotation) // annotation ?
{
var cs = data.GetUInt32(offset, Endian.Little);
offset += 4;
annotation = data.GetString(offset, cs);
offset += cs;
}
var et = new EventTemplate(od, eventIndex++, name, inherited, argType, annotation, listenable);
od.events.Add(et); od.events.Add(et);
} }
// constant // constant
else if (type == 3) else if (type == 3)
{ {
string annotation = null; var (len, ct) = ConstantTemplate.Parse(data, offset, propertyIndex++, inherited);
var hasAnnotation = ((data[offset++] & 0x10) == 0x10); offset += len;
var name = data.GetString(offset + 1, data[offset]);
offset += (uint)data[offset] + 1;
var (dts, valueType) = TRU.Parse(data, offset);
offset += dts;
(dts, var value) = Codec.ParseSync(data, offset, Warehouse.Default);
offset += dts;
if (hasAnnotation) // annotation ?
{
var cs = data.GetUInt32(offset, Endian.Little);
offset += 4;
annotation = data.GetString(offset, cs);
offset += cs;
}
var ct = new ConstantTemplate(od, eventIndex++, name, inherited, valueType, value, annotation);
od.constants.Add(ct); od.constants.Add(ct);
} }
} }
// append signals
for (int i = 0; i < od.events.Count; i++)
od.members.Add(od.events[i]);
// append slots
for (int i = 0; i < od.functions.Count; i++)
od.members.Add(od.functions[i]);
// append properties
for (int i = 0; i < od.properties.Count; i++)
od.members.Add(od.properties[i]);
// append constants
for (int i = 0; i < od.constants.Count; i++)
od.members.Add(od.constants[i]);
return od; return od;
} }

View File

@@ -425,7 +425,7 @@ public class Warehouse
/// <param name="resource">Resource instance.</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="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> /// <param name="parent">Parent resource. if not presented the store becomes the parent for the resource.</param>
public async AsyncReply<T> Put<T>(string path, T resource, TypeTemplate customTemplate = null, ulong age = 0, IPermissionsManager manager = null, object attributes = null) where T : IResource public async AsyncReply<T> Put<T>(string path, T resource, ulong age = 0, IPermissionsManager manager = null, object attributes = null) where T : IResource
{ {
if (resource.Instance != null) if (resource.Instance != null)
throw new Exception("Resource already initialized."); throw new Exception("Resource already initialized.");
@@ -464,7 +464,7 @@ public class Warehouse
var resourceReference = new WeakReference<IResource>(resource); var resourceReference = new WeakReference<IResource>(resource);
resource.Instance = new Instance(this, resourceCounter++, instanceName, resource, store, customTemplate, age); resource.Instance = new Instance(this, resourceCounter++, instanceName, resource, store, age);
if (attributes != null) if (attributes != null)
if (attributes is Map<string, object> attrs) if (attributes is Map<string, object> attrs)
@@ -574,7 +574,7 @@ public class Warehouse
public async AsyncReply<IResource> New(Type type, string path, IPermissionsManager manager = null, object attributes = null, object properties = null) public async AsyncReply<IResource> New(Type type, string path, IPermissionsManager manager = null, object attributes = null, object properties = null)
{ {
var res = Create(type, properties); var res = Create(type, properties);
return await Put(path, res, null, 0, manager, attributes); return await Put(path, res, 0, manager, attributes);
} }
public async AsyncReply<T> New<T>(string path, IPermissionsManager manager = null, object attributes = null, object properties = null) public async AsyncReply<T> New<T>(string path, IPermissionsManager manager = null, object attributes = null, object properties = null)