diff --git a/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj b/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj
index 1dfb42c..4d94287 100644
--- a/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj
+++ b/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj
@@ -11,6 +11,7 @@
http://www.esiur.com
https://github.com/esiur/esiur-dotnet/
True
+ 1.1.0
diff --git a/Esiur.Stores.MongoDB/MongoDBStore.cs b/Esiur.Stores.MongoDB/MongoDBStore.cs
index 932cbf1..ebbd106 100644
--- a/Esiur.Stores.MongoDB/MongoDBStore.cs
+++ b/Esiur.Stores.MongoDB/MongoDBStore.cs
@@ -460,7 +460,6 @@ namespace Esiur.Stores.MongoDB
var list = resourcesCollection.Find(filter).ToList();
- Console.WriteLine(list.Count);
// if (list.Count == 0)
// return new AsyncBag(new IResource[0]);
diff --git a/Esiur/Esiur.csproj b/Esiur/Esiur.csproj
index 0750132..c0e7e75 100644
--- a/Esiur/Esiur.csproj
+++ b/Esiur/Esiur.csproj
@@ -6,8 +6,8 @@
Ahmed Kh. Zamil
https://github.com/esiur/esiur-dotnet/blob/master/LICENSE
http://www.esiur.com
- False
- 1.0.0
+ true
+ 1.1.0
https://github.com/esiur/esiur-dotnet
Ahmed Kh. Zamil
diff --git a/Esiur/Net/HTTP/HTTPServer.cs b/Esiur/Net/HTTP/HTTPServer.cs
index 6e1819d..53d3e4e 100644
--- a/Esiur/Net/HTTP/HTTPServer.cs
+++ b/Esiur/Net/HTTP/HTTPServer.cs
@@ -395,7 +395,7 @@ namespace Esiur.Net.HTTP
//Console.WriteLine("IN: " + this.Connections.Count);
- foreach (IResource resource in Instance.Children)
+ foreach (var resource in Instance.Children)
{
if (resource is HTTPFilter)
{
@@ -406,7 +406,7 @@ namespace Esiur.Net.HTTP
public void Destroy()
{
- throw new NotImplementedException();
+
}
/*
diff --git a/Esiur/Net/IIP/DistributedConnection.cs b/Esiur/Net/IIP/DistributedConnection.cs
index 625c72e..205457f 100644
--- a/Esiur/Net/IIP/DistributedConnection.cs
+++ b/Esiur/Net/IIP/DistributedConnection.cs
@@ -404,9 +404,14 @@ namespace Esiur.Net.IIP
break;
// Invoke
- case IIPPacket.IIPPacketAction.InvokeFunction:
- IIPRequestInvokeFunction(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content);
+ case IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments:
+ IIPRequestInvokeFunctionArrayArguments(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content);
break;
+
+ case IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments:
+ IIPRequestInvokeFunctionNamedArguments(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content);
+ break;
+
case IIPPacket.IIPPacketAction.GetProperty:
IIPRequestGetProperty(packet.CallbackId, packet.ResourceId, packet.MethodIndex);
break;
@@ -482,10 +487,11 @@ namespace Esiur.Net.IIP
break;
// Invoke
- case IIPPacket.IIPPacketAction.InvokeFunction:
+ case IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments:
+ case IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments:
IIPReplyInvoke(packet.CallbackId, packet.Content);
-
break;
+
case IIPPacket.IIPPacketAction.GetProperty:
IIPReply(packet.CallbackId, packet.Content);
break;
diff --git a/Esiur/Net/IIP/DistributedConnectionProtocol.cs b/Esiur/Net/IIP/DistributedConnectionProtocol.cs
index 75076fc..a979e7a 100644
--- a/Esiur/Net/IIP/DistributedConnectionProtocol.cs
+++ b/Esiur/Net/IIP/DistributedConnectionProtocol.cs
@@ -100,13 +100,13 @@ namespace Esiur.Net.IIP
Send(bl.ToArray());
}
- internal AsyncReply SendInvoke(uint instanceId, byte index, object[] parameters)
+ internal AsyncReply SendInvokeByArrayArguments(uint instanceId, byte index, object[] parameters)
{
var pb = Codec.ComposeVarArray(parameters, this, true);
var reply = new AsyncReply();
callbackCounter++;
- var bl = new BinaryList((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunction),
+ var bl = new BinaryList((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments),
callbackCounter, instanceId, index, pb);
Send(bl.ToArray());
requests.Add(callbackCounter, reply);
@@ -114,6 +114,21 @@ namespace Esiur.Net.IIP
return reply;
}
+ internal AsyncReply SendInvokeByNamedArguments(uint instanceId, byte index, Structure parameters)
+ {
+ var pb = Codec.ComposeStructure(parameters, this, true, true, true);
+
+ var reply = new AsyncReply();
+ callbackCounter++;
+ var bl = new BinaryList((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments),
+ callbackCounter, instanceId, index, pb);
+ Send(bl.ToArray());
+ requests.Add(callbackCounter, reply);
+
+ return reply;
+ }
+
+
void SendError(AsyncReply.ErrorType type, uint callbackId, ushort errorCode, string errorMessage = "")
{
var msg = DC.ToBytes(errorMessage);
@@ -917,7 +932,7 @@ namespace Esiur.Net.IIP
}
- void IIPRequestInvokeFunction(uint callback, uint resourceId, byte index, byte[] content)
+ void IIPRequestInvokeFunctionArrayArguments(uint callback, uint resourceId, byte index, byte[] content)
{
//Console.WriteLine("IIPRequestInvokeFunction " + callback + " " + resourceId + " " + index);
@@ -932,12 +947,12 @@ namespace Esiur.Net.IIP
{
if (r is DistributedResource)
{
- var rt = (r as DistributedResource)._Invoke(index, arguments);
+ var rt = (r as DistributedResource)._InvokeByArrayArguments(index, arguments);
if (rt != null)
{
rt.Then(res =>
{
- SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback, Codec.Compose(res, this));
+ SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback, Codec.Compose(res, this));
});
}
else
@@ -1005,7 +1020,7 @@ namespace Esiur.Net.IIP
foreach (var v in enu)
SendChunk(callback, v);
- SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback, (byte)DataType.Void);
+ SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback, (byte)DataType.Void);
}
else if (rt is Task)
@@ -1017,7 +1032,7 @@ namespace Esiur.Net.IIP
#else
var res = t.GetType().GetProperty("Result").GetValue(t);
#endif
- SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback, Codec.Compose(res, this));
+ SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback, Codec.Compose(res, this));
});
//await t;
@@ -1027,7 +1042,7 @@ namespace Esiur.Net.IIP
{
(rt as AsyncReply).Then(res =>
{
- SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback, Codec.Compose(res, this));
+ SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback, Codec.Compose(res, this));
}).Error(ex =>
{
SendError(AsyncReply.ErrorType.Exception, callback, (ushort)ex.Code, ex.Message);
@@ -1041,7 +1056,146 @@ namespace Esiur.Net.IIP
}
else
{
- SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback, Codec.Compose(rt, this));
+ SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback, Codec.Compose(rt, this));
+ }
+ }
+ else
+ {
+ // ft found, fi not found, this should never happen
+ }
+ }
+ }
+ else
+ {
+ // no function at this index
+ }
+ });
+ }
+ else
+ {
+ // no resource with this id
+ }
+ });
+ }
+
+
+ void IIPRequestInvokeFunctionNamedArguments(uint callback, uint resourceId, byte index, byte[] content)
+ {
+
+ Warehouse.Get(resourceId).Then((r) =>
+ {
+ if (r != null)
+ {
+ Codec.ParseStructure(content, 0, (uint)content.Length, this).Then((namedArgs) =>
+ {
+ var ft = r.Instance.Template.GetFunctionTemplate(index);
+ if (ft != null)
+ {
+ if (r is DistributedResource)
+ {
+ var rt = (r as DistributedResource)._InvokeByNamedArguments(index, namedArgs);
+ if (rt != null)
+ {
+ rt.Then(res =>
+ {
+ SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback, Codec.Compose(res, this));
+ });
+ }
+ else
+ {
+
+ // function not found on a distributed object
+ }
+ }
+ else
+ {
+#if NETSTANDARD1_5
+ var fi = r.GetType().GetTypeInfo().GetMethod(ft.Name);
+#else
+ var fi = r.GetType().GetMethod(ft.Name);
+#endif
+
+ if (fi != null)
+ {
+ if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied)
+ {
+ SendError(AsyncReply.ErrorType.Management, callback,
+ (ushort)ExceptionCode.InvokeDenied);
+ return;
+ }
+
+ // cast arguments
+ ParameterInfo[] pi = fi.GetParameters();
+
+ object[] args = new object[pi.Length];
+
+ for (var i = 0; i < pi.Length; i++)
+ {
+ if (pi[i].ParameterType == typeof(DistributedConnection))
+ {
+ args[i] = this;
+ }
+ else if (namedArgs.ContainsKey(pi[i].Name))
+ {
+ args[i] = DC.CastConvert(namedArgs[pi[i].Name], pi[i].ParameterType);
+ }
+ }
+
+
+ object rt;
+
+ try
+ {
+ rt = fi.Invoke(r, args);
+ }
+ catch (Exception ex)
+ {
+ SendError(AsyncReply.ErrorType.Exception, callback, 0, ex.ToString());
+ return;
+ }
+
+ if (rt is System.Collections.IEnumerable && !(rt is Array))
+ {
+ var enu = rt as System.Collections.IEnumerable;
+
+ foreach (var v in enu)
+ SendChunk(callback, v);
+
+ SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback, (byte)DataType.Void);
+
+ }
+ else if (rt is Task)
+ {
+ (rt as Task).ContinueWith(t =>
+ {
+#if NETSTANDARD1_5
+ var res = t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t);
+#else
+ var res = t.GetType().GetProperty("Result").GetValue(t);
+#endif
+ SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback, Codec.Compose(res, this));
+ });
+
+ }
+ else if (rt is AsyncReply)
+ {
+ (rt as AsyncReply).Then(res =>
+ {
+ SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback, Codec.Compose(res, this));
+ }).Error(ex =>
+ {
+ SendError(AsyncReply.ErrorType.Exception, callback, (ushort)ex.Code, ex.Message);
+ }).Progress((pt, pv, pm) =>
+ {
+ SendProgress(callback, pv, pm);
+ }).Chunk(v =>
+ {
+ SendChunk(callback, v);
+ });
+ }
+ else
+ {
+ SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback, Codec.Compose(rt, this));
}
}
else
diff --git a/Esiur/Net/IIP/DistributedResource.cs b/Esiur/Net/IIP/DistributedResource.cs
index 5266577..78f15f3 100644
--- a/Esiur/Net/IIP/DistributedResource.cs
+++ b/Esiur/Net/IIP/DistributedResource.cs
@@ -234,7 +234,7 @@ namespace Esiur.Net.IIP
Instance.EmitResourceEvent(null, null, et.Name, args);
}
- public AsyncReply _Invoke(byte index, object[] args)
+ public AsyncReply _InvokeByNamedArguments(byte index, Structure namedArgs)
{
if (destroyed)
throw new Exception("Trying to access destroyed object");
@@ -242,28 +242,20 @@ namespace Esiur.Net.IIP
if (index >= Instance.Template.Functions.Length)
throw new Exception("Function index is incorrect");
- // var reply = new AsyncReply();
- return connection.SendInvoke(instanceId, index, args);
+ return connection.SendInvokeByNamedArguments(instanceId, index, namedArgs);
+ }
- //var parameters = Codec.ComposeVarArray(args, connection, true);
- //return connection.SendRequest(Packets.IIPPacket.IIPPacketAction.InvokeFunction, instanceId, index, parameters);
-
- /*.Then((res) =>
- {
- Codec.Parse((byte[])res[0], 0, connection).Then((rt) =>
- {
- reply.Trigger(rt);
- });
- }).Error((ex) => {
- reply.TriggerError(ex);
- }).Progress((t, pv, pm)=> {
- reply.TriggerProgress(t, pv, pm);
- }).Chunk(v => reply.TriggerChunk(v));
+ public AsyncReply _InvokeByArrayArguments(byte index, object[] args)
+ {
+ if (destroyed)
+ throw new Exception("Trying to access destroyed object");
-
- return reply;
- */
+ if (index >= Instance.Template.Functions.Length)
+ throw new Exception("Function index is incorrect");
+
+
+ return connection.SendInvokeByArrayArguments(instanceId, index, args);
}
@@ -275,7 +267,33 @@ namespace Esiur.Net.IIP
if (isAttached && ft!=null)
{
- result = _Invoke(ft.Index, args);
+ 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 namedArgs = new Structure();
+
+ var pi = type.GetProperties();
+ foreach (var p in pi)
+ namedArgs[p.Name] = p.GetValue(args[0]);
+ result = _InvokeByNamedArguments(ft.Index, namedArgs);
+ }
+ else
+ {
+ result = _InvokeByArrayArguments(ft.Index, args);
+ }
+
+ }
+ else
+ {
+ result = _InvokeByArrayArguments(ft.Index, args);
+ }
return true;
}
else
diff --git a/Esiur/Net/IIP/DistributedServer.cs b/Esiur/Net/IIP/DistributedServer.cs
index c234c52..0cec3fe 100644
--- a/Esiur/Net/IIP/DistributedServer.cs
+++ b/Esiur/Net/IIP/DistributedServer.cs
@@ -121,7 +121,7 @@ namespace Esiur.Net.IIP
}
- private void SessionModified(DistributedConnection Session, string Key, object NewValue)
+ private void SessionModified(DistributedConnection session, string key, object newValue)
{
}
diff --git a/Esiur/Net/Packets/IIPPacket.cs b/Esiur/Net/Packets/IIPPacket.cs
index 03d2fd8..714c913 100644
--- a/Esiur/Net/Packets/IIPPacket.cs
+++ b/Esiur/Net/Packets/IIPPacket.cs
@@ -109,10 +109,11 @@ namespace Esiur.Net.Packets
ResourceParents,
// Request Invoke
- InvokeFunction = 0x10,
+ InvokeFunctionArrayArguments = 0x10,
GetProperty,
GetPropertyIfModified,
SetProperty,
+ InvokeFunctionNamedArguments,
// Request Attribute
GetAllAttributes = 0x18,
@@ -517,7 +518,8 @@ namespace Esiur.Net.Packets
offset += 8;
}
- else if (Action == IIPPacketAction.InvokeFunction)
+ else if (Action == IIPPacketAction.InvokeFunctionArrayArguments
+ || Action == IIPPacketAction.InvokeFunctionNamedArguments)
{
if (NotEnough(offset, ends, 9))
return -dataLengthNeeded;
@@ -700,7 +702,8 @@ namespace Esiur.Net.Packets
Content = data.Clip(offset, cl);
offset += cl;
}
- else if (Action == IIPPacketAction.InvokeFunction
+ else if (Action == IIPPacketAction.InvokeFunctionArrayArguments
+ || Action == IIPPacketAction.InvokeFunctionNamedArguments
|| Action == IIPPacketAction.GetProperty
|| Action == IIPPacketAction.GetPropertyIfModified)
{
diff --git a/Esiur/Net/TCP/TCPServer.cs b/Esiur/Net/TCP/TCPServer.cs
index 16cd88b..b5b739b 100644
--- a/Esiur/Net/TCP/TCPServer.cs
+++ b/Esiur/Net/TCP/TCPServer.cs
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2017 Ahmed Kh. Zamil
+Copyright (c) 2017-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
@@ -95,122 +95,45 @@ namespace Esiur.Net.TCP
protected override void DataReceived(TCPConnection sender, NetworkBuffer data)
{
- //throw new NotImplementedException();
var msg = data.Read();
- foreach (Instance instance in Instance.Children)
+ foreach (var resource in Instance.Children)
{
- var f = instance.Resource as TCPFilter;
- if (f.Execute(msg, data, sender))
- return;
- }
- }
-
- private void SessionModified(TCPConnection Session, string Key, object NewValue)
- {
-
- }
-
- /*
- public TCPServer(string IP, int Port, int Timeout, int Clock)
- : base(IP, Port, Timeout, Clock)
- {
- if (Timeout > 0 && Clock > 0)
- {
- mTimer = new Timer(OnlineThread, null, 0, Clock * 1000);// TimeSpan.FromSeconds(Clock));
- mTimeout = Timeout;
- }
- }
- */
-
- /*
- private void OnlineThread(object state)
- {
- List ToBeClosed = null;
- //Console.WriteLine("Minute Thread");
-
- if (Connections.Count > 0)
- {
- Global.Log("TCPServer:OnlineThread", LogType.Debug,
- //"Tick:" + DateTime.Now.Subtract(Connections[0].LastAction).TotalSeconds + ":" + mTimeout + ":" +
- "Tick | Connections: " + Connections.Count + " Threads:" + System.Diagnostics.Process.GetCurrentProcess().Threads.Count);
- }
-
-
- try
- {
- foreach (TCPConnection c in Connections)//.Values)
+ if (resource is TCPFilter)
{
- if (DateTime.Now.Subtract(c.LastAction).TotalSeconds >= mTimeout)
- {
- if (ToBeClosed == null)
- ToBeClosed = new List();
- ToBeClosed.Add(c);
- }
- }
-
- if (ToBeClosed != null)
- {
-
- Global.Log("TCPServer:OnlineThread", LogType.Debug, "Inactive Closed:" + ToBeClosed.Count);
-
- foreach (TCPConnection c in ToBeClosed)
- c.Close();
-
- ToBeClosed.Clear();
- ToBeClosed = null;
-
-
+ var f = resource as TCPFilter;
+ if (f.Execute(msg, data, sender))
+ return;
}
}
- catch (Exception ex)
- {
- Global.Log("TCPServer:OnlineThread", LogType.Debug, ex.ToString());
- }
}
- */
- //~TCPServer()
- //{
- // StopServer();
- //}
-
-
+ private void SessionModified(TCPConnection session, string key, object newValue)
+ {
+ }
protected override void ClientConnected(TCPConnection sender)
{
- //Console.WriteLine("TCP Client Connected");
-
- // Global.Log("TCPServer",
- // LogType.Debug,
- // "Connected:" + Connections.Count
- // + ":" + sender.RemoteEndPoint.ToString());
-
- foreach (Instance instance in Instance.Children)
+ foreach (var resource in Instance.Children)
{
- var f = instance.Resource as TCPFilter;
- f.Connected(sender);
+ if (resource is TCPFilter)
+ {
+ var f = resource as TCPFilter;
+ f.Connected(sender);
+ }
}
}
protected override void ClientDisconnected(TCPConnection sender)
{
- //Console.WriteLine("TCP Client Disconnected");
-
- // Global.Log("TCPServer", LogType.Debug, "Disconnected:" + Connections.Count);// + ":" + sender.RemoteEndPoint.ToString());
-
- foreach (Instance instance in Instance.Children)
+ foreach (var resource in Instance.Children)
{
- try
+ if (resource is TCPFilter)
{
- var f = instance.Resource as TCPFilter;
+ var f = resource as TCPFilter;
f.Disconnected(sender);
}
- catch(Exception ex)
- {
- Global.Log(ex);
- }
}
}
diff --git a/Test/MyObject.cs b/Test/MyObject.cs
index 1bef6b8..4f199de 100644
--- a/Test/MyObject.cs
+++ b/Test/MyObject.cs
@@ -1,5 +1,6 @@
using Esiur.Data;
using Esiur.Engine;
+using Esiur.Net.IIP;
using Esiur.Resource;
using System;
using System.Collections.Generic;
@@ -8,20 +9,14 @@ using System.Threading;
namespace Test
{
- class MyObject : IResource
+ class MyObject : Resource
{
- public Instance Instance { get; set; }
-
- public event DestroyedEvent OnDestroy;
+
[ResourceEvent]
public event ResourceEventHanlder LevelUp;
[ResourceEvent]
public event ResourceEventHanlder LevelDown;
- public void Destroy()
- {
-
- }
public MyObject()
{
Info = new Structure();
@@ -32,10 +27,6 @@ namespace Test
Level = 5;
}
- public AsyncReply Trigger(ResourceTrigger trigger)
- {
- return new AsyncReply();
- }
[ResourceFunction]
public int Add(int value)
@@ -45,6 +36,12 @@ namespace Test
return Level;
}
+ [ResourceFunction]
+ public double Divide(float nominator, float denominator, DistributedConnection sender)
+ {
+ return nominator / denominator;
+ }
+
[ResourceFunction]
public int Subtract(int value)
{