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

View File

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

View File

@ -0,0 +1,42 @@
/*
Copyright (c) 2021 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource
{
[AttributeUsage(AttributeTargets.Event)]
public class ListenableAttribute : System.Attribute
{
public ListenableAttribute()
{
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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