From 2d9f61c0d9ed4252295f222b3fcad8274a996242 Mon Sep 17 00:00:00 2001 From: Ahmed Zamil Date: Sun, 21 Jul 2019 05:29:58 +0300 Subject: [PATCH] AsyncReply is awaitable --- .../Esiur.Stores.MongoDB.csproj | 2 +- Esiur.Stores.MongoDB/MongoDBStore.cs | 17 +- Esiur/Data/Codec.cs | 39 ++-- Esiur/Engine/AsyncAwaiter.cs | 40 ++++ Esiur/Engine/AsyncBag.cs | 14 +- Esiur/Engine/AsyncException.cs | 16 +- Esiur/Engine/AsyncQueue.cs | 12 +- Esiur/Engine/AsyncReply.cs | 12 +- Esiur/Engine/AsyncReplyGeneric.cs | 179 +++++++++++++++++- Esiur/Engine/ErrorType.cs | 12 ++ Esiur/Engine/IAsyncReply.cs | 21 ++ Esiur/Engine/ProgressType.cs | 12 ++ Esiur/Esiur.csproj | 7 +- Esiur/Net/DataLink/PacketFilter.cs | 2 +- Esiur/Net/HTTP/IIPoWS.cs | 29 +++ Esiur/Net/IIP/DistributedConnection.cs | 12 +- .../Net/IIP/DistributedConnectionProtocol.cs | 137 +++++++------- Esiur/Net/IIP/DistributedResource.cs | 10 +- Esiur/Resource/IStore.cs | 1 + Esiur/Resource/Template/FunctionTemplate.cs | 2 +- Esiur/Resource/Template/PropertyTemplate.cs | 6 +- Esiur/Resource/Template/ResourceTemplate.cs | 4 +- Esiur/Resource/Warehouse.cs | 38 +++- Esiur/Stores/MemoryStore.cs | 5 + Test/MyObject.cs | 12 +- Test/Program.cs | 133 ++++++------- 26 files changed, 561 insertions(+), 213 deletions(-) create mode 100644 Esiur/Engine/AsyncAwaiter.cs create mode 100644 Esiur/Engine/ErrorType.cs create mode 100644 Esiur/Engine/IAsyncReply.cs create mode 100644 Esiur/Engine/ProgressType.cs diff --git a/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj b/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj index 4d94287..8aa98d7 100644 --- a/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj +++ b/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj @@ -11,7 +11,7 @@ http://www.esiur.com https://github.com/esiur/esiur-dotnet/ True - 1.1.0 + 1.2.0 diff --git a/Esiur.Stores.MongoDB/MongoDBStore.cs b/Esiur.Stores.MongoDB/MongoDBStore.cs index ebbd106..40dce94 100644 --- a/Esiur.Stores.MongoDB/MongoDBStore.cs +++ b/Esiur.Stores.MongoDB/MongoDBStore.cs @@ -185,7 +185,7 @@ namespace Esiur.Stores.MongoDB return rt; } - AsyncReply Parse(BsonValue value) + IAsyncReply Parse(BsonValue value) { if (value.BsonType == BsonType.Document) { @@ -217,7 +217,7 @@ namespace Esiur.Stores.MongoDB return rt; } else - return new AsyncReply(null); + return new AsyncReply(null); } else if (value.BsonType == BsonType.Array) { @@ -233,12 +233,12 @@ namespace Esiur.Stores.MongoDB } else if (value.BsonType == BsonType.DateTime) { - return new AsyncReply(value.ToUniversalTime()); + return new AsyncReply(value.ToUniversalTime()); } else { - return new AsyncReply(value.RawValue); + return new AsyncReply(value.RawValue); } } @@ -633,7 +633,7 @@ namespace Esiur.Stores.MongoDB var reply = new AsyncReply>(); - AsyncBag bag = new AsyncBag(); + AsyncBag bag = new AsyncBag(); foreach (var p in properties) bag.Add(GetPropertyRecordByAge(resource, p.Name, fromAge, toAge)); @@ -642,7 +642,7 @@ namespace Esiur.Stores.MongoDB bag.Then(x => { - var list = new KeyList(); + var list = new KeyList(); for (var i = 0; i < x.Length; i++) list.Add(properties[i], x[i]); @@ -696,5 +696,10 @@ namespace Esiur.Stores.MongoDB return true; } + + public AsyncReply Open(Structure settings) + { + return new AsyncReply(true); + } } } diff --git a/Esiur/Data/Codec.cs b/Esiur/Data/Codec.cs index d8ff15b..cc79fc9 100644 --- a/Esiur/Data/Codec.cs +++ b/Esiur/Data/Codec.cs @@ -171,7 +171,7 @@ namespace Esiur.Data var result = (StructureComparisonResult)data[offset++]; - AsyncReply previous = null; + IAsyncReply previous = null; // string[] previousKeys = null; // DataType[] previousTypes = null; @@ -362,7 +362,7 @@ namespace Esiur.Data /// DistributedConnection is required in case a structure in the array holds items at the other end. /// DataType, in case the data is not prepended with DataType /// Structure - public static AsyncReply Parse(byte[] data, uint offset, DistributedConnection connection, DataType dataType = DataType.Unspecified) + public static IAsyncReply Parse(byte[] data, uint offset, DistributedConnection connection, DataType dataType = DataType.Unspecified) { uint size; return Parse(data, offset, out size, connection); @@ -377,10 +377,9 @@ namespace Esiur.Data /// DistributedConnection is required in case a structure in the array holds items at the other end. /// DataType, in case the data is not prepended with DataType /// Value - public static AsyncReply Parse(byte[] data, uint offset, out uint size, DistributedConnection connection, DataType dataType = DataType.Unspecified) + public static IAsyncReply Parse(byte[] data, uint offset, out uint size, DistributedConnection connection, DataType dataType = DataType.Unspecified) { - var reply = new AsyncReply(); - + bool isArray; DataType t; @@ -480,40 +479,40 @@ namespace Esiur.Data return new AsyncReply(null); case DataType.Bool: - return new AsyncReply(data.GetBoolean(offset)); + return new AsyncReply(data.GetBoolean(offset)); case DataType.UInt8: - return new AsyncReply(data[offset]); + return new AsyncReply(data[offset]); case DataType.Int8: - return new AsyncReply((sbyte)data[offset]); + return new AsyncReply((sbyte)data[offset]); case DataType.Char: - return new AsyncReply(data.GetChar(offset)); + return new AsyncReply(data.GetChar(offset)); case DataType.Int16: - return new AsyncReply(data.GetInt16(offset)); + return new AsyncReply(data.GetInt16(offset)); case DataType.UInt16: - return new AsyncReply(data.GetUInt16(offset)); + return new AsyncReply(data.GetUInt16(offset)); case DataType.Int32: - return new AsyncReply(data.GetInt32(offset)); + return new AsyncReply(data.GetInt32(offset)); case DataType.UInt32: - return new AsyncReply(data.GetUInt32(offset)); + return new AsyncReply(data.GetUInt32(offset)); case DataType.Int64: - return new AsyncReply(data.GetInt64(offset)); + return new AsyncReply(data.GetInt64(offset)); case DataType.UInt64: - return new AsyncReply(data.GetUInt64(offset)); + return new AsyncReply(data.GetUInt64(offset)); case DataType.Float32: - return new AsyncReply(data.GetFloat32(offset)); + return new AsyncReply(data.GetFloat32(offset)); case DataType.Float64: - return new AsyncReply(data.GetFloat64(offset)); + return new AsyncReply(data.GetFloat64(offset)); case DataType.String: return new AsyncReply(data.GetString(offset, contentLength)); @@ -525,7 +524,7 @@ namespace Esiur.Data return ParseDistributedResource(data, offset, connection); case DataType.DateTime: - return new AsyncReply(data.GetDateTime(offset)); + return new AsyncReply(data.GetDateTime(offset)); case DataType.Structure: return ParseStructure(data, offset, contentLength, connection); @@ -694,7 +693,7 @@ namespace Esiur.Data // var result = (ResourceComparisonResult)data[offset++]; - AsyncReply previous = null; + IAsyncReply previous = null; if (result == ResourceComparisonResult.Null) previous = new AsyncReply(null); @@ -716,7 +715,7 @@ namespace Esiur.Data { result = (ResourceComparisonResult)data[offset++]; - AsyncReply current = null; + IAsyncReply current = null; if (result == ResourceComparisonResult.Null) { diff --git a/Esiur/Engine/AsyncAwaiter.cs b/Esiur/Engine/AsyncAwaiter.cs new file mode 100644 index 0000000..2c1af2e --- /dev/null +++ b/Esiur/Engine/AsyncAwaiter.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; + +namespace Esiur.Engine +{ + public class AsyncAwaiter : INotifyCompletion + { + Action callback = null; + T result; + private bool completed; + + public AsyncAwaiter(AsyncReply reply) + { + reply.Then(x => + { + completed = true; + result = x; + callback?.Invoke(); + }); + } + + public T GetResult() + { + return result; + } + + public bool IsCompleted => completed; + + //From INotifyCompletion + public void OnCompleted(Action continuation) + { + Console.WriteLine("Continue...."); + } + + + + } +} diff --git a/Esiur/Engine/AsyncBag.cs b/Esiur/Engine/AsyncBag.cs index 8ac4f95..e277df5 100644 --- a/Esiur/Engine/AsyncBag.cs +++ b/Esiur/Engine/AsyncBag.cs @@ -30,21 +30,23 @@ using System.Threading.Tasks; namespace Esiur.Engine { - public class AsyncBag:AsyncReply + public class AsyncBag: AsyncReply { //Dictionary results = new Dictionary(); - List replies = new List(); + List> replies = new List>(); List results = new List(); int count = 0; bool sealedBag = false; + /* public AsyncBag Then(Action callback) { base.Then(new Action(o => callback((T[])o))); return this; } + */ public void Seal() { @@ -72,7 +74,7 @@ namespace Esiur.Engine } } - public void Add(AsyncReply reply) + public void Add(IAsyncReply reply) { if (!sealedBag) { @@ -82,6 +84,12 @@ namespace Esiur.Engine //results.Add(reply, default(T)); } + public void AddBag(AsyncBag bag) + { + foreach (var r in bag.replies) + Add(r); + } + public AsyncBag() { diff --git a/Esiur/Engine/AsyncException.cs b/Esiur/Engine/AsyncException.cs index ecc75a3..fea9a4b 100644 --- a/Esiur/Engine/AsyncException.cs +++ b/Esiur/Engine/AsyncException.cs @@ -63,23 +63,21 @@ namespace Esiur.Engine { - AsyncReply.ErrorType type; - ExceptionCode code; + public readonly ErrorType Type; + public readonly ExceptionCode Code; - public AsyncReply.ErrorType Type => type; - public ExceptionCode Code => code; - public AsyncException(AsyncReply.ErrorType type, ushort code, string message) - : base(type == AsyncReply.ErrorType.Management ? ((ExceptionCode)code).ToString() : message) + public AsyncException(ErrorType type, ushort code, string message) + : base(type == ErrorType.Management ? ((ExceptionCode)code).ToString() : message) { - this.type = type; - this.code = (ExceptionCode)code; + this.Type = type; + this.Code = (ExceptionCode)code; } public override string ToString() { - return code.ToString() + ": " + Message; + return Code.ToString() + ": " + Message; } } } diff --git a/Esiur/Engine/AsyncQueue.cs b/Esiur/Engine/AsyncQueue.cs index 3900f50..4ad2c0e 100644 --- a/Esiur/Engine/AsyncQueue.cs +++ b/Esiur/Engine/AsyncQueue.cs @@ -30,18 +30,18 @@ using System.Threading.Tasks; namespace Esiur.Engine { - public class AsyncQueue : AsyncReply + public class AsyncQueue : AsyncReply { List> list = new List>(); //Action callback; object queueLock = new object(); - public AsyncQueue Then(Action callback) - { - base.Then(new Action(o => callback((T)o))); + //public AsyncQueue Then(Action callback) + //{ + // base.Then(new Action(o => callback((T)o))); - return this; - } + //return this; + //} public void Add(AsyncReply reply) { diff --git a/Esiur/Engine/AsyncReply.cs b/Esiur/Engine/AsyncReply.cs index 6d4b822..5105337 100644 --- a/Esiur/Engine/AsyncReply.cs +++ b/Esiur/Engine/AsyncReply.cs @@ -32,17 +32,9 @@ namespace Esiur.Engine { public class AsyncReply { - public enum ErrorType - { - Management, - Exception - } + + - public enum ProgressType - { - Execution, - Network, - } protected List> callbacks = new List>(); protected object result; diff --git a/Esiur/Engine/AsyncReplyGeneric.cs b/Esiur/Engine/AsyncReplyGeneric.cs index 9546703..c32c0b2 100644 --- a/Esiur/Engine/AsyncReplyGeneric.cs +++ b/Esiur/Engine/AsyncReplyGeneric.cs @@ -29,13 +29,175 @@ using System.Text; using System.Threading.Tasks; using Esiur.Resource; using System.Reflection; +using System.Threading; +using System.Runtime.CompilerServices; namespace Esiur.Engine { - public class AsyncReply: AsyncReply + public class AsyncReply: IAsyncReply { + + protected List> callbacks = new List>(); + protected T result; + + protected List> errorCallbacks = new List>(); - public AsyncReply Then(Action callback) + protected List> progressCallbacks = new List>(); + + protected List> chunkCallbacks = new List>(); + + //List awaiters = new List(); + + object callbacksLock = new object(); + + protected bool resultReady = false; + AsyncException exception; + + TaskCompletionSource tcs = new TaskCompletionSource(); + + + public bool Ready + { + get { return resultReady; } + + } + + + + public object Result + { + get { return result; } + } + + public IAsyncReply Then(Action callback) + { + callbacks.Add(callback); + + if (resultReady) + callback(result); + + return this; + } + + public IAsyncReply Error(Action callback) + { + errorCallbacks.Add(callback); + + if (exception != null) + { + callback(exception); + tcs.SetException(exception); + } + + return this; + } + + public IAsyncReply Progress(Action callback) + { + progressCallbacks.Add(callback); + return this; + } + + + public IAsyncReply Chunk(Action callback) + { + chunkCallbacks.Add(callback); + return this; + } + + public void Trigger(object result) + { + + lock (callbacksLock) + { + if (resultReady) + return; + + this.result = (T)result; + resultReady = true; + + foreach (var cb in callbacks) + cb((T)result); + + tcs.TrySetResult(result); + + } + + } + + public void TriggerError(AsyncException exception) + { + if (resultReady) + return; + + this.exception = exception; + + + lock (callbacksLock) + { + foreach (var cb in errorCallbacks) + cb(exception); + } + + tcs.TrySetException(exception); + } + + public void TriggerProgress(ProgressType type, int value, int max) + { + if (resultReady) + return; + + lock (callbacksLock) + { + foreach (var cb in progressCallbacks) + cb(type, value, max); + + } + } + + + public void TriggerChunk(object value) + { + if (resultReady) + return; + + lock (callbacksLock) + { + foreach (var cb in chunkCallbacks) + cb((T)value); + + } + } + + public AsyncAwaiter GetAwaiter() + { + return new AsyncAwaiter(this); + } + + public Task Task + { + get + { + return tcs.Task; + } + } + + + + public AsyncReply() + { + + } + + public AsyncReply(T result) + { + resultReady = true; + tcs.SetResult(result); + this.result = result; + } + + /* + public AsyncReply Then(Action callback) { base.Then(new Action(o => callback((T)o))); return this; @@ -46,6 +208,15 @@ namespace Esiur.Engine Trigger((object)result); } + public Task MoveNext(CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public void Dispose() + { + } + public AsyncReply() { @@ -67,13 +238,15 @@ namespace Esiur.Engine } } + public T Current => throw new NotImplementedException(); + public AsyncReply(T result) : base(result) { } - + */ } } diff --git a/Esiur/Engine/ErrorType.cs b/Esiur/Engine/ErrorType.cs new file mode 100644 index 0000000..f6b55f3 --- /dev/null +++ b/Esiur/Engine/ErrorType.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Engine +{ + public enum ErrorType + { + Management, + Exception + } +} diff --git a/Esiur/Engine/IAsyncReply.cs b/Esiur/Engine/IAsyncReply.cs new file mode 100644 index 0000000..d302561 --- /dev/null +++ b/Esiur/Engine/IAsyncReply.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; + +namespace Esiur.Engine +{ + public interface IAsyncReply//IAsyncEnumerator + { + IAsyncReply Then(Action callback); + IAsyncReply Error(Action callback); + IAsyncReply Progress(Action callback); + IAsyncReply Chunk(Action callback); + void Trigger(object result); + void TriggerError(AsyncException exception); + void TriggerProgress(ProgressType type, int value, int max); + void TriggerChunk(object value); + + + } +} diff --git a/Esiur/Engine/ProgressType.cs b/Esiur/Engine/ProgressType.cs new file mode 100644 index 0000000..a72cad7 --- /dev/null +++ b/Esiur/Engine/ProgressType.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Engine +{ + public enum ProgressType + { + Execution, + Network, + } +} diff --git a/Esiur/Esiur.csproj b/Esiur/Esiur.csproj index c0e7e75..356bf69 100644 --- a/Esiur/Esiur.csproj +++ b/Esiur/Esiur.csproj @@ -7,9 +7,11 @@ https://github.com/esiur/esiur-dotnet/blob/master/LICENSE http://www.esiur.com true - 1.1.0 + 1.2.3 https://github.com/esiur/esiur-dotnet Ahmed Kh. Zamil + 1.2.3.0 + Esiur Foundation @@ -22,6 +24,7 @@ + @@ -30,12 +33,14 @@ + + diff --git a/Esiur/Net/DataLink/PacketFilter.cs b/Esiur/Net/DataLink/PacketFilter.cs index 753930d..9acb2b2 100644 --- a/Esiur/Net/DataLink/PacketFilter.cs +++ b/Esiur/Net/DataLink/PacketFilter.cs @@ -50,7 +50,7 @@ namespace Esiur.Net.DataLink public void Destroy() { - throw new NotImplementedException(); + } } } diff --git a/Esiur/Net/HTTP/IIPoWS.cs b/Esiur/Net/HTTP/IIPoWS.cs index f7ee919..1957e7c 100644 --- a/Esiur/Net/HTTP/IIPoWS.cs +++ b/Esiur/Net/HTTP/IIPoWS.cs @@ -36,8 +36,36 @@ namespace Esiur.Net.HTTP { public class IIPoWS: HTTPFilter { + [ResourceProperty] + public DistributedServer DistributedServer + { + get; + set; + } + public override bool Execute(HTTPConnection sender) { + + if (DistributedServer == null) + return false; + + var tcpSocket = sender.Unassign(); + + if (tcpSocket == null) + return false; + + var httpServer = sender.Parent; + var wsSocket = new WSSocket(tcpSocket); + httpServer.RemoveConnection(sender); + + var iipConnection = new DistributedConnection(); + + DistributedServer.AddConnection(iipConnection); + iipConnection.Assign(wsSocket); + wsSocket.Begin(); + + return true; + /* if (sender.Request.Filename.StartsWith("/iip/")) { // find the service @@ -73,6 +101,7 @@ namespace Esiur.Net.HTTP } return false; + */ } private void IipConnection_OnReady(DistributedConnection sender) diff --git a/Esiur/Net/IIP/DistributedConnection.cs b/Esiur/Net/IIP/DistributedConnection.cs index 205457f..d5982e1 100644 --- a/Esiur/Net/IIP/DistributedConnection.cs +++ b/Esiur/Net/IIP/DistributedConnection.cs @@ -524,13 +524,13 @@ namespace Esiur.Net.IIP switch (packet.Report) { case IIPPacketReport.ManagementError: - IIPReportError(packet.CallbackId, AsyncReply.ErrorType.Management, packet.ErrorCode, null); + IIPReportError(packet.CallbackId, ErrorType.Management, packet.ErrorCode, null); break; case IIPPacketReport.ExecutionError: - IIPReportError(packet.CallbackId, AsyncReply.ErrorType.Exception, packet.ErrorCode, packet.ErrorMessage); + IIPReportError(packet.CallbackId, ErrorType.Exception, packet.ErrorCode, packet.ErrorMessage); break; case IIPPacketReport.ProgressReport: - IIPReportProgress(packet.CallbackId, AsyncReply.ProgressType.Execution, packet.ProgressValue, packet.ProgressMax); + IIPReportProgress(packet.CallbackId, ProgressType.Execution, packet.ProgressValue, packet.ProgressMax); break; case IIPPacketReport.ChunkStream: IIPReportChunk(packet.CallbackId, packet.Content); @@ -735,5 +735,11 @@ namespace Esiur.Net.IIP // nothing to do return true; } + + public AsyncReply Open(Structure settings) + { + + return new AsyncReply(true); + } } } diff --git a/Esiur/Net/IIP/DistributedConnectionProtocol.cs b/Esiur/Net/IIP/DistributedConnectionProtocol.cs index a979e7a..31e74c4 100644 --- a/Esiur/Net/IIP/DistributedConnectionProtocol.cs +++ b/Esiur/Net/IIP/DistributedConnectionProtocol.cs @@ -50,7 +50,7 @@ namespace Esiur.Net.IIP Dictionary templates = new Dictionary(); - KeyList requests = new KeyList(); + KeyList> requests = new KeyList>(); uint callbackCounter = 0; @@ -62,7 +62,7 @@ namespace Esiur.Net.IIP /// Packet action. /// Arguments to send. /// - internal AsyncReply SendRequest(IIPPacket.IIPPacketAction action, params object[] args) + internal IAsyncReply SendRequest(IIPPacket.IIPPacketAction action, params object[] args) { var reply = new AsyncReply(); callbackCounter++; @@ -100,11 +100,11 @@ namespace Esiur.Net.IIP Send(bl.ToArray()); } - internal AsyncReply SendInvokeByArrayArguments(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(); + var reply = new AsyncReply(); callbackCounter++; var bl = new BinaryList((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments), callbackCounter, instanceId, index, pb); @@ -114,11 +114,11 @@ namespace Esiur.Net.IIP return reply; } - internal AsyncReply SendInvokeByNamedArguments(uint instanceId, byte index, Structure parameters) + internal AsyncReply SendInvokeByNamedArguments(uint instanceId, byte index, Structure parameters) { var pb = Codec.ComposeStructure(parameters, this, true, true, true); - var reply = new AsyncReply(); + var reply = new AsyncReply(); callbackCounter++; var bl = new BinaryList((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments), callbackCounter, instanceId, index, pb); @@ -129,12 +129,12 @@ namespace Esiur.Net.IIP } - void SendError(AsyncReply.ErrorType type, uint callbackId, ushort errorCode, string errorMessage = "") + void SendError(ErrorType type, uint callbackId, ushort errorCode, string errorMessage = "") { var msg = DC.ToBytes(errorMessage); - if (type == AsyncReply.ErrorType.Management) + if (type == ErrorType.Management) SendParams((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ManagementError), callbackId, errorCode); - else if (type == AsyncReply.ErrorType.Exception) + else if (type == ErrorType.Exception) SendParams((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ExecutionError), callbackId, errorCode, (ushort)msg.Length, msg); } @@ -165,13 +165,13 @@ namespace Esiur.Net.IIP }); } - void IIPReportError(uint callbackId, AsyncReply.ErrorType errorType, ushort errorCode, string errorMessage) + void IIPReportError(uint callbackId, ErrorType errorType, ushort errorCode, string errorMessage) { var req = requests.Take(callbackId); req?.TriggerError(new AsyncException(errorType, errorCode, errorMessage)); } - void IIPReportProgress(uint callbackId, AsyncReply.ProgressType type, int value, int max) + void IIPReportProgress(uint callbackId, ProgressType type, int value, int max) { var req = requests[callbackId]; req?.TriggerProgress(type, value, max); @@ -379,7 +379,7 @@ namespace Esiur.Net.IIP { if (res.Instance.Applicable(session, ActionType.Attach, null) == Ruling.Denied) { - SendError(AsyncReply.ErrorType.Management, callback, 6); + SendError(ErrorType.Management, callback, 6); return; } @@ -415,7 +415,7 @@ namespace Esiur.Net.IIP { // reply failed //SendParams(0x80, r.Instance.Id, r.Instance.Age, r.Instance.Serialize(false, this)); - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); } }); } @@ -459,7 +459,7 @@ namespace Esiur.Net.IIP else { // reply failed - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); } }); } @@ -480,7 +480,7 @@ namespace Esiur.Net.IIP else { // reply failed - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); } }); } @@ -492,20 +492,20 @@ namespace Esiur.Net.IIP { if (store == null) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.StoreNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.StoreNotFound); return; } if (!(store is IStore)) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceIsNotStore); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceIsNotStore); return; } // check security if (store.Instance.Applicable(session, ActionType.CreateResource, null) != Ruling.Allowed) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.CreateDenied); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.CreateDenied); return; } @@ -517,7 +517,7 @@ namespace Esiur.Net.IIP if (parent != null) if (parent.Instance.Applicable(session, ActionType.AddChild, null) != Ruling.Allowed) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.AddChildDenied); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AddChildDenied); return; } @@ -537,7 +537,7 @@ namespace Esiur.Net.IIP if (type == null) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ClassNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ClassNotFound); return; } @@ -614,13 +614,13 @@ namespace Esiur.Net.IIP { if (r == null) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); return; } if (r.Instance.Store.Instance.Applicable(session, ActionType.Delete, null) != Ruling.Allowed) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.DeleteDenied); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.DeleteDenied); return; } @@ -628,7 +628,7 @@ namespace Esiur.Net.IIP SendReply(IIPPacket.IIPPacketAction.DeleteResource, callback); //SendParams((byte)0x84, callback); else - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.DeleteFailed); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.DeleteFailed); }); } @@ -638,14 +638,14 @@ namespace Esiur.Net.IIP { if (r == null) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); return; } // if (!r.Instance.Store.Instance.Applicable(r, session, ActionType.InquireAttributes, null)) if (r.Instance.Applicable(session, ActionType.InquireAttributes, null) != Ruling.Allowed) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ViewAttributeDenied); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ViewAttributeDenied); return; } @@ -660,7 +660,7 @@ namespace Esiur.Net.IIP SendReply(all ? IIPPacket.IIPPacketAction.GetAllAttributes : IIPPacket.IIPPacketAction.GetAttributes, callback, Codec.ComposeStructure(st, this, true, true, true)); else - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.GetAttributesFailed); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.GetAttributesFailed); }); } @@ -671,7 +671,7 @@ namespace Esiur.Net.IIP { if (parent == null) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); return; } @@ -679,19 +679,19 @@ namespace Esiur.Net.IIP { if (child == null) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); return; } if (parent.Instance.Applicable(this.session, ActionType.AddChild, null) != Ruling.Allowed) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.AddChildDenied); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AddChildDenied); return; } if (child.Instance.Applicable(this.session, ActionType.AddParent, null) != Ruling.Allowed) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.AddParentDenied); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AddParentDenied); return; } @@ -710,7 +710,7 @@ namespace Esiur.Net.IIP { if (parent == null) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); return; } @@ -718,19 +718,19 @@ namespace Esiur.Net.IIP { if (child == null) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); return; } if (parent.Instance.Applicable(this.session, ActionType.RemoveChild, null) != Ruling.Allowed) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.AddChildDenied); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AddChildDenied); return; } if (child.Instance.Applicable(this.session, ActionType.RemoveParent, null) != Ruling.Allowed) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.AddParentDenied); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AddParentDenied); return; } @@ -749,13 +749,13 @@ namespace Esiur.Net.IIP { if (resource == null) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); return; } if (resource.Instance.Applicable(this.session, ActionType.Rename, null) != Ruling.Allowed) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.RenameDenied); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.RenameDenied); return; } @@ -771,7 +771,7 @@ namespace Esiur.Net.IIP { if (resource == null) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); return; } @@ -789,7 +789,7 @@ namespace Esiur.Net.IIP { if (resource == null) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); return; } @@ -807,13 +807,13 @@ namespace Esiur.Net.IIP { if (r == null) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); return; } if (r.Instance.Store.Instance.Applicable(session, ActionType.UpdateAttributes, null) != Ruling.Allowed) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeDenied); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeDenied); return; } @@ -825,7 +825,7 @@ namespace Esiur.Net.IIP if (r.Instance.RemoveAttributes(attrs)) SendReply(all ? IIPPacket.IIPPacketAction.ClearAllAttributes : IIPPacket.IIPPacketAction.ClearAttributes, callback); else - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeFailed); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeFailed); }); } @@ -836,13 +836,13 @@ namespace Esiur.Net.IIP { if (r == null) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); return; } if (r.Instance.Store.Instance.Applicable(session, ActionType.UpdateAttributes, null) != Ruling.Allowed) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeDenied); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeDenied); return; } @@ -852,7 +852,7 @@ namespace Esiur.Net.IIP SendReply(clearAttributes ? IIPPacket.IIPPacketAction.ClearAllAttributes : IIPPacket.IIPPacketAction.ClearAttributes, callback); else - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeFailed); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeFailed); }); }); @@ -868,7 +868,7 @@ namespace Esiur.Net.IIP else { // reply failed - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound); } }); } @@ -882,7 +882,7 @@ namespace Esiur.Net.IIP else { // reply failed - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound); } }); } @@ -899,7 +899,7 @@ namespace Esiur.Net.IIP else { // reply failed - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound); } }); } @@ -916,7 +916,7 @@ namespace Esiur.Net.IIP var list = r.Where(x => x.Instance.Applicable(session, ActionType.Attach, null) != Ruling.Denied).ToArray(); if (list.Length == 0) - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); else SendReply(IIPPacket.IIPPacketAction.QueryLink, callback, Codec.ComposeResourceArray(list, this, true)); //} @@ -973,7 +973,7 @@ namespace Esiur.Net.IIP { if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied) { - SendError(AsyncReply.ErrorType.Management, callback, + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.InvokeDenied); return; } @@ -1009,7 +1009,7 @@ namespace Esiur.Net.IIP } catch(Exception ex) { - SendError(AsyncReply.ErrorType.Exception, callback, 0, ex.ToString()); + SendError(ErrorType.Exception, callback, 0, ex.ToString()); return; } @@ -1038,14 +1038,15 @@ namespace Esiur.Net.IIP //await t; //SendParams((byte)0x90, callback, Codec.Compose(res, this)); } - else if (rt is AsyncReply) //(rt.GetType().IsGenericType && (rt.GetType().GetGenericTypeDefinition() == typeof(AsyncReply<>))) + else if (rt.GetType().GetTypeInfo().IsGenericType + && rt.GetType().GetGenericTypeDefinition() == typeof(IAsyncReply<>)) { - (rt as AsyncReply).Then(res => + (rt as IAsyncReply).Then(res => { SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback, Codec.Compose(res, this)); }).Error(ex => { - SendError(AsyncReply.ErrorType.Exception, callback, (ushort)ex.Code, ex.Message); + SendError(ErrorType.Exception, callback, (ushort)ex.Code, ex.Message); }).Progress((pt, pv, pm) => { SendProgress(callback, pv, pm); @@ -1119,7 +1120,7 @@ namespace Esiur.Net.IIP { if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied) { - SendError(AsyncReply.ErrorType.Management, callback, + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.InvokeDenied); return; } @@ -1150,7 +1151,7 @@ namespace Esiur.Net.IIP } catch (Exception ex) { - SendError(AsyncReply.ErrorType.Exception, callback, 0, ex.ToString()); + SendError(ErrorType.Exception, callback, 0, ex.ToString()); return; } @@ -1177,14 +1178,16 @@ namespace Esiur.Net.IIP }); } - else if (rt is AsyncReply) - { - (rt as AsyncReply).Then(res => +// else if (rt is AsyncReply) + else if (rt.GetType().GetTypeInfo().IsGenericType + && rt.GetType().GetGenericTypeDefinition() == typeof(IAsyncReply<>)) + { + (rt as IAsyncReply).Then(res => { SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback, Codec.Compose(res, this)); }).Error(ex => { - SendError(AsyncReply.ErrorType.Exception, callback, (ushort)ex.Code, ex.Message); + SendError(ErrorType.Exception, callback, (ushort)ex.Code, ex.Message); }).Progress((pt, pv, pm) => { SendProgress(callback, pv, pm); @@ -1376,13 +1379,13 @@ namespace Esiur.Net.IIP if (r.Instance.Applicable(session, ActionType.SetProperty, pt, this) == Ruling.Denied) { - SendError(AsyncReply.ErrorType.Exception, callback, (ushort)ExceptionCode.SetPropertyDenied); + SendError(ErrorType.Exception, callback, (ushort)ExceptionCode.SetPropertyDenied); return; } if (!pi.CanWrite) { - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ReadOnlyProperty); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ReadOnlyProperty); return; } @@ -1405,14 +1408,14 @@ namespace Esiur.Net.IIP } catch(Exception ex) { - SendError(AsyncReply.ErrorType.Exception, callback, 0, ex.Message); + SendError(ErrorType.Exception, callback, 0, ex.Message); } } else { // pt found, pi not found, this should never happen - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.PropertyNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.PropertyNotFound); } } @@ -1421,13 +1424,13 @@ namespace Esiur.Net.IIP else { // property not found - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.PropertyNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.PropertyNotFound); } } else { // resource not found - SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); } }); } @@ -1718,7 +1721,7 @@ namespace Esiur.Net.IIP SendRequest(IIPPacket.IIPPacketAction.ResourceChildren, resource.Instance.Id).Then(ar => { - var d = (byte[])ar; + var d = (byte[])ar[0]; Codec.ParseResourceArray(d, 0, (uint)d.Length, this).Then(resources => { rt.Trigger(resources); @@ -1734,7 +1737,7 @@ namespace Esiur.Net.IIP SendRequest(IIPPacket.IIPPacketAction.ResourceParents, resource.Instance.Id).Then(ar => { - var d = (byte[])ar; + var d = (byte[])ar[0]; Codec.ParseResourceArray(d, 0, (uint)d.Length, this).Then(resources => { rt.Trigger(resources); diff --git a/Esiur/Net/IIP/DistributedResource.cs b/Esiur/Net/IIP/DistributedResource.cs index 78f15f3..140ae9f 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 _InvokeByNamedArguments(byte index, Structure namedArgs) + public AsyncReply _InvokeByNamedArguments(byte index, Structure namedArgs) { if (destroyed) throw new Exception("Trying to access destroyed object"); @@ -246,7 +246,7 @@ namespace Esiur.Net.IIP return connection.SendInvokeByNamedArguments(instanceId, index, namedArgs); } - public AsyncReply _InvokeByArrayArguments(byte index, object[] args) + public AsyncReply _InvokeByArrayArguments(byte index, object[] args) { if (destroyed) throw new Exception("Trying to access destroyed object"); @@ -263,7 +263,7 @@ namespace Esiur.Net.IIP { var ft = Instance.Template.GetFunctionTemplate(binder.Name); - var reply = new AsyncReply(); + var reply = new AsyncReply(); if (isAttached && ft!=null) { @@ -358,12 +358,12 @@ namespace Esiur.Net.IIP /// Zero-based property index. /// Value /// Indicator when the property is set. - internal AsyncReply _Set(byte index, object value) + internal AsyncReply _Set(byte index, object value) { if (index >= properties.Length) return null; - var reply = new AsyncReply(); + var reply = new AsyncReply(); var parameters = Codec.Compose(value, connection); connection.SendRequest(Packets.IIPPacket.IIPPacketAction.SetProperty, instanceId, index, parameters).Then((res) => diff --git a/Esiur/Resource/IStore.cs b/Esiur/Resource/IStore.cs index 96df8af..1b03ea1 100644 --- a/Esiur/Resource/IStore.cs +++ b/Esiur/Resource/IStore.cs @@ -35,6 +35,7 @@ namespace Esiur.Resource { public interface IStore:IResource { + AsyncReply Open(Structure settings); AsyncReply Get(string path); AsyncReply Retrieve(uint iid); bool Put(IResource resource); diff --git a/Esiur/Resource/Template/FunctionTemplate.cs b/Esiur/Resource/Template/FunctionTemplate.cs index 512c35e..694df5a 100644 --- a/Esiur/Resource/Template/FunctionTemplate.cs +++ b/Esiur/Resource/Template/FunctionTemplate.cs @@ -30,7 +30,7 @@ namespace Esiur.Resource.Template if (Expansion != null) { var exp = DC.ToBytes(Expansion); - return BinaryList.ToBytes((byte)(0x10 | (IsVoid ? 0x8 : 0x0)), exp.Length, exp, (byte)name.Length, name); + return BinaryList.ToBytes((byte)(0x10 | (IsVoid ? 0x8 : 0x0)), (byte)name.Length, name, exp.Length, exp); } else return BinaryList.ToBytes((byte)(IsVoid ? 0x8 : 0x0), (byte)name.Length, name); diff --git a/Esiur/Resource/Template/PropertyTemplate.cs b/Esiur/Resource/Template/PropertyTemplate.cs index 3bc8df3..9f6fade 100644 --- a/Esiur/Resource/Template/PropertyTemplate.cs +++ b/Esiur/Resource/Template/PropertyTemplate.cs @@ -66,17 +66,17 @@ namespace Esiur.Resource.Template { var rexp = DC.ToBytes(ReadExpansion); var wexp = DC.ToBytes(WriteExpansion); - return BinaryList.ToBytes((byte)(0x38 | pv), wexp.Length, wexp, rexp.Length, rexp, (byte)name.Length, name); + return BinaryList.ToBytes((byte)(0x38 | pv), (byte)name.Length, name, wexp.Length, wexp, rexp.Length, rexp); } else if (WriteExpansion != null) { var wexp = DC.ToBytes(WriteExpansion); - return BinaryList.ToBytes((byte)(0x30 | pv), wexp.Length, wexp, (byte)name.Length, name); + return BinaryList.ToBytes((byte)(0x30 | pv), (byte)name.Length, name, wexp.Length, wexp); } else if (ReadExpansion != null) { var rexp = DC.ToBytes(ReadExpansion); - return BinaryList.ToBytes((byte)(0x28 | pv), rexp.Length, rexp, (byte)name.Length, name); + return BinaryList.ToBytes((byte)(0x28 | pv), (byte)name.Length, name, rexp.Length, rexp); } else return BinaryList.ToBytes((byte)(0x20 | pv), (byte)name.Length, name); diff --git a/Esiur/Resource/Template/ResourceTemplate.cs b/Esiur/Resource/Template/ResourceTemplate.cs index ce52094..fa54fa0 100644 --- a/Esiur/Resource/Template/ResourceTemplate.cs +++ b/Esiur/Resource/Template/ResourceTemplate.cs @@ -228,7 +228,7 @@ namespace Esiur.Resource.Template od.classId = data.GetGuid(offset); offset += 16; - od.className = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]); + od.className = data.GetString(offset + 1, data[offset]); offset += (uint)data[offset] + 1; od.version = data.GetInt32(offset); @@ -250,7 +250,7 @@ namespace Esiur.Resource.Template string expansion = null; var hasExpansion = ((data[offset] & 0x10) == 0x10); var isVoid = ((data[offset++] & 0x08) == 0x08); - var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]); + var name = data.GetString(offset + 1, data[offset]); offset += (uint)data[offset] + 1; if (hasExpansion) // expansion ? diff --git a/Esiur/Resource/Warehouse.cs b/Esiur/Resource/Warehouse.cs index e049f10..54f4d27 100644 --- a/Esiur/Resource/Warehouse.cs +++ b/Esiur/Resource/Warehouse.cs @@ -53,6 +53,7 @@ namespace Esiur.Resource public static event StoreConnectedEvent StoreConnected; public static event StoreDisconnectedEvent StoreDisconnected; + static KeyList protocols = new KeyList(); /// /// Get a store by its name. @@ -234,7 +235,7 @@ namespace Esiur.Resource /// /// /// Resource instance. - public static AsyncReply Get(string path) + public static AsyncReply Get(string path, Structure settings = null, IResource parent = null, IPermissionsManager manager = null) { var p = path.Split('/'); @@ -265,6 +266,41 @@ namespace Esiur.Resource return new AsyncReply(res); } + // Should we create a new store ? + if (path.Contains("://")) + { + var url = path.Split(new string[] { "://" }, 2, StringSplitOptions.None); + var hostname = url[1].Split(new char[] { '/' }, 2)[0]; + 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 = Activator.CreateInstance(handler.GetType()) as IStore; + Put(store, url[0] + "://" + hostname, null, parent, null, 0, manager); + + store.Open(settings).Then(x => { + if (pathname.Length > 0 && pathname != "") + store.Get(pathname).Then(r => { + rt.Trigger(r); + }).Error(e => rt.TriggerError(e)); + else + rt.Trigger(store); + + }).Error(e => { + rt.TriggerError(e); + Warehouse.Remove(store); + }); + } + + return rt; + } + + return new AsyncReply(null); } diff --git a/Esiur/Stores/MemoryStore.cs b/Esiur/Stores/MemoryStore.cs index 499a5ba..691488d 100644 --- a/Esiur/Stores/MemoryStore.cs +++ b/Esiur/Stores/MemoryStore.cs @@ -75,5 +75,10 @@ namespace Esiur.Stores { return true; } + + public AsyncReply Open(Structure settings) + { + return new AsyncReply(true); + } } } diff --git a/Test/MyObject.cs b/Test/MyObject.cs index 4f199de..87d39b5 100644 --- a/Test/MyObject.cs +++ b/Test/MyObject.cs @@ -36,10 +36,10 @@ namespace Test return Level; } - [ResourceFunction] - public double Divide(float nominator, float denominator, DistributedConnection sender) + [ResourceFunction("Divide takes two arguments nominator and denominator")] + public double Divide(float n, float d, DistributedConnection sender) { - return nominator / denominator; + return n / d; } [ResourceFunction] @@ -50,7 +50,7 @@ namespace Test return Level; } - [ResourceFunction] + [ResourceFunction("use it with next()")] public IEnumerable Enum(int count) { var msg = new string[] { "Have you throught what if a function has multiple returns ?", "So you can return chunks of IO operation that not yet finished.", "Also, what about the progress ?", "This is an example of both.", "Use it anyway you like" }; @@ -62,7 +62,7 @@ namespace Test } } - [ResourceFunction] + [ResourceFunction("Stream returns progress")] public AsyncReply Stream(int count) { var reply = new AsyncReply(); @@ -73,7 +73,7 @@ namespace Test timer = new Timer((x) => { - reply.TriggerProgress(AsyncReply.ProgressType.Execution, count, 22); + reply.TriggerProgress(ProgressType.Execution, count, 22); if (count % 2 == 0 && msgCounter < msg.Length) reply.TriggerChunk(msg[msgCounter++]); diff --git a/Test/Program.cs b/Test/Program.cs index e6cb797..b467762 100644 --- a/Test/Program.cs +++ b/Test/Program.cs @@ -43,15 +43,10 @@ namespace Test static DistributedResource remoteObject; - - static void Main(string[] args) - { - MainAsync().Wait(); - //Thread.Sleep(-1); - } - static async Task MainAsync() - { + + static async Task Main(string[] args) + { //AsyncContext.Run(() => ()); // Create stores to keep objects. @@ -59,65 +54,71 @@ namespace Test var remote = Warehouse.New("remote"); var mongo = Warehouse.New("db"); + /* + var system = await Warehouse.Get("mem://system").Task; + var remote = await Warehouse.Get("mem://remote").Task; + var mongo = await Warehouse.Get("mongo://db").Task; + var iip = await Warehouse.Get("iip://:5000").Task; + var iws = await Warehouse.Get("iipows://:5001", new Structure() { ["iip"] = iip }).Task; + */ + + var ok = await Warehouse.Open(); + + // Open the warehouse - var ok = await Warehouse.Open().Task; - // Create new object if the store is empty - if (mongo.Count == 0) - myObject = Warehouse.New("my", mongo, null, - new UserPermissionsManager(new Structure() - { - ["demo@localhost"] = new Structure() - { - ["Subtract"] = new Structure { ["Execute"] = "yes" }, - ["Stream"] = new Structure { ["Execute"] = "yes" }, - ["_attach"] = "yes", - ["_get_attributes"] = "yes", - ["_set_attributes"] = "yes", - } - })); - else - Warehouse.Get("db/my").Then((o) => { myObject = (MyObject)o; }); - - // Create new distributed server object - var iip = Warehouse.New("iip", system); - // 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); - - - // 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); - - // Create IIP over Websocket HTTP module and give it to HTTP server. - var wsOverHttp = Warehouse.New("IIPoWS", system, http); - - - - Warehouse.StoreConnected += (store, name) => - { - if (store.Instance.Parents.Contains(iip)) + // Create new object if the store is empty + if (mongo.Count == 0) + myObject = Warehouse.New("my", mongo, null, + new UserPermissionsManager(new Structure() { - store.Get("local/js").Then((r) => + ["demo@localhost"] = new Structure() { - if (r != null) - { - dynamic d = r; - d.send("Welcome"); - } - }); - } - }; - + ["Subtract"] = new Structure { ["Execute"] = "yes" }, + ["Stream"] = new Structure { ["Execute"] = "yes" }, + ["_attach"] = "yes", + ["_get_attributes"] = "yes", + ["_set_attributes"] = "yes", + } + })); + else + myObject =(MyObject) (await Warehouse.Get("db/my"));//.Then((o) => { myObject = (MyObject)o; }); - // Start testing - // TestClient(); - + // Create new distributed server object + var iip = Warehouse.New("iip", system); + // 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); + // 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); + + // Create IIP over Websocket HTTP module and give it to HTTP server. + var wsOverHttp = Warehouse.New("IIPoWS", system, http); + + wsOverHttp.DistributedServer = iip; + + Warehouse.StoreConnected += (store, name) => + { + if (store.Instance.Parents.Contains(iip)) + { + store.Get("local/js").Then((r) => + { + if (r != null) + { + dynamic d = r; + d.send("Welcome"); + } + }); + } + }; + + // Start testing + // TestClient(); var running = true; @@ -137,6 +138,8 @@ namespace Test else Console.WriteLine(myObject.Name + " " + myObject.Level); } + + } private static void TestClient() @@ -148,12 +151,12 @@ namespace Test // Put the client in our memory store var remote = Warehouse.GetStore("remote"); Warehouse.Put(client, "Endpoint", remote); - - + + client.OnReady += async (c) => { // Get remote object from the server. - remoteObject = await client.Get("db/my").Task as DistributedResource; + //remoteObject = await client.Get("db/my").Task as DistributedResource; dynamic x = remoteObject; @@ -169,13 +172,13 @@ namespace Test Console.WriteLine("LevelUp " + parameters[0] + " " + parameters[1]); }); - (x.Stream(10) as AsyncReply).Then(r => + (x.Stream(10) as AsyncReply).Then(r => { Console.WriteLine("Stream ended: " + r); - }).Chunk(r=> + }).Chunk(r => { Console.WriteLine("Chunk..." + r); - }).Progress((t, v, m)=> Console.WriteLine("Processing {0}/{1}", v, m)); + }).Progress((t, v, m) => Console.WriteLine("Processing {0}/{1}", v, m)); var rt = await x.Subtract(10).Task;