2
0
mirror of https://github.com/esiur/esiur-dotnet.git synced 2025-05-07 12:02:59 +00:00

AsyncReply is awaitable

This commit is contained in:
Ahmed Zamil 2019-07-21 05:29:58 +03:00
parent 48e450ffc4
commit 2d9f61c0d9
26 changed files with 561 additions and 213 deletions

View File

@ -11,7 +11,7 @@
<PackageProjectUrl>http://www.esiur.com</PackageProjectUrl> <PackageProjectUrl>http://www.esiur.com</PackageProjectUrl>
<RepositoryUrl>https://github.com/esiur/esiur-dotnet/</RepositoryUrl> <RepositoryUrl>https://github.com/esiur/esiur-dotnet/</RepositoryUrl>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild> <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Version>1.1.0</Version> <Version>1.2.0</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -185,7 +185,7 @@ namespace Esiur.Stores.MongoDB
return rt; return rt;
} }
AsyncReply Parse(BsonValue value) IAsyncReply<object> Parse(BsonValue value)
{ {
if (value.BsonType == BsonType.Document) if (value.BsonType == BsonType.Document)
{ {
@ -217,7 +217,7 @@ namespace Esiur.Stores.MongoDB
return rt; return rt;
} }
else else
return new AsyncReply(null); return new AsyncReply<object>(null);
} }
else if (value.BsonType == BsonType.Array) else if (value.BsonType == BsonType.Array)
{ {
@ -233,12 +233,12 @@ namespace Esiur.Stores.MongoDB
} }
else if (value.BsonType == BsonType.DateTime) else if (value.BsonType == BsonType.DateTime)
{ {
return new AsyncReply(value.ToUniversalTime()); return new AsyncReply<object>(value.ToUniversalTime());
} }
else else
{ {
return new AsyncReply(value.RawValue); return new AsyncReply<object>(value.RawValue);
} }
} }
@ -633,7 +633,7 @@ namespace Esiur.Stores.MongoDB
var reply = new AsyncReply<KeyList<PropertyTemplate, PropertyValue[]>>(); var reply = new AsyncReply<KeyList<PropertyTemplate, PropertyValue[]>>();
AsyncBag<PropertyValue> bag = new AsyncBag<PropertyValue>(); AsyncBag<PropertyValue[]> bag = new AsyncBag<PropertyValue[]>();
foreach (var p in properties) foreach (var p in properties)
bag.Add(GetPropertyRecordByAge(resource, p.Name, fromAge, toAge)); bag.Add(GetPropertyRecordByAge(resource, p.Name, fromAge, toAge));
@ -642,7 +642,7 @@ namespace Esiur.Stores.MongoDB
bag.Then(x => bag.Then(x =>
{ {
var list = new KeyList<PropertyTemplate, PropertyValue>(); var list = new KeyList<PropertyTemplate, PropertyValue[]>();
for (var i = 0; i < x.Length; i++) for (var i = 0; i < x.Length; i++)
list.Add(properties[i], x[i]); list.Add(properties[i], x[i]);
@ -696,5 +696,10 @@ namespace Esiur.Stores.MongoDB
return true; return true;
} }
public AsyncReply<bool> Open(Structure settings)
{
return new AsyncReply<bool>(true);
}
} }
} }

View File

