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) {