diff --git a/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj b/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj
index 55baa8f..3608435 100644
--- a/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj
+++ b/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj
@@ -1,7 +1,7 @@
- netstandard1.5
+ netstandard2.0
Ahmed Kh. Zamil
Esiur
Esiur MongoDB Store
@@ -11,12 +11,12 @@
http://www.esiur.com
https://github.com/esiur/esiur-dotnet/
True
- 1.2.5
+ 1.2.8
-
-
+
+
diff --git a/Esiur.Stores.MongoDB/MongoDBStore.cs b/Esiur.Stores.MongoDB/MongoDBStore.cs
index aab580f..b09f5fd 100644
--- a/Esiur.Stores.MongoDB/MongoDBStore.cs
+++ b/Esiur.Stores.MongoDB/MongoDBStore.cs
@@ -23,15 +23,22 @@ namespace Esiur.Stores.MongoDB
MongoClient client;
IMongoDatabase database;
IMongoCollection resourcesCollection;
+
+ //List storeParents = new List();
+ //List storeChildren = new List();
+
//string collectionName;
//string dbName;
- Dictionary resources = new Dictionary();
+ Dictionary resources = new Dictionary();
- public int Count
+ public long Count
{
- get { return resources.Count; }
+ get
+ {
+ return resourcesCollection.CountDocuments(x => true);
+ }// resources.Count; }
}
public void Destroy()
@@ -39,7 +46,7 @@ namespace Esiur.Stores.MongoDB
}
-
+
public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime date)
{
var objectId = resource.Instance.Attributes["objectId"].ToString();
@@ -77,21 +84,35 @@ namespace Esiur.Stores.MongoDB
return true;
}
- AsyncReply Fetch(string id)
+ AsyncReply Fetch(string id) where T : IResource
{
+
+ if (resources.ContainsKey(id) && resources[id].IsAlive)
+ {
+ if (resources[id].Target is T)
+ return new AsyncReply((T)resources[id].Target);
+ else
+ return new AsyncReply(default(T)); ;
+ }
+
var filter = Builders.Filter.Eq("_id", new BsonObjectId(new ObjectId(id)));
var list = resourcesCollection.Find(filter).ToList();
if (list.Count == 0)
- return new AsyncReply(null);
+ return new AsyncReply(default(T));
var document = list[0];
var type = Type.GetType(document["classname"].AsString);
if (type == null)
- return new AsyncReply(null);
+ return new AsyncReply(default(T));
IResource resource = (IResource)Activator.CreateInstance(ResourceProxy.GetProxy(type));
- resources.Add(document["_id"].AsObjectId.ToString(), resource);
+
+ //var iid = document["_id"].AsObjectId.ToString();
+ if (resources.ContainsKey(id))
+ resources[id] = new WeakReference(resource);
+ else
+ resources.Add(id, new WeakReference(resource));
Warehouse.Put(resource, document["name"].AsString, this);
@@ -100,14 +121,16 @@ namespace Esiur.Stores.MongoDB
var children = document["children"].AsBsonArray;
//var managers = document["managers"].AsBsonArray;
- var attributes = Parse(document["attributes"]).Then(x=> {
+ var attributes = Parse(document["attributes"]).Then(x =>
+ {
resource.Instance.SetAttributes(x as Structure);
});
var bag = new AsyncBag
\ No newline at end of file
diff --git a/Esiur/Net/DataLink/PacketServer.cs b/Esiur/Net/DataLink/PacketServer.cs
index 8eac7da..1e62ab5 100644
--- a/Esiur/Net/DataLink/PacketServer.cs
+++ b/Esiur/Net/DataLink/PacketServer.cs
@@ -72,20 +72,20 @@ namespace Esiur.Net.DataLink
{
if (trigger == ResourceTrigger.Initialize)
{
-
- foreach (Instance instance in Instance.Children)
+ /*
+ foreach (var resource in Instance.Children())
{
- if (instance.Resource is PacketFilter)
+ if (resource is PacketFilter)
{
- filters.Add(instance.Resource as PacketFilter);
+ filters.Add(resource as PacketFilter);
}
- else if (instance.Resource is PacketSource)
+ else if (resource is PacketSource)
{
- sources.Add(instance.Resource as PacketSource);
+ sources.Add(resource as PacketSource);
}
}
-
+ */
foreach (var src in sources)
{
src.OnNewPacket += PacketReceived;
diff --git a/Esiur/Net/HTTP/HTTPServer.cs b/Esiur/Net/HTTP/HTTPServer.cs
index 5b43499..5b6299a 100644
--- a/Esiur/Net/HTTP/HTTPServer.cs
+++ b/Esiur/Net/HTTP/HTTPServer.cs
@@ -44,6 +44,7 @@ namespace Esiur.Net.HTTP
public class HTTPServer : NetworkServer, IResource
{
Dictionary sessions= new Dictionary();
+ HTTPFilter[] filters = null;
public Instance Instance
{
@@ -183,13 +184,8 @@ namespace Esiur.Net.HTTP
{
//Console.WriteLine("OUT: " + this.Connections.Count);
- foreach (IResource resource in Instance.Children)
- {
- if (resource is HTTPFilter)
- {
- (resource as HTTPFilter).ClientDisconnected(sender);
- }
- }
+ foreach (var filter in filters)
+ filter.ClientDisconnected(sender);
}
@@ -268,16 +264,11 @@ namespace Esiur.Net.HTTP
try
{
- foreach (IResource resource in Instance.Children)
- {
- if (resource is HTTPFilter)
- {
- if ((resource as HTTPFilter).Execute(sender))
- return;
- }
- }
+ foreach (var resource in filters)
+ resource.Execute(sender);
+
- sender.Send("Bad Request");
+ sender.Send("Bad Request");
sender.Close();
}
catch (Exception ex)
@@ -289,21 +280,19 @@ namespace Esiur.Net.HTTP
//Console.WriteLine(ex.ToString());
//EventLog.WriteEntry("HttpServer", ex.ToString(), EventLogEntryType.Error);
- sender.Send(Return500(ex.Message));
+ sender.Send(Error500(ex.Message));
}
}
}
- private string Return500(string sMessage)
+ private string Error500(string msg)
{
- string sTMP = null;
- sTMP = "500 Internal Server Error
\r\n";
- sTMP = sTMP + "
\r\n";
- sTMP = sTMP + "500 Sorry - Internal Server Error
" + sMessage + "\r\n";
- sTMP = sTMP + "
\r\n";
- sTMP = sTMP + "
\r\n";
- return sTMP;
+ return "500 Internal Server Error
\r\n"
+ + "
\r\n"
+ + "500 Internal Server Error
" + msg + "\r\n"
+ + "
\r\n"
+ + "
\r\n";
}
@@ -382,6 +371,10 @@ namespace Esiur.Net.HTTP
Trigger(ResourceTrigger.Terminate);
Trigger(ResourceTrigger.Initialize);
}
+ else if (trigger == ResourceTrigger.SystemInitialized)
+ {
+ Instance.Children().Then(x => filters = x);
+ }
return new AsyncReply(true);
@@ -395,12 +388,9 @@ namespace Esiur.Net.HTTP
//Console.WriteLine("IN: " + this.Connections.Count);
- foreach (var resource in Instance.Children)
+ foreach (var resource in filters)
{
- if (resource is HTTPFilter)
- {
- (resource as HTTPFilter).ClientConnected(sender);
- }
+ resource.ClientConnected(sender);
}
}
diff --git a/Esiur/Net/HTTP/IIPoWS.cs b/Esiur/Net/HTTP/IIPoWS.cs
index f9cd2cd..73714f7 100644
--- a/Esiur/Net/HTTP/IIPoWS.cs
+++ b/Esiur/Net/HTTP/IIPoWS.cs
@@ -46,25 +46,31 @@ namespace Esiur.Net.HTTP
public override bool Execute(HTTPConnection sender)
{
- if (DistributedServer == null)
- return false;
+ if (sender.IsWebsocketRequest())
+ {
+ if (DistributedServer == null)
+ return false;
- var tcpSocket = sender.Unassign();
+ var tcpSocket = sender.Unassign();
- if (tcpSocket == null)
- return false;
+ if (tcpSocket == null)
+ return false;
- var httpServer = sender.Parent;
- var wsSocket = new WSSocket(tcpSocket);
- httpServer.RemoveConnection(sender);
+ var httpServer = sender.Parent;
+ var wsSocket = new WSSocket(tcpSocket);
+ httpServer.RemoveConnection(sender);
- var iipConnection = new DistributedConnection();
+ var iipConnection = new DistributedConnection();
- DistributedServer.AddConnection(iipConnection);
- iipConnection.Assign(wsSocket);
- wsSocket.Begin();
+ DistributedServer.AddConnection(iipConnection);
+ iipConnection.Assign(wsSocket);
+ wsSocket.Begin();
+
+ return true;
+ }
+
+ return false;
- return true;
/*
if (sender.Request.Filename.StartsWith("/iip/"))
{
diff --git a/Esiur/Net/IIP/DistributedConnection.cs b/Esiur/Net/IIP/DistributedConnection.cs
index cd5a3dd..3c7e918 100644
--- a/Esiur/Net/IIP/DistributedConnection.cs
+++ b/Esiur/Net/IIP/DistributedConnection.cs
@@ -312,7 +312,7 @@ namespace Esiur.Net.IIP
{
var rt = packet.Parse(msg, offset, ends);
//Console.WriteLine("Rec: " + chunkId + " " + packet.ToString());
-
+
/*
if (packet.Command == IIPPacketCommand.Event)
Console.WriteLine("Rec: " + packet.Command.ToString() + " " + packet.Event.ToString());
@@ -321,21 +321,27 @@ namespace Esiur.Net.IIP
else
Console.WriteLine("Rec: " + packet.Command.ToString() + " " + packet.Action.ToString() + " " + packet.ResourceId + " " + offset + "/" + ends);
*/
-
+
//packs.Add(packet.Command.ToString() + " " + packet.Action.ToString() + " " + packet.Event.ToString());
//if (packs.Count > 1)
- // Console.WriteLine("P2");
+ // Console.WriteLine("P2");
+
+ //Console.WriteLine("");
if (rt <= 0)
{
+ //Console.WriteLine("Hold");
var size = ends - offset;
data.HoldFor(msg, offset, size, size + (uint)(-rt));
return ends;
}
else
{
+
+ //Console.WriteLine($"CMD {packet.Command} {offset} {ends}");
+
offset += (uint)rt;
if (packet.Command == IIPPacket.IIPPacketCommand.Event)
@@ -807,7 +813,9 @@ namespace Esiur.Net.IIP
sock.Connect(domain, port).Then((x)=> {
Assign(sock);
//rt.trigger(true);
- }).Error((x) => openReply.TriggerError(x));
+ }).Error((x) =>
+ openReply.TriggerError(x)
+ );
return openReply;
}
@@ -840,6 +848,65 @@ namespace Esiur.Net.IIP
// nothing to do
return true;
}
-
+
+ AsyncReply IStore.AddChild(IResource parent, IResource child)
+ {
+ // not implemented
+ throw new NotImplementedException();
+ }
+
+ AsyncReply IStore.RemoveChild(IResource parent, IResource child)
+ {
+ // not implemeneted
+ throw new NotImplementedException();
+ }
+
+ public AsyncReply AddParent(IResource child, IResource parent)
+ {
+ throw new NotImplementedException();
+ }
+
+ public AsyncReply RemoveParent(IResource child, IResource parent)
+ {
+ throw new NotImplementedException();
+ }
+
+ public AsyncBag Children(IResource resource, string name) where T : IResource
+ {
+ throw new Exception("SS");
+
+ //if (Codec.IsLocalResource(resource, this))
+ // return new AsyncBag((resource as DistributedResource).children.Where(x => x.GetType() == typeof(T)).Select(x => (T)x));
+
+ return null;
+ }
+
+ public AsyncBag Parents(IResource resource, string name) where T : IResource
+ {
+ throw new Exception("SS");
+ //if (Codec.IsLocalResource(resource, this))
+ // return (resource as DistributedResource).parents.Where(x => x.GetType() == typeof(T)).Select(x => (T)x);
+
+ return null;
+ }
+
+ /*
+ public AsyncBag Children(IResource resource)
+ {
+ if (Codec.IsLocalResource(resource, this))
+ return (resource as DistributedResource).children.Where(x => x.GetType() == typeof(T)).Select(x => (T)x);
+
+ return null;
+ }
+
+ public AsyncBag Parents(IResource resource)
+ {
+ if (Codec.IsLocalResource(resource, this))
+ return (resource as DistributedResource).parents.Where(x => x.GetType() == typeof(T)).Select(x => (T)x);
+
+ return null;
+ }
+ */
+
}
}
diff --git a/Esiur/Net/IIP/DistributedConnectionProtocol.cs b/Esiur/Net/IIP/DistributedConnectionProtocol.cs
index a58401c..7c0bc88 100644
--- a/Esiur/Net/IIP/DistributedConnectionProtocol.cs
+++ b/Esiur/Net/IIP/DistributedConnectionProtocol.cs
@@ -387,7 +387,10 @@ namespace Esiur.Net.IIP
{
Fetch(childId).Then(child =>
{
- parent.Instance.Children.Add(child);
+ parent.children.Add(child);
+ child.parents.Add(parent);
+
+ //parent.Instance.Children.Add(child);
});
});
}
@@ -398,7 +401,10 @@ namespace Esiur.Net.IIP
{
Fetch(childId).Then(child =>
{
- parent.Instance.Children.Remove(child);
+ parent.children.Remove(child);
+ child.parents.Remove(parent);
+
+// parent.Instance.Children.Remove(child);
});
});
}
@@ -443,16 +449,16 @@ namespace Esiur.Net.IIP
r.Instance.ResourceEventOccurred -= Instance_EventOccurred;
r.Instance.ResourceModified -= Instance_PropertyModified;
r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed;
- r.Instance.Children.OnAdd -= Children_OnAdd;
- r.Instance.Children.OnRemoved -= Children_OnRemoved;
+ // r.Instance.Children.OnAdd -= Children_OnAdd;
+ // r.Instance.Children.OnRemoved -= Children_OnRemoved;
r.Instance.Attributes.OnModified -= Attributes_OnModified;
// subscribe
r.Instance.ResourceEventOccurred += Instance_EventOccurred;
r.Instance.ResourceModified += Instance_PropertyModified;
r.Instance.ResourceDestroyed += Instance_ResourceDestroyed;
- r.Instance.Children.OnAdd += Children_OnAdd;
- r.Instance.Children.OnRemoved += Children_OnRemoved;
+ //r.Instance.Children.OnAdd += Children_OnAdd;
+ //r.Instance.Children.OnRemoved += Children_OnRemoved;
r.Instance.Attributes.OnModified += Attributes_OnModified;
var link = DC.ToBytes(r.Instance.Link);
@@ -520,6 +526,28 @@ namespace Esiur.Net.IIP
.Done();
}
+
+ public bool RemoveChild(IResource parent, IResource child)
+ {
+ SendEvent(IIPPacket.IIPPacketEvent.ChildRemoved)
+ .AddUInt32((parent as DistributedResource).Id)
+ .AddUInt32((child as DistributedResource).Id)
+ .Done();
+
+ return true;
+ }
+
+ public bool AddChild(IResource parent, IResource child)
+ {
+ SendEvent(IIPPacket.IIPPacketEvent.ChildAdded)
+ .AddUInt32((parent as DistributedResource).Id)
+ .AddUInt32((child as DistributedResource).Id)
+ .Done();
+
+ return true;
+ }
+
+
void IIPRequestReattachResource(uint callback, uint resourceId, ulong resourceAge)
{
Warehouse.Get(resourceId).Then((res) =>
@@ -531,16 +559,16 @@ namespace Esiur.Net.IIP
r.Instance.ResourceEventOccurred -= Instance_EventOccurred;
r.Instance.ResourceModified -= Instance_PropertyModified;
r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed;
- r.Instance.Children.OnAdd -= Children_OnAdd;
- r.Instance.Children.OnRemoved -= Children_OnRemoved;
+ //r.Instance.Children.OnAdd -= Children_OnAdd;
+ //r.Instance.Children.OnRemoved -= Children_OnRemoved;
r.Instance.Attributes.OnModified -= Attributes_OnModified;
// subscribe
r.Instance.ResourceEventOccurred += Instance_EventOccurred;
r.Instance.ResourceModified += Instance_PropertyModified;
r.Instance.ResourceDestroyed += Instance_ResourceDestroyed;
- r.Instance.Children.OnAdd += Children_OnAdd;
- r.Instance.Children.OnRemoved += Children_OnRemoved;
+ //r.Instance.Children.OnAdd += Children_OnAdd;
+ //r.Instance.Children.OnRemoved += Children_OnRemoved;
r.Instance.Attributes.OnModified += Attributes_OnModified;
// reply ok
@@ -646,7 +674,7 @@ namespace Esiur.Net.IIP
Codec.ParseStructure(content, offset, cl, this).Then(values =>
{
-#if NETSTANDARD1_5
+#if NETSTANDARD
var constructors = Type.GetType(className).GetTypeInfo().GetConstructors();
#else
var constructors = Type.GetType(className).GetConstructors();
@@ -791,7 +819,7 @@ namespace Esiur.Net.IIP
return;
}
- parent.Instance.Children.Add(child);
+ parent.Instance.Store.AddChild(parent, child);
SendReply(IIPPacket.IIPPacketAction.AddChild, callback).Done();
//child.Instance.Parents
@@ -830,7 +858,7 @@ namespace Esiur.Net.IIP
return;
}
- parent.Instance.Children.Remove(child);
+ parent.Instance.Store.RemoveChild(parent, child);// Children.Remove(child);
SendReply(IIPPacket.IIPPacketAction.RemoveChild, callback).Done();
//child.Instance.Parents
@@ -871,9 +899,14 @@ namespace Esiur.Net.IIP
return;
}
- SendReply(IIPPacket.IIPPacketAction.ResourceChildren, callback)
- .AddUInt8Array(Codec.ComposeResourceArray(resource.Instance.Children.ToArray(), this, true))
- .Done();
+ resource.Instance.Children().Then(children =>
+ {
+ SendReply(IIPPacket.IIPPacketAction.ResourceChildren, callback)
+ .AddUInt8Array(Codec.ComposeResourceArray(children, this, true))
+ .Done();
+
+ });
+
});
}
@@ -888,9 +921,14 @@ namespace Esiur.Net.IIP
return;
}
- SendReply(IIPPacket.IIPPacketAction.ResourceParents, callback)
- .AddUInt8Array(Codec.ComposeResourceArray(resource.Instance.Parents.ToArray(), this, true))
- .Done();
+ resource.Instance.Parents().Then(parents =>
+ {
+ SendReply(IIPPacket.IIPPacketAction.ResourceParents, callback)
+ .AddUInt8Array(Codec.ComposeResourceArray(parents, this, true))
+ .Done();
+
+ });
+
});
}
@@ -1010,7 +1048,8 @@ namespace Esiur.Net.IIP
void IIPRequestQueryResources(uint callback, string resourceLink)
{
- Warehouse.Query(resourceLink).Then((r) =>
+
+ Action queryCallback = (r) =>
{
//if (r != null)
//{
@@ -1022,12 +1061,12 @@ namespace Esiur.Net.IIP
SendReply(IIPPacket.IIPPacketAction.QueryLink, callback)
.AddUInt8Array(Codec.ComposeResourceArray(list, this, true))
.Done();
- //}
- //else
- //{
- // reply failed
- //}
- });
+ };
+
+ if (Server?.EntryPoint != null)
+ Server.EntryPoint.Query(resourceLink, this).Then(queryCallback);
+ else
+ Warehouse.Query(resourceLink).ContinueWith(x => queryCallback(x.Result));
}
void IIPRequestResourceAttribute(uint callback, uint resourceId)
@@ -1068,7 +1107,7 @@ namespace Esiur.Net.IIP
}
else
{
-#if NETSTANDARD1_5
+#if NETSTANDARD
var fi = r.GetType().GetTypeInfo().GetMethod(ft.Name);
#else
var fi = r.GetType().GetMethod(ft.Name);
@@ -1134,7 +1173,7 @@ namespace Esiur.Net.IIP
{
(rt as Task).ContinueWith(t =>
{
-#if NETSTANDARD1_5
+#if NETSTANDARD
var res = t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t);
#else
var res = t.GetType().GetProperty("Result").GetValue(t);
@@ -1225,7 +1264,7 @@ namespace Esiur.Net.IIP
}
else
{
-#if NETSTANDARD1_5
+#if NETSTANDARD
var fi = r.GetType().GetTypeInfo().GetMethod(ft.Name);
#else
var fi = r.GetType().GetMethod(ft.Name);
@@ -1285,7 +1324,7 @@ namespace Esiur.Net.IIP
{
(rt as Task).ContinueWith(t =>
{
-#if NETSTANDARD1_5
+#if NETSTANDARD
var res = t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t);
#else
var res = t.GetType().GetProperty("Result").GetValue(t);
@@ -1358,7 +1397,7 @@ namespace Esiur.Net.IIP
}
else
{
-#if NETSTANDARD1_5
+#if NETSTANDARD
var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name);
#else
var pi = r.GetType().GetProperty(pt.Name);
@@ -1435,7 +1474,7 @@ namespace Esiur.Net.IIP
{
if (r.Instance.GetAge(index) > age)
{
-#if NETSTANDARD1_5
+#if NETSTANDARD
var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name);
#else
var pi = r.GetType().GetProperty(pt.Name);
@@ -1498,7 +1537,7 @@ namespace Esiur.Net.IIP
{
/*
-#if NETSTANDARD1_5
+#if NETSTANDARD
var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name);
#else
var pi = r.GetType().GetProperty(pt.Name);
@@ -1748,12 +1787,18 @@ namespace Esiur.Net.IIP
Query(path).Then(ar =>
{
+
+ //if (filter != null)
+ // ar = ar?.Where(filter).ToArray();
+
+ // MISSING: should dispatch the unused resources.
if (ar?.Length > 0)
rt.Trigger(ar[0]);
else
rt.Trigger(null);
}).Error(ex => rt.TriggerError(ex));
+
return rt;
/*
diff --git a/Esiur/Net/IIP/DistributedResource.cs b/Esiur/Net/IIP/DistributedResource.cs
index dbd6519..dfcc2c7 100644
--- a/Esiur/Net/IIP/DistributedResource.cs
+++ b/Esiur/Net/IIP/DistributedResource.cs
@@ -53,7 +53,7 @@ namespace Esiur.Net.IIP
/// Raised when the distributed resource is destroyed.
///
public event DestroyedEvent OnDestroy;
-
+ public event Instance.ResourceModifiedEvent OnModified;
uint instanceId;
DistributedConnection connection;
@@ -68,6 +68,9 @@ namespace Esiur.Net.IIP
//ulong age;
//ulong[] ages;
object[] properties;
+ internal List parents = new List();
+ internal List children = new List();
+
DistributedResourceEvent[] events;
//ResourceTemplate template;
@@ -171,10 +174,12 @@ namespace Esiur.Net.IIP
this.link = link;
this.connection = connection;
this.instanceId = instanceId;
+
//this.Instance.Template = template;
//this.Instance.Age = age;
//this.template = template;
//this.age = age;
+
}
internal void _Ready()
@@ -270,16 +275,12 @@ namespace Esiur.Net.IIP
if (args.Length == 1)
{
// Detect anonymous types
- var type = args[0].GetType().GetTypeInfo();
- var hasCompilerGeneratedAttribute = type.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Count() > 0;
- var nameContainsAnonymousType = type.FullName.Contains("AnonymousType");
- var isAnonymousType = hasCompilerGeneratedAttribute && nameContainsAnonymousType;
-
- if (isAnonymousType)
+ var type = args[0].GetType();
+ if (Codec.IsAnonymous(type))
{
var namedArgs = new Structure();
- var pi = type.GetProperties();
+ var pi = type.GetTypeInfo().GetProperties();
foreach (var p in pi)
namedArgs[p.Name] = p.GetValue(args[0]);
result = _InvokeByNamedArguments(ft.Index, namedArgs);
@@ -453,9 +454,10 @@ namespace Esiur.Net.IIP
public DistributedResource()
{
//stack = new DistributedResourceStack(this);
+ //this.Instance.ResourceModified += this.OnModified;
}
-
+
///
/// Resource interface.
///
@@ -463,6 +465,10 @@ namespace Esiur.Net.IIP
///
public AsyncReply Trigger(ResourceTrigger trigger)
{
+
+ if (trigger == ResourceTrigger.Initialize)
+ this.Instance.ResourceModified += this.OnModified;
+
// do nothing.
return new AsyncReply(true);
}
diff --git a/Esiur/Net/IIP/DistributedServer.cs b/Esiur/Net/IIP/DistributedServer.cs
index b3611c9..04e2b02 100644
--- a/Esiur/Net/IIP/DistributedServer.cs
+++ b/Esiur/Net/IIP/DistributedServer.cs
@@ -56,6 +56,12 @@ namespace Esiur.Net.IIP
set;
}
+ public EntryPoint EntryPoint
+ {
+ get;
+ set;
+ }
+
//[Storable]
//[ResourceProperty]
public ushort port
@@ -128,8 +134,7 @@ namespace Esiur.Net.IIP
protected override void ClientConnected(DistributedConnection sender)
{
- Console.WriteLine("DistributedConnection Client Connected");
-
+ //Console.WriteLine("DistributedConnection Client Connected");
}
private void Sender_OnReady(DistributedConnection sender)
diff --git a/Esiur/Net/IIP/EntryPoint.cs b/Esiur/Net/IIP/EntryPoint.cs
new file mode 100644
index 0000000..253b528
--- /dev/null
+++ b/Esiur/Net/IIP/EntryPoint.cs
@@ -0,0 +1,40 @@
+/*
+
+Copyright (c) 2019 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.Text;
+using Esiur.Core;
+using Esiur.Data;
+using Esiur.Resource;
+using Esiur.Resource.Template;
+
+namespace Esiur.Net.IIP
+{
+ public abstract class EntryPoint : Esiur.Resource.Resource
+ {
+
+ public abstract AsyncReply Query(string path, DistributedConnection sender);
+ public abstract override bool Create();
+ }
+}
diff --git a/Esiur/Net/Packets/IIPPacket.cs b/Esiur/Net/Packets/IIPPacket.cs
index 5cfb1aa..ade655a 100644
--- a/Esiur/Net/Packets/IIPPacket.cs
+++ b/Esiur/Net/Packets/IIPPacket.cs
@@ -209,8 +209,8 @@ namespace Esiur.Net.Packets
{
if (offset + needed > ends)
{
- //dataLengthNeeded = needed - (ends - offset);
- dataLengthNeeded = needed - (ends - originalOffset);
+ dataLengthNeeded = needed - (ends - offset);
+ //dataLengthNeeded = needed - (ends - originalOffset);
return true;
}
diff --git a/Esiur/Net/Sockets/TCPSocket.cs b/Esiur/Net/Sockets/TCPSocket.cs
index 9cb77fd..75b58f1 100644
--- a/Esiur/Net/Sockets/TCPSocket.cs
+++ b/Esiur/Net/Sockets/TCPSocket.cs
@@ -53,6 +53,7 @@ namespace Esiur.Net.Sockets
bool asyncSending;
bool began = false;
+
SocketState state = SocketState.Initial;
public event ISocketReceiveEvent OnReceive;
@@ -313,23 +314,23 @@ namespace Esiur.Net.Sockets
public void Close()
{
if (state != SocketState.Closed && state != SocketState.Terminated)
+ {
state = SocketState.Closed;
- if (sock.Connected)
- {
- try
+ if (sock.Connected)
{
- sock.Shutdown(SocketShutdown.Both);
- }
- catch
- {
- state = SocketState.Terminated;
+ try
+ {
+ sock.Shutdown(SocketShutdown.Both);
+ }
+ catch
+ {
+ state = SocketState.Terminated;
+ }
}
- sock.Shutdown(SocketShutdown.Both);// Close();
OnClose?.Invoke();
}
-
}
public void Send(byte[] message)
diff --git a/Esiur/Net/TCP/TCPServer.cs b/Esiur/Net/TCP/TCPServer.cs
index 3c2ccd5..05dbe73 100644
--- a/Esiur/Net/TCP/TCPServer.cs
+++ b/Esiur/Net/TCP/TCPServer.cs
@@ -65,18 +65,24 @@ namespace Esiur.Net.TCP
}
public Instance Instance { get; set; }
+ TCPFilter[] filters = null;
+
+
public AsyncReply Trigger(ResourceTrigger trigger)
{
if (trigger == ResourceTrigger.Initialize)
{
TCPSocket listener;
+
if (ip != null)
listener =new TCPSocket(new IPEndPoint(IPAddress.Parse(ip), port));
else
listener = new TCPSocket(new IPEndPoint(IPAddress.Any, port));
Start(listener, timeout, clock);
+
+
}
else if (trigger == ResourceTrigger.Terminate)
{
@@ -87,6 +93,10 @@ namespace Esiur.Net.TCP
Trigger(ResourceTrigger.Terminate);
Trigger(ResourceTrigger.Initialize);
}
+ else if (trigger == ResourceTrigger.SystemInitialized)
+ {
+ Instance.Children().Then(x => filters = x);
+ }
return new AsyncReply(true);
}
@@ -97,14 +107,10 @@ namespace Esiur.Net.TCP
{
var msg = data.Read();
- foreach (var resource in Instance.Children)
- {
- if (resource is TCPFilter)
- {
- var f = resource as TCPFilter;
- if (f.Execute(msg, data, sender))
+ foreach (var filter in filters)
+ {
+ if (filter.Execute(msg, data, sender))
return;
- }
}
}
@@ -115,25 +121,17 @@ namespace Esiur.Net.TCP
protected override void ClientConnected(TCPConnection sender)
{
- foreach (var resource in Instance.Children)
+ foreach (var filter in filters)
{
- if (resource is TCPFilter)
- {
- var f = resource as TCPFilter;
- f.Connected(sender);
- }
+ filter.Connected(sender);
}
}
protected override void ClientDisconnected(TCPConnection sender)
{
- foreach (var resource in Instance.Children)
+ foreach (var filter in filters)
{
- if (resource is TCPFilter)
- {
- var f = resource as TCPFilter;
- f.Disconnected(sender);
- }
+ filter.Disconnected(sender);
}
}
diff --git a/Esiur/Properties/PublishProfiles/FolderProfile.pubxml b/Esiur/Properties/PublishProfiles/FolderProfile.pubxml
index 2716dc5..7f2b03b 100644
--- a/Esiur/Properties/PublishProfiles/FolderProfile.pubxml
+++ b/Esiur/Properties/PublishProfiles/FolderProfile.pubxml
@@ -5,8 +5,8 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
FileSystem
- Release
- netstandard1.5
+ Debug
+ netstandard2.0
M:\opt\esiur
Any CPU
diff --git a/Esiur/Proxy/ResourceProxy.cs b/Esiur/Proxy/ResourceProxy.cs
index 45300f6..050aff0 100644
--- a/Esiur/Proxy/ResourceProxy.cs
+++ b/Esiur/Proxy/ResourceProxy.cs
@@ -12,7 +12,7 @@ namespace Esiur.Proxy
{
static Dictionary cache = new Dictionary();
-#if NETSTANDARD1_5
+#if NETSTANDARD
static MethodInfo modifyMethod = typeof(Instance).GetTypeInfo().GetMethod("Modified");
static MethodInfo instanceGet = typeof(IResource).GetTypeInfo().GetProperty("Instance").GetGetMethod();
#else
@@ -44,7 +44,7 @@ namespace Esiur.Proxy
if (cache.ContainsKey(type))
return cache[type];
-#if NETSTANDARD1_5
+#if NETSTANDARD
var typeInfo = type.GetTypeInfo();
if (typeInfo.IsSealed)
@@ -78,7 +78,7 @@ namespace Esiur.Proxy
-#if NETSTANDARD1_5
+#if NETSTANDARD
var t = typeBuilder.CreateTypeInfo().AsType();
cache.Add(type, t);
return t;
diff --git a/Esiur/Resource/IStore.cs b/Esiur/Resource/IStore.cs
index 577a252..f446451 100644
--- a/Esiur/Resource/IStore.cs
+++ b/Esiur/Resource/IStore.cs
@@ -35,13 +35,27 @@ namespace Esiur.Resource
{
public interface IStore:IResource
{
- AsyncReply Get(string path);
- AsyncReply Retrieve(uint iid);
+ AsyncReply Get(string path);//, Func filter = null);
+ //AsyncReply 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 AddChild(IResource parent, IResource child);
+ AsyncReply RemoveChild(IResource parent, IResource child);
+
+ AsyncReply AddParent(IResource child, IResource parent);
+ AsyncReply RemoveParent(IResource child, IResource parent);
+
+
+ AsyncBag Children(IResource resource, string name) where T : IResource;
+ AsyncBag Parents(IResource resource, string name) where T : IResource;
+
+
+
//AsyncReply GetPropertyRecord(IResource resource, string propertyName, ulong fromAge, ulong toAge);
//AsyncReply GetPropertyRecordByDate(IResource resource, string propertyName, DateTime fromDate, DateTime toDate);
diff --git a/Esiur/Resource/Instance.cs b/Esiur/Resource/Instance.cs
index 1524b92..f4cd329 100644
--- a/Esiur/Resource/Instance.cs
+++ b/Esiur/Resource/Instance.cs
@@ -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 children;// = new AutoList();
- IResource resource;
+ //IQueryable children;//
+ //AutoList children;// = new AutoList();
+ WeakReference resource;
IStore store;
- AutoList parents;// = new AutoList();
+ //AutoList parents;// = new AutoList();
//bool inherit;
ResourceTemplate template;
AutoList managers;// = new AutoList();
-
+
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 attributes;
List ages = new List();
@@ -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;
}
-
+
///
/// Load property value (used by stores)
///
@@ -266,13 +275,19 @@ namespace Esiur.Resource
///
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
///
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);
+ }
}
///
@@ -484,6 +514,9 @@ namespace Esiur.Resource
///
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);
+ }
}
///
@@ -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
///
/// List of parents.
///
- public AutoList Parents
- {
- get { return parents; }
- }
+ //public AutoList Parents => parents;
///
/// Store responsible for creating and keeping the resource.
@@ -572,15 +615,54 @@ namespace Esiur.Resource
///
/// List of children.
///
- public AutoList Children
- {
- get { return children; }
- }
+ // public AutoList Children => children;
///
/// The unique and permanent link to the resource.
///
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 Children(string name = null) where T : IResource
+ {
+ IResource res;
+ if (this.resource.TryGetTarget(out res))
+ {
+ //if (!(store is null))
+ return store.Children(res, name);
+ //else
+ // return (res as IStore).Children(res, name);
+ }
+ else
+ return new AsyncBag(null);
+ }
+
+ public AsyncBag Parents(string name = null) where T : IResource
+ {
+ IResource res;
+ if (this.resource.TryGetTarget(out res))
+ {
+ return store.Parents(res, name);
+ }
+ else
+ return new AsyncBag(null);
+ }
+
+ /*
{
get
{
@@ -607,6 +689,8 @@ namespace Esiur.Resource
}
}
}
+ *
+ */
///
/// Instance name.
@@ -623,7 +707,16 @@ namespace Esiur.Resource
///
public IResource Resource
{
- get { return resource; }
+ get
+ {
+ IResource res;
+ if (this.resource.TryGetTarget(out res))
+ {
+ return res;
+ }
+ else
+ return null;
+ }
}
///
@@ -658,11 +751,15 @@ namespace Esiur.Resource
/// Ruling.
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(resource);
this.id = id;
this.name = name;
this.instanceAge = age;
this.attributes = new KeyList(this);
- children = new AutoList(this);
- parents = new AutoList(this);
+ //children = new AutoList(this);
+ //parents = new AutoList(this);
managers = new AutoList(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 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)
{
diff --git a/Esiur/Resource/Resource.cs b/Esiur/Resource/Resource.cs
index 0b31c8f..990785c 100644
--- a/Esiur/Resource/Resource.cs
+++ b/Esiur/Resource/Resource.cs
@@ -36,7 +36,7 @@ namespace Esiur.Resource
public virtual void Destroy()
{
-
+ OnDestroy?.Invoke(this);
}
public virtual AsyncReply Trigger(ResourceTrigger trigger)
@@ -51,5 +51,10 @@ namespace Esiur.Resource
{
return true;
}
+
+ ~Resource()
+ {
+ Destroy();
+ }
}
}
diff --git a/Esiur/Resource/ResourceQuery.cs b/Esiur/Resource/ResourceQuery.cs
new file mode 100644
index 0000000..fb08457
--- /dev/null
+++ b/Esiur/Resource/ResourceQuery.cs
@@ -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
+ {
+ public Type ElementType => throw new NotImplementedException();
+
+ public Expression Expression => throw new NotImplementedException();
+
+ public IQueryProvider Provider => throw new NotImplementedException();
+
+ public IEnumerator GetEnumerator()
+ {
+ throw new NotImplementedException();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/Esiur/Resource/Template/ResourceTemplate.cs b/Esiur/Resource/Template/ResourceTemplate.cs
index 6e05d58..6b7e1f1 100644
--- a/Esiur/Resource/Template/ResourceTemplate.cs
+++ b/Esiur/Resource/Template/ResourceTemplate.cs
@@ -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);
diff --git a/Esiur/Resource/Warehouse.cs b/Esiur/Resource/Warehouse.cs
index 45ea9e6..6453e60 100644
--- a/Esiur/Resource/Warehouse.cs
+++ b/Esiur/Resource/Warehouse.cs
@@ -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 stores = new AutoList(null);
- static Dictionary resources = new Dictionary();
+ static AutoList stores = new AutoList(null);
+ static Dictionary> resources = new Dictionary>();
static uint resourceCounter = 0;
static KeyList templates = new KeyList();
- 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> Protocols { get; } = new KeyList>();
+ public static KeyList> Protocols { get; } = getSupportedProtocols();
+
+
+ static KeyList> getSupportedProtocols()
+ {
+ var rt = new KeyList>();
+ rt.Add("iip", () => new DistributedConnection());
+ return rt;
+ }
///
/// Get a store by its name.
@@ -77,7 +87,13 @@ namespace Esiur.Resource
public static AsyncReply Get(uint id)
{
if (resources.ContainsKey(id))
- return new AsyncReply(resources[id]);
+ {
+ IResource r;
+ if (resources[id].TryGetTarget(out r))
+ return new AsyncReply(r);
+ else
+ return new AsyncReply(null);
+ }
else
return new AsyncReply(null);
}
@@ -109,7 +125,11 @@ namespace Esiur.Resource
var rBag = new AsyncBag();
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();
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 resources)
+ /*
+ private static IResource[] QureyIn(string[] path, int index, IEnumerable resources)// AutoList resources)
{
var rt = new List();
@@ -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()));
return rt.ToArray();
}
public static AsyncReply 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().Count() == 0).ToArray();
return new AsyncReply(roots);
}
else
@@ -229,6 +263,51 @@ namespace Esiur.Resource
}
}
+ */
+
+
+
+ public static async Task Query(string path)
+ {
+ var rt = new AsyncReply();
+
+ 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(p[i]);
+ if (children.Length > 0)
+ {
+ if (i == p.Length - 1)
+ return children;
+ else
+ resource = children[0];
+ }
+ else
+ break;
+ }
+
+ return null;
+ }
+
+
+
+ return null;
+ }
///
/// Get a resource by its path.
@@ -236,38 +315,15 @@ namespace Esiur.Resource
///
///
/// Resource instance.
- public static AsyncReply Get(string path, Structure attributes = null, IResource parent = null, IPermissionsManager manager = null)
+ public static AsyncReply 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(res);
- }
+ var rt = new AsyncReply();
+
// 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();
-
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(null);
}
///
@@ -312,12 +380,31 @@ namespace Esiur.Resource
/// Resource name.
/// IStore that manages the resource. Can be null if the resource is a store.
/// Parent resource. if not presented the store becomes the parent for the resource.
- 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(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);
}
diff --git a/Esiur/Security/Permissions/ParentalPermissionsManager.cs b/Esiur/Security/Permissions/StorePermissionsManager.cs
similarity index 79%
rename from Esiur/Security/Permissions/ParentalPermissionsManager.cs
rename to Esiur/Security/Permissions/StorePermissionsManager.cs
index fb878d6..01c6102 100644
--- a/Esiur/Security/Permissions/ParentalPermissionsManager.cs
+++ b/Esiur/Security/Permissions/StorePermissionsManager.cs
@@ -33,7 +33,7 @@ using Esiur.Security.Authority;
namespace Esiur.Security.Permissions
{
- public class ParentalPermissionsManager : IPermissionsManager
+ public class StorePermissionsManager : IPermissionsManager
{
Structure settings;
@@ -41,20 +41,12 @@ namespace Esiur.Security.Permissions
public Ruling Applicable(IResource resource, Session session, ActionType action, MemberTemplate member, object inquirer = null)
{
-
- foreach (IResource parent in resource.Instance.Parents)
- {
- var ruling = parent.Instance.Applicable(session, action, member, inquirer);
- if (ruling != Ruling.DontCare)
- return ruling;
- }
-
- return Ruling.DontCare;
+ return resource.Instance.Store.Instance.Applicable(session, action, member, inquirer);
}
public bool Initialize(Structure settings, IResource resource)
{
- throw new NotImplementedException();
+ return true;
}
}
}
diff --git a/Esiur/Stores/MemoryStore.cs b/Esiur/Stores/MemoryStore.cs
index f80d048..23ef5e9 100644
--- a/Esiur/Stores/MemoryStore.cs
+++ b/Esiur/Stores/MemoryStore.cs
@@ -33,19 +33,31 @@ namespace Esiur.Stores
public AsyncReply Get(string path)
{
+ foreach (var r in resources)
+ if (r.Value.Instance.Name == path)
+ return new AsyncReply(r.Value);
+
return new AsyncReply(null);
}
public bool Put(IResource resource)
{
- resources.Add(resource.Instance.Id, resource);
+ resources.Add(resource.Instance.Id, resource);// new WeakReference(resource));
+ resource.Instance.Attributes["children"] = new AutoList(resource.Instance);
+ resource.Instance.Attributes["parents"] = new AutoList(resource.Instance);
+
return true;
}
public AsyncReply Retrieve(uint iid)
{
if (resources.ContainsKey(iid))
- return new AsyncReply(resources[iid]);
+ {
+ if (resources.ContainsKey(iid))// .TryGetTarget(out r))
+ return new AsyncReply(resources[iid]);
+ else
+ return new AsyncReply(null);
+ }
else
return new AsyncReply(null);
}
@@ -75,6 +87,59 @@ namespace Esiur.Stores
{
return true;
}
-
+
+ public AsyncReply AddChild(IResource parent, IResource child)
+ {
+ if (parent.Instance.Store == this)
+ {
+ (parent.Instance.Attributes["children"] as AutoList).Add(child);
+ return new AsyncReply(true);
+ }
+ else
+ return new AsyncReply(false);
+ }
+
+ public AsyncReply RemoveChild(IResource parent, IResource child)
+ {
+ throw new NotImplementedException();
+ }
+
+ public AsyncReply AddParent(IResource resource, IResource parent)
+ {
+
+ if (resource.Instance.Store == this)
+ {
+ (resource.Instance.Attributes["parents"] as AutoList).Add(parent);
+ return new AsyncReply(true);
+ }
+ else
+ return new AsyncReply(false);
+ }
+
+ public AsyncReply RemoveParent(IResource child, IResource parent)
+ {
+ throw new NotImplementedException();
+ }
+
+ public AsyncBag Children(IResource resource, string name) where T : IResource
+ {
+ var children = (resource.Instance.Attributes["children"] as AutoList);
+
+ if (name == null)
+ return new AsyncBag(children.Where(x=>x is T).Select(x=>(T)x).ToArray());
+ else
+ return new AsyncBag(children.Where(x => x is T && x.Instance.Name == name).Select(x => (T)x).ToArray());
+
+ }
+
+ public AsyncBag Parents(IResource resource, string name) where T : IResource
+ {
+ var parents = (resource.Instance.Attributes["parents"] as AutoList);
+
+ if (name == null)
+ return new AsyncBag(parents.Where(x => x is T).Select(x => (T)x).ToArray());
+ else
+ return new AsyncBag(parents.Where(x => x is T && x.Instance.Name == name).Select(x => (T)x).ToArray());
+ }
}
}
diff --git a/Esiur/Stores/TemporaryStore.cs b/Esiur/Stores/TemporaryStore.cs
new file mode 100644
index 0000000..c1ca559
--- /dev/null
+++ b/Esiur/Stores/TemporaryStore.cs
@@ -0,0 +1,118 @@
+using Esiur.Resource;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Esiur.Core;
+using Esiur.Data;
+using Esiur.Resource.Template;
+
+namespace Esiur.Stores
+{
+ public class TemporaryStore : IStore
+ {
+ public Instance Instance { get; set; }
+
+ public event DestroyedEvent OnDestroy;
+
+ Dictionary resources = new Dictionary();
+
+ public void Destroy()
+ {
+
+ }
+
+ public string Link(IResource resource)
+ {
+ if (resource.Instance.Store == this)
+ return this.Instance.Name + "/" + resource.Instance.Id;
+
+ return null;
+ }
+
+ public AsyncReply Get(string path)
+ {
+ foreach (var r in resources)
+ if (r.Value.IsAlive && (r.Value.Target as IResource).Instance.Name == path)
+ return new AsyncReply(r.Value.Target as IResource);
+
+ return new AsyncReply(null);
+ }
+
+ public bool Put(IResource resource)
+ {
+ resources.Add(resource.Instance.Id, new WeakReference( resource));// new WeakReference(resource));
+ return true;
+ }
+
+ public AsyncReply Retrieve(uint iid)
+ {
+ if (resources.ContainsKey(iid))
+ {
+ if (resources.ContainsKey(iid) && resources[iid].IsAlive)// .TryGetTarget(out r))
+ return new AsyncReply(resources[iid].Target as IResource);
+ else
+ return new AsyncReply(null);
+ }
+ else
+ return new AsyncReply(null);
+ }
+
+ public AsyncReply Trigger(ResourceTrigger trigger)
+ {
+ return new AsyncReply(true);
+ }
+
+ public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime)
+ {
+ throw new NotImplementedException();
+ }
+
+ public AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate)
+ {
+ throw new NotImplementedException();
+ }
+
+ public bool Remove(IResource resource)
+ {
+ resources.Remove(resource.Instance.Id);
+ return true;
+ }
+
+ public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime)
+ {
+ return true;
+ }
+
+ public AsyncReply AddChild(IResource parent, IResource child)
+ {
+ throw new NotImplementedException();
+ }
+
+ public AsyncReply RemoveChild(IResource parent, IResource child)
+ {
+ throw new NotImplementedException();
+ }
+
+ public AsyncReply AddParent(IResource child, IResource parent)
+ {
+ throw new NotImplementedException();
+ }
+
+ public AsyncReply RemoveParent(IResource child, IResource parent)
+ {
+ throw new NotImplementedException();
+ }
+
+ public AsyncBag Children(IResource resource, string name) where T : IResource
+ {
+ throw new NotImplementedException();
+ }
+
+ public AsyncBag Parents(IResource resource, string name) where T : IResource
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/Esiurd.sln b/Esiurd.sln
new file mode 100644
index 0000000..d62c2b1
Binary files /dev/null and b/Esiurd.sln differ
diff --git a/Test/MyObject.cs b/Test/MyObject.cs
index 9e6f44d..cfcce58 100644
--- a/Test/MyObject.cs
+++ b/Test/MyObject.cs
@@ -9,7 +9,7 @@ using System.Threading;
namespace Test
{
- public class MyObject : Resource
+ public class MyObject : EntryPoint
{
[ResourceEvent]
@@ -90,6 +90,16 @@ namespace Test
return reply;
}
+ public override AsyncReply Query(string path, DistributedConnection sender)
+ {
+ return new AsyncReply(new IResource[] { this });
+ }
+
+ public override bool Create()
+ {
+ return true;
+ }
+
[ResourceProperty]
public Structure Info
{
diff --git a/Test/Program.cs b/Test/Program.cs
index 2b53bf6..54c8bbb 100644
--- a/Test/Program.cs
+++ b/Test/Program.cs
@@ -51,8 +51,6 @@ namespace Test
{
- Warehouse.Protocols.Add("iip", () => new DistributedConnection());
-
// Create stores to keep objects.
var system = Warehouse.New("system");
var remote = Warehouse.New("remote");
@@ -64,12 +62,12 @@ namespace Test
// Set membership which handles authentication.
iip.Membership = Warehouse.New("ms", system);
// Start the server on port 5000.
- iip.Start(new TCPSocket(new System.Net.IPEndPoint(System.Net.IPAddress.Any, 5000)), 600000, 60000);
+ iip.Start(new TCPSocket(new System.Net.IPEndPoint(System.Net.IPAddress.Any, 500)), 600000, 60000);
// Create http server to handle IIP over Websockets
var http = Warehouse.New("http", system);
- http.Start(new TCPSocket(new System.Net.IPEndPoint(System.Net.IPAddress.Any, 5001)), 600000, 60000);
+ http.Start(new TCPSocket(new System.Net.IPEndPoint(System.Net.IPAddress.Any, 501)), 600000, 60000);
// Create IIP over Websocket HTTP module and give it to HTTP server.
var wsOverHttp = Warehouse.New("IIPoWS", system, http);
@@ -106,13 +104,10 @@ namespace Test
}
}));
else
- localObject = (MyObject)(await Warehouse.Get("db/my"));//.Then((o) => { myObject = (MyObject)o; });
+ localObject = (MyObject)(await Warehouse.Get("db/my"));
- //var obj = ProxyObject.();
- //Warehouse.Put(obj, "dd", system);
- //obj.Level2= 33;
-
+ iip.EntryPoint = localObject;
Warehouse.StoreConnected += (store, name) =>
{
@@ -160,7 +155,7 @@ namespace Test
private static async void TestClient()
{
- remoteObject = await Warehouse.Get("iip://localhost:5000/db/my", new Structure() { ["username"] = "demo", ["password"] = "1234" });
+ remoteObject = await Warehouse.Get("iip://localhost:500/db/my", new { username= "demo", password = 1234 });
dynamic x = remoteObject;