2
0
mirror of https://github.com/esiur/esiur-dotnet.git synced 2025-06-26 21:13:13 +00:00

Add project files.

This commit is contained in:
Ahmed Zamil
2017-09-15 23:40:03 +03:00
parent 4c95cb1cc6
commit 7ae722ab51
99 changed files with 14687 additions and 0 deletions

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Data;
using Esiur.Engine;
namespace Esiur.Resource
{
public delegate bool QueryFilter<T>(T value);
public interface IResource : IDestructible
{
AsyncReply<bool> Trigger(ResourceTrigger trigger);
Instance Instance
{
get;
set;
}
}
}

17
Esiur/Resource/IStore.cs Normal file
View File

@ -0,0 +1,17 @@
using Esiur.Engine;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource
{
public interface IStore:IResource
{
AsyncReply<IResource> Get(string path);
AsyncReply<IResource> Retrieve(uint iid);
bool Put(IResource resource);
string Link(IResource resource);
}
}

427
Esiur/Resource/Instance.cs Normal file
View File

@ -0,0 +1,427 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Esiur.Data;
using System.Runtime.CompilerServices;
using System.Reflection;
using Esiur.Net.IIP;
using Esiur.Misc;
using Esiur.Security.Permissions;
using Esiur.Resource.Template;
namespace Esiur.Resource
{
public class Instance
{
string name;
AutoList<IResource, Instance> children;// = new AutoList<IResource, Instance>();
IResource resource;
IStore store;
AutoList<IResource, Instance> parents;// = new AutoList<IResource>();
bool inherit;
ResourceTemplate template;
AutoList<IPermissionManager, Instance> managers;// = new AutoList<IPermissionManager, Instance>();
public delegate void ResourceModifiedEvent(IResource resource, string propertyName, object newValue, object oldValue);
public delegate void ResourceEventOccurredEvent(IResource resource, string eventName, string[] receivers, object[] args);
public delegate void ResourceDestroyedEvent(IResource resource);
public event ResourceModifiedEvent ResourceModified;
public event ResourceEventOccurredEvent ResourceEventOccured;
public event ResourceDestroyedEvent ResourceDestroyed;
KeyList<string, object> attributes = new KeyList<string, object>();
List<uint> ages = new List<uint>();
private uint age;
uint id;
/// <summary>
/// Instance attributes are custom properties associated with the instance, a place to store information by IStore.
/// </summary>
public KeyList<string, object> Attributes
{
get
{
return attributes;
}
}
/// <summary>
/// Get the age of a given property index.
/// </summary>
/// <param name="index">Zero-based property index.</param>
/// <returns>Age.</returns>
public uint GetAge(byte index)
{
if (index < ages.Count)
return ages[index];
else
return 0;
}
/// <summary>
/// Age of the instance, increments by 1 in every modification.
/// </summary>
public uint Age
{
get { return age; }
internal set { age = value; }
}
/// <summary>
/// Instance Id.
/// </summary>
public uint Id
{
get { return id; }
}
/// <summary>
/// Import properties from bytes array.
/// </summary>
/// <param name="properties"></param>
/// <returns></returns>
public bool Deserialize(object[] properties)
{
foreach (var pt in template.Properties)
{
#if NETSTANDARD1_5
var pi = resource.GetType().GetTypeInfo().GetProperty(pt.Name);
#else
var pi = resource.GetType().GetProperty(pt.Name);
#endif
if (!(properties[pt.Index] is NotModified))
pi.SetValue(resource, properties[pt.Index]);
}
return true;
}
/// <summary>
/// Export all properties with ResourceProperty attributed as bytes array.
/// </summary>
/// <returns></returns>
public object[] Serialize()
{
List<object> props = new List<object>();
foreach (var pt in template.Properties)
{
#if NETSTANDARD1_5
var pi = resource.GetType().GetTypeInfo().GetProperty(pt.Name);
#else
var pi = resource.GetType().GetProperty(pt.Name);
#endif
var rt = pi.GetValue(resource, null);
props.Add(rt);
}
return props.ToArray();
}
/*
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>
/// If True, the instance can be stored to disk.
/// </summary>
/// <returns></returns>
public bool IsStorable()
{
#if NETSTANDARD1_5
var attrs = resource.GetType().GetTypeInfo().GetCustomAttributes(typeof(Storable), true).ToArray();
#else
var attrs = resource.GetType().GetCustomAttributes(typeof(Storable), true);
#endif
return attrs.Length > 0;
}
/// <summary>
/// Notify listeners that a property was modified.
/// </summary>
/// <param name="propertyName"></param>
/// <param name="newValue"></param>
/// <param name="oldValue"></param>
public void Modified([CallerMemberName] string propertyName = "", object newValue = null, object oldValue = null)
{
if (newValue == null)
{
object val;
if (GetPropertyValue(propertyName, out val))
ResourceModified?.Invoke(resource, propertyName, val, oldValue);
}
else
ResourceModified?.Invoke(resource, propertyName, newValue, oldValue);
}
internal void EmitResourceEvent(string name, string[] receivers, object[] args)
{
ResourceEventOccured?.Invoke(resource, name, receivers, args);
}
/// <summary>
/// Get the value of a given property by name.
/// </summary>
/// <param name="name">Property name</param>
/// <param name="value">Output value</param>
/// <returns>True, if the resource has the property.</returns>
public bool GetPropertyValue(string name, out object value)
{
#if NETSTANDARD1_5
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
if (pi != null)
{
#if NETSTANDARD1_5
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);
//if (value is Func<IManager, object>)
// value = (value as Func<IManager, object>)(sender);
return true;
}
}
value = null;
return false;
}
public bool Inherit
{
get { return inherit; }
}
/// <summary>
/// List of parents.
/// </summary>
public AutoList<IResource, Instance> Parents
{
get { return parents; }
}
/// <summary>
/// Store responsible for creating and keeping the resource.
/// </summary>
public IStore Store
{
get { return store; }
}
/// <summary>
/// List of children.
/// </summary>
public AutoList<IResource, Instance> Children
{
get { return children; }
}
/// <summary>
/// The unique and permanent link to the resource.
/// </summary>
public string Link
{
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>
/// Instance name.
/// </summary>
public string Name
{
get { return name; }
}
/// <summary>
/// Resource managed by this instance.
/// </summary>
public IResource Resource
{
get { return resource; }
}
/// <summary>
/// Resource template describes the properties, functions and events of the resource.
/// </summary>
public ResourceTemplate Template
{
get { return template; }
}
/// <summary>
/// Create new instance.
/// </summary>
/// <param name="id">Instance Id.</param>
/// <param name="name">Name of the instance.</param>
/// <param name="resource">Resource to manage.</param>
/// <param name="store">Store responsible for the resource.</param>
public Instance(uint id, string name, IResource resource, IStore store)
{
this.store = store;
this.resource = resource;
this.id = id;
this.name = name;
children = new AutoList<IResource, Instance>(this);
parents = new AutoList<IResource, Instance>(this);
managers = new AutoList<IPermissionManager, Instance>(this);
children.OnAdd += Children_OnAdd;
children.OnRemoved += Children_OnRemoved;
resource.OnDestroy += Resource_OnDestroy;
template = Warehouse.GetTemplate(resource.GetType());
// set ages
for (byte i = 0; i < template.Properties.Length; i++)
ages.Add(0);
// connect events
Type t = resource.GetType();
#if NETSTANDARD1_5
var events = t.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
#else
var events = t.GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
#endif
foreach (var evt in events)
{
if (evt.EventHandlerType != typeof(ResourceEventHanlder))
continue;
var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true);
if (ca.Length == 0)
continue;
ResourceEventHanlder proxyDelegate = (receivers, args) => EmitResourceEvent(evt.Name, receivers, args);
evt.AddEventHandler(resource, proxyDelegate);
}
}
private void Children_OnRemoved(Instance parent, IResource value)
{
value.Instance.parents.Remove(resource);
}
private void Children_OnAdd(Instance parent, IResource value)
{
value.Instance.parents.Add(resource);
}
private void Resource_OnDestroy(object sender)
{
ResourceDestroyed?.Invoke((IResource)sender);
}
}
}

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource
{
[AttributeUsage(AttributeTargets.Event)]
public class ResourceEvent : System.Attribute
{
string expansion;
public string Expansion
{
get
{
return expansion;
}
}
public ResourceEvent(string expansion = null)
{
this.expansion = expansion;
}
}
}

View File

@ -0,0 +1,13 @@
using Esiur.Data;
using Esiur.Engine;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource
{
public delegate void ResourceEventHanlder(string[] receivers, params object[] args);
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource
{
[AttributeUsage(AttributeTargets.Method)]
public class ResourceFunction : System.Attribute
{
private string expansion = null;
public string Expansion
{
get
{
return expansion;
}
}
public ResourceFunction(string expansion = null)
{
this.expansion = expansion;
}
}
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource
{
[AttributeUsage(AttributeTargets.Property)]
public class ResourceProperty : System.Attribute
{
string readExpansion;
string writeExpansion;
public string ReadExpansion
{
get
{
return readExpansion;
}
}
public string WriteExpansion
{
get
{
return writeExpansion;
}
}
public ResourceProperty(string readExpansion = null, string writeExpansion = null)
{
this.readExpansion = readExpansion;
this.writeExpansion = writeExpansion;
}
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource
{
public enum ResourceTrigger : int
{
Loaded = 0,
Initialize,
Terminate,
Configure,
SystemInitialized,
SystemTerminated,
SystemReload,
}
}

View File

@ -0,0 +1,48 @@
using Esiur.Data;
using Esiur.Engine;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource
{
[AttributeUsage(AttributeTargets.All)]
public class Storable : global::System.Attribute
{
public delegate object SerializerFunction(object value);
public delegate object DeserializerFunction(object data);
SerializerFunction serializer;
DeserializerFunction deserializer;
DataType type;
public Storable()
{
type = DataType.Void;
}
public DeserializerFunction Deserializer
{
get { return deserializer; }
}
public SerializerFunction Serializer
{
get { return serializer; }
}
public Storable(DataType type)
{
this.type = type;
}
public Storable(DataType type, SerializerFunction serializer, DeserializerFunction deserializer)
{
this.type = type;
this.serializer = serializer;
this.deserializer = deserializer;
}
}
}

View File

@ -0,0 +1,33 @@
using Esiur.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource.Template
{
public class EventTemplate : MemberTemplate
{
public string Expansion
{
get;
set;
}
public override byte[] Compose()
{
var name = base.Compose();
if (Expansion != null)
{
var exp = DC.ToBytes(Expansion);
return BinaryList.ToBytes((byte)0x50, exp.Length, exp, (byte)name.Length, name);
}
else
return BinaryList.ToBytes((byte)0x40, (byte)name.Length, name);
}
public EventTemplate() { Type = MemberType.Event; }
}
}

View File

@ -0,0 +1,42 @@
using Esiur.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource.Template
{
public class FunctionTemplate : MemberTemplate
{
public string Expansion
{
get;
set;
}
public bool IsVoid
{
get;
set;
}
public override byte[] Compose()
{
var name = base.Compose();
if (Expansion != null)
{
var exp = DC.ToBytes(Expansion);
return BinaryList.ToBytes((byte)(0x10 | (IsVoid ? 0x8 : 0x0)), exp.Length, exp, (byte)name.Length, name);
}
else
return BinaryList.ToBytes((byte)(IsVoid ? 0x8 : 0x0), (byte)name.Length, name);
}
public FunctionTemplate() { Type = MemberType.Function; }
}
}

View File

@ -0,0 +1,29 @@
using Esiur.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource.Template
{
public class MemberTemplate
{
public enum MemberType
{
Function = 0,
Property = 1,
Event = 2,
}
public byte Index { get; set; }
public string Name { get; set; }
public MemberType Type { get; set; }
public virtual byte[] Compose()
{
return DC.ToBytes(Name);
}
}
}

View File

@ -0,0 +1,71 @@
using Esiur.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource.Template
{
public class PropertyTemplate : MemberTemplate
{
public enum PropertyPermission:byte
{
Read = 1,
Write,
ReadWrite
}
//bool ReadOnly;
//IIPTypes::DataType ReturnType;
public PropertyPermission Permission {
get;
set;
}
public string ReadExpansion
{
get;
set;
}
public string WriteExpansion
{
get;
set;
}
public bool Storable
{
get;
set;
}
public override byte[] Compose()
{
var name = base.Compose();
if (WriteExpansion != null && ReadExpansion != null)
{
var rexp = DC.ToBytes(ReadExpansion);
var wexp = DC.ToBytes(WriteExpansion);
return BinaryList.ToBytes((byte)(0x38 | (byte)Permission), wexp.Length, wexp, rexp.Length, rexp, (byte)name.Length, name);
}
else if (WriteExpansion != null)
{
var wexp = DC.ToBytes(WriteExpansion);
return BinaryList.ToBytes((byte)(0x30 | (byte)Permission), wexp.Length, wexp, (byte)name.Length, name);
}
else if (ReadExpansion != null)
{
var rexp = DC.ToBytes(ReadExpansion);
return BinaryList.ToBytes((byte)(0x28 | (byte)Permission), rexp.Length, rexp, (byte)name.Length, name);
}
else
return BinaryList.ToBytes((byte)(0x20 | (byte)Permission), (byte)name.Length, name);
}
public PropertyTemplate() { Type = MemberType.Property; }
}
}

View File

@ -0,0 +1,359 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Esiur.Misc;
using Esiur.Data;
using Esiur.Engine;
using System.Security.Cryptography;
namespace Esiur.Resource.Template
{
public class ResourceTemplate
{
Guid classId;
string className;
List<MemberTemplate> members = new List<MemberTemplate>();
List<FunctionTemplate> functions = new List<FunctionTemplate>();
List<EventTemplate> events = new List<EventTemplate>();
List<PropertyTemplate> properties = new List<PropertyTemplate>();
int version;
//bool isReady;
byte[] content;
public byte[] Content
{
get { return content; }
}
public MemberTemplate GetMemberTemplate(MemberInfo member)
{
if (member is MethodInfo)
return GetFunctionTemplate(member.Name);
else if (member is EventInfo)
return GetEventTemplate(member.Name);
else if (member is PropertyInfo)
return GetPropertyTemplate(member.Name);
else
return null;
}
public EventTemplate GetEventTemplate(string eventName)
{
foreach (var i in events)
if (i.Name == eventName)
return i;
return null;
}
public EventTemplate GetEventTemplate(byte index)
{
foreach (var i in events)
if (i.Index == index)
return i;
return null;
}
public FunctionTemplate GetFunctionTemplate(string functionName)
{
foreach (var i in functions)
if (i.Name == functionName)
return i;
return null;
}
public FunctionTemplate GetFunctionTemplate(byte index)
{
foreach (var i in functions)
if (i.Index == index)
return i;
return null;
}
public PropertyTemplate GetPropertyTemplate(byte index)
{
foreach (var i in properties)
if (i.Index == index)
return i;
return null;
}
public PropertyTemplate GetPropertyTemplate(string propertyName)
{
foreach (var i in properties)
if (i.Name == propertyName)
return i;
return null;
}
public Guid ClassId
{
get { return classId; }
}
public string ClassName
{
get { return className; }
}
public MemberTemplate[] Methods
{
get{return members.ToArray();}
}
public FunctionTemplate[] Functions
{
get { return functions.ToArray(); }
}
public EventTemplate[] Events
{
get { return events.ToArray(); }
}
public PropertyTemplate[] Properties
{
get { return properties.ToArray(); }
}
public ResourceTemplate()
{
}
public ResourceTemplate(Type type)
{
// set guid
var typeName = Encoding.UTF8.GetBytes(type.FullName);
var hash = SHA256.Create().ComputeHash(typeName).Clip(0, 16);
classId = new Guid(hash);
className = type.FullName;
#if NETSTANDARD1_5
PropertyInfo[] propsInfo = type.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
EventInfo[] eventsInfo = type.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
MethodInfo[] methodsInfo = type.GetTypeInfo().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
#else
PropertyInfo[] propsInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
EventInfo[] eventsInfo = type.GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
MethodInfo[] methodsInfo = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
#endif
//byte currentIndex = 0;
byte i = 0;
foreach (var pi in propsInfo)
{
var ps = (ResourceProperty[])pi.GetCustomAttributes(typeof(ResourceProperty), true);
if (ps.Length > 0)
{
var pt = new PropertyTemplate();
pt.Name = pi.Name;
pt.Index = i++;
pt.ReadExpansion = ps[0].ReadExpansion;
pt.WriteExpansion = ps[0].WriteExpansion;
properties.Add(pt);
}
}
i = 0;
foreach (var ei in eventsInfo)
{
var es = (ResourceEvent[])ei.GetCustomAttributes(typeof(ResourceEvent), true);
if (es.Length > 0)
{
var et = new EventTemplate();
et.Name = ei.Name;
et.Index = i++;
et.Expansion = es[0].Expansion;
events.Add(et);
}
}
i = 0;
foreach (MethodInfo mi in methodsInfo)
{
var fs = (ResourceFunction[])mi.GetCustomAttributes(typeof(ResourceFunction), true);
if (fs.Length > 0)
{
var ft = new FunctionTemplate();
ft.Name = mi.Name;
ft.Index = i++;
ft.IsVoid = mi.ReturnType == typeof(void);
ft.Expansion = fs[0].Expansion;
functions.Add(ft);
}
}
// append signals
for (i = 0; i < events.Count; i++)
members.Add(events[i]);
// append slots
for (i = 0; i < functions.Count; i++)
members.Add(functions[i]);
// append properties
for (i = 0; i < properties.Count; i++)
members.Add(properties[i]);
// bake it binarily
var b = new BinaryList();
b.Append(classId);
b.Append((byte)className.Length, className);
b.Append(version);
b.Append((ushort)members.Count);
foreach (var ft in functions)
b.Append(ft.Compose());
foreach (var pt in properties)
b.Append(pt.Compose());
foreach (var et in events)
b.Append(et.Compose());
content = b.ToArray();
}
public static ResourceTemplate Parse(byte[] data)
{
return Parse(data, 0, (uint)data.Length);
}
public static ResourceTemplate Parse(byte[] data, uint offset, uint contentLength)
{
uint ends = offset + contentLength;
uint oOffset = offset;
// start parsing...
var od = new ResourceTemplate();
od.content = data.Clip(offset, contentLength);
od.classId = data.GetGuid(offset);
offset += 16;
od.className = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]);
offset += (uint)data[offset] + 1;
od.version = data.GetInt32(offset);
offset += 4;
ushort methodsCount = data.GetUInt16(offset);
offset += 2;
byte functionIndex = 0;
byte propertyIndex = 0;
byte eventIndex = 0;
for (int i = 0; i < methodsCount; i++)
{
var type = data[offset] >> 5;
if (type == 0) // function
{
var ft = new FunctionTemplate();
ft.Index = functionIndex++;
var expansion = ((data[offset] & 0x10) == 0x10);
ft.IsVoid = ((data[offset++] & 0x08) == 0x08);
ft.Name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]);
offset += (uint)data[offset] + 1;
if (expansion) // expansion ?
{
var cs = data.GetUInt32(offset);
offset += 4;
ft.Expansion = data.GetString(offset, cs);
offset += cs;
}
od.functions.Add(ft);
}
else if (type == 1) // property
{
var pt = new PropertyTemplate();
pt.Index = propertyIndex++;
var readExpansion = ((data[offset] & 0x8) == 0x8);
var writeExpansion = ((data[offset] & 0x10) == 0x10);
pt.Permission = (PropertyTemplate.PropertyPermission)((data[offset++] >> 1) & 0x3);
pt.Name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]);
offset += (uint)data[offset] + 1;
if (readExpansion) // expansion ?
{
var cs = data.GetUInt32(offset);
offset += 4;
pt.ReadExpansion = data.GetString(offset, cs);
offset += cs;
}
if (writeExpansion) // expansion ?
{
var cs = data.GetUInt32(offset);
offset += 4;
pt.WriteExpansion = data.GetString(offset, cs);
offset += cs;
}
od.properties.Add(pt);
}
else if (type == 2) // Event
{
var et = new EventTemplate();
et.Index = eventIndex++;
var expansion = ((data[offset++] & 0x10) == 0x10);
et.Name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, (int)data[offset]);
offset += (uint)data[offset] + 1;
if (expansion) // expansion ?
{
var cs = data.GetUInt32(offset);
offset += 4;
et.Expansion = data.GetString(offset, cs);
offset += cs;
}
od.events.Add(et);
}
}
// 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]);
//od.isReady = true;
/*
var oo = owner.Socket.Engine.GetObjectDescription(od.GUID);
if (oo != null)
{
Console.WriteLine("Already there ! description");
return oo;
}
else
{
owner.Socket.Engine.AddObjectDescription(od);
return od;
}
*/
return od;
}
}
}

