mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2025-06-26 21:13:13 +00:00
WeakRef
This commit is contained in:
@ -35,13 +35,27 @@ namespace Esiur.Resource
|
||||
{
|
||||
public interface IStore:IResource
|
||||
{
|
||||
AsyncReply<IResource> Get(string path);
|
||||
AsyncReply<IResource> Retrieve(uint iid);
|
||||
AsyncReply<IResource> Get(string path);//, Func<IResource, bool> filter = null);
|
||||
//AsyncReply<IResource> Retrieve(uint iid);
|
||||
bool Put(IResource resource);
|
||||
string Link(IResource resource);
|
||||
bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime);
|
||||
bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime);
|
||||
bool Remove(IResource resource);
|
||||
|
||||
|
||||
AsyncReply<bool> AddChild(IResource parent, IResource child);
|
||||
AsyncReply<bool> RemoveChild(IResource parent, IResource child);
|
||||
|
||||
AsyncReply<bool> AddParent(IResource child, IResource parent);
|
||||
AsyncReply<bool> RemoveParent(IResource child, IResource parent);
|
||||
|
||||
|
||||
AsyncBag<T> Children<T>(IResource resource, string name) where T : IResource;
|
||||
AsyncBag<T> Parents<T>(IResource resource, string name) where T : IResource;
|
||||
|
||||
|
||||
|
||||
//AsyncReply<PropertyValue[]> GetPropertyRecord(IResource resource, string propertyName, ulong fromAge, ulong toAge);
|
||||
//AsyncReply<PropertyValue[]> GetPropertyRecordByDate(IResource resource, string propertyName, DateTime fromDate, DateTime toDate);
|
||||
|
||||
|
@ -12,6 +12,7 @@ using Esiur.Security.Permissions;
|
||||
using Esiur.Resource.Template;
|
||||
using Esiur.Security.Authority;
|
||||
using Esiur.Proxy;
|
||||
using Esiur.Core;
|
||||
|
||||
namespace Esiur.Resource
|
||||
{
|
||||
@ -19,16 +20,17 @@ namespace Esiur.Resource
|
||||
{
|
||||
string name;
|
||||
|
||||
AutoList<IResource, Instance> children;// = new AutoList<IResource, Instance>();
|
||||
IResource resource;
|
||||
//IQueryable<IResource> children;//
|
||||
//AutoList<IResource, Instance> children;// = new AutoList<IResource, Instance>();
|
||||
WeakReference<IResource> resource;
|
||||
IStore store;
|
||||
AutoList<IResource, Instance> parents;// = new AutoList<IResource>();
|
||||
//AutoList<IResource, Instance> parents;// = new AutoList<IResource>();
|
||||
//bool inherit;
|
||||
ResourceTemplate template;
|
||||
|
||||
AutoList<IPermissionsManager, Instance> managers;// = new AutoList<IPermissionManager, Instance>();
|
||||
|
||||
|
||||
|
||||
public delegate void ResourceModifiedEvent(IResource resource, string propertyName, object newValue);
|
||||
//public delegate void ResourceEventOccurredEvent(IResource resource, string eventName, string[] users, DistributedConnection[] connections, object[] args);
|
||||
|
||||
@ -40,6 +42,8 @@ namespace Esiur.Resource
|
||||
public event ResourceEventOccurredEvent ResourceEventOccurred;
|
||||
public event ResourceDestroyedEvent ResourceDestroyed;
|
||||
|
||||
bool loading = false;
|
||||
|
||||
KeyList<string, object> attributes;
|
||||
|
||||
List<ulong> ages = new List<ulong>();
|
||||
@ -90,7 +94,7 @@ namespace Esiur.Resource
|
||||
attributes = clone.ToArray();// this.attributes.Keys.ToList().Add("managers");
|
||||
}
|
||||
|
||||
foreach(var attr in attributes)
|
||||
foreach (var attr in attributes)
|
||||
{
|
||||
if (attr == "name")
|
||||
st["name"] = this.name;
|
||||
@ -109,15 +113,15 @@ namespace Esiur.Resource
|
||||
}
|
||||
else if (attr == "parents")
|
||||
{
|
||||
st["parents"] = parents.ToArray();
|
||||
//st["parents"] = parents.ToArray();
|
||||
}
|
||||
else if (attr == "children")
|
||||
{
|
||||
st["children"] = children.ToArray();
|
||||
//st["children"] = children.ToArray();
|
||||
}
|
||||
else if (attr == "childrenCount")
|
||||
{
|
||||
st["childrenCount"] = children.Count;
|
||||
//st["childrenCount"] = children.Count;
|
||||
}
|
||||
else if (attr == "type")
|
||||
{
|
||||
@ -131,7 +135,7 @@ namespace Esiur.Resource
|
||||
}
|
||||
|
||||
public bool SetAttributes(Structure attributes, bool clearAttributes = false)
|
||||
{
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@ -155,8 +159,13 @@ namespace Esiur.Resource
|
||||
{
|
||||
var settings = m["settings"] as Structure;
|
||||
var manager = Activator.CreateInstance(type) as IPermissionsManager;
|
||||
manager.Initialize(settings, this.resource);
|
||||
this.managers.Add(manager);
|
||||
|
||||
IResource res;
|
||||
if (this.resource.TryGetTarget(out res))
|
||||
{
|
||||
manager.Initialize(settings, res);
|
||||
this.managers.Add(manager);
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
@ -166,7 +175,7 @@ namespace Esiur.Resource
|
||||
{
|
||||
this.attributes[attr.Key] = attr.Value;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
@ -175,7 +184,7 @@ namespace Esiur.Resource
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
public Structure GetAttributes()
|
||||
{
|
||||
@ -256,7 +265,7 @@ namespace Esiur.Resource
|
||||
return DateTime.MinValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Load property value (used by stores)
|
||||
/// </summary>
|
||||
@ -266,13 +275,19 @@ namespace Esiur.Resource
|
||||
/// <returns></returns>
|
||||
public bool LoadProperty(string name, ulong age, DateTime modificationDate, object value)
|
||||
{
|
||||
|
||||
IResource res;
|
||||
|
||||
if (!resource.TryGetTarget(out res))
|
||||
return false;
|
||||
|
||||
var pt = template.GetPropertyTemplateByName(name);
|
||||
|
||||
if (pt == null)
|
||||
return false;
|
||||
|
||||
/*
|
||||
#if NETSTANDARD1_5
|
||||
#if NETSTANDARD
|
||||
var pi = resource.GetType().GetTypeInfo().GetProperty(name, new[] { resource.GetType() });
|
||||
#else
|
||||
var pi = resource.GetType().GetProperty(pt.Name);
|
||||
@ -282,18 +297,25 @@ namespace Esiur.Resource
|
||||
if (pt.Info.PropertyType == typeof(DistributedPropertyContext))
|
||||
return false;
|
||||
|
||||
|
||||
try
|
||||
|
||||
if (pt.Info.CanWrite)
|
||||
{
|
||||
if (pt.Info.CanWrite)
|
||||
pt.Info.SetValue(resource, DC.CastConvert(value, pt.Info.PropertyType));
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
//Console.WriteLine(resource.ToString() + " " + name);
|
||||
Global.Log(ex);
|
||||
try
|
||||
{
|
||||
loading = true;
|
||||
|
||||
pt.Info.SetValue(res, DC.CastConvert(value, pt.Info.PropertyType));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//Console.WriteLine(resource.ToString() + " " + name);
|
||||
Global.Log(ex);
|
||||
}
|
||||
|
||||
loading = false;
|
||||
}
|
||||
|
||||
|
||||
SetAge(pt.Index, age);
|
||||
SetModificationDate(pt.Index, modificationDate);
|
||||
|
||||
@ -359,16 +381,19 @@ namespace Esiur.Resource
|
||||
foreach (var pt in template.Properties)
|
||||
{
|
||||
/*
|
||||
#if NETSTANDARD1_5
|
||||
#if NETSTANDARD
|
||||
var pi = resource.GetType().GetTypeInfo().GetProperty(pt.Name);
|
||||
#else
|
||||
var pi = resource.GetType().GetProperty(pt.Name);
|
||||
#endif
|
||||
*/
|
||||
|
||||
|
||||
var rt = pt.Info.GetValue(resource, null);
|
||||
props.Add(new PropertyValue(rt, ages[pt.Index], modificationDates[pt.Index]));
|
||||
IResource res;
|
||||
if (resource.TryGetTarget(out res))
|
||||
{
|
||||
var rt = pt.Info.GetValue(res, null);
|
||||
props.Add(new PropertyValue(rt, ages[pt.Index], modificationDates[pt.Index]));
|
||||
}
|
||||
}
|
||||
|
||||
return props.ToArray();
|
||||
@ -446,7 +471,7 @@ namespace Esiur.Resource
|
||||
/// <returns></returns>
|
||||
public bool IsStorable()
|
||||
{
|
||||
#if NETSTANDARD1_5
|
||||
#if NETSTANDARD
|
||||
var attrs = resource.GetType().GetTypeInfo().GetCustomAttributes(typeof(Storable), true).ToArray();
|
||||
#else
|
||||
var attrs = resource.GetType().GetCustomAttributes(typeof(Storable), true);
|
||||
@ -458,22 +483,27 @@ namespace Esiur.Resource
|
||||
|
||||
internal void EmitModification(PropertyTemplate pt, object value)
|
||||
{
|
||||
instanceAge++;
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
ages[pt.Index] = instanceAge;
|
||||
modificationDates[pt.Index] = now;
|
||||
|
||||
if (pt.Storage == StorageMode.NonVolatile)
|
||||
IResource res;
|
||||
if (this.resource.TryGetTarget(out res))
|
||||
{
|
||||
store.Modify(resource, pt.Name, value, ages[pt.Index], now);
|
||||
}
|
||||
else if (pt.Storage == StorageMode.Recordable)
|
||||
{
|
||||
store.Record(resource, pt.Name, value, ages[pt.Index], now);
|
||||
}
|
||||
instanceAge++;
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
ResourceModified?.Invoke(resource, pt.Name, value);
|
||||
ages[pt.Index] = instanceAge;
|
||||
modificationDates[pt.Index] = now;
|
||||
|
||||
if (pt.Storage == StorageMode.NonVolatile)
|
||||
{
|
||||
store.Modify(res, pt.Name, value, ages[pt.Index], now);
|
||||
}
|
||||
else if (pt.Storage == StorageMode.Recordable)
|
||||
{
|
||||
store.Record(res, pt.Name, value, ages[pt.Index], now);
|
||||
}
|
||||
|
||||
ResourceModified?.Invoke(res, pt.Name, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -484,6 +514,9 @@ namespace Esiur.Resource
|
||||
/// <param name="oldValue"></param>
|
||||
public void Modified([CallerMemberName] string propertyName = "")
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
object value;
|
||||
if (GetPropertyValue(propertyName, out value))
|
||||
{
|
||||
@ -496,7 +529,12 @@ namespace Esiur.Resource
|
||||
|
||||
internal void EmitResourceEvent(object issuer, Session[] receivers, string name, object[] args)
|
||||
{
|
||||
ResourceEventOccurred?.Invoke(resource, issuer, receivers, name, args);
|
||||
IResource res;
|
||||
if (this.resource.TryGetTarget(out res))
|
||||
{
|
||||
|
||||
ResourceEventOccurred?.Invoke(res, issuer, receivers, name, args);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -508,7 +546,7 @@ namespace Esiur.Resource
|
||||
public bool GetPropertyValue(string name, out object value)
|
||||
{
|
||||
/*
|
||||
#if NETSTANDARD1_5
|
||||
#if NETSTANDARD
|
||||
PropertyInfo pi = resource.GetType().GetTypeInfo().GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
|
||||
|
||||
#else
|
||||
@ -521,7 +559,7 @@ namespace Esiur.Resource
|
||||
if (pt != null && pt.Info != null)
|
||||
{
|
||||
/*
|
||||
#if NETSTANDARD1_5
|
||||
#if NETSTANDARD
|
||||
object[] ca = pi.GetCustomAttributes(typeof(ResourceProperty), false).ToArray();
|
||||
|
||||
#else
|
||||
@ -537,7 +575,15 @@ namespace Esiur.Resource
|
||||
}
|
||||
*/
|
||||
|
||||
value = pt.Info.GetValue(resource, null);
|
||||
IResource res;
|
||||
if (resource.TryGetTarget(out res))
|
||||
value = pt.Info.GetValue(res, null);
|
||||
else
|
||||
{
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
@ -556,10 +602,7 @@ namespace Esiur.Resource
|
||||
/// <summary>
|
||||
/// List of parents.
|
||||
/// </summary>
|
||||
public AutoList<IResource, Instance> Parents
|
||||
{
|
||||
get { return parents; }
|
||||
}
|
||||
//public AutoList<IResource, Instance> Parents => parents;
|
||||
|
||||
/// <summary>
|
||||
/// Store responsible for creating and keeping the resource.
|
||||
@ -572,15 +615,54 @@ namespace Esiur.Resource
|
||||
/// <summary>
|
||||
/// List of children.
|
||||
/// </summary>
|
||||
public AutoList<IResource, Instance> Children
|
||||
{
|
||||
get { return children; }
|
||||
}
|
||||
// public AutoList<IResource, Instance> Children => children;
|
||||
|
||||
/// <summary>
|
||||
/// The unique and permanent link to the resource.
|
||||
/// </summary>
|
||||
public string Link
|
||||
{
|
||||
get
|
||||
{
|
||||
IResource res;
|
||||
if (this.resource.TryGetTarget(out res))
|
||||
{
|
||||
if (res == res.Instance.store)
|
||||
return name; // root store
|
||||
else
|
||||
return store.Link(res);
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public AsyncBag<T> Children<T>(string name = null) where T : IResource
|
||||
{
|
||||
IResource res;
|
||||
if (this.resource.TryGetTarget(out res))
|
||||
{
|
||||
//if (!(store is null))
|
||||
return store.Children<T>(res, name);
|
||||
//else
|
||||
// return (res as IStore).Children<T>(res, name);
|
||||
}
|
||||
else
|
||||
return new AsyncBag<T>(null);
|
||||
}
|
||||
|
||||
public AsyncBag<T> Parents<T>(string name = null) where T : IResource
|
||||
{
|
||||
IResource res;
|
||||
if (this.resource.TryGetTarget(out res))
|
||||
{
|
||||
return store.Parents<T>(res, name);
|
||||
}
|
||||
else
|
||||
return new AsyncBag<T>(null);
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -607,6 +689,8 @@ namespace Esiur.Resource
|
||||
}
|
||||
}
|
||||
}
|
||||
*
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Instance name.
|
||||
@ -623,7 +707,16 @@ namespace Esiur.Resource
|
||||
/// </summary>
|
||||
public IResource Resource
|
||||
{
|
||||
get { return resource; }
|
||||
get
|
||||
{
|
||||
IResource res;
|
||||
if (this.resource.TryGetTarget(out res))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -658,11 +751,15 @@ namespace Esiur.Resource
|
||||
/// <returns>Ruling.</returns>
|
||||
public Ruling Applicable(Session session, ActionType action, MemberTemplate member, object inquirer = null)
|
||||
{
|
||||
foreach (IPermissionsManager manager in managers)
|
||||
IResource res;
|
||||
if (this.resource.TryGetTarget(out res))
|
||||
{
|
||||
var r = manager.Applicable(this.resource, session, action, member, inquirer);
|
||||
if (r != Ruling.DontCare)
|
||||
return r;
|
||||
foreach (IPermissionsManager manager in managers)
|
||||
{
|
||||
var r = manager.Applicable(res, session, action, member, inquirer);
|
||||
if (r != Ruling.DontCare)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return Ruling.DontCare;
|
||||
@ -684,19 +781,19 @@ namespace Esiur.Resource
|
||||
public Instance(uint id, string name, IResource resource, IStore store, ResourceTemplate customTemplate = null, ulong age = 0)
|
||||
{
|
||||
this.store = store;
|
||||
this.resource = resource;
|
||||
this.resource = new WeakReference<IResource>(resource);
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.instanceAge = age;
|
||||
|
||||
this.attributes = new KeyList<string, object>(this);
|
||||
children = new AutoList<IResource, Instance>(this);
|
||||
parents = new AutoList<IResource, Instance>(this);
|
||||
//children = new AutoList<IResource, Instance>(this);
|
||||
//parents = new AutoList<IResource, Instance>(this);
|
||||
managers = new AutoList<IPermissionsManager, Instance>(this);
|
||||
children.OnAdd += Children_OnAdd;
|
||||
children.OnRemoved += Children_OnRemoved;
|
||||
parents.OnAdd += Parents_OnAdd;
|
||||
parents.OnRemoved += Parents_OnRemoved;
|
||||
//children.OnAdd += Children_OnAdd;
|
||||
//children.OnRemoved += Children_OnRemoved;
|
||||
//parents.OnAdd += Parents_OnAdd;
|
||||
//parents.OnRemoved += Parents_OnRemoved;
|
||||
|
||||
resource.OnDestroy += Resource_OnDestroy;
|
||||
|
||||
@ -715,7 +812,7 @@ namespace Esiur.Resource
|
||||
// connect events
|
||||
Type t = ResourceProxy.GetBaseType(resource);
|
||||
|
||||
#if NETSTANDARD1_5
|
||||
#if NETSTANDARD
|
||||
var events = t.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
|
||||
|
||||
#else
|
||||
@ -783,7 +880,12 @@ namespace Esiur.Resource
|
||||
}
|
||||
}
|
||||
|
||||
private void Children_OnRemoved(Instance parent, IResource value)
|
||||
|
||||
//IQueryable<IResource> Children => store.GetChildren(this);
|
||||
|
||||
|
||||
/*
|
||||
* private void Children_OnRemoved(Instance parent, IResource value)
|
||||
{
|
||||
value.Instance.parents.Remove(resource);
|
||||
}
|
||||
@ -804,7 +906,7 @@ namespace Esiur.Resource
|
||||
if (!value.Instance.children.Contains(resource))
|
||||
value.Instance.children.Add(resource);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
private void Resource_OnDestroy(object sender)
|
||||
{
|
||||
|
@ -36,7 +36,7 @@ namespace Esiur.Resource
|
||||
|
||||
public virtual void Destroy()
|
||||
{
|
||||
|
||||
OnDestroy?.Invoke(this);
|
||||
}
|
||||
|
||||
public virtual AsyncReply<bool> Trigger(ResourceTrigger trigger)
|
||||
@ -51,5 +51,10 @@ namespace Esiur.Resource
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
~Resource()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
28
Esiur/Resource/ResourceQuery.cs
Normal file
28
Esiur/Resource/ResourceQuery.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
|
||||
namespace Esiur.Resource
|
||||
{
|
||||
public class ResourceQuery : IQueryable<IResource>
|
||||
{
|
||||
public Type ElementType => throw new NotImplementedException();
|
||||
|
||||
public Expression Expression => throw new NotImplementedException();
|
||||
|
||||
public IQueryProvider Provider => throw new NotImplementedException();
|
||||
|
||||
public IEnumerator<IResource> GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -139,7 +139,7 @@ namespace Esiur.Resource.Template
|
||||
className = type.FullName;
|
||||
|
||||
|
||||
#if NETSTANDARD1_5
|
||||
#if NETSTANDARD
|
||||
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);
|
||||
|
@ -32,6 +32,8 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Esiur.Net.IIP;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Esiur.Resource
|
||||
{
|
||||
@ -40,13 +42,13 @@ namespace Esiur.Resource
|
||||
{
|
||||
//static byte prefixCounter;
|
||||
|
||||
static AutoList<IResource, Instance> stores = new AutoList<IResource, Instance>(null);
|
||||
static Dictionary<uint, IResource> resources = new Dictionary<uint, IResource>();
|
||||
static AutoList<IStore, Instance> stores = new AutoList<IStore, Instance>(null);
|
||||
static Dictionary<uint, WeakReference<IResource>> resources = new Dictionary<uint, WeakReference<IResource>>();
|
||||
static uint resourceCounter = 0;
|
||||
|
||||
static KeyList<Guid, ResourceTemplate> templates = new KeyList<Guid, ResourceTemplate>();
|
||||
|
||||
static bool storeIsOpen = false;
|
||||
static bool warehouseIsOpen = false;
|
||||
|
||||
public delegate void StoreConnectedEvent(IStore store, string name);
|
||||
public delegate void StoreDisconnectedEvent(IStore store);
|
||||
@ -54,7 +56,15 @@ namespace Esiur.Resource
|
||||
public static event StoreConnectedEvent StoreConnected;
|
||||
public static event StoreDisconnectedEvent StoreDisconnected;
|
||||
|
||||
public static KeyList<string, Func<IStore>> Protocols { get; } = new KeyList<string, Func<IStore>>();
|
||||
public static KeyList<string, Func<IStore>> Protocols { get; } = getSupportedProtocols();
|
||||
|
||||
|
||||
static KeyList<string, Func<IStore>> getSupportedProtocols()
|
||||
{
|
||||
var rt = new KeyList<string, Func<IStore>>();
|
||||
rt.Add("iip", () => new DistributedConnection());
|
||||
return rt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a store by its name.
|
||||
@ -77,7 +87,13 @@ namespace Esiur.Resource
|
||||
public static AsyncReply<IResource> Get(uint id)
|
||||
{
|
||||
if (resources.ContainsKey(id))
|
||||
return new AsyncReply<IResource>(resources[id]);
|
||||
{
|
||||
IResource r;
|
||||
if (resources[id].TryGetTarget(out r))
|
||||
return new AsyncReply<IResource>(r);
|
||||
else
|
||||
return new AsyncReply<IResource>(null);
|
||||
}
|
||||
else
|
||||
return new AsyncReply<IResource>(null);
|
||||
}
|
||||
@ -109,7 +125,11 @@ namespace Esiur.Resource
|
||||
|
||||
var rBag = new AsyncBag<bool>();
|
||||
foreach (var rk in resources)
|
||||
rBag.Add(rk.Value.Trigger(ResourceTrigger.SystemInitialized));
|
||||
{
|
||||
IResource r;
|
||||
if (rk.Value.TryGetTarget(out r))
|
||||
rBag.Add(r.Trigger(ResourceTrigger.SystemInitialized));
|
||||
}
|
||||
|
||||
rBag.Seal();
|
||||
|
||||
@ -123,7 +143,7 @@ namespace Esiur.Resource
|
||||
}
|
||||
|
||||
rt.Trigger(true);
|
||||
storeIsOpen = true;
|
||||
warehouseIsOpen = true;
|
||||
});
|
||||
|
||||
});
|
||||
@ -142,15 +162,30 @@ namespace Esiur.Resource
|
||||
var bag = new AsyncBag<bool>();
|
||||
|
||||
foreach (var resource in resources.Values)
|
||||
if (!(resource is IStore))
|
||||
bag.Add(resource.Trigger(ResourceTrigger.Terminate));
|
||||
{
|
||||
IResource r;
|
||||
if (resource.TryGetTarget(out r))
|
||||
{
|
||||
if (!(r is IStore))
|
||||
bag.Add(r.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));
|
||||
{
|
||||
IResource r;
|
||||
if (resource.TryGetTarget(out r))
|
||||
{
|
||||
if (!(r is IStore))
|
||||
bag.Add(r.Trigger(ResourceTrigger.SystemTerminated));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach (var store in stores)
|
||||
bag.Add(store.Trigger(ResourceTrigger.SystemTerminated));
|
||||
@ -174,7 +209,8 @@ namespace Esiur.Resource
|
||||
}
|
||||
|
||||
|
||||
private static IResource[] QureyIn(string[] path, int index, AutoList<IResource, Instance> resources)
|
||||
/*
|
||||
private static IResource[] QureyIn(string[] path, int index, IEnumerable<IResource> resources)// AutoList<IResource, Instance> resources)
|
||||
{
|
||||
var rt = new List<IResource>();
|
||||
|
||||
@ -191,18 +227,16 @@ namespace Esiur.Resource
|
||||
else
|
||||
foreach (IResource child in resources)
|
||||
if (child.Instance.Name == path[index])
|
||||
rt.AddRange(QureyIn(path, index+1, child.Instance.Children));
|
||||
rt.AddRange(QureyIn(path, index+1, child.Instance.Children<IResource>()));
|
||||
|
||||
return rt.ToArray();
|
||||
}
|
||||
|
||||
public static AsyncReply<IResource[]> Query(string path)
|
||||
{
|
||||
|
||||
|
||||
if (path == null || path == "")
|
||||
{
|
||||
var roots = stores.Where(s => s.Instance.Parents.Count == 0).ToArray();
|
||||
var roots = stores.Where(s => s.Instance.Parents<IResource>().Count() == 0).ToArray();
|
||||
return new AsyncReply<IResource[]>(roots);
|
||||
}
|
||||
else
|
||||
@ -229,6 +263,51 @@ namespace Esiur.Resource
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
public static async Task<IResource[]> Query(string path)
|
||||
{
|
||||
var rt = new AsyncReply<IResource[]>();
|
||||
|
||||
var p = path.Trim().Split('/');
|
||||
IResource resource;
|
||||
|
||||
foreach (var store in stores)
|
||||
if (p[0] == store.Instance.Name)
|
||||
{
|
||||
|
||||
if (p.Length == 1)
|
||||
return new IResource[] { store };
|
||||
|
||||
var res = await store.Get(String.Join("/", p.Skip(1).ToArray()));
|
||||
if (res != null)
|
||||
return new IResource[] { res };
|
||||
|
||||
|
||||
resource = store;
|
||||
for (var i = 1; i < p.Length; i++)
|
||||
{
|
||||
var children = await resource.Instance.Children<IResource>(p[i]);
|
||||
if (children.Length > 0)
|
||||
{
|
||||
if (i == p.Length - 1)
|
||||
return children;
|
||||
else
|
||||
resource = children[0];
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a resource by its path.
|
||||
@ -236,38 +315,15 @@ namespace Esiur.Resource
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns>Resource instance.</returns>
|
||||
public static AsyncReply<IResource> Get(string path, Structure attributes = null, IResource parent = null, IPermissionsManager manager = null)
|
||||
public static AsyncReply<IResource> Get(string path, object attributes = null, IResource parent = null, IPermissionsManager manager = null)
|
||||
{
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
var rt = new AsyncReply<IResource>();
|
||||
|
||||
// Should we create a new store ?
|
||||
|
||||
if (path.Contains("://"))
|
||||
{
|
||||
var url = path.Split(new string[] { "://" }, 2, StringSplitOptions.None);
|
||||
@ -275,17 +331,18 @@ namespace Esiur.Resource
|
||||
var pathname = string.Join("/", url[1].Split(new char[] { '/' }).Skip(1));
|
||||
|
||||
|
||||
var rt = new AsyncReply<IResource>();
|
||||
|
||||
if (Protocols.ContainsKey(url[0]))
|
||||
{
|
||||
var handler = Protocols[url[0]];
|
||||
|
||||
var store = handler();// Activator.CreateInstance(handler.GetType()) as IStore;
|
||||
Put(store, url[0] + "://" + hostname, null, parent, null, 0, manager, attributes);
|
||||
var store = handler();
|
||||
Put(store, hostname, null, parent, null, 0, manager, attributes);
|
||||
|
||||
|
||||
store.Trigger(ResourceTrigger.Open).Then(x => {
|
||||
|
||||
warehouseIsOpen = true;
|
||||
|
||||
if (pathname.Length > 0 && pathname != "")
|
||||
store.Get(pathname).Then(r => {
|
||||
rt.Trigger(r);
|
||||
@ -296,13 +353,24 @@ namespace Esiur.Resource
|
||||
rt.TriggerError(e);
|
||||
Warehouse.Remove(store);
|
||||
});
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
|
||||
Query(path).ContinueWith(rs =>
|
||||
{
|
||||
// rt.TriggerError(new Exception());
|
||||
if (rs.Result != null && rs.Result.Length > 0)
|
||||
rt.Trigger(rs.Result[0]);
|
||||
else
|
||||
rt.Trigger(null);
|
||||
});
|
||||
|
||||
return rt;
|
||||
|
||||
|
||||
|
||||
return new AsyncReply<IResource>(null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -312,12 +380,31 @@ namespace Esiur.Resource
|
||||
/// <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, ResourceTemplate customTemplate = null, ulong age = 0, IPermissionsManager manager = null, Structure attributes = null)
|
||||
public static void Put(IResource resource, string name, IStore store = null, IResource parent = null, ResourceTemplate customTemplate = null, ulong age = 0, IPermissionsManager manager = null, object attributes = null)
|
||||
{
|
||||
|
||||
if (store == null)
|
||||
{
|
||||
// assign parent as a store
|
||||
if (parent is IStore)
|
||||
store = (IStore)parent;
|
||||
// assign parent's store as a store
|
||||
else if (parent != null)
|
||||
store = parent.Instance.Store;
|
||||
// assign self as a store (root store)
|
||||
else if (resource is IStore)
|
||||
{
|
||||
store = (IStore)resource;
|
||||
stores.Add(resource as IStore);
|
||||
}
|
||||
else
|
||||
throw new Exception("Can't find a store for the resource.");
|
||||
}
|
||||
|
||||
resource.Instance = new Instance(resourceCounter++, name, resource, store, customTemplate, age);
|
||||
|
||||
if (attributes != null)
|
||||
resource.Instance.SetAttributes(attributes);
|
||||
resource.Instance.SetAttributes(Structure.FromObject(attributes));
|
||||
|
||||
if (manager != null)
|
||||
resource.Instance.Managers.Add(manager);
|
||||
@ -325,6 +412,8 @@ namespace Esiur.Resource
|
||||
if (store == parent)
|
||||
parent = null;
|
||||
|
||||
|
||||
/*
|
||||
if (parent == null)
|
||||
{
|
||||
if (!(resource is IStore))
|
||||
@ -332,20 +421,26 @@ namespace Esiur.Resource
|
||||
}
|
||||
else
|
||||
parent.Instance.Children.Add(resource);
|
||||
|
||||
*/
|
||||
|
||||
|
||||
if (resource is IStore)
|
||||
{
|
||||
stores.Add(resource as IStore);
|
||||
if (resource is IStore)
|
||||
StoreConnected?.Invoke(resource as IStore, name);
|
||||
}
|
||||
else
|
||||
store.Put(resource);
|
||||
|
||||
resources.Add(resource.Instance.Id, resource);
|
||||
|
||||
if (storeIsOpen)
|
||||
if (parent != null)
|
||||
{
|
||||
parent.Instance.Store.AddChild(parent, resource);
|
||||
store.AddParent(resource, parent);
|
||||
//store.AddChild(parent, resource);
|
||||
|
||||
}
|
||||
|
||||
resources.Add(resource.Instance.Id, new WeakReference<IResource>(resource));
|
||||
|
||||
if (warehouseIsOpen)
|
||||
resource.Trigger(ResourceTrigger.Initialize);
|
||||
|
||||
}
|
||||
@ -430,9 +525,17 @@ namespace Esiur.Resource
|
||||
stores.Remove(resource as IStore);
|
||||
|
||||
// remove all objects associated with the store
|
||||
var toBeRemoved = resources.Values.Where(x => x.Instance.Store == resource);
|
||||
var toBeRemoved = resources.Values.Where(x => {
|
||||
IResource r;
|
||||
return x.TryGetTarget(out r) && r.Instance.Store == resource;
|
||||
});
|
||||
|
||||
foreach (var o in toBeRemoved)
|
||||
Remove(o);
|
||||
{
|
||||
IResource r;
|
||||
if (o.TryGetTarget(out r))
|
||||
Remove(r);
|
||||
}
|
||||
|
||||
StoreDisconnected?.Invoke(resource as IStore);
|
||||
}
|
||||
|
Reference in New Issue
Block a user