mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2025-06-26 21:13:13 +00:00
1.6.1
This commit is contained in:
@ -41,7 +41,6 @@ namespace Esiur.Resource
|
||||
{
|
||||
|
||||
AsyncReply<bool> Trigger(ResourceTrigger trigger);
|
||||
|
||||
Instance Instance
|
||||
{
|
||||
get;
|
||||
|
42
Esiur/Resource/ListenableAttribute.cs
Normal file
42
Esiur/Resource/ListenableAttribute.cs
Normal 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()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
{
|
||||
|
@ -47,6 +47,7 @@ namespace Esiur.Resource
|
||||
return new AsyncReply<bool>(true);
|
||||
}
|
||||
|
||||
|
||||
protected virtual bool Create()
|
||||
{
|
||||
return true;
|
||||
|
15
Esiur/Resource/ResourceAttribute.cs
Normal file
15
Esiur/Resource/ResourceAttribute.cs
Normal 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()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user