2
0
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:
Esiur Project 2022-08-07 23:09:31 +03:00
parent 0dc457bf7e
commit af94ce318a
18 changed files with 784 additions and 259 deletions

View File

@ -47,5 +47,4 @@ public class AsyncAwaiter<T> : INotifyCompletion
callback = continuation; callback = continuation;
} }
} }

View File

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

View File

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

20
Esiur/Data/VarInfo.cs Normal file
View 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
View 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>

View File

@ -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>

View File

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

View File

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

View File

@ -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;
} }
} }
@ -781,28 +854,28 @@ public partial class DistributedConnection : NetworkConnection, IStore
{ {
Server.Membership.TokenExists(authPacket.RemoteTokenIndex, authPacket.Domain).Then(x => Server.Membership.TokenExists(authPacket.RemoteTokenIndex, authPacket.Domain).Then(x =>
{ {
if (x != null) if (x != null)
{ {
session.RemoteAuthentication.Username = x; session.RemoteAuthentication.Username = x;
session.RemoteAuthentication.TokenIndex = authPacket.RemoteTokenIndex; session.RemoteAuthentication.TokenIndex = authPacket.RemoteTokenIndex;
remoteNonce = authPacket.RemoteNonce; remoteNonce = authPacket.RemoteNonce;
session.RemoteAuthentication.Domain = authPacket.Domain; session.RemoteAuthentication.Domain = authPacket.Domain;
SendParams() SendParams()
.AddUInt8(0xa0) .AddUInt8(0xa0)
.AddUInt8Array(localNonce) .AddUInt8Array(localNonce)
.Done(); .Done();
} }
else else
{ {
//Console.WriteLine("User not found"); //Console.WriteLine("User not found");
SendParams() SendParams()
.AddUInt8(0xc0) .AddUInt8(0xc0)
.AddUInt8((byte)ExceptionCode.UserOrTokenNotFound) .AddUInt8((byte)ExceptionCode.UserOrTokenNotFound)
.AddUInt16(15) .AddUInt16(15)
.AddString("Token not found") .AddString("Token not found")
.Done(); .Done();
} }
}); });
} }
} }
catch (Exception ex) catch (Exception ex)
@ -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)
x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed")); {
try
{
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)
x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed")); {
try
{
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)
x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed")); {
try
{
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();
foreach (var x in resources.Values)
x.Suspend();
UnsubscribeAll();
Warehouse.Remove(this); if (Server != null) {
foreach (var x in resources.Values)
x.Suspend();
UnsubscribeAll();
Warehouse.Remove(this);
if (ready)
Server.Membership?.Logout(session);
};
if (ready)
Server?.Membership?.Logout(session);
ready = false; ready = false;
} }

View File

@ -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,128 +1392,135 @@ 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)
{
if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied)
{
SendError(ErrorType.Management, callback,
(ushort)ExceptionCode.InvokeDenied);
return;
}
// cast arguments
ParameterInfo[] pis = fi.GetParameters();
object[] args = new object[pis.Length];
if (pis.Length > 0)
{
if (pis.Last().ParameterType == typeof(DistributedConnection))
{
for (byte i = 0; i < pis.Length - 1; i++)
args[i] = arguments.ContainsKey(i) ?
DC.CastConvert(arguments[i], pis[i].ParameterType) : Type.Missing;
args[args.Length - 1] = this;
}
else
{
for (byte i = 0; i < pis.Length; i++)
args[i] = arguments.ContainsKey(i) ?
DC.CastConvert(arguments[i], pis[i].ParameterType) : Type.Missing;
}
}
object rt;
try
{
rt = fi.Invoke(r, args);
}
catch (Exception ex)
{
var (code, msg) = SummerizeException(ex);
SendError(ErrorType.Exception, callback, code, msg);
return;
}
if (rt is System.Collections.IEnumerable && !(rt is Array || rt is Map<string, object> || rt is string))
{
var enu = rt as System.Collections.IEnumerable;
try
{
foreach (var v in enu)
SendChunk(callback, v);
SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback)
.AddUInt8((byte)TransmissionTypeIdentifier.Null)
.Done();
}
catch (Exception ex)
{
var (code, msg) = SummerizeException(ex);
SendError(ErrorType.Exception, callback, code, msg);
}
}
else if (rt is Task)
{
(rt as Task).ContinueWith(t =>
{
#if NETSTANDARD
var res = t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t);
#else
var res = t.GetType().GetProperty("Result").GetValue(t);
#endif
SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback)
.AddUInt8Array(Codec.Compose(res, this))
.Done();
});
//await t;
//SendParams((byte)0x90, callback, Codec.Compose(res, this));
}
else if (rt is AsyncReply)// Codec.ImplementsInterface(rt.GetType(), typeof(IAsyncReply<>)))// rt.GetType().GetTypeInfo().IsGenericType
//&& rt.GetType().GetGenericTypeDefinition() == typeof(IAsyncReply<>))
{
(rt as AsyncReply).Then(res =>
{
SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback)
.AddUInt8Array(Codec.Compose(res, this))
.Done();
}).Error(ex =>
{
var (code, msg) = SummerizeException(ex);
SendError(ErrorType.Exception, callback, code, msg);
}).Progress((pt, pv, pm) =>
{
SendProgress(callback, pv, pm);
}).Chunk(v =>
{
SendChunk(callback, v);
});
}
else
{
SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback)
.AddUInt8Array(Codec.Compose(rt, this))
.Done();
}
}
else
{ {
// ft found, fi not found, this should never happen // ft found, fi not found, this should never happen
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound);
return;
} }
if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied)
{
SendError(ErrorType.Management, callback,
(ushort)ExceptionCode.InvokeDenied);
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
ParameterInfo[] pis = fi.GetParameters();
object[] args = new object[pis.Length];
if (pis.Length > 0)
{
if (pis.Last().ParameterType == typeof(DistributedConnection))
{
for (byte i = 0; i < pis.Length - 1; i++)
args[i] = arguments.ContainsKey(i) ?
DC.CastConvert(arguments[i], pis[i].ParameterType) : Type.Missing;
args[args.Length - 1] = this;
}
else
{
for (byte i = 0; i < pis.Length; i++)
args[i] = arguments.ContainsKey(i) ?
DC.CastConvert(arguments[i], pis[i].ParameterType) : Type.Missing;
}
}
object rt;
try
{
rt = fi.Invoke(target, args);
}
catch (Exception 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);
return;
}
if (rt is System.Collections.IEnumerable && !(rt is Array || rt is Map<string, object> || rt is string))
{
var enu = rt as System.Collections.IEnumerable;
try
{
foreach (var v in enu)
SendChunk(callback, v);
SendReply(actionType, callback)
.AddUInt8((byte)TransmissionTypeIdentifier.Null)
.Done();
}
catch (Exception ex)
{
var (code, msg) = SummerizeException(ex);
SendError(ErrorType.Exception, callback, code, msg);
}
}
else if (rt is Task)
{
(rt as Task).ContinueWith(t =>
{
#if NETSTANDARD
var res = t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t);
#else
var res = t.GetType().GetProperty("Result").GetValue(t);
#endif
SendReply(actionType, callback)
.AddUInt8Array(Codec.Compose(res, this))
.Done();
});
//await t;
//SendParams((byte)0x90, callback, Codec.Compose(res, this));
}
else if (rt is AsyncReply)// Codec.ImplementsInterface(rt.GetType(), typeof(IAsyncReply<>)))// rt.GetType().GetTypeInfo().IsGenericType
//&& rt.GetType().GetGenericTypeDefinition() == typeof(IAsyncReply<>))
{
(rt as AsyncReply).Then(res =>
{
SendReply(actionType, callback)
.AddUInt8Array(Codec.Compose(res, this))
.Done();
}).Error(ex =>
{
var (code, msg) = SummerizeException(ex);
SendError(ErrorType.Exception, callback, code, msg);
}).Progress((pt, pv, pm) =>
{
SendProgress(callback, pv, pm);
}).Chunk(v =>
{
SendChunk(callback, v);
});
}
else
{
SendReply(actionType, callback)
.AddUInt8Array(Codec.Compose(rt, this))
.Done();
}
}
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;
}
} }

