mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2025-05-06 11:32:59 +00:00
Static Calling
This commit is contained in:
parent
0dc457bf7e
commit
af94ce318a
@ -47,5 +47,4 @@ public class AsyncAwaiter<T> : INotifyCompletion
|
|||||||
callback = continuation;
|
callback = continuation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -90,6 +90,16 @@ public class AsyncReply
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AsyncReply Timeout(int milliseconds, Action callback)
|
||||||
|
{
|
||||||
|
Task.Delay(milliseconds).ContinueWith(x =>
|
||||||
|
{
|
||||||
|
if (!resultReady && exception == null)
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public object Wait(int millisecondsTimeout)
|
public object Wait(int millisecondsTimeout)
|
||||||
{
|
{
|
||||||
|
@ -40,5 +40,6 @@ public enum ExceptionCode : ushort
|
|||||||
NotAttached,
|
NotAttached,
|
||||||
AlreadyListened,
|
AlreadyListened,
|
||||||
AlreadyUnlistened,
|
AlreadyUnlistened,
|
||||||
NotListenable
|
NotListenable,
|
||||||
|
ParseError
|
||||||
}
|
}
|
||||||
|
20
Esiur/Data/VarInfo.cs
Normal file
20
Esiur/Data/VarInfo.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace Esiur.Data
|
||||||
|
{
|
||||||
|
struct VarInfo
|
||||||
|
{
|
||||||
|
public string Pre;
|
||||||
|
public string Post;
|
||||||
|
public string VarName;
|
||||||
|
|
||||||
|
public string Build()
|
||||||
|
{
|
||||||
|
return Regex.Escape(Pre) + @"(?<" + VarName + @">[^\{]*)" + Regex.Escape(Post);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
111
Esiur/Esiur - Backup.csproj
Normal file
111
Esiur/Esiur - Backup.csproj
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<Description>Distributed Resources Platform</Description>
|
||||||
|
<Copyright>Ahmed Kh. Zamil</Copyright>
|
||||||
|
<PackageProjectUrl>http://www.esiur.com</PackageProjectUrl>
|
||||||
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
|
<Version>2.2.6.1</Version>
|
||||||
|
<RepositoryUrl>https://github.com/esiur/esiur-dotnet</RepositoryUrl>
|
||||||
|
<Authors>Ahmed Kh. Zamil</Authors>
|
||||||
|
<AssemblyVersion></AssemblyVersion>
|
||||||
|
<Company>Esiur Foundation</Company>
|
||||||
|
<FileVersion></FileVersion>
|
||||||
|
<AssemblyName>Esiur</AssemblyName>
|
||||||
|
<RootNamespace>Esiur</RootNamespace>
|
||||||
|
<PackageId>Esiur</PackageId>
|
||||||
|
<Product>Esiur</Product>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
|
<DefineConstants>TRACE;DEBUG;NETSTANDARD</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="obj\**" />
|
||||||
|
<EmbeddedResource Remove="obj\**" />
|
||||||
|
<None Remove="obj\**" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="Core\AsyncBagAwaiterGeneric.cs" />
|
||||||
|
<Compile Remove="Core\AsyncBagGeneric.cs" />
|
||||||
|
<Compile Remove="Core\AsyncReplyNon.cs" />
|
||||||
|
<Compile Remove="Core\IAsyncReply.cs" />
|
||||||
|
<Compile Remove="Data\DataType.cs" />
|
||||||
|
<Compile Remove="Resource\ResourceEvent.cs" />
|
||||||
|
<Compile Remove="Resource\ResourceFunction.cs" />
|
||||||
|
<Compile Remove="Resource\ResourceProperty.cs" />
|
||||||
|
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Net\DataLink\Sources\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="Core\AsyncBagAwaiterGeneric.cs" />
|
||||||
|
<None Include="Core\AsyncReplyNon.cs" />
|
||||||
|
<None Include="Core\IAsyncReply.cs" />
|
||||||
|
<None Include="Data\DataType.cs" />
|
||||||
|
<None Include="Resource\ResourceEvent.cs" />
|
||||||
|
<None Include="Resource\ResourceFunction.cs" />
|
||||||
|
<None Include="Resource\ResourceProperty.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.2.0" />
|
||||||
|
<PackageReference Include="System.Collections" Version="4.3.0" />
|
||||||
|
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||||
|
<PackageReference Include="System.Diagnostics.StackTrace" Version="4.3.0" />
|
||||||
|
<PackageReference Include="System.Dynamic.Runtime" Version="4.3.0" />
|
||||||
|
<PackageReference Include="System.Interactive.Async" Version="6.0.1" />
|
||||||
|
<PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
|
||||||
|
<PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" />
|
||||||
|
<PackageReference Include="System.Net.Security" Version="4.3.2" />
|
||||||
|
<PackageReference Include="System.Reflection.Emit" Version="4.7.0" />
|
||||||
|
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" />
|
||||||
|
<PackageReference Include="System.Text.Json" Version="6.0.4" GeneratePathProperty="true" />
|
||||||
|
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
|
||||||
|
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.2.0" PrivateAssets="all" />
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" PrivateAssets="all" />
|
||||||
|
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
||||||
|
<!-- Package the Newtonsoft.Json dependency alongside the generator assembly -->
|
||||||
|
<None Include="$(PkgSystem_Text_Json)\lib\netstandard2.0\*.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
||||||
|
<None Include="Tools/*" Pack="true" PackagePath="tools/" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="Core\AsyncBagGeneric.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="LICENSE" Pack="true" PackagePath="">
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Include="Core\AsyncBagAwaiterGeneric.cs" />
|
||||||
|
<Page Include="Core\AsyncBagGeneric.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</Project>
|
@ -6,7 +6,7 @@
|
|||||||
<Copyright>Ahmed Kh. Zamil</Copyright>
|
<Copyright>Ahmed Kh. Zamil</Copyright>
|
||||||
<PackageProjectUrl>http://www.esiur.com</PackageProjectUrl>
|
<PackageProjectUrl>http://www.esiur.com</PackageProjectUrl>
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<Version>2.2.5</Version>
|
<Version>2.2.6.2</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></AssemblyVersion>
|
<AssemblyVersion></AssemblyVersion>
|
||||||
|
@ -482,6 +482,36 @@ public static Hashtable Cached
|
|||||||
else
|
else
|
||||||
return Expression;
|
return Expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static Regex GetRouteRegex(string url)
|
||||||
|
{
|
||||||
|
var sc = Regex.Match(url, @"([^\{]*)\{([^\}]*)\}([^\{]*)");
|
||||||
|
|
||||||
|
List<VarInfo> vars = new List<VarInfo>();
|
||||||
|
|
||||||
|
while (sc.Success)
|
||||||
|
{
|
||||||
|
vars.Add(new VarInfo()
|
||||||
|
{
|
||||||
|
Pre = sc.Groups[1].Value,
|
||||||
|
VarName = sc.Groups[2].Value,
|
||||||
|
Post = sc.Groups[3].Value
|
||||||
|
});
|
||||||
|
sc = sc.NextMatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vars.Count > 0)
|
||||||
|
{
|
||||||
|
return new Regex("^" + String.Join("", vars.Select(x => x.Build()).ToArray()) + "$");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new Regex("^" + Regex.Escape(url) + "$");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//public void Replace(string Expression, string Find, string Replacement, int Start, int Count)
|
//public void Replace(string Expression, string Find, string Replacement, int Start, int Count)
|
||||||
//{
|
//{
|
||||||
// Expression.IndexOf(
|
// Expression.IndexOf(
|
||||||
|
@ -128,46 +128,9 @@ public class HTTPServer : NetworkServer<HTTPConnection>, IResource
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VarInfo
|
|
||||||
{
|
|
||||||
public string Pre;
|
|
||||||
public string Post;
|
|
||||||
public string VarName;
|
|
||||||
|
|
||||||
public string Build()
|
|
||||||
{
|
|
||||||
return Regex.Escape(Pre) + @"(?<" + VarName + @">[^\{]*)" + Regex.Escape(Post);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static Regex getRouteRegex(string url)
|
|
||||||
{
|
|
||||||
var sc = Regex.Match(url, @"([^\{]*)\{([^\}]*)\}([^\{]*)");
|
|
||||||
|
|
||||||
List<VarInfo> vars = new List<VarInfo>();
|
|
||||||
|
|
||||||
while (sc.Success)
|
|
||||||
{
|
|
||||||
vars.Add(new VarInfo()
|
|
||||||
{
|
|
||||||
Pre = sc.Groups[1].Value,
|
|
||||||
VarName = sc.Groups[2].Value,
|
|
||||||
Post = sc.Groups[3].Value
|
|
||||||
});
|
|
||||||
sc = sc.NextMatch();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vars.Count > 0)
|
|
||||||
{
|
|
||||||
return new Regex("^" + String.Join("", vars.Select(x => x.Build()).ToArray()) + "$");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new Regex("^" + Regex.Escape(url) + "$");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Instance Instance
|
public Instance Instance
|
||||||
@ -276,18 +239,17 @@ public class HTTPServer : NetworkServer<HTTPConnection>, IResource
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//public delegate void HTTPGetHandler(HTTPConnection connection, object[] params values);
|
|
||||||
|
|
||||||
public void MapGet(string pattern, Delegate handler)
|
public void MapGet(string pattern, Delegate handler)
|
||||||
{
|
{
|
||||||
var regex = getRouteRegex(pattern);
|
var regex = Global.GetRouteRegex(pattern);
|
||||||
var list = routes[HTTPRequestPacket.HTTPMethod.GET];
|
var list = routes[HTTPRequestPacket.HTTPMethod.GET];
|
||||||
list.Add(new RouteInfo(handler, regex));
|
list.Add(new RouteInfo(handler, regex));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MapPost(string pattern, Delegate handler)
|
public void MapPost(string pattern, Delegate handler)
|
||||||
{
|
{
|
||||||
var regex = getRouteRegex(pattern);
|
var regex = Global.GetRouteRegex(pattern);
|
||||||
var list = routes[HTTPRequestPacket.HTTPMethod.POST];
|
var list = routes[HTTPRequestPacket.HTTPMethod.POST];
|
||||||
list.Add(new RouteInfo(handler, regex));
|
list.Add(new RouteInfo(handler, regex));
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ using System.Linq;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using static Esiur.Net.Packets.IIPPacket;
|
using static Esiur.Net.Packets.IIPPacket;
|
||||||
using Esiur.Net.HTTP;
|
using Esiur.Net.HTTP;
|
||||||
|
using System.Timers;
|
||||||
|
|
||||||
namespace Esiur.Net.IIP;
|
namespace Esiur.Net.IIP;
|
||||||
public partial class DistributedConnection : NetworkConnection, IStore
|
public partial class DistributedConnection : NetworkConnection, IStore
|
||||||
@ -47,6 +48,9 @@ public partial class DistributedConnection : NetworkConnection, IStore
|
|||||||
public delegate void ReadyEvent(DistributedConnection sender);
|
public delegate void ReadyEvent(DistributedConnection sender);
|
||||||
public delegate void ErrorEvent(DistributedConnection sender, byte errorCode, string errorMessage);
|
public delegate void ErrorEvent(DistributedConnection sender, byte errorCode, string errorMessage);
|
||||||
|
|
||||||
|
|
||||||
|
Timer keepAliveTimer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ready event is raised when the connection is fully established.
|
/// Ready event is raised when the connection is fully established.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -330,13 +334,64 @@ public partial class DistributedConnection : NetworkConnection, IStore
|
|||||||
else
|
else
|
||||||
x.Resource._UpdatePropertyByIndex(x.Index, x.Value);
|
x.Resource._UpdatePropertyByIndex(x.Index, x.Value);
|
||||||
});
|
});
|
||||||
//q.timeout?.Dispose();
|
|
||||||
|
|
||||||
var r = new Random();
|
var r = new Random();
|
||||||
localNonce = new byte[32];
|
localNonce = new byte[32];
|
||||||
r.NextBytes(localNonce);
|
r.NextBytes(localNonce);
|
||||||
|
|
||||||
|
keepAliveTimer = new Timer(KeepAliveInterval * 1000);
|
||||||
|
keepAliveTimer.Elapsed += KeepAliveTimer_Elapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Public] public virtual uint Jitter { get; set; }
|
||||||
|
|
||||||
|
public uint KeepAliveTime { get; set; } = 10;
|
||||||
|
|
||||||
|
DateTime? lastKeepAliveSent;
|
||||||
|
|
||||||
|
private void KeepAliveTimer_Elapsed(object sender, ElapsedEventArgs e)
|
||||||
|
{
|
||||||
|
if (!IsConnected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
keepAliveTimer.Stop();
|
||||||
|
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
|
uint interval = lastKeepAliveSent == null ? 0 :
|
||||||
|
(uint)(now - (DateTime)lastKeepAliveSent).TotalMilliseconds;
|
||||||
|
|
||||||
|
lastKeepAliveSent = now;
|
||||||
|
|
||||||
|
SendRequest(IIPPacketAction.KeepAlive)
|
||||||
|
.AddDateTime(now)
|
||||||
|
.AddUInt32(interval)
|
||||||
|
.Done()
|
||||||
|
.Then(x =>
|
||||||
|
{
|
||||||
|
|
||||||
|
Jitter = (uint)x[1];
|
||||||
|
keepAliveTimer.Start();
|
||||||
|
//Console.WriteLine($"Keep Alive Received {Jitter}");
|
||||||
|
}).Error(ex =>
|
||||||
|
{
|
||||||
|
keepAliveTimer.Stop();
|
||||||
|
Close();
|
||||||
|
}).Timeout((int)(KeepAliveTime * 1000), () =>
|
||||||
|
{
|
||||||
|
keepAliveTimer.Stop();
|
||||||
|
Close();
|
||||||
|
});
|
||||||
|
|
||||||
|
//Console.WriteLine("Keep Alive sent");
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint KeepAliveInterval { get; set; } = 30;
|
||||||
|
|
||||||
public override void Destroy()
|
public override void Destroy()
|
||||||
{
|
{
|
||||||
UnsubscribeAll();
|
UnsubscribeAll();
|
||||||
@ -535,6 +590,19 @@ public partial class DistributedConnection : NetworkConnection, IStore
|
|||||||
// @TODO : fix this
|
// @TODO : fix this
|
||||||
//IIPRequestClearAttributes(packet.CallbackId, packet.ResourceId, packet.Content, false);
|
//IIPRequestClearAttributes(packet.CallbackId, packet.ResourceId, packet.Content, false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IIPPacketAction.KeepAlive:
|
||||||
|
IIPRequestKeepAlive(packet.CallbackId, packet.CurrentTime, packet.Interval);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IIPPacketAction.ProcedureCall:
|
||||||
|
IIPRequestProcedureCall(packet.CallbackId, packet.Procedure, (TransmissionType)packet.DataType, msg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IIPPacketAction.StaticCall:
|
||||||
|
IIPRequestStaticCall(packet.CallbackId, packet.ClassId, packet.MethodIndex, (TransmissionType)packet.DataType, msg);
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (packet.Command == IIPPacket.IIPPacketCommand.Reply)
|
else if (packet.Command == IIPPacket.IIPPacketCommand.Reply)
|
||||||
@ -584,7 +652,9 @@ public partial class DistributedConnection : NetworkConnection, IStore
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// Invoke
|
// Invoke
|
||||||
case IIPPacket.IIPPacketAction.InvokeFunction:
|
case IIPPacketAction.InvokeFunction:
|
||||||
|
case IIPPacketAction.StaticCall:
|
||||||
|
case IIPPacketAction.ProcedureCall:
|
||||||
IIPReplyInvoke(packet.CallbackId, (TransmissionType)packet.DataType, msg);// packet.Content);
|
IIPReplyInvoke(packet.CallbackId, (TransmissionType)packet.DataType, msg);// packet.Content);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -615,6 +685,9 @@ public partial class DistributedConnection : NetworkConnection, IStore
|
|||||||
IIPReply(packet.CallbackId);
|
IIPReply(packet.CallbackId);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IIPPacketAction.KeepAlive:
|
||||||
|
IIPReply(packet.CallbackId, packet.CurrentTime, packet.Jitter);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -937,7 +1010,6 @@ public partial class DistributedConnection : NetworkConnection, IStore
|
|||||||
{
|
{
|
||||||
Warehouse.Put(this.RemoteUsername, this, null, Server).Then(x =>
|
Warehouse.Put(this.RemoteUsername, this, null, Server).Then(x =>
|
||||||
{
|
{
|
||||||
|
|
||||||
ready = true;
|
ready = true;
|
||||||
openReply?.Trigger(true);
|
openReply?.Trigger(true);
|
||||||
OnReady?.Invoke(this);
|
OnReady?.Invoke(this);
|
||||||
@ -1061,6 +1133,9 @@ public partial class DistributedConnection : NetworkConnection, IStore
|
|||||||
openReply?.Trigger(true);
|
openReply?.Trigger(true);
|
||||||
OnReady?.Invoke(this);
|
OnReady?.Invoke(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// start perodic keep alive timer
|
||||||
|
keepAliveTimer.Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Error)
|
else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Error)
|
||||||
@ -1326,28 +1401,61 @@ public partial class DistributedConnection : NetworkConnection, IStore
|
|||||||
// clean up
|
// clean up
|
||||||
readyToEstablish = false;
|
readyToEstablish = false;
|
||||||
|
|
||||||
|
keepAliveTimer.Stop();
|
||||||
|
|
||||||
|
|
||||||
foreach (var x in requests.Values)
|
foreach (var x in requests.Values)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed"));
|
x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Global.Log(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var x in resourceRequests.Values)
|
foreach (var x in resourceRequests.Values)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed"));
|
x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Global.Log(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var x in templateRequests.Values)
|
foreach (var x in templateRequests.Values)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed"));
|
x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Global.Log(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
requests.Clear();
|
requests.Clear();
|
||||||
resourceRequests.Clear();
|
resourceRequests.Clear();
|
||||||
templateRequests.Clear();
|
templateRequests.Clear();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (Server != null) {
|
||||||
foreach (var x in resources.Values)
|
foreach (var x in resources.Values)
|
||||||
x.Suspend();
|
x.Suspend();
|
||||||
|
|
||||||
UnsubscribeAll();
|
UnsubscribeAll();
|
||||||
|
|
||||||
Warehouse.Remove(this);
|
Warehouse.Remove(this);
|
||||||
|
|
||||||
if (ready)
|
if (ready)
|
||||||
Server?.Membership?.Logout(session);
|
Server.Membership?.Logout(session);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
ready = false;
|
ready = false;
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,9 @@ partial class DistributedConnection
|
|||||||
|
|
||||||
AsyncQueue<DistributedResourceQueueItem> queue = new AsyncQueue<DistributedResourceQueueItem>();
|
AsyncQueue<DistributedResourceQueueItem> queue = new AsyncQueue<DistributedResourceQueueItem>();
|
||||||
|
|
||||||
|
|
||||||
|
DateTime? lastKeepAliveReceived;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Send IIP request.
|
/// Send IIP request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -99,18 +102,6 @@ partial class DistributedConnection
|
|||||||
|
|
||||||
internal SendList SendReply(IIPPacket.IIPPacketAction action, uint callbackId)
|
internal SendList SendReply(IIPPacket.IIPPacketAction action, uint callbackId)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
if (callbackId > maxcallerid)
|
|
||||||
{
|
|
||||||
maxcallerid = callbackId;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.Beep();
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
return (SendList)SendParams().AddUInt8((byte)(0x80 | (byte)action)).AddUInt32(callbackId);
|
return (SendList)SendParams().AddUInt8((byte)(0x80 | (byte)action)).AddUInt32(callbackId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,6 +141,53 @@ partial class DistributedConnection
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public AsyncReply<object> StaticCall(Guid classId, byte index, Map<byte, object> parameters)
|
||||||
|
{
|
||||||
|
var pb = Codec.Compose(parameters, this);// Codec.ComposeVarArray(parameters, this, true);
|
||||||
|
|
||||||
|
var reply = new AsyncReply<object>();
|
||||||
|
var c = callbackCounter++;
|
||||||
|
requests.Add(c, reply);
|
||||||
|
|
||||||
|
|
||||||
|
SendParams().AddUInt8((byte)(0x40 | (byte)IIPPacket.IIPPacketAction.StaticCall))
|
||||||
|
.AddUInt32(c)
|
||||||
|
.AddGuid(classId)
|
||||||
|
.AddUInt8(index)
|
||||||
|
.AddUInt8Array(pb)
|
||||||
|
.Done();
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncReply<object> Call(string procedureCall, params object[] parameters)
|
||||||
|
{
|
||||||
|
var args = new Map<byte, object>();
|
||||||
|
for (byte i = 0; i < parameters.Length; i++)
|
||||||
|
args.Add(i, parameters[i]);
|
||||||
|
return Call(procedureCall, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncReply<object> Call(string procedureCall, Map<byte, object> parameters)
|
||||||
|
{
|
||||||
|
var pb = Codec.Compose(parameters, this);
|
||||||
|
|
||||||
|
var reply = new AsyncReply<object>();
|
||||||
|
var c = callbackCounter++;
|
||||||
|
requests.Add(c, reply);
|
||||||
|
|
||||||
|
var callName = DC.ToBytes(procedureCall);
|
||||||
|
|
||||||
|
SendParams().AddUInt8((byte)(0x40 | (byte)IIPPacket.IIPPacketAction.ProcedureCall))
|
||||||
|
.AddUInt32(c)
|
||||||
|
.AddUInt16((ushort)callName.Length)
|
||||||
|
.AddUInt8Array(callName)
|
||||||
|
.AddUInt8Array(pb)
|
||||||
|
.Done();
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
internal AsyncReply<object> SendInvoke(uint instanceId, byte index, Map<byte, object> parameters)
|
internal AsyncReply<object> SendInvoke(uint instanceId, byte index, Map<byte, object> parameters)
|
||||||
{
|
{
|
||||||
var pb = Codec.Compose(parameters, this);// Codec.ComposeVarArray(parameters, this, true);
|
var pb = Codec.Compose(parameters, this);// Codec.ComposeVarArray(parameters, this, true);
|
||||||
@ -158,17 +196,12 @@ partial class DistributedConnection
|
|||||||
var c = callbackCounter++;
|
var c = callbackCounter++;
|
||||||
requests.Add(c, reply);
|
requests.Add(c, reply);
|
||||||
|
|
||||||
SendParams().AddUInt8((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunction))
|
SendParams().AddUInt8((byte)(0x40 | (byte)IIPPacket.IIPPacketAction.InvokeFunction))
|
||||||
.AddUInt32(c)
|
.AddUInt32(c)
|
||||||
.AddUInt32(instanceId)
|
.AddUInt32(instanceId)
|
||||||
.AddUInt8(index)
|
.AddUInt8(index)
|
||||||
.AddUInt8Array(pb)
|
.AddUInt8Array(pb)
|
||||||
.Done();
|
.Done();
|
||||||
|
|
||||||
//var bl = new BinaryList((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments),
|
|
||||||
// callbackCounter, instanceId, index, pb);
|
|
||||||
//Send(bl.ToArray());
|
|
||||||
|
|
||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1212,6 +1245,102 @@ partial class DistributedConnection
|
|||||||
return new Tuple<ushort, string>((ushort)code, $"{source}: {msg}\n{trace}");
|
return new Tuple<ushort, string>((ushort)code, $"{source}: {msg}\n{trace}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void IIPRequestProcedureCall(uint callback, string procedureCall, TransmissionType transmissionType, byte[] content)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (Server == null)
|
||||||
|
{
|
||||||
|
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.GeneralFailure);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var call = Server.Calls[procedureCall];
|
||||||
|
|
||||||
|
if (call == null)
|
||||||
|
{
|
||||||
|
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var (_, parsed) = Codec.Parse(content, 0, this, null, transmissionType);
|
||||||
|
|
||||||
|
parsed.Then(results =>
|
||||||
|
{
|
||||||
|
var arguments = (Map<byte, object>)results;// (object[])results;
|
||||||
|
|
||||||
|
// un hold the socket to send data immediately
|
||||||
|
this.Socket.Unhold();
|
||||||
|
|
||||||
|
// @TODO: Make managers for procedure calls
|
||||||
|
//if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied)
|
||||||
|
//{
|
||||||
|
// SendError(ErrorType.Management, callback,
|
||||||
|
// (ushort)ExceptionCode.InvokeDenied);
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
|
||||||
|
InvokeFunction(call.Method, callback, arguments, IIPPacket.IIPPacketAction.ProcedureCall, call.Target);
|
||||||
|
|
||||||
|
}).Error(x =>
|
||||||
|
{
|
||||||
|
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ParseError);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void IIPRequestStaticCall(uint callback, Guid classId, byte index, TransmissionType transmissionType, byte[] content)
|
||||||
|
{
|
||||||
|
var template = Warehouse.GetTemplateByClassId(classId);
|
||||||
|
|
||||||
|
if (template == null)
|
||||||
|
{
|
||||||
|
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ft = template.GetFunctionTemplateByIndex(index);
|
||||||
|
|
||||||
|
if (ft == null)
|
||||||
|
{
|
||||||
|
// no function at this index
|
||||||
|
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var (_, parsed) = Codec.Parse(content, 0, this, null, transmissionType);
|
||||||
|
|
||||||
|
parsed.Then(results =>
|
||||||
|
{
|
||||||
|
var arguments = (Map<byte, object>)results;// (object[])results;
|
||||||
|
|
||||||
|
// un hold the socket to send data immediately
|
||||||
|
this.Socket.Unhold();
|
||||||
|
|
||||||
|
var fi = ft.MethodInfo;
|
||||||
|
|
||||||
|
if (fi == null)
|
||||||
|
{
|
||||||
|
// ft found, fi not found, this should never happen
|
||||||
|
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO: Make managers for static calls
|
||||||
|
//if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied)
|
||||||
|
//{
|
||||||
|
// SendError(ErrorType.Management, callback,
|
||||||
|
// (ushort)ExceptionCode.InvokeDenied);
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
|
||||||
|
InvokeFunction(fi, callback, arguments, IIPPacket.IIPPacketAction.StaticCall, null);
|
||||||
|
|
||||||
|
}).Error(x =>
|
||||||
|
{
|
||||||
|
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ParseError);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void IIPRequestInvokeFunction(uint callback, uint resourceId, byte index, TransmissionType transmissionType, byte[] content)
|
void IIPRequestInvokeFunction(uint callback, uint resourceId, byte index, TransmissionType transmissionType, byte[] content)
|
||||||
{
|
{
|
||||||
//Console.WriteLine("IIPRequestInvokeFunction " + callback + " " + resourceId + " " + index);
|
//Console.WriteLine("IIPRequestInvokeFunction " + callback + " " + resourceId + " " + index);
|
||||||
@ -1263,10 +1392,17 @@ partial class DistributedConnection
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
var fi = r.GetType().GetMethod(ft.Name);
|
var fi = r.GetType().GetMethod(ft.Name);
|
||||||
|
|
||||||
if (fi != null)
|
if (fi == null)
|
||||||
{
|
{
|
||||||
|
// ft found, fi not found, this should never happen
|
||||||
|
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied)
|
if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied)
|
||||||
{
|
{
|
||||||
SendError(ErrorType.Management, callback,
|
SendError(ErrorType.Management, callback,
|
||||||
@ -1274,6 +1410,17 @@ partial class DistributedConnection
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InvokeFunction(fi, callback, arguments, IIPPacket.IIPPacketAction.InvokeFunction, r);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void InvokeFunction(MethodInfo fi, uint callback, Map<byte, object> arguments, IIPPacket.IIPPacketAction actionType, object target = null)
|
||||||
|
{
|
||||||
|
|
||||||
// cast arguments
|
// cast arguments
|
||||||
ParameterInfo[] pis = fi.GetParameters();
|
ParameterInfo[] pis = fi.GetParameters();
|
||||||
|
|
||||||
@ -1300,11 +1447,13 @@ partial class DistributedConnection
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
rt = fi.Invoke(r, args);
|
rt = fi.Invoke(target, args);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
var (code, msg) = SummerizeException(ex);
|
var (code, msg) = SummerizeException(ex);
|
||||||
|
msg = "Arguments: " + string.Join(", ", args.Select(x => x?.ToString() ?? "[Null]").ToArray()) + "\r\n" + msg;
|
||||||
|
|
||||||
SendError(ErrorType.Exception, callback, code, msg);
|
SendError(ErrorType.Exception, callback, code, msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1317,7 +1466,7 @@ partial class DistributedConnection
|
|||||||
{
|
{
|
||||||
foreach (var v in enu)
|
foreach (var v in enu)
|
||||||
SendChunk(callback, v);
|
SendChunk(callback, v);
|
||||||
SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback)
|
SendReply(actionType, callback)
|
||||||
.AddUInt8((byte)TransmissionTypeIdentifier.Null)
|
.AddUInt8((byte)TransmissionTypeIdentifier.Null)
|
||||||
.Done();
|
.Done();
|
||||||
}
|
}
|
||||||
@ -1337,7 +1486,7 @@ partial class DistributedConnection
|
|||||||
#else
|
#else
|
||||||
var res = t.GetType().GetProperty("Result").GetValue(t);
|
var res = t.GetType().GetProperty("Result").GetValue(t);
|
||||||
#endif
|
#endif
|
||||||
SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback)
|
SendReply(actionType, callback)
|
||||||
.AddUInt8Array(Codec.Compose(res, this))
|
.AddUInt8Array(Codec.Compose(res, this))
|
||||||
.Done();
|
.Done();
|
||||||
});
|
});
|
||||||
@ -1350,7 +1499,7 @@ partial class DistributedConnection
|
|||||||
{
|
{
|
||||||
(rt as AsyncReply).Then(res =>
|
(rt as AsyncReply).Then(res =>
|
||||||
{
|
{
|
||||||
SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback)
|
SendReply(actionType, callback)
|
||||||
.AddUInt8Array(Codec.Compose(res, this))
|
.AddUInt8Array(Codec.Compose(res, this))
|
||||||
.Done();
|
.Done();
|
||||||
}).Error(ex =>
|
}).Error(ex =>
|
||||||
@ -1367,24 +1516,11 @@ partial class DistributedConnection
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback)
|
SendReply(actionType, callback)
|
||||||
.AddUInt8Array(Codec.Compose(rt, this))
|
.AddUInt8Array(Codec.Compose(rt, this))
|
||||||
.Done();
|
.Done();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// ft found, fi not found, this should never happen
|
|
||||||
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void IIPRequestListen(uint callback, uint resourceId, byte index)
|
void IIPRequestListen(uint callback, uint resourceId, byte index)
|
||||||
{
|
{
|
||||||
@ -1651,11 +1787,11 @@ partial class DistributedConnection
|
|||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#if NETSTANDARD
|
#if NETSTANDARD
|
||||||
var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name);
|
var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name);
|
||||||
#else
|
#else
|
||||||
var pi = r.GetType().GetProperty(pt.Name);
|
var pi = r.GetType().GetProperty(pt.Name);
|
||||||
#endif*/
|
#endif*/
|
||||||
|
|
||||||
var pi = pt.PropertyInfo;
|
var pi = pt.PropertyInfo;
|
||||||
|
|
||||||
@ -2531,4 +2667,31 @@ partial class DistributedConnection
|
|||||||
.AddUInt8Array(Codec.Compose(info.Value, this))
|
.AddUInt8Array(Codec.Compose(info.Value, this))
|
||||||
.Done();
|
.Done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void IIPRequestKeepAlive(uint callbackId, DateTime peerTime, uint interval)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint jitter = 0;
|
||||||
|
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
|
if (lastKeepAliveReceived != null)
|
||||||
|
{
|
||||||
|
var diff = (uint)(now - (DateTime)lastKeepAliveReceived).TotalMilliseconds;
|
||||||
|
//Console.WriteLine("Diff " + diff + " " + interval);
|
||||||
|
|
||||||
|
jitter = (uint)Math.Abs((int)diff - (int)interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
SendParams()
|
||||||
|
.AddUInt8((byte)(0x80 | (byte)IIPPacket.IIPPacketAction.KeepAlive))
|
||||||
|
.AddUInt32(callbackId)
|
||||||
|
.AddDateTime(now)
|
||||||
|
.AddUInt32(jitter)
|
||||||
|
.Done();
|
||||||
|
|
||||||
|
lastKeepAliveReceived = now;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,9 +222,8 @@ public class DistributedResource : DynamicObject, IResource
|
|||||||
|
|
||||||
public AsyncReply<object> _Invoke(byte index, Map<byte, object> args)
|
public AsyncReply<object> _Invoke(byte index, Map<byte, object> args)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (destroyed)
|
if (destroyed)
|
||||||
throw new Exception("Trying to access destroyed object");
|
throw new Exception("Trying to access a destroyed object");
|
||||||
|
|
||||||
if (suspended)
|
if (suspended)
|
||||||
throw new Exception("Trying to access suspended object");
|
throw new Exception("Trying to access suspended object");
|
||||||
@ -232,11 +231,17 @@ public class DistributedResource : DynamicObject, IResource
|
|||||||
if (index >= Instance.Template.Functions.Length)
|
if (index >= Instance.Template.Functions.Length)
|
||||||
throw new Exception("Function index is incorrect");
|
throw new Exception("Function index is incorrect");
|
||||||
|
|
||||||
|
var ft = Instance.Template.GetFunctionTemplateByIndex(index);
|
||||||
|
|
||||||
|
if (ft == null)
|
||||||
|
throw new Exception("Function template not found.");
|
||||||
|
|
||||||
|
if (ft.IsStatic)
|
||||||
|
return connection.StaticCall(Instance.Template.ClassId, index, args);
|
||||||
|
else
|
||||||
return connection.SendInvoke(instanceId, index, args);
|
return connection.SendInvoke(instanceId, index, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public AsyncReply Listen(EventTemplate et)
|
public AsyncReply Listen(EventTemplate et)
|
||||||
{
|
{
|
||||||
if (et == null)
|
if (et == null)
|
||||||
|
@ -176,5 +176,11 @@ public class DistributedServer : NetworkServer<DistributedConnection>, IResource
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public KeyList<string, Delegate> Calls { get; } = new KeyList<string, Delegate>();
|
||||||
|
|
||||||
|
public void MapCall(string call, Delegate handler)
|
||||||
|
{
|
||||||
|
Calls.Add(call, handler);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,13 @@ class IIPPacket : Packet
|
|||||||
ClearAllAttributes,
|
ClearAllAttributes,
|
||||||
GetAttributes,
|
GetAttributes,
|
||||||
UpdateAttributes,
|
UpdateAttributes,
|
||||||
ClearAttributes
|
ClearAttributes,
|
||||||
|
|
||||||
|
|
||||||
|
// Static calling
|
||||||
|
KeepAlive = 0x20,
|
||||||
|
ProcedureCall,
|
||||||
|
StaticCall
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum IIPPacketReport : byte
|
public enum IIPPacketReport : byte
|
||||||
@ -200,6 +206,11 @@ class IIPPacket : Packet
|
|||||||
public ulong FromAge { get; set; }
|
public ulong FromAge { get; set; }
|
||||||
public ulong ToAge { get; set; }
|
public ulong ToAge { get; set; }
|
||||||
|
|
||||||
|
public DateTime CurrentTime { get; set; }
|
||||||
|
public uint Interval { get; set; }
|
||||||
|
public uint Jitter { get; set; }
|
||||||
|
public string Procedure { get; set; }
|
||||||
|
|
||||||
private uint dataLengthNeeded;
|
private uint dataLengthNeeded;
|
||||||
private uint originalOffset;
|
private uint originalOffset;
|
||||||
|
|
||||||
@ -615,6 +626,60 @@ class IIPPacket : Packet
|
|||||||
//Content = data.Clip(offset, cl);
|
//Content = data.Clip(offset, cl);
|
||||||
offset += cl;
|
offset += cl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (Action == IIPPacketAction.KeepAlive)
|
||||||
|
{
|
||||||
|
if (NotEnough(offset, ends, 12))
|
||||||
|
return -dataLengthNeeded;
|
||||||
|
|
||||||
|
CurrentTime = data.GetDateTime(offset, Endian.Little);
|
||||||
|
offset += 8;
|
||||||
|
Interval = data.GetUInt32(offset, Endian.Little);
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (Action == IIPPacketAction.ProcedureCall)
|
||||||
|
{
|
||||||
|
if (NotEnough(offset, ends, 2))
|
||||||
|
return -dataLengthNeeded;
|
||||||
|
|
||||||
|
var cl = data.GetUInt16(offset, Endian.Little);
|
||||||
|
offset += 2;
|
||||||
|
|
||||||
|
if (NotEnough(offset, ends, cl))
|
||||||
|
return -dataLengthNeeded;
|
||||||
|
|
||||||
|
Procedure = data.GetString(offset, cl);
|
||||||
|
offset += cl;
|
||||||
|
|
||||||
|
if (NotEnough(offset, ends, 1))
|
||||||
|
return -dataLengthNeeded;
|
||||||
|
|
||||||
|
(var size, DataType) = TransmissionType.Parse(data, offset, ends);
|
||||||
|
|
||||||
|
if (DataType == null)
|
||||||
|
return -(int)size;
|
||||||
|
|
||||||
|
offset += (uint)size;
|
||||||
|
|
||||||
|
} else if (Action == IIPPacketAction.StaticCall)
|
||||||
|
{
|
||||||
|
if (NotEnough(offset, ends, 18))
|
||||||
|
return -dataLengthNeeded;
|
||||||
|
|
||||||
|
ClassId = data.GetGuid(offset);//, Endian.Little);
|
||||||
|
offset += 16;
|
||||||
|
|
||||||
|
MethodIndex = data[offset++];
|
||||||
|
|
||||||
|
|
||||||
|
(var size, DataType) = TransmissionType.Parse(data, offset, ends);
|
||||||
|
|
||||||
|
if (DataType == null)
|
||||||
|
return -(int)size;
|
||||||
|
|
||||||
|
offset += (uint)size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (Command == IIPPacketCommand.Reply)
|
else if (Command == IIPPacketCommand.Reply)
|
||||||
{
|
{
|
||||||
@ -690,7 +755,7 @@ class IIPPacket : Packet
|
|||||||
if (NotEnough(offset, ends, 1))
|
if (NotEnough(offset, ends, 1))
|
||||||
return -dataLengthNeeded;
|
return -dataLengthNeeded;
|
||||||
|
|
||||||
(var size, DataType) = TransmissionType.Parse(data, offset, ends );
|
(var size, DataType) = TransmissionType.Parse(data, offset, ends);
|
||||||
|
|
||||||
if (DataType == null)
|
if (DataType == null)
|
||||||
return -(int)size;
|
return -(int)size;
|
||||||
@ -706,9 +771,9 @@ class IIPPacket : Packet
|
|||||||
//Content = data.Clip(offset, cl);
|
//Content = data.Clip(offset, cl);
|
||||||
//offset += cl;
|
//offset += cl;
|
||||||
}
|
}
|
||||||
else if (Action == IIPPacketAction.InvokeFunction)
|
else if (Action == IIPPacketAction.InvokeFunction
|
||||||
//|| Action == IIPPacketAction.GetProperty
|
|| Action == IIPPacketAction.ProcedureCall
|
||||||
//|| Action == IIPPacketAction.GetPropertyIfModified)
|
|| Action == IIPPacketAction.StaticCall)
|
||||||
{
|
{
|
||||||
if (NotEnough(offset, ends, 1))
|
if (NotEnough(offset, ends, 1))
|
||||||
return -dataLengthNeeded;
|
return -dataLengthNeeded;
|
||||||
@ -728,6 +793,16 @@ class IIPPacket : Packet
|
|||||||
{
|
{
|
||||||
// nothing to do
|
// nothing to do
|
||||||
}
|
}
|
||||||
|
else if (Action == IIPPacketAction.KeepAlive)
|
||||||
|
{
|
||||||
|
if (NotEnough(offset, ends, 12))
|
||||||
|
return -dataLengthNeeded;
|
||||||
|
|
||||||
|
CurrentTime = data.GetDateTime(offset, Endian.Little);
|
||||||
|
offset += 8;
|
||||||
|
Jitter = data.GetUInt32(offset, Endian.Little);
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (Command == IIPPacketCommand.Report)
|
else if (Command == IIPPacketCommand.Report)
|
||||||
{
|
{
|
||||||
@ -775,7 +850,7 @@ class IIPPacket : Packet
|
|||||||
return -dataLengthNeeded;
|
return -dataLengthNeeded;
|
||||||
|
|
||||||
|
|
||||||
(var size, DataType) = TransmissionType.Parse(Data, offset, ends );
|
(var size, DataType) = TransmissionType.Parse(Data, offset, ends);
|
||||||
|
|
||||||
if (DataType == null)
|
if (DataType == null)
|
||||||
return -(int)size;
|
return -(int)size;
|
||||||
|
@ -69,7 +69,7 @@ public static class TemplateGenerator
|
|||||||
var rt = new StringBuilder();
|
var rt = new StringBuilder();
|
||||||
|
|
||||||
rt.AppendLine("using System;\r\nusing Esiur.Resource;\r\nusing Esiur.Core;\r\nusing Esiur.Data;\r\nusing Esiur.Net.IIP;");
|
rt.AppendLine("using System;\r\nusing Esiur.Resource;\r\nusing Esiur.Core;\r\nusing Esiur.Data;\r\nusing Esiur.Net.IIP;");
|
||||||
rt.AppendLine($"namespace { nameSpace} {{");
|
rt.AppendLine($"namespace {nameSpace} {{");
|
||||||
|
|
||||||
if (template.Annotation != null)
|
if (template.Annotation != null)
|
||||||
rt.AppendLine($"[Annotation({ToLiteral(template.Annotation)})]");
|
rt.AppendLine($"[Annotation({ToLiteral(template.Annotation)})]");
|
||||||
@ -99,7 +99,7 @@ public static class TemplateGenerator
|
|||||||
var rt = new StringBuilder();
|
var rt = new StringBuilder();
|
||||||
|
|
||||||
rt.AppendLine("using System;\r\nusing Esiur.Resource;\r\nusing Esiur.Core;\r\nusing Esiur.Data;\r\nusing Esiur.Net.IIP;");
|
rt.AppendLine("using System;\r\nusing Esiur.Resource;\r\nusing Esiur.Core;\r\nusing Esiur.Data;\r\nusing Esiur.Net.IIP;");
|
||||||
rt.AppendLine($"namespace { nameSpace} {{");
|
rt.AppendLine($"namespace {nameSpace} {{");
|
||||||
|
|
||||||
if (template.Annotation != null)
|
if (template.Annotation != null)
|
||||||
rt.AppendLine($"[Annotation({ToLiteral(template.Annotation)})]");
|
rt.AppendLine($"[Annotation({ToLiteral(template.Annotation)})]");
|
||||||
@ -136,7 +136,7 @@ public static class TemplateGenerator
|
|||||||
representationType.Identifier == RepresentationTypeIdentifier.Tuple5 ||
|
representationType.Identifier == RepresentationTypeIdentifier.Tuple5 ||
|
||||||
representationType.Identifier == RepresentationTypeIdentifier.Tuple6 ||
|
representationType.Identifier == RepresentationTypeIdentifier.Tuple6 ||
|
||||||
representationType.Identifier == RepresentationTypeIdentifier.Tuple7)
|
representationType.Identifier == RepresentationTypeIdentifier.Tuple7)
|
||||||
name = "(" + String.Join(",", representationType.SubTypes.Select(x=> GetTypeName(x, templates)))
|
name = "(" + String.Join(",", representationType.SubTypes.Select(x => GetTypeName(x, templates)))
|
||||||
+ ")";
|
+ ")";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -263,7 +263,7 @@ public static class TemplateGenerator
|
|||||||
var rt = new StringBuilder();
|
var rt = new StringBuilder();
|
||||||
|
|
||||||
rt.AppendLine("using System;\r\nusing Esiur.Resource;\r\nusing Esiur.Core;\r\nusing Esiur.Data;\r\nusing Esiur.Net.IIP;");
|
rt.AppendLine("using System;\r\nusing Esiur.Resource;\r\nusing Esiur.Core;\r\nusing Esiur.Data;\r\nusing Esiur.Net.IIP;");
|
||||||
rt.AppendLine($"namespace { nameSpace} {{");
|
rt.AppendLine($"namespace {nameSpace} {{");
|
||||||
|
|
||||||
if (template.Annotation != null)
|
if (template.Annotation != null)
|
||||||
rt.AppendLine($"[Annotation({ToLiteral(template.Annotation)})]");
|
rt.AppendLine($"[Annotation({ToLiteral(template.Annotation)})]");
|
||||||
@ -289,8 +289,22 @@ public static class TemplateGenerator
|
|||||||
var optionalArgs = f.Arguments.Where((x) => x.Optional).ToArray();
|
var optionalArgs = f.Arguments.Where((x) => x.Optional).ToArray();
|
||||||
|
|
||||||
|
|
||||||
rt.Append($"[Public] public AsyncReply<{rtTypeName}> {f.Name}(");
|
if (f.IsStatic)
|
||||||
|
{
|
||||||
|
rt.Append($"[Public] public static AsyncReply<{rtTypeName}> {f.Name}(DistributedConnection connection");
|
||||||
|
|
||||||
|
if (positionalArgs.Length > 0)
|
||||||
|
rt.Append(", " +
|
||||||
|
String.Join(", ", positionalArgs.Select((a) => GetTypeName(a.Type, templates) + " " + a.Name)));
|
||||||
|
|
||||||
|
if (optionalArgs.Length > 0)
|
||||||
|
rt.Append(", " +
|
||||||
|
String.Join(", ", optionalArgs.Select((a) => GetTypeName(a.Type.ToNullable(), templates) + " " + a.Name + " = null")));
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rt.Append($"[Public] public AsyncReply<{rtTypeName}> {f.Name}(");
|
||||||
|
|
||||||
if (positionalArgs.Length > 0)
|
if (positionalArgs.Length > 0)
|
||||||
rt.Append(
|
rt.Append(
|
||||||
@ -303,23 +317,27 @@ public static class TemplateGenerator
|
|||||||
rt.Append(
|
rt.Append(
|
||||||
String.Join(", ", optionalArgs.Select((a) => GetTypeName(a.Type.ToNullable(), templates) + " " + a.Name + " = null")));
|
String.Join(", ", optionalArgs.Select((a) => GetTypeName(a.Type.ToNullable(), templates) + " " + a.Name + " = null")));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//rt.Append(string.Join(",", f.Arguments.Select(x => GetTypeName(x.Type, templates) + " " + x.Name)));
|
|
||||||
|
|
||||||
rt.AppendLine(") {");
|
rt.AppendLine(") {");
|
||||||
|
|
||||||
rt.AppendLine(
|
rt.AppendLine(
|
||||||
$"var args = new Map<byte, object>(){{{ String.Join(", ", positionalArgs.Select((e) => "[" + e.Index + "] = " + e.Name))}}};");
|
$"var args = new Map<byte, object>(){{{String.Join(", ", positionalArgs.Select((e) => "[" + e.Index + "] = " + e.Name))}}};");
|
||||||
|
|
||||||
foreach(var a in optionalArgs) {
|
foreach (var a in optionalArgs)
|
||||||
|
{
|
||||||
rt.AppendLine(
|
rt.AppendLine(
|
||||||
$"if ({a.Name} != null) args[{a.Index}] = {a.Name};");
|
$"if ({a.Name} != null) args[{a.Index}] = {a.Name};");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
rt.AppendLine($"var rt = new AsyncReply<{rtTypeName}>();");
|
rt.AppendLine($"var rt = new AsyncReply<{rtTypeName}>();");
|
||||||
//rt.AppendLine($"_Invoke({f.Index}, new Map<byte, object>[] {{ { string.Join(", ", f.Arguments.Select(x => x.Name)) } }})");
|
|
||||||
|
if (f.IsStatic)
|
||||||
|
rt.AppendLine($"connection.StaticCall(Guid.Parse(\"{template.ClassId.ToString()}\"), {f.Index}, args)");
|
||||||
|
else
|
||||||
rt.AppendLine($"_Invoke({f.Index}, args)");
|
rt.AppendLine($"_Invoke({f.Index}, args)");
|
||||||
|
|
||||||
rt.AppendLine($".Then(x => rt.Trigger(({rtTypeName})x))");
|
rt.AppendLine($".Then(x => rt.Trigger(({rtTypeName})x))");
|
||||||
rt.AppendLine($".Error(x => rt.TriggerError(x))");
|
rt.AppendLine($".Error(x => rt.TriggerError(x))");
|
||||||
rt.AppendLine($".Chunk(x => rt.TriggerChunk(x));");
|
rt.AppendLine($".Chunk(x => rt.TriggerChunk(x));");
|
||||||
|
@ -24,6 +24,8 @@ public class FunctionTemplate : MemberTemplate
|
|||||||
|
|
||||||
public RepresentationType ReturnType { get; set; }
|
public RepresentationType ReturnType { get; set; }
|
||||||
|
|
||||||
|
public bool IsStatic { get; set; }
|
||||||
|
|
||||||
public ArgumentTemplate[] Arguments { get; set; }
|
public ArgumentTemplate[] Arguments { get; set; }
|
||||||
|
|
||||||
public MethodInfo MethodInfo
|
public MethodInfo MethodInfo
|
||||||
@ -53,20 +55,20 @@ public class FunctionTemplate : MemberTemplate
|
|||||||
var exp = DC.ToBytes(Annotation);
|
var exp = DC.ToBytes(Annotation);
|
||||||
bl.AddInt32(exp.Length)
|
bl.AddInt32(exp.Length)
|
||||||
.AddUInt8Array(exp);
|
.AddUInt8Array(exp);
|
||||||
bl.InsertUInt8(0, Inherited ? (byte)0x90 : (byte)0x10);
|
bl.InsertUInt8(0, (byte)((Inherited ? (byte)0x90 : (byte)0x10) | (IsStatic ? 0x4 : 0)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
bl.InsertUInt8(0, Inherited ? (byte)0x80 : (byte)0x0);
|
bl.InsertUInt8(0, (byte)((Inherited ? (byte)0x80 : (byte)0x0) | (IsStatic ? 0x4 : 0)));
|
||||||
|
|
||||||
return bl.ToArray();
|
return bl.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public FunctionTemplate(TypeTemplate template, byte index, string name, bool inherited, ArgumentTemplate[] arguments, RepresentationType returnType, string annotation = null)
|
public FunctionTemplate(TypeTemplate template, byte index, string name, bool inherited, bool isStatic, ArgumentTemplate[] arguments, RepresentationType returnType, string annotation = null)
|
||||||
: base(template, index, name, inherited)
|
: base(template, index, name, inherited)
|
||||||
{
|
{
|
||||||
//this.IsVoid = isVoid;
|
|
||||||
this.Arguments = arguments;
|
this.Arguments = arguments;
|
||||||
this.ReturnType = returnType;
|
this.ReturnType = returnType;
|
||||||
this.Annotation = annotation;
|
this.Annotation = annotation;
|
||||||
|
this.IsStatic = isStatic;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -409,9 +409,9 @@ public class TypeTemplate
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
PropertyInfo[] propsInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly);
|
PropertyInfo[] propsInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||||
EventInfo[] eventsInfo = type.GetEvents(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly);
|
EventInfo[] eventsInfo = type.GetEvents(BindingFlags.Public | BindingFlags.Instance);
|
||||||
MethodInfo[] methodsInfo = type.GetMethods(BindingFlags.Public | BindingFlags.Instance); // | BindingFlags.DeclaredOnly);
|
MethodInfo[] methodsInfo = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
|
||||||
FieldInfo[] constantsInfo = type.GetFields(BindingFlags.Public | BindingFlags.Static);
|
FieldInfo[] constantsInfo = type.GetFields(BindingFlags.Public | BindingFlags.Static);
|
||||||
|
|
||||||
|
|
||||||
@ -423,7 +423,7 @@ public class TypeTemplate
|
|||||||
var annotationAttr = ci.GetCustomAttribute<AnnotationAttribute>(true);
|
var annotationAttr = ci.GetCustomAttribute<AnnotationAttribute>(true);
|
||||||
var nullableAttr = ci.GetCustomAttribute<NullableAttribute>(true);
|
var nullableAttr = ci.GetCustomAttribute<NullableAttribute>(true);
|
||||||
|
|
||||||
var valueType = RepresentationType.FromType(ci.FieldType);//, nullable != null && nullable.NullableFlags[0] == 2);
|
var valueType = RepresentationType.FromType(ci.FieldType);
|
||||||
|
|
||||||
if (valueType == null)
|
if (valueType == null)
|
||||||
throw new Exception($"Unsupported type `{ci.FieldType}` in constant `{type.Name}.{ci.Name}`");
|
throw new Exception($"Unsupported type `{ci.FieldType}` in constant `{type.Name}.{ci.Name}`");
|
||||||
@ -447,8 +447,6 @@ public class TypeTemplate
|
|||||||
RepresentationType.FromType(pi.PropertyType.GetGenericArguments()[0]) :
|
RepresentationType.FromType(pi.PropertyType.GetGenericArguments()[0]) :
|
||||||
RepresentationType.FromType(pi.PropertyType);
|
RepresentationType.FromType(pi.PropertyType);
|
||||||
|
|
||||||
//var propType = RepresentationType.FromType(pi.PropertyType);//, nullableAttr != null && nullableAttr.Flag == 2);
|
|
||||||
|
|
||||||
if (propType == null)
|
if (propType == null)
|
||||||
throw new Exception($"Unsupported type `{pi.PropertyType}` in property `{type.Name}.{pi.Name}`");
|
throw new Exception($"Unsupported type `{pi.PropertyType}` in property `{type.Name}.{pi.Name}`");
|
||||||
|
|
||||||
@ -497,7 +495,7 @@ public class TypeTemplate
|
|||||||
var addEvent = (EventInfo ei, PublicAttribute publicAttr) =>
|
var addEvent = (EventInfo ei, PublicAttribute publicAttr) =>
|
||||||
{
|
{
|
||||||
var argType = ei.EventHandlerType.GenericTypeArguments[0];
|
var argType = ei.EventHandlerType.GenericTypeArguments[0];
|
||||||
var evtType = RepresentationType.FromType(argType);//, argIsNull);
|
var evtType = RepresentationType.FromType(argType);
|
||||||
|
|
||||||
if (evtType == null)
|
if (evtType == null)
|
||||||
throw new Exception($"Unsupported type `{argType}` in event `{type.Name}.{ei.Name}`");
|
throw new Exception($"Unsupported type `{argType}` in event `{type.Name}.{ei.Name}`");
|
||||||
@ -641,7 +639,9 @@ public class TypeTemplate
|
|||||||
|
|
||||||
var fn = publicAttr.Name ?? mi.Name;
|
var fn = publicAttr.Name ?? mi.Name;
|
||||||
|
|
||||||
var ft = new FunctionTemplate(this, (byte)functions.Count, fn, mi.DeclaringType != type, arguments, rtType);
|
var ft = new FunctionTemplate(this, (byte)functions.Count, fn, mi.DeclaringType != type,
|
||||||
|
mi.IsStatic,
|
||||||
|
arguments, rtType);
|
||||||
|
|
||||||
if (annotationAttr != null)
|
if (annotationAttr != null)
|
||||||
ft.Annotation = annotationAttr.Annotation;
|
ft.Annotation = annotationAttr.Annotation;
|
||||||
@ -918,6 +918,9 @@ public class TypeTemplate
|
|||||||
if (type == 0) // function
|
if (type == 0) // function
|
||||||
{
|
{
|
||||||
string annotation = null;
|
string annotation = null;
|
||||||
|
var isStatic = ((data[offset] & 0x4) == 0x4);
|
||||||
|
|
||||||
|
|
||||||
var hasAnnotation = ((data[offset++] & 0x10) == 0x10);
|
var hasAnnotation = ((data[offset++] & 0x10) == 0x10);
|
||||||
|
|
||||||
var name = data.GetString(offset + 1, data[offset]);
|
var name = data.GetString(offset + 1, data[offset]);
|
||||||
@ -947,7 +950,7 @@ public class TypeTemplate
|
|||||||
offset += cs;
|
offset += cs;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ft = new FunctionTemplate(od, functionIndex++, name, inherited, arguments.ToArray(), returnType, annotation);
|
var ft = new FunctionTemplate(od, functionIndex++, name, inherited, isStatic, arguments.ToArray(), returnType, annotation);
|
||||||
|
|
||||||
od.functions.Add(ft);
|
od.functions.Add(ft);
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,8 @@ public partial class MyService
|
|||||||
return new MyGenericRecord<MyResource>() { Needed = 3, Start = 10, Results = new MyResource[0], Total = 102 };
|
return new MyGenericRecord<MyResource>() { Needed = 3, Start = 10, Results = new MyResource[0], Total = 102 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Public] public static string staticFunction(string name) => $"Hello {name}";
|
||||||
|
|
||||||
[Public] byte uInt8Test = 8;
|
[Public] byte uInt8Test = 8;
|
||||||
[Public] byte? uInt8Null = null;
|
[Public] byte? uInt8Null = null;
|
||||||
[Public] byte[] uInt8Array = new byte[] { 0, 1, 2, 3, 4, 5 };
|
[Public] byte[] uInt8Array = new byte[] { 0, 1, 2, 3, 4, 5 };
|
||||||
|
@ -57,7 +57,14 @@ namespace Test
|
|||||||
// Create stores to keep objects.
|
// Create stores to keep objects.
|
||||||
var system = await Warehouse.Put("sys", new MemoryStore());
|
var system = await Warehouse.Put("sys", new MemoryStore());
|
||||||
var server = await Warehouse.Put("sys/server", new DistributedServer());
|
var server = await Warehouse.Put("sys/server", new DistributedServer());
|
||||||
var web = await Warehouse.Put("sys/web", new HTTPServer() { Port = 8888});
|
|
||||||
|
server.MapCall("Hello", (string msg, DateTime time, DistributedConnection sender) =>
|
||||||
|
{
|
||||||
|
Console.WriteLine(msg);
|
||||||
|
return "Hi " + DateTime.UtcNow;
|
||||||
|
});
|
||||||
|
|
||||||
|
var web = await Warehouse.Put("sys/web", new HTTPServer() { Port = 8088});
|
||||||
|
|
||||||
var service = await Warehouse.Put("sys/service", new MyService());
|
var service = await Warehouse.Put("sys/service", new MyService());
|
||||||
var res1 = await Warehouse.Put("sys/service/r1", new MyResource() { Description = "Testing 1", CategoryId = 10 });
|
var res1 = await Warehouse.Put("sys/service/r1", new MyResource() { Description = "Testing 1", CategoryId = 10 });
|
||||||
@ -95,6 +102,9 @@ namespace Test
|
|||||||
dynamic remote = await Warehouse.Get<IResource>("iip://localhost/sys/service");
|
dynamic remote = await Warehouse.Get<IResource>("iip://localhost/sys/service");
|
||||||
|
|
||||||
var con = remote.Connection as DistributedConnection;
|
var con = remote.Connection as DistributedConnection;
|
||||||
|
|
||||||
|
var pcall = await con.Call("Hello", "whats up ?", DateTime.UtcNow);
|
||||||
|
|
||||||
var template = await con.GetTemplateByClassName("Test.MyResource");
|
var template = await con.GetTemplateByClassName("Test.MyResource");
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user