@ -171,7 +171,7 @@ namespace Esiur.Data
var result = (StructureComparisonResult)data[offset++]; var result = (StructureComparisonResult)data[offset++];
AsyncReply previous = null; IAsyncReply<Structure> previous = null;
// string[] previousKeys = null; // string[] previousKeys = null;
// DataType[] previousTypes = null; // DataType[] previousTypes = null;
@ -362,7 +362,7 @@ namespace Esiur.Data
/// <param name="connection">DistributedConnection is required in case a structure in the array holds items at the other end.</param> /// <param name="connection">DistributedConnection is required in case a structure in the array holds items at the other end.</param>
/// <param name="dataType">DataType, in case the data is not prepended with DataType</param> /// <param name="dataType">DataType, in case the data is not prepended with DataType</param>
/// <returns>Structure</returns> /// <returns>Structure</returns>
public static AsyncReply Parse(byte[] data, uint offset, DistributedConnection connection, DataType dataType = DataType.Unspecified) public static IAsyncReply<object> Parse(byte[] data, uint offset, DistributedConnection connection, DataType dataType = DataType.Unspecified)
{ {
uint size; uint size;
return Parse(data, offset, out size, connection); return Parse(data, offset, out size, connection);
@ -377,10 +377,9 @@ namespace Esiur.Data
/// <param name="connection">DistributedConnection is required in case a structure in the array holds items at the other end.</param> /// <param name="connection">DistributedConnection is required in case a structure in the array holds items at the other end.</param>
/// <param name="dataType">DataType, in case the data is not prepended with DataType</param> /// <param name="dataType">DataType, in case the data is not prepended with DataType</param>
/// <returns>Value</returns> /// <returns>Value</returns>
public static AsyncReply Parse(byte[] data, uint offset, out uint size, DistributedConnection connection, DataType dataType = DataType.Unspecified) public static IAsyncReply<object> Parse(byte[] data, uint offset, out uint size, DistributedConnection connection, DataType dataType = DataType.Unspecified)
{ {
var reply = new AsyncReply();
bool isArray; bool isArray;
DataType t; DataType t;
@ -480,40 +479,40 @@ namespace Esiur.Data
return new AsyncReply<object>(null); return new AsyncReply<object>(null);
case DataType.Bool: case DataType.Bool:
return new AsyncReply<bool>(data.GetBoolean(offset)); return new AsyncReply<object>(data.GetBoolean(offset));
case DataType.UInt8: case DataType.UInt8:
return new AsyncReply<byte>(data[offset]); return new AsyncReply<object>(data[offset]);
case DataType.Int8: case DataType.Int8:
return new AsyncReply<sbyte>((sbyte)data[offset]); return new AsyncReply<object>((sbyte)data[offset]);
case DataType.Char: case DataType.Char:
return new AsyncReply<char>(data.GetChar(offset)); return new AsyncReply<object>(data.GetChar(offset));
case DataType.Int16: case DataType.Int16:
return new AsyncReply<short>(data.GetInt16(offset)); return new AsyncReply<object>(data.GetInt16(offset));
case DataType.UInt16: case DataType.UInt16:
return new AsyncReply<ushort>(data.GetUInt16(offset)); return new AsyncReply<object>(data.GetUInt16(offset));
case DataType.Int32: case DataType.Int32:
return new AsyncReply<int>(data.GetInt32(offset)); return new AsyncReply<object>(data.GetInt32(offset));
case DataType.UInt32: case DataType.UInt32:
return new AsyncReply<uint>(data.GetUInt32(offset)); return new AsyncReply<object>(data.GetUInt32(offset));
case DataType.Int64: case DataType.Int64:
return new AsyncReply<long>(data.GetInt64(offset)); return new AsyncReply<object>(data.GetInt64(offset));
case DataType.UInt64: case DataType.UInt64:
return new AsyncReply<ulong>(data.GetUInt64(offset)); return new AsyncReply<object>(data.GetUInt64(offset));
case DataType.Float32: case DataType.Float32:
return new AsyncReply<float>(data.GetFloat32(offset)); return new AsyncReply<object>(data.GetFloat32(offset));
case DataType.Float64: case DataType.Float64:
return new AsyncReply<double>(data.GetFloat64(offset)); return new AsyncReply<object>(data.GetFloat64(offset));
case DataType.String: case DataType.String:
return new AsyncReply<string>(data.GetString(offset, contentLength)); return new AsyncReply<string>(data.GetString(offset, contentLength));
@ -525,7 +524,7 @@ namespace Esiur.Data
return ParseDistributedResource(data, offset, connection); return ParseDistributedResource(data, offset, connection);
case DataType.DateTime: case DataType.DateTime:
return new AsyncReply<DateTime>(data.GetDateTime(offset)); return new AsyncReply<object>(data.GetDateTime(offset));
case DataType.Structure: case DataType.Structure:
return ParseStructure(data, offset, contentLength, connection); return ParseStructure(data, offset, contentLength, connection);
@ -694,7 +693,7 @@ namespace Esiur.Data
// //
var result = (ResourceComparisonResult)data[offset++]; var result = (ResourceComparisonResult)data[offset++];
AsyncReply previous = null; IAsyncReply<IResource> previous = null;
if (result == ResourceComparisonResult.Null) if (result == ResourceComparisonResult.Null)
previous = new AsyncReply<IResource>(null); previous = new AsyncReply<IResource>(null);
@ -716,7 +715,7 @@ namespace Esiur.Data
{ {
result = (ResourceComparisonResult)data[offset++]; result = (ResourceComparisonResult)data[offset++];
AsyncReply current = null; IAsyncReply<IResource> current = null;
if (result == ResourceComparisonResult.Null) if (result == ResourceComparisonResult.Null)
{ {

View File

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
namespace Esiur.Engine
{
public class AsyncAwaiter<T> : INotifyCompletion
{
Action callback = null;
T result;
private bool completed;
public AsyncAwaiter(AsyncReply<T> 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....");
}
}
}

View File

@ -30,21 +30,23 @@ using System.Threading.Tasks;
namespace Esiur.Engine namespace Esiur.Engine
{ {
public class AsyncBag<T>:AsyncReply public class AsyncBag<T>: AsyncReply<T[]>
{ {
//Dictionary<AsyncReply, T> results = new Dictionary<AsyncReply, T>(); //Dictionary<AsyncReply, T> results = new Dictionary<AsyncReply, T>();
List<AsyncReply> replies = new List<AsyncReply>(); List<IAsyncReply<T>> replies = new List<IAsyncReply<T>>();
List<T> results = new List<T>(); List<T> results = new List<T>();
int count = 0; int count = 0;
bool sealedBag = false; bool sealedBag = false;
/*
public AsyncBag<T> Then(Action<T[]> callback) public AsyncBag<T> Then(Action<T[]> callback)
{ {
base.Then(new Action<object>(o => callback((T[])o))); base.Then(new Action<object>(o => callback((T[])o)));
return this; return this;
} }
*/
public void Seal() public void Seal()
{ {
@ -72,7 +74,7 @@ namespace Esiur.Engine
} }
} }
public void Add(AsyncReply reply) public void Add(IAsyncReply<T> reply)
{ {
if (!sealedBag) if (!sealedBag)
{ {
@ -82,6 +84,12 @@ namespace Esiur.Engine
//results.Add(reply, default(T)); //results.Add(reply, default(T));
} }
public void AddBag(AsyncBag<T> bag)
{
foreach (var r in bag.replies)
Add(r);
}
public AsyncBag() public AsyncBag()
{ {

View File

@ -63,23 +63,21 @@ namespace Esiur.Engine
{ {
AsyncReply.ErrorType type; public readonly ErrorType Type;
ExceptionCode code; public readonly ExceptionCode Code;
public AsyncReply.ErrorType Type => type;
public ExceptionCode Code => code;
public AsyncException(AsyncReply.ErrorType type, ushort code, string message) public AsyncException(ErrorType type, ushort code, string message)
: base(type == AsyncReply.ErrorType.Management ? ((ExceptionCode)code).ToString() : message) : base(type == ErrorType.Management ? ((ExceptionCode)code).ToString() : message)
{ {
this.type = type; this.Type = type;
this.code = (ExceptionCode)code; this.Code = (ExceptionCode)code;
} }
public override string ToString() public override string ToString()
{ {
return code.ToString() + ": " + Message; return Code.ToString() + ": " + Message;
} }
} }
} }

View File

@ -30,18 +30,18 @@ using System.Threading.Tasks;
namespace Esiur.Engine namespace Esiur.Engine
{ {
public class AsyncQueue<T> : AsyncReply public class AsyncQueue<T> : AsyncReply<T>
{ {
List<AsyncReply<T>> list = new List<AsyncReply<T>>(); List<AsyncReply<T>> list = new List<AsyncReply<T>>();
//Action<T> callback; //Action<T> callback;
object queueLock = new object(); object queueLock = new object();
public AsyncQueue<T> Then(Action<T> callback) //public AsyncQueue<T> Then(Action<T> callback)
{ //{
base.Then(new Action<object>(o => callback((T)o))); // base.Then(new Action<object>(o => callback((T)o)));
return this; //return this;
} //}
public void Add(AsyncReply<T> reply) public void Add(AsyncReply<T> reply)
{ {

View File

@ -32,17 +32,9 @@ namespace Esiur.Engine
{ {
public class AsyncReply public class AsyncReply
{ {
public enum ErrorType
{
Management,
Exception
}
public enum ProgressType
{
Execution,
Network,
}
protected List<Action<object>> callbacks = new List<Action<object>>(); protected List<Action<object>> callbacks = new List<Action<object>>();
protected object result; protected object result;

View File

@ -29,13 +29,175 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Esiur.Resource; using Esiur.Resource;
using System.Reflection; using System.Reflection;
using System.Threading;
using System.Runtime.CompilerServices;
namespace Esiur.Engine namespace Esiur.Engine
{ {
public class AsyncReply<T>: AsyncReply public class AsyncReply<T>: IAsyncReply<T>
{ {
protected List<Action<T>> callbacks = new List<Action<T>>();
protected T result;
protected List<Action<AsyncException>> errorCallbacks = new List<Action<AsyncException>>();
public AsyncReply<T> Then(Action<T> callback) protected List<Action<ProgressType, int, int>> progressCallbacks = new List<Action<ProgressType, int, int>>();
protected List<Action<T>> chunkCallbacks = new List<Action<T>>();
//List<AsyncAwaiter> awaiters = new List<AsyncAwaiter>();
object callbacksLock = new object();
protected bool resultReady = false;
AsyncException exception;
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
public bool Ready
{
get { return resultReady; }
}
public object Result
{
get { return result; }
}
public IAsyncReply<T> Then(Action<T> callback)
{
callbacks.Add(callback);
if (resultReady)
callback(result);
return this;
}
public IAsyncReply<T> Error(Action<AsyncException> callback)
{
errorCallbacks.Add(callback);
if (exception != null)
{
callback(exception);
tcs.SetException(exception);
}
return this;
}
public IAsyncReply<T> Progress(Action<ProgressType, int, int> callback)
{
progressCallbacks.Add(callback);
return this;
}
public IAsyncReply<T> Chunk(Action<T> 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<T> GetAwaiter()
{
return new AsyncAwaiter<T>(this);
}
public Task Task
{
get
{
return tcs.Task;
}
}
public AsyncReply()
{
}
public AsyncReply(T result)
{
resultReady = true;
tcs.SetResult(result);
this.result = result;
}
/*
public AsyncReply<T> Then(Action<T> callback)
{ {
base.Then(new Action<object>(o => callback((T)o))); base.Then(new Action<object>(o => callback((T)o)));
return this; return this;
@ -46,6 +208,15 @@ namespace Esiur.Engine
Trigger((object)result); Trigger((object)result);
} }
public Task<bool> MoveNext(CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public void Dispose()
{
}
public AsyncReply() public AsyncReply()
{ {
@ -67,13 +238,15 @@ namespace Esiur.Engine
} }
} }
public T Current => throw new NotImplementedException();
public AsyncReply(T result) public AsyncReply(T result)
: base(result) : base(result)
{ {
} }
*/
} }
} }

12
Esiur/Engine/ErrorType.cs Normal file
View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Engine
{
public enum ErrorType
{
Management,
Exception
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
namespace Esiur.Engine
{
public interface IAsyncReply<out T>//IAsyncEnumerator<T>
{
IAsyncReply<T> Then(Action<T> callback);
IAsyncReply<T> Error(Action<AsyncException> callback);
IAsyncReply<T> Progress(Action<ProgressType, int, int> callback);
IAsyncReply<T> Chunk(Action<T> callback);
void Trigger(object result);
void TriggerError(AsyncException exception);
void TriggerProgress(ProgressType type, int value, int max);
void TriggerChunk(object value);
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Engine
{
public enum ProgressType
{
Execution,
Network,
}
}

View File

@ -7,9 +7,11 @@
<PackageLicenseUrl>https://github.com/esiur/esiur-dotnet/blob/master/LICENSE</PackageLicenseUrl> <PackageLicenseUrl>https://github.com/esiur/esiur-dotnet/blob/master/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>http://www.esiur.com</PackageProjectUrl> <PackageProjectUrl>http://www.esiur.com</PackageProjectUrl>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>1.1.0</Version> <Version>1.2.3</Version>
<RepositoryUrl>https://github.com/esiur/esiur-dotnet</RepositoryUrl> <RepositoryUrl>https://github.com/esiur/esiur-dotnet</RepositoryUrl>
<Authors>Ahmed Kh. Zamil</Authors> <Authors>Ahmed Kh. Zamil</Authors>
<AssemblyVersion>1.2.3.0</AssemblyVersion>
<Company>Esiur Foundation</Company>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@ -22,6 +24,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Remove="Engine\AsyncReply.cs" />
<Compile Remove="Net\UDP\UDPServer.cs" /> <Compile Remove="Net\UDP\UDPServer.cs" />
</ItemGroup> </ItemGroup>
@ -30,12 +33,14 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Engine\AsyncReply.cs" />
<None Include="Net\UDP\UDPServer.cs" /> <None Include="Net\UDP\UDPServer.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Diagnostics.StackTrace" Version="4.3.0" /> <PackageReference Include="System.Diagnostics.StackTrace" Version="4.3.0" />
<PackageReference Include="System.Dynamic.Runtime" Version="4.3.0" /> <PackageReference Include="System.Dynamic.Runtime" Version="4.3.0" />
<PackageReference Include="System.Interactive.Async" Version="3.2.0" />
<PackageReference Include="System.Net.NameResolution" Version="4.3.0" /> <PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
<PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" /> <PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" />
<PackageReference Include="System.Net.Security" Version="4.3.1" /> <PackageReference Include="System.Net.Security" Version="4.3.1" />

View File

@ -50,7 +50,7 @@ namespace Esiur.Net.DataLink
public void Destroy() public void Destroy()
{ {
throw new NotImplementedException();
} }
} }
} }

View File

@ -36,8 +36,36 @@ namespace Esiur.Net.HTTP
{ {
public class IIPoWS: HTTPFilter public class IIPoWS: HTTPFilter
{ {
[ResourceProperty]
public DistributedServer DistributedServer
{
get;
set;
}
public override bool Execute(HTTPConnection sender) 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/")) if (sender.Request.Filename.StartsWith("/iip/"))
{ {
// find the service // find the service
@ -73,6 +101,7 @@ namespace Esiur.Net.HTTP
} }
return false; return false;
*/
} }
private void IipConnection_OnReady(DistributedConnection sender) private void IipConnection_OnReady(DistributedConnection sender)

View File

@ -524,13 +524,13 @@ namespace Esiur.Net.IIP
switch (packet.Report) switch (packet.Report)
{ {
case IIPPacketReport.ManagementError: case IIPPacketReport.ManagementError:
IIPReportError(packet.CallbackId, AsyncReply.ErrorType.Management, packet.ErrorCode, null); IIPReportError(packet.CallbackId, ErrorType.Management, packet.ErrorCode, null);
break; break;
case IIPPacketReport.ExecutionError: case IIPPacketReport.ExecutionError:
IIPReportError(packet.CallbackId, AsyncReply.ErrorType.Exception, packet.ErrorCode, packet.ErrorMessage); IIPReportError(packet.CallbackId, ErrorType.Exception, packet.ErrorCode, packet.ErrorMessage);
break; break;
case IIPPacketReport.ProgressReport: case IIPPacketReport.ProgressReport:
IIPReportProgress(packet.CallbackId, AsyncReply.ProgressType.Execution, packet.ProgressValue, packet.ProgressMax); IIPReportProgress(packet.CallbackId, ProgressType.Execution, packet.ProgressValue, packet.ProgressMax);
break; break;
case IIPPacketReport.ChunkStream: case IIPPacketReport.ChunkStream:
IIPReportChunk(packet.CallbackId, packet.Content); IIPReportChunk(packet.CallbackId, packet.Content);
@ -735,5 +735,11 @@ namespace Esiur.Net.IIP
// nothing to do // nothing to do
return true; return true;
} }
public AsyncReply<bool> Open(Structure settings)
{
return new AsyncReply<bool>(true);
}
} }
} }

View File

@ -50,7 +50,7 @@ namespace Esiur.Net.IIP
Dictionary<Guid, ResourceTemplate> templates = new Dictionary<Guid, ResourceTemplate>(); Dictionary<Guid, ResourceTemplate> templates = new Dictionary<Guid, ResourceTemplate>();
KeyList<uint, AsyncReply> requests = new KeyList<uint, AsyncReply>(); KeyList<uint, IAsyncReply<object>> requests = new KeyList<uint, IAsyncReply<object>>();
uint callbackCounter = 0; uint callbackCounter = 0;
@ -62,7 +62,7 @@ namespace Esiur.Net.IIP
/// <param name="action">Packet action.</param> /// <param name="action">Packet action.</param>
/// <param name="args">Arguments to send.</param> /// <param name="args">Arguments to send.</param>
/// <returns></returns> /// <returns></returns>
internal AsyncReply<object[]> SendRequest(IIPPacket.IIPPacketAction action, params object[] args) internal IAsyncReply<object[]> SendRequest(IIPPacket.IIPPacketAction action, params object[] args)
{ {
var reply = new AsyncReply<object[]>(); var reply = new AsyncReply<object[]>();
callbackCounter++; callbackCounter++;
@ -100,11 +100,11 @@ namespace Esiur.Net.IIP
Send(bl.ToArray()); Send(bl.ToArray());
} }
internal AsyncReply SendInvokeByArrayArguments(uint instanceId, byte index, object[] parameters) internal AsyncReply<object> SendInvokeByArrayArguments(uint instanceId, byte index, object[] parameters)
{ {
var pb = Codec.ComposeVarArray(parameters, this, true); var pb = Codec.ComposeVarArray(parameters, this, true);
var reply = new AsyncReply(); var reply = new AsyncReply<object>();
callbackCounter++; callbackCounter++;
var bl = new BinaryList((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments), var bl = new BinaryList((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments),
callbackCounter, instanceId, index, pb); callbackCounter, instanceId, index, pb);
@ -114,11 +114,11 @@ namespace Esiur.Net.IIP
return reply; return reply;
} }
internal AsyncReply SendInvokeByNamedArguments(uint instanceId, byte index, Structure parameters) internal AsyncReply<object> SendInvokeByNamedArguments(uint instanceId, byte index, Structure parameters)
{ {
var pb = Codec.ComposeStructure(parameters, this, true, true, true); var pb = Codec.ComposeStructure(parameters, this, true, true, true);
var reply = new AsyncReply(); var reply = new AsyncReply<object>();
callbackCounter++; callbackCounter++;
var bl = new BinaryList((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments), var bl = new BinaryList((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments),
callbackCounter, instanceId, index, pb); 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); var msg = DC.ToBytes(errorMessage);
if (type == AsyncReply.ErrorType.Management) if (type == ErrorType.Management)
SendParams((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ManagementError), callbackId, errorCode); 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); 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); var req = requests.Take(callbackId);
req?.TriggerError(new AsyncException(errorType, errorCode, errorMessage)); 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]; var req = requests[callbackId];
req?.TriggerProgress(type, value, max); req?.TriggerProgress(type, value, max);
@ -379,7 +379,7 @@ namespace Esiur.Net.IIP
{ {
if (res.Instance.Applicable(session, ActionType.Attach, null) == Ruling.Denied) if (res.Instance.Applicable(session, ActionType.Attach, null) == Ruling.Denied)
{ {
SendError(AsyncReply.ErrorType.Management, callback, 6); SendError(ErrorType.Management, callback, 6);
return; return;
} }
@ -415,7 +415,7 @@ namespace Esiur.Net.IIP
{ {
// reply failed // reply failed
//SendParams(0x80, r.Instance.Id, r.Instance.Age, r.Instance.Serialize(false, this)); //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 else
{ {
// reply failed // 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 else
{ {
// reply failed // 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) if (store == null)
{ {
SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.StoreNotFound); SendError(ErrorType.Management, callback, (ushort)ExceptionCode.StoreNotFound);
return; return;
} }
if (!(store is IStore)) if (!(store is IStore))
{ {
SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceIsNotStore); SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceIsNotStore);
return; return;
} }
// check security // check security
if (store.Instance.Applicable(session, ActionType.CreateResource, null) != Ruling.Allowed) 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; return;
} }
@ -517,7 +517,7 @@ namespace Esiur.Net.IIP
if (parent != null) if (parent != null)
if (parent.Instance.Applicable(session, ActionType.AddChild, null) != Ruling.Allowed) 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; return;
} }
@ -537,7 +537,7 @@ namespace Esiur.Net.IIP
if (type == null) if (type == null)
{ {
SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ClassNotFound); SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ClassNotFound);
return; return;
} }
@ -614,13 +614,13 @@ namespace Esiur.Net.IIP
{ {
if (r == null) if (r == null)
{ {
SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound);
return; return;
} }
if (r.Instance.Store.Instance.Applicable(session, ActionType.Delete, null) != Ruling.Allowed) 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; return;
} }
@ -628,7 +628,7 @@ namespace Esiur.Net.IIP
SendReply(IIPPacket.IIPPacketAction.DeleteResource, callback); SendReply(IIPPacket.IIPPacketAction.DeleteResource, callback);
//SendParams((byte)0x84, callback); //SendParams((byte)0x84, callback);
else 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) if (r == null)
{ {
SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound);
return; return;
} }
// if (!r.Instance.Store.Instance.Applicable(r, session, ActionType.InquireAttributes, null)) // if (!r.Instance.Store.Instance.Applicable(r, session, ActionType.InquireAttributes, null))
if (r.Instance.Applicable(session, ActionType.InquireAttributes, null) != Ruling.Allowed) 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; return;
} }
@ -660,7 +660,7 @@ namespace Esiur.Net.IIP
SendReply(all ? IIPPacket.IIPPacketAction.GetAllAttributes : IIPPacket.IIPPacketAction.GetAttributes, callback, SendReply(all ? IIPPacket.IIPPacketAction.GetAllAttributes : IIPPacket.IIPPacketAction.GetAttributes, callback,
Codec.ComposeStructure(st, this, true, true, true)); Codec.ComposeStructure(st, this, true, true, true));
else 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) if (parent == null)
{ {
SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound);
return; return;
} }
@ -679,19 +679,19 @@ namespace Esiur.Net.IIP
{ {
if (child == null) if (child == null)
{ {
SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound);
return; return;
} }
if (parent.Instance.Applicable(this.session, ActionType.AddChild, null) != Ruling.Allowed) 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; return;
} }
if (child.Instance.Applicable(this.session, ActionType.AddParent, null) != Ruling.Allowed) 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; return;
} }
@ -710,7 +710,7 @@ namespace Esiur.Net.IIP
{ {
if (parent == null) if (parent == null)
{ {
SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound);
return; return;
} }
@ -718,19 +718,19 @@ namespace Esiur.Net.IIP
{ {
if (child == null) if (child == null)
{ {
SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound);
return; return;
} }
if (parent.Instance.Applicable(this.session, ActionType.RemoveChild, null) != Ruling.Allowed) 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; return;
} }
if (child.Instance.Applicable(this.session, ActionType.RemoveParent, null) != Ruling.Allowed) 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; return;
} }
@ -749,13 +749,13 @@ namespace Esiur.Net.IIP
{ {
if (resource == null) if (resource == null)
{ {
SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound);
return; return;
} }
if (resource.Instance.Applicable(this.session, ActionType.Rename, null) != Ruling.Allowed) 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; return;
} }
@ -771,7 +771,7 @@ namespace Esiur.Net.IIP
{ {
if (resource == null) if (resource == null)
{ {
SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound);
return; return;
} }
@ -789,7 +789,7 @@ namespace Esiur.Net.IIP
{ {
if (resource == null) if (resource == null)
{ {
SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound);
return; return;
} }
@ -807,13 +807,13 @@ namespace Esiur.Net.IIP
{ {
if (r == null) if (r == null)
{ {
SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound);
return; return;
} }
if (r.Instance.Store.Instance.Applicable(session, ActionType.UpdateAttributes, null) != Ruling.Allowed) 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; return;
} }
@ -825,7 +825,7 @@ namespace Esiur.Net.IIP
if (r.Instance.RemoveAttributes(attrs)) if (r.Instance.RemoveAttributes(attrs))
SendReply(all ? IIPPacket.IIPPacketAction.ClearAllAttributes : IIPPacket.IIPPacketAction.ClearAttributes, callback); SendReply(all ? IIPPacket.IIPPacketAction.ClearAllAttributes : IIPPacket.IIPPacketAction.ClearAttributes, callback);
else 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) if (r == null)
{ {
SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound);
return; return;
} }
if (r.Instance.Store.Instance.Applicable(session, ActionType.UpdateAttributes, null) != Ruling.Allowed) 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; return;
} }
@ -852,7 +852,7 @@ namespace Esiur.Net.IIP
SendReply(clearAttributes ? IIPPacket.IIPPacketAction.ClearAllAttributes : IIPPacket.IIPPacketAction.ClearAttributes, SendReply(clearAttributes ? IIPPacket.IIPPacketAction.ClearAllAttributes : IIPPacket.IIPPacketAction.ClearAttributes,
callback); callback);
else 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 else
{ {
// reply failed // 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 else
{ {
// reply failed // 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 else
{ {
// reply failed // 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(); var list = r.Where(x => x.Instance.Applicable(session, ActionType.Attach, null) != Ruling.Denied).ToArray();
if (list.Length == 0) if (list.Length == 0)
SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound);
else else
SendReply(IIPPacket.IIPPacketAction.QueryLink, callback, Codec.ComposeResourceArray(list, this, true)); 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) if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied)
{ {
SendError(AsyncReply.ErrorType.Management, callback, SendError(ErrorType.Management, callback,
(ushort)ExceptionCode.InvokeDenied); (ushort)ExceptionCode.InvokeDenied);
return; return;
} }
@ -1009,7 +1009,7 @@ namespace Esiur.Net.IIP
} }
catch(Exception ex) catch(Exception ex)
{ {
SendError(AsyncReply.ErrorType.Exception, callback, 0, ex.ToString()); SendError(ErrorType.Exception, callback, 0, ex.ToString());
return; return;
} }
@ -1038,14 +1038,15 @@ namespace Esiur.Net.IIP
//await t; //await t;
//SendParams((byte)0x90, callback, Codec.Compose(res, this)); //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<object>).Then(res =>
{ {
SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback, Codec.Compose(res, this)); SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback, Codec.Compose(res, this));
}).Error(ex => }).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) => }).Progress((pt, pv, pm) =>
{ {
SendProgress(callback, pv, pm); SendProgress(callback, pv, pm);
@ -1119,7 +1120,7 @@ namespace Esiur.Net.IIP
{ {
if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied) if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied)
{ {
SendError(AsyncReply.ErrorType.Management, callback, SendError(ErrorType.Management, callback,
(ushort)ExceptionCode.InvokeDenied); (ushort)ExceptionCode.InvokeDenied);
return; return;
} }
@ -1150,7 +1151,7 @@ namespace Esiur.Net.IIP
} }
catch (Exception ex) catch (Exception ex)
{ {
SendError(AsyncReply.ErrorType.Exception, callback, 0, ex.ToString()); SendError(ErrorType.Exception, callback, 0, ex.ToString());
return; return;
} }
@ -1177,14 +1178,16 @@ namespace Esiur.Net.IIP
}); });
} }
else if (rt is AsyncReply) // else if (rt is AsyncReply)
{ else if (rt.GetType().GetTypeInfo().IsGenericType
(rt as AsyncReply).Then(res => && rt.GetType().GetGenericTypeDefinition() == typeof(IAsyncReply<>))
{
(rt as IAsyncReply<object>).Then(res =>
{ {
SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback, Codec.Compose(res, this)); SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback, Codec.Compose(res, this));
}).Error(ex => }).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) => }).Progress((pt, pv, pm) =>
{ {
SendProgress(callback, 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) 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; return;
} }
if (!pi.CanWrite) if (!pi.CanWrite)
{ {
SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ReadOnlyProperty); SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ReadOnlyProperty);
return; return;
} }
@ -1405,14 +1408,14 @@ namespace Esiur.Net.IIP
} }
catch(Exception ex) catch(Exception ex)
{ {
SendError(AsyncReply.ErrorType.Exception, callback, 0, ex.Message); SendError(ErrorType.Exception, callback, 0, ex.Message);
} }
} }
else else
{ {
// pt found, pi not found, this should never happen // 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 else
{ {
// property not found // property not found
SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.PropertyNotFound); SendError(ErrorType.Management, callback, (ushort)ExceptionCode.PropertyNotFound);
} }
} }
else else
{ {
// resource not found // 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 => 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 => Codec.ParseResourceArray(d, 0, (uint)d.Length, this).Then(resources =>
{ {
rt.Trigger(resources); rt.Trigger(resources);
@ -1734,7 +1737,7 @@ namespace Esiur.Net.IIP
SendRequest(IIPPacket.IIPPacketAction.ResourceParents, resource.Instance.Id).Then(ar => 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 => Codec.ParseResourceArray(d, 0, (uint)d.Length, this).Then(resources =>
{ {
rt.Trigger(resources); rt.Trigger(resources);

View File

@ -234,7 +234,7 @@ namespace Esiur.Net.IIP
Instance.EmitResourceEvent(null, null, et.Name, args); Instance.EmitResourceEvent(null, null, et.Name, args);
} }
public AsyncReply _InvokeByNamedArguments(byte index, Structure namedArgs) public AsyncReply<object> _InvokeByNamedArguments(byte index, Structure namedArgs)
{ {
if (destroyed) if (destroyed)
throw new Exception("Trying to access destroyed object"); throw new Exception("Trying to access destroyed object");
@ -246,7 +246,7 @@ namespace Esiur.Net.IIP
return connection.SendInvokeByNamedArguments(instanceId, index, namedArgs); return connection.SendInvokeByNamedArguments(instanceId, index, namedArgs);
} }
public AsyncReply _InvokeByArrayArguments(byte index, object[] args) public AsyncReply<object> _InvokeByArrayArguments(byte index, object[] args)
{ {
if (destroyed) if (destroyed)
throw new Exception("Trying to access destroyed object"); throw new Exception("Trying to access destroyed object");
@ -263,7 +263,7 @@ namespace Esiur.Net.IIP
{ {
var ft = Instance.Template.GetFunctionTemplate(binder.Name); var ft = Instance.Template.GetFunctionTemplate(binder.Name);
var reply = new AsyncReply(); var reply = new AsyncReply<object>();
if (isAttached && ft!=null) if (isAttached && ft!=null)
{ {
@ -358,12 +358,12 @@ namespace Esiur.Net.IIP
/// <param name="index">Zero-based property index.</param> /// <param name="index">Zero-based property index.</param>
/// <param name="value">Value</param> /// <param name="value">Value</param>
/// <returns>Indicator when the property is set.</returns> /// <returns>Indicator when the property is set.</returns>
internal AsyncReply _Set(byte index, object value) internal AsyncReply<object> _Set(byte index, object value)
{ {
if (index >= properties.Length) if (index >= properties.Length)
return null; return null;
var reply = new AsyncReply(); var reply = new AsyncReply<object>();
var parameters = Codec.Compose(value, connection); var parameters = Codec.Compose(value, connection);
connection.SendRequest(Packets.IIPPacket.IIPPacketAction.SetProperty, instanceId, index, parameters).Then((res) => connection.SendRequest(Packets.IIPPacket.IIPPacketAction.SetProperty, instanceId, index, parameters).Then((res) =>

View File

@ -35,6 +35,7 @@ namespace Esiur.Resource
{ {
public interface IStore:IResource public interface IStore:IResource
{ {
AsyncReply<bool> Open(Structure settings);
AsyncReply<IResource> Get(string path); AsyncReply<IResource> Get(string path);
AsyncReply<IResource> Retrieve(uint iid); AsyncReply<IResource> Retrieve(uint iid);
bool Put(IResource resource); bool Put(IResource resource);

View File

@ -30,7 +30,7 @@ namespace Esiur.Resource.Template
if (Expansion != null) if (Expansion != null)
{ {
var exp = DC.ToBytes(Expansion); 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 else
return BinaryList.ToBytes((byte)(IsVoid ? 0x8 : 0x0), (byte)name.Length, name); return BinaryList.ToBytes((byte)(IsVoid ? 0x8 : 0x0), (byte)name.Length, name);

View File

@ -66,17 +66,17 @@ namespace Esiur.Resource.Template
{ {
var rexp = DC.ToBytes(ReadExpansion); var rexp = DC.ToBytes(ReadExpansion);
var wexp = DC.ToBytes(WriteExpansion); 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) else if (WriteExpansion != null)
{ {
var wexp = DC.ToBytes(WriteExpansion); 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) else if (ReadExpansion != null)
{ {
var rexp = DC.ToBytes(ReadExpansion); 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 else
return BinaryList.ToBytes((byte)(0x20 | pv), (byte)name.Length, name); return BinaryList.ToBytes((byte)(0x20 | pv), (byte)name.Length, name);

View File

@ -228,7 +228,7 @@ namespace Esiur.Resource.Template
od.classId = data.GetGuid(offset); od.classId = data.GetGuid(offset);
offset += 16; 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; offset += (uint)data[offset] + 1;
od.version = data.GetInt32(offset); od.version = data.GetInt32(offset);
@ -250,7 +250,7 @@ namespace Esiur.Resource.Template
string expansion = null; string expansion = null;
var hasExpansion = ((data[offset] & 0x10) == 0x10); var hasExpansion = ((data[offset] & 0x10) == 0x10);
var isVoid = ((data[offset++] & 0x08) == 0x08); 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; offset += (uint)data[offset] + 1;
if (hasExpansion) // expansion ? if (hasExpansion) // expansion ?

View File

@ -53,6 +53,7 @@ namespace Esiur.Resource
public static event StoreConnectedEvent StoreConnected; public static event StoreConnectedEvent StoreConnected;
public static event StoreDisconnectedEvent StoreDisconnected; public static event StoreDisconnectedEvent StoreDisconnected;
static KeyList<string, IStore> protocols = new KeyList<string, IStore>();
/// <summary> /// <summary>
/// Get a store by its name. /// Get a store by its name.
@ -234,7 +235,7 @@ namespace Esiur.Resource
/// </summary> /// </summary>
/// <param name="path"></param> /// <param name="path"></param>
/// <returns>Resource instance.</returns> /// <returns>Resource instance.</returns>
public static AsyncReply<IResource> Get(string path) public static AsyncReply<IResource> Get(string path, Structure settings = null, IResource parent = null, IPermissionsManager manager = null)
{ {
var p = path.Split('/'); var p = path.Split('/');
@ -265,6 +266,41 @@ namespace Esiur.Resource
return new AsyncReply<IResource>(res); return new AsyncReply<IResource>(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<IResource>();
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<IResource>(null); return new AsyncReply<IResource>(null);
} }

View File

@ -75,5 +75,10 @@ namespace Esiur.Stores
{ {
return true; return true;
} }
public AsyncReply<bool> Open(Structure settings)
{
return new AsyncReply<bool>(true);
}
} }
} }

View File

@ -36,10 +36,10 @@ namespace Test
return Level; return Level;
} }
[ResourceFunction] [ResourceFunction("Divide takes two arguments nominator and denominator")]
public double Divide(float nominator, float denominator, DistributedConnection sender) public double Divide(float n, float d, DistributedConnection sender)
{ {
return nominator / denominator; return n / d;
} }
[ResourceFunction] [ResourceFunction]
@ -50,7 +50,7 @@ namespace Test
return Level; return Level;
} }
[ResourceFunction] [ResourceFunction("use it with next()")]
public IEnumerable<string> Enum(int count) public IEnumerable<string> 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" }; 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<string> Stream(int count) public AsyncReply<string> Stream(int count)
{ {
var reply = new AsyncReply<string>(); var reply = new AsyncReply<string>();
@ -73,7 +73,7 @@ namespace Test
timer = new Timer((x) => timer = new Timer((x) =>
{ {
reply.TriggerProgress(AsyncReply.ProgressType.Execution, count, 22); reply.TriggerProgress(ProgressType.Execution, count, 22);
if (count % 2 == 0 && msgCounter < msg.Length) if (count % 2 == 0 && msgCounter < msg.Length)
reply.TriggerChunk(msg[msgCounter++]); reply.TriggerChunk(msg[msgCounter++]);

View File

@ -43,15 +43,10 @@ namespace Test
static DistributedResource remoteObject; 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(() => ()); //AsyncContext.Run(() => ());
// Create stores to keep objects. // Create stores to keep objects.
@ -59,65 +54,71 @@ namespace Test
var remote = Warehouse.New<MemoryStore>("remote"); var remote = Warehouse.New<MemoryStore>("remote");
var mongo = Warehouse.New<MongoDBStore>("db"); var mongo = Warehouse.New<MongoDBStore>("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 // Open the warehouse
var ok = await Warehouse.Open().Task;
// Create new object if the store is empty // Create new object if the store is empty
if (mongo.Count == 0) if (mongo.Count == 0)
myObject = Warehouse.New<MyObject>("my", mongo, null, myObject = Warehouse.New<MyObject>("my", mongo, null,
new UserPermissionsManager(new Structure() 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<DistributedServer>("iip", system);
// Set membership which handles authentication.
iip.Membership = Warehouse.New<MyMembership>("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<HTTPServer>("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>("IIPoWS", system, http);
Warehouse.StoreConnected += (store, name) =>
{
if (store.Instance.Parents.Contains(iip))
{ {
store.Get("local/js").Then((r) => ["demo@localhost"] = new Structure()
{ {
if (r != null) ["Subtract"] = new Structure { ["Execute"] = "yes" },
{ ["Stream"] = new Structure { ["Execute"] = "yes" },
dynamic d = r; ["_attach"] = "yes",
d.send("Welcome"); ["_get_attributes"] = "yes",
} ["_set_attributes"] = "yes",
}); }
} }));
}; else
myObject =(MyObject) (await Warehouse.Get("db/my"));//.Then((o) => { myObject = (MyObject)o; });
// Start testing // Create new distributed server object
// TestClient(); var iip = Warehouse.New<DistributedServer>("iip", system);
// Set membership which handles authentication.
iip.Membership = Warehouse.New<MyMembership>("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<HTTPServer>("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>("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; var running = true;
@ -137,6 +138,8 @@ namespace Test
else else
Console.WriteLine(myObject.Name + " " + myObject.Level); Console.WriteLine(myObject.Name + " " + myObject.Level);
} }
} }
private static void TestClient() private static void TestClient()
@ -148,12 +151,12 @@ namespace Test
// Put the client in our memory store // Put the client in our memory store
var remote = Warehouse.GetStore("remote"); var remote = Warehouse.GetStore("remote");
Warehouse.Put(client, "Endpoint", remote); Warehouse.Put(client, "Endpoint", remote);
client.OnReady += async (c) => client.OnReady += async (c) =>
{ {
// Get remote object from the server. // 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; dynamic x = remoteObject;
@ -169,13 +172,13 @@ namespace Test
Console.WriteLine("LevelUp " + parameters[0] + " " + parameters[1]); Console.WriteLine("LevelUp " + parameters[0] + " " + parameters[1]);
}); });
(x.Stream(10) as AsyncReply).Then(r => (x.Stream(10) as AsyncReply<object>).Then(r =>
{ {
Console.WriteLine("Stream ended: " + r); Console.WriteLine("Stream ended: " + r);
}).Chunk(r=> }).Chunk(r =>
{ {
Console.WriteLine("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; var rt = await x.Subtract(10).Task;