diff --git a/Esiur/Core/AsyncReply.cs b/Esiur/Core/AsyncReply.cs index 1d61129..aad464e 100644 --- a/Esiur/Core/AsyncReply.cs +++ b/Esiur/Core/AsyncReply.cs @@ -38,7 +38,7 @@ namespace Esiur.Core; [AsyncMethodBuilder(typeof(AsyncReplyBuilder))] public class AsyncReply { - public bool Debug = false; + //public bool Debug = false; protected List> callbacks = new List>(); protected object result; @@ -75,14 +75,14 @@ public class AsyncReply if (resultReady) return result; - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Wait"); + //if (Debug) + // Console.WriteLine($"AsyncReply: {Id} Wait"); //mutex = new AutoResetEvent(false); mutex.WaitOne(); - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Wait ended"); + //if (Debug) + // Console.WriteLine($"AsyncReply: {Id} Wait ended"); if (exception != null) throw exception; @@ -90,12 +90,19 @@ public class AsyncReply return result; } - public AsyncReply Timeout(int milliseconds, Action callback) + + public AsyncReply Timeout(int milliseconds, Action callback = null) { + Task.Delay(milliseconds).ContinueWith(x => { if (!resultReady && exception == null) - callback(); + { + TriggerError(new AsyncException(ErrorType.Management, + (ushort)ExceptionCode.Timeout, "Execution timeout expired.")); + + callback?.Invoke(); + } }); return this; @@ -106,8 +113,8 @@ public class AsyncReply if (resultReady) return result; - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Wait"); + //if (Debug) + // Console.WriteLine($"AsyncReply: {Id} Wait"); if (!mutex.WaitOne(millisecondsTimeout)) { @@ -116,8 +123,8 @@ public class AsyncReply throw e; } - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Wait ended"); + //if (Debug) + // Console.WriteLine($"AsyncReply: {Id} Wait ended"); return result; } @@ -138,8 +145,8 @@ public class AsyncReply if (resultReady) { - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Then ready"); + //if (Debug) + // Console.WriteLine($"AsyncReply: {Id} Then ready"); callback(result); return this; @@ -159,8 +166,8 @@ public class AsyncReply //}, null, 15000, 0); - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Then pending"); + //if (Debug) + // Console.WriteLine($"AsyncReply: {Id} Then pending"); @@ -210,8 +217,11 @@ public class AsyncReply { //timeout?.Dispose(); - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Trigger"); + if (exception != null) + return this; + + //if (Debug) + // Console.WriteLine($"AsyncReply: {Id} Trigger"); if (resultReady) return this; @@ -227,8 +237,8 @@ public class AsyncReply cb(result); - if (Debug) - Console.WriteLine($"AsyncReply: {Id} Trigger ended"); + //if (Debug) + // Console.WriteLine($"AsyncReply: {Id} Trigger ended"); } diff --git a/Esiur/Core/ExceptionCode.cs b/Esiur/Core/ExceptionCode.cs index 6ee93a7..a54e75a 100644 --- a/Esiur/Core/ExceptionCode.cs +++ b/Esiur/Core/ExceptionCode.cs @@ -41,5 +41,6 @@ public enum ExceptionCode : ushort AlreadyListened, AlreadyUnlistened, NotListenable, - ParseError + ParseError, + Timeout } diff --git a/Esiur/Data/DataDeserializer.cs b/Esiur/Data/DataDeserializer.cs index c01987b..dcb61d8 100644 --- a/Esiur/Data/DataDeserializer.cs +++ b/Esiur/Data/DataDeserializer.cs @@ -132,14 +132,12 @@ public static class DataDeserializer { fixed (byte* ptr = &data[offset]) return connection.Fetch(*(uint*)ptr, requestSequence); - } public static unsafe AsyncReply LocalResourceParser(byte[] data, uint offset, uint length, DistributedConnection connection, uint[] requestSequence) { fixed (byte* ptr = &data[offset]) return Warehouse.GetById(*(uint*)ptr); - } diff --git a/Esiur/Net/IIP/DistributedConnection.cs b/Esiur/Net/IIP/DistributedConnection.cs index deede51..859110c 100644 --- a/Esiur/Net/IIP/DistributedConnection.cs +++ b/Esiur/Net/IIP/DistributedConnection.cs @@ -41,6 +41,7 @@ using System.Diagnostics; using static Esiur.Net.Packets.IIPPacket; using Esiur.Net.HTTP; using System.Timers; +using System.Threading.Tasks; namespace Esiur.Net.IIP; public partial class DistributedConnection : NetworkConnection, IStore @@ -374,7 +375,7 @@ public partial class DistributedConnection : NetworkConnection, IStore Jitter = (uint)x[1]; keepAliveTimer.Start(); - //Console.WriteLine($"Keep Alive Received {Jitter}"); + //Console.WriteLine($"Keep Alive Received {Jitter}"); }).Error(ex => { keepAliveTimer.Stop(); @@ -1001,7 +1002,7 @@ public partial class DistributedConnection : NetworkConnection, IStore var r = new Random(); session.Id = new byte[32]; r.NextBytes(session.Id); - //SendParams((byte)0x28, session.Id); + SendParams().AddUInt8(0x28) .AddUInt8Array(session.Id) .Done(); @@ -1012,6 +1013,7 @@ public partial class DistributedConnection : NetworkConnection, IStore { ready = true; openReply?.Trigger(true); + openReply = null; OnReady?.Invoke(this); Server?.Membership?.Login(session); @@ -1020,12 +1022,16 @@ public partial class DistributedConnection : NetworkConnection, IStore }).Error(x => { openReply?.TriggerError(x); + openReply = null; + }); } else { ready = true; openReply?.Trigger(true); + openReply = null; + OnReady?.Invoke(this); Server?.Membership?.Login(session); } @@ -1125,12 +1131,20 @@ public partial class DistributedConnection : NetworkConnection, IStore { openReply?.Trigger(true); OnReady?.Invoke(this); + openReply = null; - }).Error(x => openReply?.TriggerError(x)); + + }).Error(x => + { + openReply?.TriggerError(x); + openReply = null; + }); } else { openReply?.Trigger(true); + openReply = null; + OnReady?.Invoke(this); } @@ -1140,7 +1154,9 @@ public partial class DistributedConnection : NetworkConnection, IStore } else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Error) { + invalidCredentials = true; openReply?.TriggerError(new AsyncException(ErrorType.Management, authPacket.ErrorCode, authPacket.ErrorMessage)); + openReply = null; OnError?.Invoke(this, authPacket.ErrorCode, authPacket.ErrorMessage); Close(); } @@ -1187,6 +1203,15 @@ public partial class DistributedConnection : NetworkConnection, IStore } } + [Attribute] + public ExceptionLevel ExceptionLevel { get; set; } + = ExceptionLevel.Code | ExceptionLevel.Message | ExceptionLevel.Source | ExceptionLevel.Trace; + + + bool invalidCredentials = false; + + [Attribute] + public bool AutoReconnect { get; set; } = false; [Attribute] public string Username { get; set; } @@ -1261,6 +1286,8 @@ public partial class DistributedConnection : NetworkConnection, IStore session.LocalAuthentication.Domain = domain; session.LocalAuthentication.Username = username; localPasswordOrToken = passwordOrToken; + + invalidCredentials = false; //localPassword = password; } @@ -1275,43 +1302,98 @@ public partial class DistributedConnection : NetworkConnection, IStore if (hostname != null) this._hostname = hostname; + connectSocket(socket); + + return openReply; + } + + void connectSocket(ISocket socket) + { socket.Connect(this._hostname, this._port).Then(x => { Assign(socket); }).Error((x) => { - openReply.TriggerError(x); - openReply = null; + if (AutoReconnect) + { + Console.Write("Reconnecting socket..."); + Task.Delay(5000).ContinueWith((x) => connectSocket(socket)); + } + else + { + openReply.TriggerError(x); + openReply = null; + } }); - return openReply; } public async AsyncReply Reconnect() { try { - if (await Connect()) + if (!await Connect()) + return false; + + try { - try - { - var bag = new AsyncBag(); - for (var i = 0; i < resources.Keys.Count; i++) + var toBeRestored = new List(); + foreach (KeyValuePair> kv in suspendedResources) + { + DistributedResource r; + if (kv.Value.TryGetTarget(out r)) + toBeRestored.Add(r); + } + + foreach (var r in toBeRestored) + { + + var link = DC.ToBytes(r.Link); + + Console.WriteLine("Restoreing " + r.Link); + + try { - var index = resources.Keys.ElementAt(i); - bag.Add(Fetch(index, null)); - } + var ar = await SendRequest(IIPPacket.IIPPacketAction.QueryLink) + .AddUInt16((ushort)link.Length) + .AddUInt8Array(link) + .Done(); - bag.Seal(); - await bag; - } - catch (Exception ex) - { - Global.Log(ex); - //print(ex.toString()); + var dataType = (TransmissionType)ar[0]; + var data = ar[1] as byte[]; + + if (dataType.Identifier == TransmissionTypeIdentifier.ResourceList) + { + // parse them as int + var id = data.GetUInt32(8, Endian.Little); + if (id != r.Id) + r.Id = id; + + neededResources[id] = r; + suspendedResources.Remove(id); + + await Fetch(id, null); + + } + } + catch (AsyncException ex) + { + if (ex.Code == ExceptionCode.ResourceNotFound) + { + // skip this resource + } + else + { + break; + } + } } } + catch (Exception ex) + { + Global.Log(ex); + } } catch { @@ -1331,7 +1413,7 @@ public partial class DistributedConnection : NetworkConnection, IStore public AsyncReply Put(IResource resource) { if (Codec.IsLocalResource(resource, this)) - resources.Add((resource as DistributedResource).Id, (DistributedResource)resource); + neededResources.Add((resource as DistributedResource).Id, (DistributedResource)resource); // else ... send it to the peer return new AsyncReply(true); } @@ -1394,6 +1476,7 @@ public partial class DistributedConnection : NetworkConnection, IStore { if (session.LocalAuthentication.Type == AuthenticationType.Client) Declare(); + } protected override void Disconencted() @@ -1403,6 +1486,7 @@ public partial class DistributedConnection : NetworkConnection, IStore keepAliveTimer.Stop(); + // @TODO: lock requests foreach (var x in requests.Values) { @@ -1445,17 +1529,39 @@ public partial class DistributedConnection : NetworkConnection, IStore templateRequests.Clear(); + foreach (var x in attachedResources.Values) + { + DistributedResource r; + if (x.TryGetTarget(out r)) + { + r.Suspend(); + suspendedResources[r.Id] = x; + } + } + + if (Server != null) + { + suspendedResources.Clear(); - if (Server != null) { - foreach (var x in resources.Values) - x.Suspend(); UnsubscribeAll(); Warehouse.Remove(this); if (ready) Server.Membership?.Logout(session); - }; + } + else if (AutoReconnect && !invalidCredentials) + { + // reconnect + Task.Delay(5000).ContinueWith((x) => Reconnect()); + } + else + { + suspendedResources.Clear(); + } + + + attachedResources.Clear(); ready = false; } diff --git a/Esiur/Net/IIP/DistributedConnectionProtocol.cs b/Esiur/Net/IIP/DistributedConnectionProtocol.cs index 6919e54..4e3642d 100644 --- a/Esiur/Net/IIP/DistributedConnectionProtocol.cs +++ b/Esiur/Net/IIP/DistributedConnectionProtocol.cs @@ -37,30 +37,31 @@ using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Security.Cryptography.X509Certificates; +using Esiur.Misc; namespace Esiur.Net.IIP; partial class DistributedConnection { - KeyList resources = new KeyList(); + KeyList neededResources = new KeyList(); + KeyList> attachedResources = new KeyList>(); + KeyList> suspendedResources = new KeyList>(); + KeyList> resourceRequests = new KeyList>(); KeyList> templateRequests = new KeyList>(); KeyList> templateByNameRequests = new KeyList>(); - KeyList> pathRequests = new KeyList>(); - Dictionary templates = new Dictionary(); KeyList requests = new KeyList(); volatile uint callbackCounter = 0; - //List subscriptions = new List(); - Dictionary> subscriptions = new Dictionary>();// new List(); - + Dictionary> subscriptions = new Dictionary>(); + // resources might get attched by the client internal KeyList cache = new(); object subscriptionsLock = new object(); @@ -217,6 +218,24 @@ partial class DistributedConnection } } + public async void DetachResource(uint instanceId) + { + try + { + if (attachedResources.ContainsKey(instanceId)) + attachedResources.Remove(instanceId); + + if (suspendedResources.ContainsKey(instanceId)) + suspendedResources.Remove(instanceId); + + await SendDetachRequest(instanceId); + } + catch + { + + } + } + void SendError(ErrorType type, uint callbackId, ushort errorCode, string errorMessage = "") { var msg = DC.ToBytes(errorMessage); @@ -306,11 +325,19 @@ partial class DistributedConnection void IIPEventResourceDestroyed(uint resourceId) { - if (resources.Contains(resourceId)) + if (attachedResources.Contains(resourceId)) { - var r = resources[resourceId]; - resources.Remove(resourceId); - r.Destroy(); + DistributedResource r; + + if (attachedResources[resourceId].TryGetTarget(out r)) + r.Destroy(); + + attachedResources.Remove(resourceId); + } + else if (neededResources.Contains(resourceId)) + { + // @TODO: handle this mess + neededResources.Remove(resourceId); } } @@ -1229,9 +1256,6 @@ partial class DistributedConnection } - [Attribute] - public ExceptionLevel ExceptionLevel { get; set; } - = ExceptionLevel.Code | ExceptionLevel.Message | ExceptionLevel.Source | ExceptionLevel.Trace; private Tuple SummerizeException(Exception ex) { @@ -2115,18 +2139,18 @@ partial class DistributedConnection */ } - /// - /// Retrive a resource by its instance Id. - /// - /// Instance Id - /// Resource - public AsyncReply Retrieve(uint iid) - { - foreach (var r in resources.Values) - if (r.Instance.Id == iid) - return new AsyncReply(r); - return new AsyncReply(null); - } + ///// + ///// Retrive a resource by its instance Id. + ///// + ///// Instance Id + ///// Resource + //public AsyncReply Retrieve(uint iid) + //{ + // foreach (var r in resources.Values) + // if (r.Instance.Id == iid) + // return new AsyncReply(r); + // return new AsyncReply(null); + //} public AsyncReply GetLinkTemplates(string link) @@ -2173,7 +2197,15 @@ partial class DistributedConnection /// DistributedResource public AsyncReply Fetch(uint id, uint[] requestSequence) { - var resource = resources[id]; + DistributedResource resource = null; + + attachedResources[id]?.TryGetTarget(out resource); + + if (resource != null) + return new AsyncReply(resource); + + resource = neededResources[id]; + var request = resourceRequests[id]; if (request != null) @@ -2185,7 +2217,10 @@ partial class DistributedConnection } else if (resource != null && !resource.Suspended) { + // @REVIEW: this should never happen + Global.Log("DCON", LogType.Error, "Resource not moved to attached."); return new AsyncReply(resource); + } @@ -2220,7 +2255,10 @@ partial class DistributedConnection dr = new DistributedResource(this, id, (ulong)rt[1], (string)rt[2]); } else + { dr = resource; + template = resource.Instance.Template; + } var transmissionType = (TransmissionType)rt[3]; var content = (byte[])rt[4]; @@ -2239,6 +2277,9 @@ partial class DistributedConnection dr._Attach(pvs.ToArray());// (PropertyValue[])pvs); resourceRequests.Remove(id); + // move from needed to attached. + neededResources.Remove(id); + attachedResources[id] = new WeakReference(dr); reply.Trigger(dr); }).Error(ex => reply.TriggerError(ex)); diff --git a/Esiur/Net/IIP/DistributedResource.cs b/Esiur/Net/IIP/DistributedResource.cs index af2521a..32adb86 100644 --- a/Esiur/Net/IIP/DistributedResource.cs +++ b/Esiur/Net/IIP/DistributedResource.cs @@ -108,6 +108,7 @@ public class DistributedResource : DynamicObject, IResource public uint Id { get { return instanceId; } + internal set { instanceId = value; } } /// @@ -117,7 +118,7 @@ public class DistributedResource : DynamicObject, IResource { destroyed = true; attached = false; - connection.SendDetachRequest(instanceId); + connection.DetachResource(instanceId); OnDestroy?.Invoke(this); } @@ -223,13 +224,13 @@ public class DistributedResource : DynamicObject, IResource public AsyncReply _Invoke(byte index, Map args) { if (destroyed) - throw new Exception("Trying to access a destroyed object"); + throw new Exception("Trying to access a destroyed object."); if (suspended) - throw new Exception("Trying to access suspended object"); + throw new Exception("Trying to access a suspended object."); if (index >= Instance.Template.Functions.Length) - throw new Exception("Function index is incorrect"); + throw new Exception("Function index is incorrect."); var ft = Instance.Template.GetFunctionTemplateByIndex(index); @@ -282,6 +283,12 @@ public class DistributedResource : DynamicObject, IResource public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { + if (destroyed) + throw new Exception("Trying to access a destroyed object."); + + if (suspended) + throw new Exception("Trying to access a suspended object."); + var ft = Instance.Template.GetFunctionTemplateByName(binder.Name); var reply = new AsyncReply(); @@ -361,7 +368,7 @@ public class DistributedResource : DynamicObject, IResource public override bool TryGetMember(GetMemberBinder binder, out object result) { if (destroyed) - throw new Exception("Trying to access destroyed object"); + throw new Exception("Trying to access a destroyed object."); result = null; @@ -430,10 +437,10 @@ public class DistributedResource : DynamicObject, IResource public override bool TrySetMember(SetMemberBinder binder, object value) { if (destroyed) - throw new Exception("Trying to access destroyed object"); + throw new Exception("Trying to access a destroyed object."); if (suspended) - throw new Exception("Trying to access suspended object"); + throw new Exception("Trying to access a suspended object."); if (!attached) return false; @@ -519,4 +526,9 @@ public class DistributedResource : DynamicObject, IResource // do nothing. return new AsyncReply(true); } + + ~DistributedResource() + { + Destroy(); + } } \ No newline at end of file diff --git a/Esiur/Net/IIP/DistributedServer.cs b/Esiur/Net/IIP/DistributedServer.cs index 94d6457..cbb977d 100644 --- a/Esiur/Net/IIP/DistributedServer.cs +++ b/Esiur/Net/IIP/DistributedServer.cs @@ -34,6 +34,7 @@ using Esiur.Core; using System.Net; using Esiur.Resource; using Esiur.Security.Membership; +using System.Threading.Tasks; namespace Esiur.Net.IIP; public class DistributedServer : NetworkServer, IResource @@ -148,11 +149,20 @@ public class DistributedServer : NetworkServer, IResource // base.AddConnection(connection); //} - + bool one = false; protected override void ClientConnected(DistributedConnection connection) { + // if (!one) //connection.OnReady += ConnectionReadyEventReceiver; + Task.Delay(10000).ContinueWith((x) => + { + Console.WriteLine("By bye"); + // Remove me from here + connection.Close(); + one = true; + }); + } public override void Add(DistributedConnection connection) @@ -178,9 +188,10 @@ public class DistributedServer : NetworkServer, IResource public KeyList Calls { get; } = new KeyList(); - public void MapCall(string call, Delegate handler) + public DistributedServer MapCall(string call, Delegate handler) { Calls.Add(call, handler); + return this; } } diff --git a/Esiur/Net/Sockets/TCPSocket.cs b/Esiur/Net/Sockets/TCPSocket.cs index 9cfa15a..b097ead 100644 --- a/Esiur/Net/Sockets/TCPSocket.cs +++ b/Esiur/Net/Sockets/TCPSocket.cs @@ -158,8 +158,8 @@ public class TCPSocket : ISocket { state = SocketState.Established; - //OnConnect?.Invoke(); - Receiver?.NetworkConnect(this); + //OnConnect?.Invoke(); + Receiver?.NetworkConnect(this); Begin(); rt.Trigger(true); } @@ -396,32 +396,32 @@ public class TCPSocket : ISocket public void Close() { - if (state != SocketState.Closed)// && state != SocketState.Terminated) + if (state == SocketState.Closed) + return; // && state != SocketState.Terminated) + + state = SocketState.Closed; + + if (sock.Connected) { - state = SocketState.Closed; - - if (sock.Connected) - { - try - { - sock.Shutdown(SocketShutdown.Both); - } - catch - { - - } - } - try { - sendBufferQueue?.Clear(); - Receiver?.NetworkClose(this); + sock.Shutdown(SocketShutdown.Both); } - catch (Exception ex) + catch { - Global.Log(ex); + } } + + try + { + sendBufferQueue?.Clear(); + Receiver?.NetworkClose(this); + } + catch (Exception ex) + { + Global.Log(ex); + } } public void Send(byte[] message) @@ -543,7 +543,7 @@ public class TCPSocket : ISocket public void Destroy() { - + Close(); receiveNetworkBuffer = null; @@ -560,7 +560,7 @@ public class TCPSocket : ISocket OnDestroy?.Invoke(this); OnDestroy = null; - } + } public ISocket Accept() { diff --git a/Esiur/Resource/IStore.cs b/Esiur/Resource/IStore.cs index b974c17..1760271 100644 --- a/Esiur/Resource/IStore.cs +++ b/Esiur/Resource/IStore.cs @@ -36,8 +36,7 @@ using Esiur.Security.Authority; namespace Esiur.Resource; public interface IStore : IResource { - AsyncReply Get(string path);//, Func filter = null); - //AsyncReply Retrieve(uint iid); + AsyncReply Get(string path); AsyncReply Put(IResource resource); string Link(IResource resource); bool Record(IResource resource, string propertyName, object value, ulong? age, DateTime? dateTime); diff --git a/Esiur/Resource/Warehouse.cs b/Esiur/Resource/Warehouse.cs index 9568253..322f12c 100644 --- a/Esiur/Resource/Warehouse.cs +++ b/Esiur/Resource/Warehouse.cs @@ -873,7 +873,7 @@ public static class Warehouse resources.TryRemove(resource.Instance.Id, out resourceReference); else return false; - //} + if (resource != resource.Instance.Store) { @@ -884,30 +884,16 @@ public static class Warehouse lock (((ICollection)list).SyncRoot) list.Remove(resourceReference); - //list.TryTake(resourceReference); - }//.Remove(resourceReference); + } } if (resource is IStore) { var store = resource as IStore; - List> toBeRemoved;// = stores[store]; + List> toBeRemoved; stores.TryRemove(store, out toBeRemoved); - //lock (resourcesLock) - //{ - // // remove all objects associated with the store - // toBeRemoved = resources.Values.Where(x => - // { - // IResource r; - // if (x.TryGetTarget(out r)) - // return r.Instance.Store == resource; - // else - // return false; - // }).ToArray(); - //} - foreach (var o in toBeRemoved) { diff --git a/Esiur/Stores/MemoryStore.cs b/Esiur/Stores/MemoryStore.cs index 43c23d3..58e1635 100644 --- a/Esiur/Stores/MemoryStore.cs +++ b/Esiur/Stores/MemoryStore.cs @@ -27,17 +27,30 @@ public class MemoryStore : IStore public string Link(IResource resource) { if (resource.Instance.Store == this) - return this.Instance.Name + "/" + resource.Instance.Id; + return this.Instance.Name + "/$" + resource.Instance.Id; return null; } public AsyncReply Get(string path) { - foreach (var r in resources) - if (r.Value.Instance.Name == path) - return new AsyncReply(r.Value); + if (path.StartsWith("$")) + { + uint id; + if (uint.TryParse(path.Substring(1), out id)) + { + foreach (var r in resources) + if (r.Value.Instance.Id == id) + return new AsyncReply(r.Value); + } + } + else + { + foreach (var r in resources) + if (r.Value.Instance.Name == path) + return new AsyncReply(r.Value); + } return new AsyncReply(null); } diff --git a/Test/Program.cs b/Test/Program.cs index fbc42b9..6f38399 100644 --- a/Test/Program.cs +++ b/Test/Program.cs @@ -30,7 +30,7 @@ using Esiur.Net.Sockets; using Esiur.Resource; using Esiur.Security.Permissions; using Esiur.Stores; - using System; +using System; using System.Threading; using System.Threading.Tasks; @@ -50,7 +50,7 @@ namespace Test class Program { - + static async Task Main(string[] args) { @@ -58,19 +58,20 @@ namespace Test var system = await Warehouse.Put("sys", new MemoryStore()); var server = await Warehouse.Put("sys/server", new DistributedServer()); - server.MapCall("Hello", (string msg, DateTime time, DistributedConnection sender) => - { - Console.WriteLine(msg); - return "Hi " + DateTime.UtcNow; - }); - var web = await Warehouse.Put("sys/web", new HTTPServer() { Port = 8088}); + var web = await Warehouse.Put("sys/web", new HTTPServer() { Port = 8088 }); var service = await Warehouse.Put("sys/service", new MyService()); var res1 = await Warehouse.Put("sys/service/r1", new MyResource() { Description = "Testing 1", CategoryId = 10 }); var res2 = await Warehouse.Put("sys/service/r2", new MyResource() { Description = "Testing 2", CategoryId = 11 }); var res3 = await Warehouse.Put("sys/service/c1", new MyChildResource() { ChildName = "Child 1", Description = "Child Testing 3", CategoryId = 12 }); + var res4 = await Warehouse.Put("sys/service/c2", new MyChildResource() { ChildName = "Child 2 Destroy", Description = "Testing Destroy Handler", CategoryId = 12 }); + server.MapCall("Hello", (string msg, DateTime time, DistributedConnection sender) => + { + Console.WriteLine(msg); + return "Hi " + DateTime.UtcNow; + }).MapCall("temp", () => res4); service.Resource = res1; service.ChildResource = res3; @@ -84,7 +85,8 @@ namespace Test // sender.Send("Not found"); //}); - web.MapGet("/", (HTTPConnection sender) => { + web.MapGet("/", (HTTPConnection sender) => + { sender.Send("Hello"); }); @@ -92,19 +94,26 @@ namespace Test // Start testing TestClient(service); - // TestClient(service); + // TestClient(service); } - + private static async void TestClient(IResource local) { - dynamic remote = await Warehouse.Get("iip://localhost/sys/service"); + var con = await Warehouse.Get("iip://localhost", new { AutoReconnect = true }); - var con = remote.Connection as DistributedConnection; + //dynamic remote = await Warehouse.Get("iip://localhost/sys/service", new { AutoReconnect = true }); + + //var con = remote.Connection as DistributedConnection; + + dynamic remote = await con.Get("sys/service"); var pcall = await con.Call("Hello", "whats up ?", DateTime.UtcNow); + var temp = await con.Call("temp"); + Console.WriteLine("Temp: " + temp.GetHashCode()); + var template = await con.GetTemplateByClassName("Test.MyResource"); @@ -141,30 +150,44 @@ namespace Test await remote.InvokeEvents("Hello"); - //var childTemplate = remote.Child.Instance.Template; - var path = TemplateGenerator.GetTemplate("iip://localhost/sys/service", "Generated"); + //var path = TemplateGenerator.GetTemplate("iip://localhost/sys/service", "Generated"); - Console.WriteLine(path); + //Console.WriteLine(path); + perodicTimer = new Timer(new TimerCallback(perodicTimerElapsed), remote, 0, 1000); } - + static async void perodicTimerElapsed(object state) + { + GC.Collect(); + try + { + dynamic remote = state; + Console.WriteLine("Perodic : " + await remote.AsyncHello()); + } + catch (Exception ex) + { + Console.WriteLine("Perodic : " + ex.ToString()); + } + } + + static Timer perodicTimer; static void TestObjectProps(IResource local, DistributedResource remote) { - foreach(var pt in local.Instance.Template.Properties) + foreach (var pt in local.Instance.Template.Properties) { var lv = pt.PropertyInfo.GetValue(local); object v; var rv = remote.TryGetPropertyValue(pt.Index, out v); if (!rv) - Console.WriteLine($" ** {pt.Name } Failed"); + Console.WriteLine($" ** {pt.Name} Failed"); else - Console.WriteLine($"{pt.Name } {GetString(lv)} == {GetString(v)}"); + Console.WriteLine($"{pt.Name} {GetString(lv)} == {GetString(v)}"); } } @@ -189,15 +212,16 @@ namespace Test rt += GetString(ar.GetValue(ar.Length - 1)) + "]"; return rt; - } else if (value is IRecord) - { - return "{" + String.Join(", ", t.GetProperties().Select(x => x.Name + ": " + x.GetValue(value))) + "}"; } - + else if (value is IRecord) + { + return "{" + String.Join(", ", t.GetProperties().Select(x => x.Name + ": " + x.GetValue(value))) + "}"; + } + else return value.ToString(); } - + }