mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2025-09-13 20:43:19 +00:00
Protocol 4
This commit is contained in:
@@ -41,20 +41,23 @@ using System.Data;
|
||||
|
||||
namespace Esiur.Resource;
|
||||
|
||||
// Centeral Resource Issuer
|
||||
public static class Warehouse
|
||||
// Central Resources Manager
|
||||
public class Warehouse
|
||||
{
|
||||
|
||||
public static Warehouse Default = new Warehouse();
|
||||
|
||||
//static byte prefixCounter;
|
||||
|
||||
//static AutoList<IStore, Instance> stores = new AutoList<IStore, Instance>(null);
|
||||
static ConcurrentDictionary<uint, WeakReference<IResource>> resources = new ConcurrentDictionary<uint, WeakReference<IResource>>();
|
||||
static ConcurrentDictionary<IStore, List<WeakReference<IResource>>> stores = new ConcurrentDictionary<IStore, List<WeakReference<IResource>>>();
|
||||
ConcurrentDictionary<uint, WeakReference<IResource>> resources = new ConcurrentDictionary<uint, WeakReference<IResource>>();
|
||||
ConcurrentDictionary<IStore, List<WeakReference<IResource>>> stores = new ConcurrentDictionary<IStore, List<WeakReference<IResource>>>();
|
||||
|
||||
|
||||
static uint resourceCounter = 0;
|
||||
uint resourceCounter = 0;
|
||||
|
||||
|
||||
static KeyList<TemplateType, KeyList<UUID, TypeTemplate>> templates
|
||||
KeyList<TemplateType, KeyList<UUID, TypeTemplate>> templates
|
||||
= new KeyList<TemplateType, KeyList<UUID, TypeTemplate>>()
|
||||
{
|
||||
//[TemplateType.Unspecified] = new KeyList<Guid, TypeTemplate>(),
|
||||
@@ -64,36 +67,33 @@ public static class Warehouse
|
||||
[TemplateType.Enum] = new KeyList<UUID, TypeTemplate>(),
|
||||
};
|
||||
|
||||
static bool warehouseIsOpen = false;
|
||||
bool warehouseIsOpen = false;
|
||||
|
||||
public delegate void StoreEvent(IStore store);//, string name);
|
||||
// public delegate void StoreDisconnectedEvent(IStore store);
|
||||
|
||||
public static event StoreEvent StoreConnected;
|
||||
//public static event StoreEvent StoreOpen;
|
||||
public static event StoreEvent StoreDisconnected;
|
||||
public delegate void StoreEvent(IStore store);
|
||||
public event StoreEvent StoreConnected;
|
||||
public event StoreEvent StoreDisconnected;
|
||||
|
||||
public delegate AsyncReply<IStore> ProtocolInstance(string name, object properties);
|
||||
|
||||
public static KeyList<string, ProtocolInstance> Protocols { get; } = GetSupportedProtocols();
|
||||
public KeyList<string, ProtocolInstance> Protocols { get; } = new KeyList<string, ProtocolInstance>();
|
||||
|
||||
private static Regex urlRegex = new Regex(@"^(?:([\S]*)://([^/]*)/?)");
|
||||
private Regex urlRegex = new Regex(@"^(?:([\S]*)://([^/]*)/?)");
|
||||
|
||||
//private static object resourcesLock = new object();
|
||||
|
||||
static KeyList<string, ProtocolInstance> GetSupportedProtocols()
|
||||
public Warehouse()
|
||||
{
|
||||
var rt = new KeyList<string, ProtocolInstance>();
|
||||
rt.Add("iip", async (name, attributes) => await Warehouse.New<DistributedConnection>(name, null, null, null, attributes));
|
||||
return rt;
|
||||
Protocols.Add("iip",
|
||||
async (name, attributes)
|
||||
=> await New<DistributedConnection>(name, null, attributes));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a store by its name.
|
||||
/// </summary>
|
||||
/// <param name="name">Store instance name</param>
|
||||
/// <returns></returns>
|
||||
public static IStore GetStore(string name)
|
||||
public IStore GetStore(string name)
|
||||
{
|
||||
foreach (var s in stores)
|
||||
if (s.Key.Instance.Name == name)
|
||||
@@ -101,14 +101,14 @@ public static class Warehouse
|
||||
return null;
|
||||
}
|
||||
|
||||
public static WeakReference<IResource>[] Resources => resources.Values.ToArray();
|
||||
public WeakReference<IResource>[] Resources => resources.Values.ToArray();
|
||||
|
||||
/// <summary>
|
||||
/// Get a resource by instance Id.
|
||||
/// </summary>
|
||||
/// <param name="id">Instance Id</param>
|
||||
/// <returns></returns>
|
||||
public static AsyncReply<IResource> GetById(uint id)
|
||||
public AsyncReply<IResource> GetById(uint id)
|
||||
{
|
||||
if (resources.ContainsKey(id))
|
||||
{
|
||||
@@ -122,7 +122,7 @@ public static class Warehouse
|
||||
return new AsyncReply<IResource>(null);
|
||||
}
|
||||
|
||||
static void LoadGenerated()
|
||||
void LoadGenerated()
|
||||
{
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
@@ -155,7 +155,7 @@ public static class Warehouse
|
||||
/// This function issues the initialize trigger to all stores and resources.
|
||||
/// </summary>
|
||||
/// <returns>True, if no problem occurred.</returns>
|
||||
public static async AsyncReply<bool> Open()
|
||||
public async AsyncReply<bool> Open()
|
||||
{
|
||||
if (warehouseIsOpen)
|
||||
return false;
|
||||
@@ -193,68 +193,16 @@ public static class Warehouse
|
||||
|
||||
foreach (var r in resSnap)
|
||||
{
|
||||
//IResource r;
|
||||
//if (rk.Value.TryGetTarget(out r))
|
||||
//{
|
||||
var rt = await r.Trigger(ResourceTrigger.SystemInitialized);
|
||||
if (!rt)
|
||||
{
|
||||
Global.Log("Warehouse", LogType.Warning, $"Resource failed at SystemInitialized {r.Instance.Name} [{r.Instance.Template.ClassName}]");
|
||||
}
|
||||
//return false;
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
/*
|
||||
var bag = new AsyncBag<bool>();
|
||||
|
||||
//foreach (var store in stores)
|
||||
// bag.Add(store.Trigger(ResourceTrigger.Initialize));
|
||||
|
||||
|
||||
bag.Seal();
|
||||
|
||||
var rt = new AsyncReply<bool>();
|
||||
bag.Then((x) =>
|
||||
{
|
||||
foreach (var b in x)
|
||||
if (!b)
|
||||
{
|
||||
rt.Trigger(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var rBag = new AsyncBag<bool>();
|
||||
foreach (var rk in resources)
|
||||
{
|
||||
IResource r;
|
||||
if (rk.Value.TryGetTarget(out r))
|
||||
rBag.Add(r.Trigger(ResourceTrigger.Initialize));
|
||||
}
|
||||
|
||||
rBag.Seal();
|
||||
|
||||
rBag.Then(y =>
|
||||
{
|
||||
foreach (var b in y)
|
||||
if (!b)
|
||||
{
|
||||
rt.Trigger(false);
|
||||
return;
|
||||
}
|
||||
|
||||
rt.Trigger(true);
|
||||
warehouseIsOpen = true;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
return rt;
|
||||
*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -262,7 +210,7 @@ public static class Warehouse
|
||||
/// This function issues terminate trigger to all resources and stores.
|
||||
/// </summary>
|
||||
/// <returns>True, if no problem occurred.</returns>
|
||||
public static AsyncReply<bool> Close()
|
||||
public AsyncReply<bool> Close()
|
||||
{
|
||||
|
||||
var bag = new AsyncBag<bool>();
|
||||
@@ -315,96 +263,20 @@ public static class Warehouse
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
private static IResource[] QureyIn(string[] path, int index, IEnumerable<IResource> resources)// AutoList<IResource, Instance> resources)
|
||||
{
|
||||
var rt = new List<IResource>();
|
||||
|
||||
if (index == path.Length - 1)
|
||||
{
|
||||
if (path[index] == "")
|
||||
foreach (IResource child in resources)
|
||||
rt.Add(child);
|
||||
else
|
||||
foreach (IResource child in resources)
|
||||
if (child.Instance.Name == path[index])
|
||||
rt.Add(child);
|
||||
}
|
||||
else
|
||||
foreach (IResource child in resources)
|
||||
if (child.Instance.Name == path[index])
|
||||
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<IResource>().Count() == 0).ToArray();
|
||||
return new AsyncReply<IResource[]>(roots);
|
||||
}
|
||||
else
|
||||
{
|
||||
var rt = new AsyncReply<IResource[]>();
|
||||
Get(path).Then(x =>
|
||||
{
|
||||
var p = path.Split('/');
|
||||
|
||||
if (x == null)
|
||||
{
|
||||
rt.Trigger(QureyIn(p, 0, stores));
|
||||
}
|
||||
else
|
||||
{
|
||||
var ar = QureyIn(p, 0, stores).Where(r => r != x).ToList();
|
||||
ar.Insert(0, x);
|
||||
rt.Trigger(ar.ToArray());
|
||||
}
|
||||
});
|
||||
|
||||
return rt;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
public static async AsyncReply<IResource[]> Query(string path)
|
||||
public async AsyncReply<IResource> Query(string path)
|
||||
{
|
||||
var p = path.Trim().TrimStart('/').Split('/');
|
||||
IResource resource;
|
||||
|
||||
foreach (var store in stores.Keys)
|
||||
{
|
||||
if (p[0] == store.Instance.Name)
|
||||
{
|
||||
|
||||
if (p.Length == 1)
|
||||
return new IResource[] { store };
|
||||
return 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 != null && children.Length > 0)
|
||||
{
|
||||
if (i == p.Length - 1)
|
||||
return children;
|
||||
else
|
||||
resource = children[0];
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -419,12 +291,9 @@ public static class Warehouse
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns>Resource instance.</returns>
|
||||
public static async AsyncReply<T> Get<T>(string path, object attributes = null, IResource parent = null, IPermissionsManager manager = null)
|
||||
public async AsyncReply<T> Get<T>(string path, object attributes = null, IResource parent = null, IPermissionsManager manager = null)
|
||||
where T : IResource
|
||||
{
|
||||
//var rt = new AsyncReply<IResource>();
|
||||
|
||||
// Should we create a new store ?
|
||||
|
||||
if (urlRegex.IsMatch(path))
|
||||
{
|
||||
@@ -441,8 +310,6 @@ public static class Warehouse
|
||||
|
||||
try
|
||||
{
|
||||
//await Put(store, url[2], null, parent, null, 0, manager, attributes);
|
||||
|
||||
if (url[3].Length > 0 && url[3] != "")
|
||||
return (T)await store.Get(url[3]);
|
||||
else
|
||||
@@ -451,79 +318,21 @@ public static class Warehouse
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Warehouse.Remove(store);
|
||||
Remove(store);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// store.Get(url[3]).Then(r =>
|
||||
// {
|
||||
// rt.Trigger(r);
|
||||
// }).Error(e =>
|
||||
// {
|
||||
// Warehouse.Remove(store);
|
||||
// rt.TriggerError(e);
|
||||
// });
|
||||
// else
|
||||
// rt.Trigger(store);
|
||||
|
||||
// store.Trigger(ResourceTrigger.Open).Then(x =>
|
||||
// {
|
||||
|
||||
// warehouseIsOpen = true;
|
||||
// await Put(store, url[2], null, parent, null, 0, manager, attributes);
|
||||
|
||||
// if (url[3].Length > 0 && url[3] != "")
|
||||
// store.Get(url[3]).Then(r =>
|
||||
// {
|
||||
// rt.Trigger(r);
|
||||
// }).Error(e =>
|
||||
// {
|
||||
// Warehouse.Remove(store);
|
||||
// rt.TriggerError(e);
|
||||
// });
|
||||
// else
|
||||
// rt.Trigger(store);
|
||||
// }).Error(e =>
|
||||
// {
|
||||
// rt.TriggerError(e);
|
||||
// //Warehouse.Remove(store);
|
||||
// });
|
||||
|
||||
// return rt;
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
//await Query(path).Then(rs =>
|
||||
//{
|
||||
// // rt.TriggerError(new Exception());
|
||||
// if (rs != null && rs.Length > 0)
|
||||
// rt.Trigger(rs.First());
|
||||
// else
|
||||
// rt.Trigger(null);
|
||||
//});
|
||||
|
||||
//return rt;
|
||||
|
||||
var res = await Query(path);
|
||||
|
||||
if (res == null || res.Length == 0)
|
||||
if (res == null)
|
||||
return default(T);
|
||||
else
|
||||
return (T)res.First();
|
||||
return (T)res;
|
||||
|
||||
}
|
||||
|
||||
|
||||
//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>
|
||||
@@ -531,29 +340,27 @@ public static class Warehouse
|
||||
/// <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<T> Put<T>(string name, T resource, IStore store = null, IResource parent = null, 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, TypeTemplate 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('/');
|
||||
var location = path.TrimStart('/').Split('/');
|
||||
|
||||
if (path.Length > 1)
|
||||
IResource parent = null;
|
||||
IStore store = null;
|
||||
var instanceName = location.Last();
|
||||
|
||||
if (location.Length > 1)
|
||||
{
|
||||
if (parent != null)
|
||||
throw new Exception("Parent can't be set when using path in instance name");
|
||||
|
||||
parent = await Warehouse.Get<IResource>(string.Join("/", path.Take(path.Length - 1)));
|
||||
parent = await Get<IResource>(string.Join("/", path.Take(path.Length - 1)));
|
||||
|
||||
if (parent == null)
|
||||
throw new Exception("Can't find parent");
|
||||
|
||||
store = store ?? parent.Instance.Store;
|
||||
store = parent.Instance.Store;
|
||||
}
|
||||
|
||||
var instanceName = path.Last();
|
||||
|
||||
|
||||
var resourceReference = new WeakReference<IResource>(resource);
|
||||
|
||||
if (store == null)
|
||||
@@ -590,10 +397,13 @@ public static class Warehouse
|
||||
throw new Exception("Can't find a store for the resource.");
|
||||
}
|
||||
|
||||
resource.Instance = new Instance(resourceCounter++, instanceName, resource, store, customTemplate, age);
|
||||
resource.Instance = new Instance(this, resourceCounter++, instanceName, resource, store, customTemplate, age);
|
||||
|
||||
if (attributes != null)
|
||||
resource.Instance.SetAttributes(Map<string, object>.FromObject(attributes));
|
||||
if (attributes is Map<string, object> attrs)
|
||||
resource.Instance.SetAttributes(attrs);
|
||||
else
|
||||
resource.Instance.SetAttributes(Map<string, object>.FromObject(attributes));
|
||||
|
||||
if (manager != null)
|
||||
resource.Instance.Managers.Add(manager);
|
||||
@@ -602,8 +412,6 @@ public static class Warehouse
|
||||
parent = null;
|
||||
|
||||
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
if (resource is IStore)
|
||||
@@ -615,16 +423,15 @@ public static class Warehouse
|
||||
//return default(T);
|
||||
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
await parent.Instance.Store.AddChild(parent, resource);
|
||||
await store.AddParent(resource, parent);
|
||||
}
|
||||
//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)
|
||||
@@ -639,15 +446,14 @@ public static class Warehouse
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Warehouse.Remove(resource);
|
||||
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)
|
||||
public async AsyncReply<IResource> New(Type type, string path, IPermissionsManager manager = null, object attributes = null, object properties = null)
|
||||
{
|
||||
|
||||
type = ResourceProxy.GetProxy(type);
|
||||
@@ -703,26 +509,20 @@ public static class Warehouse
|
||||
}
|
||||
}
|
||||
|
||||
if (store != null || parent != null || res is IStore)
|
||||
{
|
||||
await Put(name, res, store, parent, null, 0, manager, attributes);
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
return await Put(path, res, null, 0, manager, attributes);
|
||||
}
|
||||
|
||||
public static async AsyncReply<T> New<T>(string name, IStore store = null, IResource parent = null, 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)
|
||||
where T : IResource
|
||||
{
|
||||
return (T)(await New(typeof(T), name, store, parent, manager, attributes, properties));
|
||||
return (T)(await New(typeof(T), path, manager, attributes, properties));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Put a resource template in the templates warehouse.
|
||||
/// </summary>
|
||||
/// <param name="template">Resource template.</param>
|
||||
public static void PutTemplate(TypeTemplate template)
|
||||
public void PutTemplate(TypeTemplate template)
|
||||
{
|
||||
if (templates[template.Type].ContainsKey(template.ClassId))
|
||||
throw new Exception($"Template with same class Id already exists. {templates[template.Type][template.ClassId].ClassName} -> {template.ClassName}");
|
||||
@@ -736,7 +536,7 @@ public static class Warehouse
|
||||
/// </summary>
|
||||
/// <param name="type">.Net type.</param>
|
||||
/// <returns>Resource template.</returns>
|
||||
public static TypeTemplate GetTemplateByType(Type type)
|
||||
public TypeTemplate GetTemplateByType(Type type)
|
||||
{
|
||||
if (!(type.IsClass || type.IsEnum))
|
||||
return null;
|
||||
@@ -762,8 +562,8 @@ public static class Warehouse
|
||||
return template;
|
||||
|
||||
// create new template for type
|
||||
template = new TypeTemplate(baseType, true);
|
||||
TypeTemplate.GetDependencies(template);
|
||||
template = new TypeTemplate(baseType, this);
|
||||
TypeTemplate.GetDependencies(template, this);
|
||||
|
||||
return template;
|
||||
}
|
||||
@@ -773,7 +573,7 @@ public static class Warehouse
|
||||
/// </summary>
|
||||
/// <param name="classId">Class Id.</param>
|
||||
/// <returns>Resource template.</returns>
|
||||
public static TypeTemplate GetTemplateByClassId(UUID classId, TemplateType? templateType = null)
|
||||
public TypeTemplate GetTemplateByClassId(UUID classId, TemplateType? templateType = null)
|
||||
{
|
||||
if (templateType == null)
|
||||
{
|
||||
@@ -807,7 +607,7 @@ public static class Warehouse
|
||||
/// </summary>
|
||||
/// <param name="className">Class name.</param>
|
||||
/// <returns>Resource template.</returns>
|
||||
public static TypeTemplate GetTemplateByClassName(string className, TemplateType? templateType = null)
|
||||
public TypeTemplate GetTemplateByClassName(string className, TemplateType? templateType = null)
|
||||
{
|
||||
if (templateType == null)
|
||||
{
|
||||
@@ -836,14 +636,12 @@ public static class Warehouse
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Remove(IResource resource)
|
||||
public bool Remove(IResource resource)
|
||||
{
|
||||
|
||||
if (resource.Instance == null)
|
||||
return false;
|
||||
|
||||
//lock (resourcesLock)
|
||||
//{
|
||||
|
||||
WeakReference<IResource> resourceReference;
|
||||
|
||||
|
Reference in New Issue
Block a user