258
Esiur/Resource/Warehouse.cs Normal file
View File

@ -0,0 +1,258 @@
using Esiur.Data;
using Esiur.Engine;
using Esiur.Resource.Template;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource
{
// Centeral Resource Issuer
public static class Warehouse
{
//static byte prefixCounter;
static List<IStore> stores = new List<IStore>();
static Dictionary<uint, IResource> resources = new Dictionary<uint, IResource>();
static uint resourceCounter = 0;
static KeyList<Guid, ResourceTemplate> templates = new KeyList<Guid, ResourceTemplate>();
/// <summary>
/// Get a store by its name.
/// </summary>
/// <param name="name">Store instance name</param>
/// <returns></returns>
public static IStore GetStore(string name)
{
foreach (var s in stores)
if (s.Instance.Name == name)
return s;
return null;
}
/// <summary>
/// Get a resource by instance Id.
/// </summary>
/// <param name="id">Instance Id</param>
/// <returns></returns>
public static AsyncReply<IResource> Get(uint id)
{
if (resources.ContainsKey(id))
return new AsyncReply<IResource>(resources[id]);
else
return null;
}
/// <summary>
/// Open the warehouse.
/// This function issues the initialize trigger to all stores and resources.
/// </summary>
/// <returns>True, if no problem occurred.</returns>
public static AsyncReply<bool> Open()
{
var bag = new AsyncBag<bool>();
foreach (var store in stores)
bag.Add(store.Trigger(ResourceTrigger.Initialize));
foreach (var store in stores)
bag.Add(store.Trigger(ResourceTrigger.SystemInitialized));
bag.Seal();
var rt = new AsyncReply<bool>();
bag.Then((x) =>
{
foreach(var b in x)
if (!b)
{
rt.Trigger(false);
return;
}
rt.Trigger(true);
});
return rt;
}
/// <summary>
/// Close the warehouse.
/// This function issues terminate trigger to all resources and stores.
/// </summary>
/// <returns>True, if no problem occurred.</returns>
public static AsyncReply<bool> Close()
{
var bag = new AsyncBag<bool>();
foreach (var resource in resources.Values)
if (!(resource is IStore))
bag.Add(resource.Trigger(ResourceTrigger.Terminate));
foreach (var store in stores)
bag.Add(store.Trigger(ResourceTrigger.Terminate));
foreach (var resource in resources.Values)
if (!(resource is IStore))
bag.Add(resource.Trigger(ResourceTrigger.SystemTerminated));
foreach (var store in stores)
bag.Add(store.Trigger(ResourceTrigger.SystemTerminated));
bag.Seal();
var rt = new AsyncReply<bool>();
bag.Then((x) =>
{
foreach (var b in x)
if (!b)
{
rt.Trigger(false);
return;
}
rt.Trigger(true);
});
return rt;
}
/// <summary>
/// Get a resource by its path.
/// Resource path is sperated by '/' character, e.g. "system/http".
/// </summary>
/// <param name="path"></param>
/// <returns>Resource instance.</returns>
public static AsyncReply<IResource> Get(string path)
{
var p = path.Split('/');
IResource res;
foreach(IStore d in stores)
if (p[0] == d.Instance.Name)
{
var i = 1;
res = d;
while(p.Length > i)
{
var si = i;
foreach (IResource r in res.Instance.Children)
if (r.Instance.Name == p[i])
{
i++;
res = r;
break;
}
if (si == i)
// not found, ask the store
return d.Get(path.Substring(p[0].Length + 1));
}
return new AsyncReply<IResource>(res);
}
return new AsyncReply<IResource>(null);
}
/// <summary>
/// Put a resource in the warehouse.
/// </summary>
/// <param name="resource">Resource instance.</param>
/// <param name="name">Resource name.</param>
/// <param name="store">IStore that manages the resource. Can be null if the resource is a store.</param>
/// <param name="parent">Parent resource. if not presented the store becomes the parent for the resource.</param>
public static void Put(IResource resource, string name, IStore store = null, IResource parent = null)
{
resource.Instance = new Instance(resourceCounter++, name, resource, store);
if (store == parent)
parent = null;
if (parent == null)
{
if (!(resource is IStore))
store.Instance.Children.Add(resource);
}
else
parent.Instance.Children.Add(resource);
if (resource is IStore)
stores.Add(resource as IStore);
else
store.Put(resource);
resources.Add(resource.Instance.Id, resource);
}
public static T New<T>(string name, IStore store = null, IResource parent = null)
{
var res = Activator.CreateInstance(typeof(T)) as IResource;
Put(res, name, store, parent);
return (T)res;
}
/// <summary>
/// Put a resource template in the templates warehouse.
/// </summary>
/// <param name="template">Resource template.</param>
public static void PutTemplate(ResourceTemplate template)
{
if (templates.ContainsKey(template.ClassId))
templates.Add(template.ClassId, template);
}
/// <summary>
/// Get a template by type from the templates warehouse. If not in the warehouse, a new ResourceTemplate is created and added to the warehouse.
/// </summary>
/// <param name="type">.Net type.</param>
/// <returns>Resource template.</returns>
public static ResourceTemplate GetTemplate(Type type)
{
// loaded ?
foreach (var t in templates.Values)
if (t.ClassName == type.FullName)
return t;
var template = new ResourceTemplate(type);
templates.Add(template.ClassId, template);
return template;
}
/// <summary>
/// Get a template by class Id from the templates warehouse. If not in the warehouse, a new ResourceTemplate is created and added to the warehouse.
/// </summary>
/// <param name="classId">Class Id.</param>
/// <returns>Resource template.</returns>
public static AsyncReply<ResourceTemplate> GetTemplate(Guid classId)
{
if (templates.ContainsKey(classId))
return new AsyncReply<ResourceTemplate>(templates[classId]);
return null;
}
/// <summary>
/// Get a template by class name from the templates warehouse. If not in the warehouse, a new ResourceTemplate is created and added to the warehouse.
/// </summary>
/// <param name="className">Class name.</param>
/// <returns>Resource template.</returns>
public static AsyncReply<ResourceTemplate> GetTemplate(string className)
{
foreach (var t in templates.Values)
if (t.ClassName == className)
return new AsyncReply<ResourceTemplate>(t);
return null;
}
}
}