View File

@ -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);
return connection.SendInvoke(instanceId, index, args); 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);
} }
public AsyncReply Listen(EventTemplate et) public AsyncReply Listen(EventTemplate et)
{ {
if (et == null) if (et == null)

View File

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

View File

@ -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;
@ -313,7 +324,7 @@ class IIPPacket : Packet
MethodIndex = data[offset++]; MethodIndex = data[offset++];
(var size, DataType) = TransmissionType.Parse(data, offset, ends); (var size, DataType) = TransmissionType.Parse(data, offset, ends);
//var dt = (DataType)data[offset++]; //var dt = (DataType)data[offset++];
@ -583,7 +594,7 @@ class IIPPacket : Packet
MethodIndex = data[offset++]; MethodIndex = data[offset++];
(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;
@ -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)
{ {
@ -641,10 +706,10 @@ class IIPPacket : Packet
offset += cl; offset += cl;
//if (NotEnough(offset, ends, 4)) //if (NotEnough(offset, ends, 4))
// 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;
@ -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,14 +771,14 @@ 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;
(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;
@ -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;

View File

@ -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,37 +289,55 @@ 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)
if (positionalArgs.Length > 0)
rt.Append(
String.Join(", ", positionalArgs.Select((a) => GetTypeName(a.Type, templates) + " " + a.Name)));
if (optionalArgs.Length > 0)
{ {
if (positionalArgs.Length > 0) rt.Append(","); 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")));
rt.Append(
String.Join(", ", optionalArgs.Select((a) => GetTypeName(a.Type.ToNullable(), templates) + " " + a.Name + " = null")));
} }
else
{
rt.Append($"[Public] public AsyncReply<{rtTypeName}> {f.Name}(");
//rt.Append(string.Join(",", f.Arguments.Select(x => GetTypeName(x.Type, templates) + " " + x.Name))); if (positionalArgs.Length > 0)
rt.Append(
String.Join(", ", positionalArgs.Select((a) => GetTypeName(a.Type, templates) + " " + a.Name)));
if (optionalArgs.Length > 0)
{
if (positionalArgs.Length > 0) rt.Append(",");
rt.Append(
String.Join(", ", optionalArgs.Select((a) => GetTypeName(a.Type.ToNullable(), templates) + " " + a.Name + " = null")));
}
}
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)) } }})");
rt.AppendLine($"_Invoke({f.Index}, args)"); if (f.IsStatic)
rt.AppendLine($"connection.StaticCall(Guid.Parse(\"{template.ClassId.ToString()}\"), {f.Index}, args)");
else
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));");
@ -350,7 +368,7 @@ public static class TemplateGenerator
if (template.Events.Length > 0) if (template.Events.Length > 0)
{ {
rt.AppendLine("protected override void _EmitEventByIndex(byte index, object args) {"); rt.AppendLine("protected override void _EmitEventByIndex(byte index, object args) {");
rt.AppendLine("switch (index) {"); rt.AppendLine("switch (index) {");

View File

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

View File

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

View File

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

View File

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