2
0
mirror of https://github.com/esiur/esiur-dotnet.git synced 2025-05-06 03:32:57 +00:00

AutoReconnect

This commit is contained in:
Esiur Project 2022-08-11 21:28:16 +03:00
parent af94ce318a
commit 21a2061fc4
12 changed files with 355 additions and 154 deletions

View File

@ -38,7 +38,7 @@ namespace Esiur.Core;
[AsyncMethodBuilder(typeof(AsyncReplyBuilder))]
public class AsyncReply
{
public bool Debug = false;
//public bool Debug = false;
protected List<Action<object>> callbacks = new List<Action<object>>();
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");
}

View File

@ -41,5 +41,6 @@ public enum ExceptionCode : ushort
AlreadyListened,
AlreadyUnlistened,
NotListenable,
ParseError
ParseError,
Timeout
}

View File

@ -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);
}

View File

@ -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<bool> Reconnect()
{
try
{
if (await Connect())
if (!await Connect())
return false;
try
{
try
{
var bag = new AsyncBag<IResource>();
for (var i = 0; i < resources.Keys.Count; i++)
var toBeRestored = new List<DistributedResource>();
foreach (KeyValuePair<uint, WeakReference<DistributedResource>> 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<bool> 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<bool>(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;
}

View File

@ -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<uint, DistributedResource> resources = new KeyList<uint, DistributedResource>();
KeyList<uint, DistributedResource> neededResources = new KeyList<uint, DistributedResource>();
KeyList<uint, WeakReference<DistributedResource>> attachedResources = new KeyList<uint, WeakReference<DistributedResource>>();
KeyList<uint, WeakReference<DistributedResource>> suspendedResources = new KeyList<uint, WeakReference<DistributedResource>>();
KeyList<uint, AsyncReply<DistributedResource>> resourceRequests = new KeyList<uint, AsyncReply<DistributedResource>>();
KeyList<Guid, AsyncReply<TypeTemplate>> templateRequests = new KeyList<Guid, AsyncReply<TypeTemplate>>();
KeyList<string, AsyncReply<TypeTemplate>> templateByNameRequests = new KeyList<string, AsyncReply<TypeTemplate>>();
KeyList<string, AsyncReply<IResource>> pathRequests = new KeyList<string, AsyncReply<IResource>>();
Dictionary<Guid, TypeTemplate> templates = new Dictionary<Guid, TypeTemplate>();
KeyList<uint, AsyncReply> requests = new KeyList<uint, AsyncReply>();
volatile uint callbackCounter = 0;
//List<IResource> subscriptions = new List<IResource>();
Dictionary<IResource, List<byte>> subscriptions = new Dictionary<IResource, List<byte>>();// new List<IResource>();
Dictionary<IResource, List<byte>> subscriptions = new Dictionary<IResource, List<byte>>();
// resources might get attched by the client
internal KeyList<IResource, DateTime> 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<ushort, string> SummerizeException(Exception ex)
{
@ -2115,18 +2139,18 @@ partial class DistributedConnection
*/
}
/// <summary>
/// Retrive a resource by its instance Id.
/// </summary>
/// <param name="iid">Instance Id</param>
/// <returns>Resource</returns>
public AsyncReply<IResource> Retrieve(uint iid)
{
foreach (var r in resources.Values)
if (r.Instance.Id == iid)
return new AsyncReply<IResource>(r);
return new AsyncReply<IResource>(null);
}
///// <summary>
///// Retrive a resource by its instance Id.
///// </summary>
///// <param name="iid">Instance Id</param>
///// <returns>Resource</returns>
//public AsyncReply<IResource> Retrieve(uint iid)
//{
// foreach (var r in resources.Values)
// if (r.Instance.Id == iid)
// return new AsyncReply<IResource>(r);
// return new AsyncReply<IResource>(null);
//}
public AsyncReply<TypeTemplate[]> GetLinkTemplates(string link)
@ -2173,7 +2197,15 @@ partial class DistributedConnection
/// <returns>DistributedResource</returns>
public AsyncReply<DistributedResource> Fetch(uint id, uint[] requestSequence)
{
var resource = resources[id];
DistributedResource resource = null;
attachedResources[id]?.TryGetTarget(out resource);
if (resource != null)
return new AsyncReply<DistributedResource>(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<DistributedResource>(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<DistributedResource>(dr);
reply.Trigger(dr);
}).Error(ex => reply.TriggerError(ex));

View File

@ -108,6 +108,7 @@ public class DistributedResource : DynamicObject, IResource
public uint Id
{
get { return instanceId; }
internal set { instanceId = value; }
}
/// <summary>
@ -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<object> _Invoke(byte index, Map<byte, object> 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<object>();
@ -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<bool>(true);
}
~DistributedResource()
{
Destroy();
}
}

View File

@ -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<DistributedConnection>, IResource
@ -148,11 +149,20 @@ public class DistributedServer : NetworkServer<DistributedConnection>, 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<DistributedConnection>, IResource
public KeyList<string, Delegate> Calls { get; } = new KeyList<string, Delegate>();
public void MapCall(string call, Delegate handler)
public DistributedServer MapCall(string call, Delegate handler)
{
Calls.Add(call, handler);
return this;
}
}

View File

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

View File

@ -36,8 +36,7 @@ using Esiur.Security.Authority;
namespace Esiur.Resource;
public interface IStore : IResource
{
AsyncReply<IResource> Get(string path);//, Func<IResource, bool> filter = null);
//AsyncReply<IResource> Retrieve(uint iid);
AsyncReply<IResource> Get(string path);
AsyncReply<bool> Put(IResource resource);
string Link(IResource resource);
bool Record(IResource resource, string propertyName, object value, ulong? age, DateTime? dateTime);

View File

@ -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<WeakReference<IResource>> toBeRemoved;// = stores[store];
List<WeakReference<IResource>> 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)
{

View File

@ -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<IResource> Get(string path)
{
foreach (var r in resources)
if (r.Value.Instance.Name == path)
return new AsyncReply<IResource>(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<IResource>(r.Value);
}
}
else
{
foreach (var r in resources)
if (r.Value.Instance.Name == path)
return new AsyncReply<IResource>(r.Value);
}
return new AsyncReply<IResource>(null);
}

View File

@ -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<IResource>("iip://localhost/sys/service");
var con = await Warehouse.Get<DistributedConnection>("iip://localhost", new { AutoReconnect = true });
var con = remote.Connection as DistributedConnection;
//dynamic remote = await Warehouse.Get<IResource>("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();
}
}