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

ResourceTemplate 2.0

This commit is contained in:
Ahmed Zamil 2021-05-25 17:06:19 +03:00
parent c8683e17e9
commit 82cbe3b01c
26 changed files with 1105 additions and 272 deletions

View File

@ -52,10 +52,10 @@ namespace Esiur.Stores.MongoDB
[Public] [Public]
public event ResourceEventHanlder ResourceAdded; public event ResourceEventHanlder<IResource> ResourceAdded;
[Public] [Public]
public event ResourceEventHanlder ResourceRemoved; public event ResourceEventHanlder<IResource> ResourceRemoved;
int count = 0; int count = 0;
@ -225,7 +225,7 @@ namespace Esiur.Stores.MongoDB
var doc = value.AsBsonDocument; var doc = value.AsBsonDocument;
if (doc["type"] == 0) if (doc["type"] == 0)
{ {
return Warehouse.Get(doc["link"].AsString); return Warehouse.Get<IResource>(doc["link"].AsString);
} // structure } // structure
else if (doc["type"] == 1) else if (doc["type"] == 1)
{ {
@ -383,7 +383,7 @@ namespace Esiur.Stores.MongoDB
foreach (var pt in template.Properties) foreach (var pt in template.Properties)
{ {
var rt = pt.Info.GetValue(resource, null); var rt = pt.PropertyInfo.GetValue(resource, null);
values.Add(pt.Name, values.Add(pt.Name,
new BsonDocument { { "age", BsonValue.Create(resource.Instance.GetAge(pt.Index)) }, new BsonDocument { { "age", BsonValue.Create(resource.Instance.GetAge(pt.Index)) },
@ -612,7 +612,7 @@ namespace Esiur.Stores.MongoDB
var pi = resource.GetType().GetProperty(pt.Name); var pi = resource.GetType().GetProperty(pt.Name);
#endif #endif
*/ */
var rt = pt.Info.GetValue(resource, null); var rt = pt.PropertyInfo.GetValue(resource, null);
values.Add(pt.Name, values.Add(pt.Name,
new BsonDocument { { "age", BsonValue.Create(resource.Instance.GetAge(pt.Index)) }, new BsonDocument { { "age", BsonValue.Create(resource.Instance.GetAge(pt.Index)) },
@ -841,7 +841,7 @@ namespace Esiur.Stores.MongoDB
foreach (var child in children) foreach (var child in children)
{ {
var r = Warehouse.Get(child); var r = Warehouse.Get<T>(child);
if (r is AsyncReply<T>) if (r is AsyncReply<T>)
rt.Add(r);// (AsyncReply<T>)r); rt.Add(r);// (AsyncReply<T>)r);
} }
@ -873,7 +873,7 @@ namespace Esiur.Stores.MongoDB
foreach (var parent in parents) foreach (var parent in parents)
{ {
var r = Warehouse.Get(parent); var r = Warehouse.Get<T>(parent);
if (r is AsyncReply<T>) if (r is AsyncReply<T>)
rt.Add(r);// (AsyncReply<T>)r); rt.Add(r);// (AsyncReply<T>)r);
} }

View File

@ -84,6 +84,8 @@ namespace Esiur.Core
if (Debug) if (Debug)
Console.WriteLine($"AsyncReply: {Id} Wait ended"); Console.WriteLine($"AsyncReply: {Id} Wait ended");
if (exception != null)
throw exception;
return result; return result;
} }

View File

@ -53,10 +53,10 @@ namespace Esiur.Data
foreach (var pt in resource.Instance.Template.Properties) foreach (var pt in resource.Instance.Template.Properties)
{ {
var rt = pt.Info.GetValue(resource, null); var rt = pt.PropertyInfo.GetValue(resource, null);
if (rt is DistributedPropertyContext) if (rt is DistributedPropertyContext)
continue; continue;
writer.WritePropertyName(options.PropertyNamingPolicy?.ConvertName(pt.Name) ?? pt.Name); writer.WritePropertyName(options.PropertyNamingPolicy?.ConvertName(pt.Name) ?? pt.Name);
if (rt is IResource) if (rt is IResource)

View File

@ -7,12 +7,12 @@
<PackageLicenseUrl>https://github.com/Esiur/Esiur-dotnet/blob/master/LICENSE</PackageLicenseUrl> <PackageLicenseUrl>https://github.com/Esiur/Esiur-dotnet/blob/master/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>http://www.esiur.com</PackageProjectUrl> <PackageProjectUrl>http://www.esiur.com</PackageProjectUrl>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>1.7.1</Version> <Version>1.8.1</Version>
<RepositoryUrl>https://github.com/esiur/esiur-dotnet</RepositoryUrl> <RepositoryUrl>https://github.com/esiur/esiur-dotnet</RepositoryUrl>
<Authors>Ahmed Kh. Zamil</Authors> <Authors>Ahmed Kh. Zamil</Authors>
<AssemblyVersion>1.7.1</AssemblyVersion> <AssemblyVersion>1.8.1.0</AssemblyVersion>
<Company>Esiur Foundation</Company> <Company>Esiur Foundation</Company>
<FileVersion>1.7.1</FileVersion> <FileVersion>1.8.1.0</FileVersion>
<AssemblyName>Esiur</AssemblyName> <AssemblyName>Esiur</AssemblyName>
<RootNamespace>Esiur</RootNamespace> <RootNamespace>Esiur</RootNamespace>
<PackageId>Esiur</PackageId> <PackageId>Esiur</PackageId>
@ -57,6 +57,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="3.9.0" /> <PackageReference Include="Microsoft.CodeAnalysis.Common" Version="3.9.0" />
<PackageReference Include="System.Collections" Version="4.3.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Diagnostics.StackTrace" Version="4.3.0" /> <PackageReference Include="System.Diagnostics.StackTrace" Version="4.3.0" />
<PackageReference Include="System.Dynamic.Runtime" Version="4.3.0" /> <PackageReference Include="System.Dynamic.Runtime" Version="4.3.0" />
@ -65,7 +66,7 @@
<PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" /> <PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" />
<PackageReference Include="System.Net.Security" Version="4.3.2" /> <PackageReference Include="System.Net.Security" Version="4.3.2" />
<PackageReference Include="System.Reflection.Emit" Version="4.7.0" /> <PackageReference Include="System.Reflection.Emit" Version="4.7.0" />
<PackageReference Include="System.Text.Json" Version="5.0.2" /> <PackageReference Include="System.Text.Json" Version="5.0.2" GeneratePathProperty="true" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" /> <PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0" PrivateAssets="all" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0" PrivateAssets="all" />
@ -76,6 +77,8 @@
<ItemGroup> <ItemGroup>
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" /> <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" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -458,7 +458,7 @@ namespace Esiur.Net.IIP
case IIPPacketAction.QueryLink: case IIPPacketAction.QueryLink:
IIPRequestQueryResources(packet.CallbackId, packet.ResourceLink); IIPRequestQueryResources(packet.CallbackId, packet.ResourceLink);
break; break;
case IIPPacketAction.ResourceChildren: case IIPPacketAction.ResourceChildren:
IIPRequestResourceChildren(packet.CallbackId, packet.ResourceId); IIPRequestResourceChildren(packet.CallbackId, packet.ResourceId);
break; break;
@ -470,6 +470,10 @@ namespace Esiur.Net.IIP
IIPRequestInquireResourceHistory(packet.CallbackId, packet.ResourceId, packet.FromDate, packet.ToDate); IIPRequestInquireResourceHistory(packet.CallbackId, packet.ResourceId, packet.FromDate, packet.ToDate);
break; break;
case IIPPacketAction.LinkTemplates:
IIPRequestLinkTemplates(packet.CallbackId, packet.ResourceLink);
break;
// Invoke // Invoke
case IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments: case IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments:
IIPRequestInvokeFunctionArrayArguments(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content); IIPRequestInvokeFunctionArrayArguments(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content);
@ -559,6 +563,7 @@ namespace Esiur.Net.IIP
case IIPPacketAction.ResourceChildren: case IIPPacketAction.ResourceChildren:
case IIPPacketAction.ResourceParents: case IIPPacketAction.ResourceParents:
case IIPPacketAction.ResourceHistory: case IIPPacketAction.ResourceHistory:
case IIPPacketAction.LinkTemplates:
IIPReply(packet.CallbackId, packet.Content); IIPReply(packet.CallbackId, packet.Content);
break; break;
@ -699,10 +704,12 @@ namespace Esiur.Net.IIP
else else
{ {
//Console.WriteLine("User not found"); //Console.WriteLine("User not found");
SendParams().AddUInt8(0xc0) SendParams()
.AddUInt8(0xc0)
.AddUInt8((byte)ExceptionCode.UserOrTokenNotFound) .AddUInt8((byte)ExceptionCode.UserOrTokenNotFound)
.AddUInt16(15) .AddUInt16(15)
.AddString("Token not found").Done(); .AddString("Token not found")
.Done();
} }
}); });
} }
@ -710,12 +717,49 @@ namespace Esiur.Net.IIP
{ {
var errMsg = DC.ToBytes(ex.Message); var errMsg = DC.ToBytes(ex.Message);
SendParams()
.AddUInt8(0xc0)
.AddUInt8((byte)ExceptionCode.GeneralFailure)
.AddUInt16((ushort)errMsg.Length)
.AddUInt8Array(errMsg)
.Done();
}
}
else if (authPacket.RemoteMethod == AuthenticationMethod.None && authPacket.LocalMethod == AuthenticationMethod.None)
{
try
{
// Check if guests are allowed
if (Server.Membership.GuestsAllowed)
{
session.RemoteAuthentication.Username = "g-" + Global.GenerateCode();
session.RemoteAuthentication.Domain = authPacket.Domain;
readyToEstablish = true;
SendParams()
.AddUInt8(0x80)
.Done();
}
else
{
SendParams()
.AddUInt8(0xc0)
.AddUInt8((byte)ExceptionCode.AccessDenied)
.AddUInt16(18)
.AddString("Guests not allowed")
.Done();
}
}
catch (Exception ex)
{
var errMsg = DC.ToBytes(ex.Message);
SendParams().AddUInt8(0xc0) SendParams().AddUInt8(0xc0)
.AddUInt8((byte)ExceptionCode.GeneralFailure) .AddUInt8((byte)ExceptionCode.GeneralFailure)
.AddUInt16((ushort)errMsg.Length) .AddUInt16((ushort)errMsg.Length)
.AddUInt8Array(errMsg).Done(); .AddUInt8Array(errMsg).Done();
} }
} }
} }
else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Action) else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Action)
{ {
@ -808,7 +852,7 @@ namespace Esiur.Net.IIP
Server?.Membership.Login(session); Server?.Membership.Login(session);
loginDate = DateTime.Now; loginDate = DateTime.Now;
}).Error(x => }).Error(x =>
{ {
openReply?.TriggerError(x); openReply?.TriggerError(x);
@ -832,22 +876,32 @@ namespace Esiur.Net.IIP
{ {
if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Acknowledge) if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Acknowledge)
{ {
remoteNonce = authPacket.RemoteNonce; if (authPacket.LocalMethod == AuthenticationMethod.None)
{
SendParams()
.AddUInt8(0x20)
.AddUInt16(0)
.Done();
}
else if (authPacket.LocalMethod == AuthenticationMethod.Credentials
|| authPacket.LocalMethod == AuthenticationMethod.Token)
{
remoteNonce = authPacket.RemoteNonce;
// send our hash // send our hash
var hashFunc = SHA256.Create(); var hashFunc = SHA256.Create();
//var localHash = hashFunc.ComputeHash(BinaryList.ToBytes(localPassword, localNonce, remoteNonce)); //var localHash = hashFunc.ComputeHash(BinaryList.ToBytes(localPassword, localNonce, remoteNonce));
var localHash = hashFunc.ComputeHash(new BinaryList() var localHash = hashFunc.ComputeHash(new BinaryList()
.AddUInt8Array(localPasswordOrToken) .AddUInt8Array(localPasswordOrToken)
.AddUInt8Array(localNonce) .AddUInt8Array(localNonce)
.AddUInt8Array(remoteNonce) .AddUInt8Array(remoteNonce)
.ToArray()); .ToArray());
SendParams()
.AddUInt8(0)
.AddUInt8Array(localHash)
.Done();
SendParams()
.AddUInt8(0)
.AddUInt8Array(localHash)
.Done();
}
//SendParams((byte)0, localHash); //SendParams((byte)0, localHash);
} }
else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Action) else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Action)
@ -867,7 +921,6 @@ namespace Esiur.Net.IIP
if (remoteHash.SequenceEqual(authPacket.Hash)) if (remoteHash.SequenceEqual(authPacket.Hash))
{ {
// send establish request // send establish request
//SendParams((byte)0x20, (ushort)0);
SendParams() SendParams()
.AddUInt8(0x20) .AddUInt8(0x20)
.AddUInt16(0) .AddUInt16(0)
@ -981,32 +1034,29 @@ namespace Esiur.Net.IIP
{ {
if (trigger == ResourceTrigger.Open) if (trigger == ResourceTrigger.Open)
{ {
if (this.Server != null)
return new AsyncReply<bool>(true);
var host = Instance.Name.Split(':');
var address = host[0];
var port = ushort.Parse(host[1]);
// assign domain from hostname if not provided
var domain = Domain != null ? Domain : address;
if (Username != null // Instance.Attributes.ContainsKey("username") if (Username != null // Instance.Attributes.ContainsKey("username")
&& Password != null)/// Instance.Attributes.ContainsKey("password")) && Password != null)/// Instance.Attributes.ContainsKey("password"))
{ {
// assign domain from hostname if not provided
var host = Instance.Name.Split(':');
var address = host[0];
var port = ushort.Parse(host[1]);
var domain = Domain != null ? Domain : address;
return Connect(AuthenticationMethod.Credentials, null, address, port, Username, 0, DC.ToBytes(Password), domain); return Connect(AuthenticationMethod.Credentials, null, address, port, Username, 0, DC.ToBytes(Password), domain);
} }
else if (Token != null) else if (Token != null)
{ {
var host = Instance.Name.Split(':');
var address = host[0];
var port = ushort.Parse(host[1]);
var domain = Domain != null ? Domain : address;
return Connect(AuthenticationMethod.Token, null, address, port, null, TokenIndex, DC.ToBytes(Token), domain); return Connect(AuthenticationMethod.Token, null, address, port, null, TokenIndex, DC.ToBytes(Token), domain);
}
else
{
return Connect(AuthenticationMethod.None, null, address, port, null, 0, null, domain);
} }
} }

View File

@ -498,8 +498,8 @@ namespace Esiur.Net.IIP
//r.Instance.CustomResourceEventOccurred -= Instance_CustomEventOccurred; //r.Instance.CustomResourceEventOccurred -= Instance_CustomEventOccurred;
//r.Instance.ResourceModified -= Instance_PropertyModified; //r.Instance.ResourceModified -= Instance_PropertyModified;
//r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed; //r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed;
// r.Instance.Children.OnAdd -= Children_OnAdd; // r.Instance.Children.OnAdd -= Children_OnAdd;
// r.Instance.Children.OnRemoved -= Children_OnRemoved; // r.Instance.Children.OnRemoved -= Children_OnRemoved;
@ -800,16 +800,16 @@ namespace Esiur.Net.IIP
// create the resource // create the resource
var resource = Activator.CreateInstance(type, args) as IResource; var resource = Activator.CreateInstance(type, args) as IResource;
Warehouse.Put( name, resource, store as IStore, parent).Then(ok => Warehouse.Put(name, resource, store as IStore, parent).Then(ok =>
{ {
SendReply(IIPPacket.IIPPacketAction.CreateResource, callback) SendReply(IIPPacket.IIPPacketAction.CreateResource, callback)
.AddUInt32(resource.Instance.Id) .AddUInt32(resource.Instance.Id)
.Done(); .Done();
}).Error(x => }).Error(x =>
{ {
SendError(ErrorType.Exception, callback, (ushort)ExceptionCode.AddToStoreFailed); SendError(ErrorType.Exception, callback, (ushort)ExceptionCode.AddToStoreFailed);
}); });
}); });
}); });
@ -1077,6 +1077,50 @@ namespace Esiur.Net.IIP
} }
void IIPRequestLinkTemplates(uint callback, string resourceLink)
{
Console.WriteLine("IIPRequestLinkTemplates " + DateTime.UtcNow);
Action<IResource[]> queryCallback = (r) =>
{
if (r == null)
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound);
else
{
var list = r.Where(x => x.Instance.Applicable(session, ActionType.ViewTemplate, null) != Ruling.Denied).ToArray();
if (list.Length == 0)
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound);
else
{
// get all templates related to this resource
var msg = new BinaryList();
var templates = new List<ResourceTemplate>();
foreach (var resource in list)
templates.AddRange(ResourceTemplate.GetRuntimeTypes(resource.Instance.Template).Where(x => !templates.Contains(x)));
foreach(var t in templates)
{
msg.AddInt32(t.Content.Length)
.AddUInt8Array(t.Content);
}
// digggg
SendReply(IIPPacket.IIPPacketAction.LinkTemplates, callback)
.AddInt32(msg.Length)
.AddUInt8Array(msg.ToArray())
.Done();
}
}
};
if (Server?.EntryPoint != null)
Server.EntryPoint.Query(resourceLink, this).Then(queryCallback);
else
Warehouse.Query(resourceLink).Then(queryCallback);
}
void IIPRequestTemplateFromClassName(uint callback, string className) void IIPRequestTemplateFromClassName(uint callback, string className)
{ {
Warehouse.GetTemplate(className).Then((t) => Warehouse.GetTemplate(className).Then((t) =>
@ -1096,19 +1140,18 @@ namespace Esiur.Net.IIP
void IIPRequestTemplateFromClassId(uint callback, Guid classId) void IIPRequestTemplateFromClassId(uint callback, Guid classId)
{ {
Warehouse.GetTemplate(classId).Then((t) => var t = Warehouse.GetTemplate(classId);
if (t != null)
SendReply(IIPPacket.IIPPacketAction.TemplateFromClassId, callback)
.AddInt32(t.Content.Length)
.AddUInt8Array(t.Content)
.Done();
else
{ {
if (t != null) // reply failed
SendReply(IIPPacket.IIPPacketAction.TemplateFromClassId, callback) SendError(ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound);
.AddInt32(t.Content.Length) }
.AddUInt8Array(t.Content)
.Done();
else
{
// reply failed
SendError(ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound);
}
});
} }
@ -1165,7 +1208,7 @@ namespace Esiur.Net.IIP
} }
[Attribute] [Attribute]
public ExceptionLevel ExceptionLevel { get; set; } public ExceptionLevel ExceptionLevel { get; set; }
= ExceptionLevel.Code | ExceptionLevel.Message | ExceptionLevel.Source | ExceptionLevel.Trace; = ExceptionLevel.Code | ExceptionLevel.Message | ExceptionLevel.Source | ExceptionLevel.Trace;
private Tuple<ushort, string> SummerizeException(Exception ex) private Tuple<ushort, string> SummerizeException(Exception ex)
@ -1477,17 +1520,17 @@ namespace Esiur.Net.IIP
.AddUInt8Array(Codec.Compose(res, this)) .AddUInt8Array(Codec.Compose(res, this))
.Done(); .Done();
}).Error(ex => }).Error(ex =>
{ {
var (code, msg) = SummerizeException(ex); var (code, msg) = SummerizeException(ex);
SendError(ErrorType.Exception, callback, code, msg); SendError(ErrorType.Exception, callback, code, msg);
}).Progress((pt, pv, pm) => }).Progress((pt, pv, pm) =>
{ {
SendProgress(callback, pv, pm); SendProgress(callback, pv, pm);
}).Chunk(v => }).Chunk(v =>
{ {
SendChunk(callback, v); SendChunk(callback, v);
}); });
} }
else else
{ {
@ -1539,7 +1582,7 @@ namespace Esiur.Net.IIP
} }
else else
{ {
lock(subscriptionsLock) lock (subscriptionsLock)
{ {
if (!subscriptions.ContainsKey(r)) if (!subscriptions.ContainsKey(r))
{ {
@ -1711,51 +1754,51 @@ namespace Esiur.Net.IIP
}); });
} }
// void IIPRequestGetPropertyIfModifiedSince(uint callback, uint resourceId, byte index, ulong age) // void IIPRequestGetPropertyIfModifiedSince(uint callback, uint resourceId, byte index, ulong age)
// { // {
// Warehouse.GetById(resourceId).Then((r) => // Warehouse.GetById(resourceId).Then((r) =>
// { // {
// if (r != null) // if (r != null)
// { // {
// var pt = r.Instance.Template.GetFunctionTemplateByIndex(index); // var pt = r.Instance.Template.GetFunctionTemplateByIndex(index);
// if (pt != null) // if (pt != null)
// { // {
// if (r.Instance.GetAge(index) > age) // if (r.Instance.GetAge(index) > age)
// { // {
//#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
// if (pi != null) // if (pi != null)
// { // {
// SendReply(IIPPacket.IIPPacketAction.GetPropertyIfModified, callback) // SendReply(IIPPacket.IIPPacketAction.GetPropertyIfModified, callback)
// .AddUInt8Array(Codec.Compose(pi.GetValue(r), this)) // .AddUInt8Array(Codec.Compose(pi.GetValue(r), this))
// .Done(); // .Done();
// } // }
// else // else
// { // {
// // pt found, pi not found, this should never happen // // pt found, pi not found, this should never happen
// } // }
// } // }
// else // else
// { // {
// SendReply(IIPPacket.IIPPacketAction.GetPropertyIfModified, callback) // SendReply(IIPPacket.IIPPacketAction.GetPropertyIfModified, callback)
// .AddUInt8((byte)DataType.NotModified) // .AddUInt8((byte)DataType.NotModified)
// .Done(); // .Done();
// } // }
// } // }
// else // else
// { // {
// // pt not found // // pt not found
// } // }
// } // }
// else // else
// { // {
// // resource not found // // resource not found
// } // }
// }); // });
// } // }
void IIPRequestSetProperty(uint callback, uint resourceId, byte index, byte[] content) void IIPRequestSetProperty(uint callback, uint resourceId, byte index, byte[] content)
{ {
@ -1791,7 +1834,7 @@ namespace Esiur.Net.IIP
var pi = r.GetType().GetProperty(pt.Name); var pi = r.GetType().GetProperty(pt.Name);
#endif*/ #endif*/
var pi = pt.Info; var pi = pt.PropertyInfo;
if (pi != null) if (pi != null)
{ {
@ -2091,6 +2134,43 @@ namespace Esiur.Net.IIP
return new AsyncReply<IResource>(null); return new AsyncReply<IResource>(null);
} }
public AsyncReply<ResourceTemplate[]> GetLinkTemplates(string link)
{
var reply = new AsyncReply<ResourceTemplate[]>();
var l = DC.ToBytes(link);
SendRequest(IIPPacket.IIPPacketAction.LinkTemplates)
.AddUInt16((ushort)l.Length)
.AddUInt8Array(l)
.Done()
.Then((rt) =>
{
var templates = new List<ResourceTemplate>();
// parse templates
var data = (byte[])rt[0];
//var offset = 0;
for (uint offset = 0; offset < data.Length;)
{
var cs = data.GetUInt32(offset);
offset += 4;
templates.Add(ResourceTemplate.Parse(data, offset, cs));
offset += cs;
}
reply.Trigger(templates.ToArray());
}).Error((ex) =>
{
reply.TriggerError(ex);
});
return reply;
}
/// <summary> /// <summary>
/// Fetch a resource from the other end /// Fetch a resource from the other end
/// </summary> /// </summary>
@ -2125,7 +2205,19 @@ namespace Esiur.Net.IIP
.Then((rt) => .Then((rt) =>
{ {
var dr = resource ?? new DistributedResource(this, id, (ulong)rt[1], (string)rt[2]); DistributedResource dr;
if (resource == null)
{
var template = Warehouse.GetTemplate((Guid)rt[0]);
if (template?.RuntimeType != null)
dr = Activator.CreateInstance(template.RuntimeType, this, id, (ulong)rt[1], (string)rt[2]) as DistributedResource;
else
dr = new DistributedResource(this, id, (ulong)rt[1], (string)rt[2]);
}
else
dr = resource;
GetTemplate((Guid)rt[0]).Then((tmp) => GetTemplate((Guid)rt[0]).Then((tmp) =>
{ {
@ -2140,7 +2232,7 @@ namespace Esiur.Net.IIP
resourceRequests.Remove(id); resourceRequests.Remove(id);
reply.Trigger(dr); reply.Trigger(dr);
}); });
}).Error(ex=>reply.TriggerError(ex)); }).Error(ex => reply.TriggerError(ex));
} }
else else
{ {
@ -2149,7 +2241,7 @@ namespace Esiur.Net.IIP
dr._Attach(ar); dr._Attach(ar);
resourceRequests.Remove(id); resourceRequests.Remove(id);
reply.Trigger(dr); reply.Trigger(dr);
}).Error(ex=>reply.TriggerError(ex)); }).Error(ex => reply.TriggerError(ex));
} }
}).Error((ex) => }).Error((ex) =>
@ -2422,9 +2514,9 @@ namespace Esiur.Net.IIP
private void UnsubscribeAll() private void UnsubscribeAll()
{ {
lock(subscriptionsLock) lock (subscriptionsLock)
{ {
foreach(var resource in subscriptions.Keys) foreach (var resource in subscriptions.Keys)
{ {
resource.Instance.ResourceEventOccurred -= Instance_EventOccurred; resource.Instance.ResourceEventOccurred -= Instance_EventOccurred;
resource.Instance.CustomResourceEventOccurred -= Instance_CustomEventOccurred; resource.Instance.CustomResourceEventOccurred -= Instance_CustomEventOccurred;
@ -2491,7 +2583,7 @@ namespace Esiur.Net.IIP
if (resource.Instance.Applicable(this.session, ActionType.ReceiveEvent, et, issuer) == Ruling.Denied) if (resource.Instance.Applicable(this.session, ActionType.ReceiveEvent, et, issuer) == Ruling.Denied)
return; return;
// compose the packet // compose the packet
SendEvent(IIPPacket.IIPPacketEvent.EventOccurred) SendEvent(IIPPacket.IIPPacketEvent.EventOccurred)
.AddUInt32(resource.Instance.Id) .AddUInt32(resource.Instance.Id)

View File

@ -67,7 +67,7 @@ namespace Esiur.Net.IIP
string link; string link;
//ulong age; //ulong age;
//ulong[] ages; //ulong[] ages;
object[] properties; protected object[] properties;
internal List<DistributedResource> parents = new List<DistributedResource>(); internal List<DistributedResource> parents = new List<DistributedResource>();
internal List<DistributedResource> children = new List<DistributedResource>(); internal List<DistributedResource> children = new List<DistributedResource>();
@ -210,13 +210,16 @@ namespace Esiur.Net.IIP
return true; return true;
} }
internal void _EmitEventByIndex(byte index, object args)
protected internal virtual void _EmitEventByIndex(byte index, object args)
{ {
var et = Instance.Template.GetEventTemplateByIndex(index); var et = Instance.Template.GetEventTemplateByIndex(index);
events[index]?.Invoke(this, args); events[index]?.Invoke(this, args);
Instance.EmitResourceEvent(et.Name, args); Instance.EmitResourceEvent(et.Name, args);
} }
public AsyncReply<object> _InvokeByNamedArguments(byte index, Structure namedArgs) public AsyncReply<object> _InvokeByNamedArguments(byte index, Structure namedArgs)
{ {
if (destroyed) if (destroyed)
@ -332,7 +335,7 @@ namespace Esiur.Net.IIP
/// </summary> /// </summary>
/// <param name="index">Zero-based property index.</param> /// <param name="index">Zero-based property index.</param>
/// <returns>Value</returns> /// <returns>Value</returns>
internal object _Get(byte index) protected internal object _Get(byte index)
{ {
if (index >= properties.Length) if (index >= properties.Length)
return null; return null;
@ -383,7 +386,7 @@ namespace Esiur.Net.IIP
/// <param name="index">Zero-based property index.</param> /// <param name="index">Zero-based property index.</param>
/// <param name="value">Value</param> /// <param name="value">Value</param>
/// <returns>Indicator when the property is set.</returns> /// <returns>Indicator when the property is set.</returns>
internal AsyncReply<object> _Set(byte index, object value) protected internal AsyncReply<object> _Set(byte index, object value)
{ {
if (index >= properties.Length) if (index >= properties.Length)
return null; return null;

View File

@ -30,5 +30,5 @@ using System.Threading.Tasks;
namespace Esiur.Net.IIP namespace Esiur.Net.IIP
{ {
public delegate void DistributedResourceEvent(DistributedResource sender, object arguments); public delegate void DistributedResourceEvent(DistributedResource sender, object argument);
} }

View File

@ -344,12 +344,15 @@ namespace Esiur.Net.Packets
LocalMethod = (AuthenticationMethod)((data[offset] >> 2) & 0x3); LocalMethod = (AuthenticationMethod)((data[offset] >> 2) & 0x3);
var encrypt = ((data[offset++] & 0x2) == 0x2); var encrypt = ((data[offset++] & 0x2) == 0x2);
if (NotEnough(offset, ends, 1)) if (RemoteMethod == AuthenticationMethod.None)
return -dataLengthNeeded; {
if (LocalMethod == AuthenticationMethod.None)
{
if (RemoteMethod == AuthenticationMethod.Credentials // do nothing
|| RemoteMethod == AuthenticationMethod.Token) }
}
else if (RemoteMethod == AuthenticationMethod.Credentials
|| RemoteMethod == AuthenticationMethod.Token)
{ {
if (LocalMethod == AuthenticationMethod.None) if (LocalMethod == AuthenticationMethod.None)
{ {

View File

@ -107,6 +107,7 @@ namespace Esiur.Net.Packets
ResourceHistory, ResourceHistory,
ResourceChildren, ResourceChildren,
ResourceParents, ResourceParents,
LinkTemplates,
// Request Invoke // Request Invoke
InvokeFunctionArrayArguments = 0x10, InvokeFunctionArrayArguments = 0x10,
@ -484,7 +485,8 @@ namespace Esiur.Net.Packets
ResourceId = data.GetUInt32(offset); ResourceId = data.GetUInt32(offset);
offset += 4; offset += 4;
} }
else if (Action == IIPPacketAction.QueryLink) else if (Action == IIPPacketAction.QueryLink
|| Action == IIPPacketAction.LinkTemplates)
{ {
if (NotEnough(offset, ends, 2)) if (NotEnough(offset, ends, 2))
return -dataLengthNeeded; return -dataLengthNeeded;
@ -691,6 +693,7 @@ namespace Esiur.Net.Packets
|| Action == IIPPacketAction.ResourceChildren || Action == IIPPacketAction.ResourceChildren
|| Action == IIPPacketAction.ResourceParents || Action == IIPPacketAction.ResourceParents
|| Action == IIPPacketAction.ResourceHistory || Action == IIPPacketAction.ResourceHistory
|| Action == IIPPacketAction.LinkTemplates
// Attribute // Attribute
|| Action == IIPPacketAction.GetAllAttributes || Action == IIPPacketAction.GetAllAttributes
|| Action == IIPPacketAction.GetAttributes) || Action == IIPPacketAction.GetAttributes)

View File

@ -6,43 +6,247 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Text; using System.Text;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions;
using Esiur.Net.IIP;
using Esiur.Resource;
using Esiur.Resource.Template;
using Esiur.Data;
using System.IO;
using Esiur.Core;
namespace Esiur.Proxy namespace Esiur.Proxy
{ {
[Generator] [Generator]
public class ResourceGenerator : ISourceGenerator public class ResourceGenerator : ISourceGenerator
{ {
private static Regex urlRegex = new Regex(@"^(?:([\S]*)://([^/]*)/?)");
private KeyList<string, ResourceTemplate[]> cache = new();
// private List<string> inProgress = new();
public void Initialize(GeneratorInitializationContext context) public void Initialize(GeneratorInitializationContext context)
{ {
// Register receiver // Register receiver
context.RegisterForSyntaxNotifications(() => new ResourceGeneratorReceiver()); context.RegisterForSyntaxNotifications(() => new ResourceGeneratorReceiver());
} }
string GetTypeName(TemplateDataType templateDataType, ResourceTemplate[] templates)
{
if (templateDataType.Type == DataType.Resource)
return templates.First(x => x.ClassId == templateDataType.TypeGuid).ClassName;
else if (templateDataType.Type == DataType.ResourceArray)
return templates.First(x => x.ClassId == templateDataType.TypeGuid).ClassName + "[]";
var name = templateDataType.Type switch
{
DataType.Bool => "bool",
DataType.BoolArray => "bool[]",
DataType.Char => "char",
DataType.CharArray => "char[]",
DataType.DateTime => "DateTime",
DataType.DateTimeArray => "DateTime[]",
DataType.Decimal => "decimal",
DataType.DecimalArray => "decimal[]",
DataType.Float32 => "float",
DataType.Float32Array => "float[]",
DataType.Float64 => "double",
DataType.Float64Array => "double[]",
DataType.Int16 => "short",
DataType.Int16Array => "short[]",
DataType.Int32 => "int",
DataType.Int32Array => "int[]",
DataType.Int64 => "long",
DataType.Int64Array => "long[]",
DataType.Int8 => "sbyte",
DataType.Int8Array => "sbyte[]",
DataType.String => "string",
DataType.StringArray => "string[]",
DataType.Structure => "Structure",
DataType.StructureArray => "Structure[]",
DataType.UInt16 => "ushort",
DataType.UInt16Array => "ushort[]",
DataType.UInt32 => "uint",
DataType.UInt32Array => "uint[]",
DataType.UInt64 => "ulong",
DataType.UInt64Array => "ulong[]",
DataType.UInt8 => "byte",
DataType.UInt8Array => "byte[]",
DataType.VarArray => "object[]",
DataType.Void => "object",
_ => "object"
};
return name;
}
void ReportError(GeneratorExecutionContext context, string title, string msg, string category)
{
context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor("MySG001", title, msg, category, DiagnosticSeverity.Error, true), Location.None));
}
string GenerateClass(ResourceTemplate template, ResourceTemplate[] templates)
{
var cls = template.ClassName.Split('.');
var nameSpace = string.Join(".", cls.Take(cls.Length - 1));
var className = cls.Last();
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($"namespace { nameSpace} {{");
rt.AppendLine($"public class {className} : DistributedResource {{");
rt.AppendLine($"public {className}(DistributedConnection connection, uint instanceId, ulong age, string link) : base(connection, instanceId, age, link) {{}}");
rt.AppendLine($"public {className}() {{}}");
foreach (var f in template.Functions)
{
var rtTypeName = GetTypeName(f.ReturnType, templates);
rt.Append($"public AsyncReply<{rtTypeName}> {f.Name}(");
rt.Append(string.Join(",", f.Arguments.Select(x => GetTypeName(x.Type, templates) + " " + x.Name)));
rt.AppendLine(") {");
rt.AppendLine($"var rt = new AsyncReply<{rtTypeName}>();");
rt.AppendLine($"_InvokeByArrayArguments({f.Index}, new object[] {{ { string.Join(", ", f.Arguments.Select(x => x.Name)) } }})");
rt.AppendLine($".Then(x => rt.Trigger(({rtTypeName})x))");
rt.AppendLine($".Error(x => rt.TriggerError(x))");
rt.AppendLine($".Chunk(x => rt.TriggerChunk(x));");
rt.AppendLine("return rt; }");
}
foreach (var p in template.Properties)
{
var ptTypeName = GetTypeName(p.ValueType, templates);
rt.AppendLine($"public {ptTypeName} {p.Name} {{");
rt.AppendLine($"get => ({ptTypeName})properties[{p.Index}];");
rt.AppendLine($"set => _Set({p.Index}, value);");
rt.AppendLine("}");
}
if (template.Events.Length > 0)
{
rt.AppendLine("protected override void _EmitEventByIndex(byte index, object args) {");
rt.AppendLine("switch (index) {");
var eventsList = new StringBuilder();
foreach (var e in template.Events)
{
var etTypeName = GetTypeName(e.ArgumentType, templates);
rt.AppendLine($"case {e.Index}: {e.Name}?.Invoke(({etTypeName})args); break;");
eventsList.AppendLine($"public event ResourceEventHanlder<{etTypeName}> {e.Name};");
}
rt.AppendLine("}}");
rt.AppendLine(eventsList.ToString());
}
rt.AppendLine("\r\n}\r\n}");
return rt.ToString();
}
void GenerateModel(GeneratorExecutionContext context, ResourceTemplate[] templates)
{
foreach (var tmp in templates)
{
var source = GenerateClass(tmp, templates);
//File.WriteAllText($@"C:\gen\{tmp.ClassName}.cs", source);
context.AddSource(tmp.ClassName + "_esiur.cs", source);
}
// generate info class
var gen = "using System; \r\n namespace Esiur { public static class Generated { public static Type[] Types {get;} = new Type[]{ " +
string.Join(",", templates.Select(x => $"typeof({x.ClassName})"))
+ " }; \r\n } \r\n}";
//File.WriteAllText($@"C:\gen\Esiur.Generated.cs", gen);
context.AddSource("Esiur.Generated.cs", gen);
}
public void Execute(GeneratorExecutionContext context) public void Execute(GeneratorExecutionContext context)
{ {
if (!(context.SyntaxContextReceiver is ResourceGeneratorReceiver receiver)) if (!(context.SyntaxContextReceiver is ResourceGeneratorReceiver receiver))
return; return;
try //if (receiver.Imports.Count > 0 && !Debugger.IsAttached)
//{
// Debugger.Launch();
//}
foreach (var path in receiver.Imports)
{ {
//#if DEBUG if (!urlRegex.IsMatch(path))
// if (!Debugger.IsAttached) continue;
// {
// Debugger.Launch();
// }
//#endif
//var toImplement = receiver.Classes.Where(x => x.Fields.Length > 0);
foreach (var ci in receiver.Classes) //File.WriteAllLines("C:\\gen\\ref.log", context.Compilation.ReferencedAssemblyNames.Select(x => x.ToString()));
if (cache.Contains(path))
{ {
GenerateModel(context, cache[path]);
continue;
}
// Syncronization
//if (inProgress.Contains(path))
// continue;
//inProgress.Add(path);
var url = urlRegex.Split(path);
try
{
var con = Warehouse.Get<DistributedConnection>(url[1] + "://" + url[2]).Wait(20000);
var templates = con.GetLinkTemplates(url[3]).Wait(60000);
cache[path] = templates;
// make sources
GenerateModel(context, templates);
}
catch (Exception ex)
{
ReportError(context, ex.Source, ex.Message, "Esiur");
System.IO.File.AppendAllText("c:\\gen\\error.log", ex.ToString() + "\r\n");
}
//inProgress.Remove(path);
}
//#if DEBUG
//#endif
//var toImplement = receiver.Classes.Where(x => x.Fields.Length > 0);
foreach (var ci in receiver.Classes.Values)
{
try
{
var code = @$"using Esiur.Resource; var code = @$"using Esiur.Resource;
using Esiur.Core; using Esiur.Core;
namespace { ci.ClassSymbol.ContainingNamespace.ToDisplayString() } {{ namespace { ci.ClassSymbol.ContainingNamespace.ToDisplayString() } {{
"; ";
if (ci.ImplementInterface) if (ci.HasInterface)
code += $"public partial class {ci.Name} {{"; code += $"public partial class {ci.Name} {{";
else else
{ {
@ -52,7 +256,7 @@ public event DestroyedEvent OnDestroy;
public virtual void Destroy() {{ OnDestroy?.Invoke(this); }} public virtual void Destroy() {{ OnDestroy?.Invoke(this); }}
"; ";
if (!ci.ImplementTrigger) if (!ci.HasTrigger)
code += "public AsyncReply<bool> Trigger(ResourceTrigger trigger) => new AsyncReply<bool>(true);\r\n"; code += "public AsyncReply<bool> Trigger(ResourceTrigger trigger) => new AsyncReply<bool>(true);\r\n";
} }
@ -70,11 +274,12 @@ public virtual void Destroy() {{ OnDestroy?.Invoke(this); }}
//System.IO.File.WriteAllText("c:\\gen\\" + ci.Name + "_esiur.cs", code); //System.IO.File.WriteAllText("c:\\gen\\" + ci.Name + "_esiur.cs", code);
context.AddSource(ci.Name + "_esiur.cs", code); context.AddSource(ci.Name + "_esiur.cs", code);
}
catch (Exception ex)
{
System.IO.File.AppendAllText("c:\\gen\\error.log", ci.Name + " " + ex.ToString() + "\r\n");
} }
}
catch //(Exception ex)
{
//System.IO.File.AppendAllText("c:\\gen\\error.log", ex.ToString() + "\r\n");
} }
} }
} }

View File

@ -9,10 +9,10 @@ namespace Esiur.Proxy
public struct ResourceGeneratorClassInfo public struct ResourceGeneratorClassInfo
{ {
public string Name { get; set; } public string Name { get; set; }
public bool ImplementInterface { get; set; } public bool HasInterface { get; set; }
public bool ImplementTrigger { get; set; } public bool HasTrigger { get; set; }
public IFieldSymbol[] Fields { get; set; } public List<IFieldSymbol> Fields { get; set; }
public ITypeSymbol ClassSymbol { get; set; } public ITypeSymbol ClassSymbol { get; set; }
public ClassDeclarationSyntax ClassDeclaration { get; set; } public ClassDeclarationSyntax ClassDeclaration { get; set; }

View File

@ -11,7 +11,9 @@ namespace Esiur.Proxy
public class ResourceGeneratorReceiver : ISyntaxContextReceiver public class ResourceGeneratorReceiver : ISyntaxContextReceiver
{ {
public List<ResourceGeneratorClassInfo> Classes { get; } = new(); public Dictionary<string, ResourceGeneratorClassInfo> Classes { get; } = new();
public List<string> Imports { get; } = new ();
public void OnVisitSyntaxNode(GeneratorSyntaxContext context) public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
{ {
@ -20,8 +22,21 @@ namespace Esiur.Proxy
{ {
var cds = context.Node as ClassDeclarationSyntax; var cds = context.Node as ClassDeclarationSyntax;
var cls = context.SemanticModel.GetDeclaredSymbol(cds) as ITypeSymbol; var cls = context.SemanticModel.GetDeclaredSymbol(cds) as ITypeSymbol;
var attrs = cls.GetAttributes();
if (cls.GetAttributes().Any(a => a.AttributeClass.ToDisplayString() == "Esiur.Resource.ResourceAttribute")) var imports = attrs.Where(a => a.AttributeClass.ToDisplayString() == "Esiur.Resource.ImportAttribute");
foreach (var import in imports)
{
// Debugger.Launch();
var url = import.ConstructorArguments.First().Value.ToString();
if (!Imports.Contains(url))
Imports.Add(url);
}
if (attrs.Any(a => a.AttributeClass.ToDisplayString() == "Esiur.Resource.ResourceAttribute"))
{ {
@ -46,16 +61,33 @@ namespace Esiur.Proxy
// get fields // get fields
Classes.Add(new ResourceGeneratorClassInfo()
{
Name = cls.Name,
ClassDeclaration = cds,
ClassSymbol = cls,
Fields = fields,
ImplementInterface = cls.Interfaces.Any(x => x.ToDisplayString() == "Esiur.Resource.IResource"),
ImplementTrigger = hasTrigger
});
var fullName = cls.ContainingAssembly + "." + cls.Name;
// Partial class check
if (Classes.ContainsKey(fullName))
{
// append fields
var c = Classes[fullName];
c.Fields.AddRange(fields);
if (!c.HasInterface)
c.HasInterface = cls.Interfaces.Any(x => x.ToDisplayString() == "Esiur.Resource.IResource");
if (!c.HasTrigger)
c.HasTrigger = hasTrigger;
} else
{
Classes.Add(fullName, new ResourceGeneratorClassInfo()
{
Name = cls.Name,
ClassDeclaration = cds,
ClassSymbol = cls,
Fields = fields.ToList(),
HasInterface = cls.Interfaces.Any(x => x.ToDisplayString() == "Esiur.Resource.IResource"),
HasTrigger = hasTrigger
});
}
return; return;
} }
} }

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Resource
{
[AttributeUsage(AttributeTargets.Class)]
public class ImportAttribute:Attribute
{
public ImportAttribute(string url)
{
}
}
}

View File

@ -185,8 +185,8 @@ namespace Esiur.Resource
var at = template.GetAttributeTemplate(kv.Key); var at = template.GetAttributeTemplate(kv.Key);
if (at != null) if (at != null)
if (at.Info.CanWrite) if (at.PropertyInfo.CanWrite)
at.Info.SetValue(res, DC.CastConvert(kv.Value, at.Info.PropertyType)); at.PropertyInfo.SetValue(res, DC.CastConvert(kv.Value, at.PropertyInfo.PropertyType));
} }
} }
@ -354,17 +354,17 @@ namespace Esiur.Resource
#endif #endif
*/ */
if (pt.Info.PropertyType == typeof(DistributedPropertyContext)) if (pt.PropertyInfo.PropertyType == typeof(DistributedPropertyContext))
return false; return false;
if (pt.Info.CanWrite) if (pt.PropertyInfo.CanWrite)
{ {
try try
{ {
loading = true; loading = true;
pt.Info.SetValue(res, DC.CastConvert(value, pt.Info.PropertyType)); pt.PropertyInfo.SetValue(res, DC.CastConvert(value, pt.PropertyInfo.PropertyType));
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -453,7 +453,7 @@ namespace Esiur.Resource
if (resource.TryGetTarget(out res)) if (resource.TryGetTarget(out res))
{ {
var rt = pt.Info.GetValue(res, null); var rt = pt.PropertyInfo.GetValue(res, null);
props.Add(new PropertyValue(rt, ages[pt.Index], modificationDates[pt.Index])); props.Add(new PropertyValue(rt, ages[pt.Index], modificationDates[pt.Index]));
} }
} }
@ -628,7 +628,7 @@ namespace Esiur.Resource
var pt = template.GetPropertyTemplateByName(name); var pt = template.GetPropertyTemplateByName(name);
if (pt != null && pt.Info != null) if (pt != null && pt.PropertyInfo != null)
{ {
/* /*
#if NETSTANDARD #if NETSTANDARD
@ -649,7 +649,7 @@ namespace Esiur.Resource
IResource res; IResource res;
if (resource.TryGetTarget(out res)) if (resource.TryGetTarget(out res))
value = pt.Info.GetValue(res, null); value = pt.PropertyInfo.GetValue(res, null);
else else
{ {
value = null; value = null;
@ -900,28 +900,30 @@ namespace Esiur.Resource
//if (evt.EventHandlerType != typeof(ResourceEventHanlder)) //if (evt.EventHandlerType != typeof(ResourceEventHanlder))
// continue; // continue;
if (evt.Info == null) if (evt.EventInfo == null)
continue; continue;
if (evt.Info.EventHandlerType == typeof(ResourceEventHanlder)) var eventGenericType = evt.EventInfo.EventHandlerType.GetGenericTypeDefinition();
if (eventGenericType == typeof(ResourceEventHanlder<>))
{ {
// var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); // var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true);
// if (ca.Length == 0) // if (ca.Length == 0)
// continue; // continue;
ResourceEventHanlder proxyDelegate = (args) => EmitResourceEvent(evt.Name, args); ResourceEventHanlder<object> proxyDelegate = (args) => EmitResourceEvent(evt.Name, args);
evt.Info.AddEventHandler(resource, proxyDelegate); evt.EventInfo.AddEventHandler(resource, proxyDelegate);
} }
else if (evt.Info.EventHandlerType == typeof(CustomResourceEventHanlder)) else if (eventGenericType == typeof(CustomResourceEventHanlder<>))
{ {
//var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); //var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true);
//if (ca.Length == 0) //if (ca.Length == 0)
// continue; // continue;
CustomResourceEventHanlder proxyDelegate = (issuer, receivers, args) => EmitCustomResourceEvent(issuer, receivers, evt.Name, args); CustomResourceEventHanlder<object> proxyDelegate = (issuer, receivers, args) => EmitCustomResourceEvent(issuer, receivers, evt.Name, args);
evt.Info.AddEventHandler(resource, proxyDelegate); evt.EventInfo.AddEventHandler(resource, proxyDelegate);
} }

View File

@ -33,12 +33,14 @@ using System.Threading.Tasks;
namespace Esiur.Resource namespace Esiur.Resource
{ {
public delegate void ResourceEventHanlder(object args); public delegate R DCovariant<out R>();
public delegate void ResourceEventHanlder<in T>(T argument);
// public delegate void CustomUsersEventHanlder(string[] usernames, params object[] args); // public delegate void CustomUsersEventHanlder(string[] usernames, params object[] args);
//public delegate void CustomReceiversEventHanlder(DistributedConnection[] connections, params object[] args); //public delegate void CustomReceiversEventHanlder(DistributedConnection[] connections, params object[] args);
//public delegate void CustomInquirerEventHanlder(object inquirer, params object[] args); //public delegate void CustomInquirerEventHanlder(object inquirer, params object[] args);
public delegate void CustomResourceEventHanlder(object issuer, Func<Session, bool> receivers, object args);// object issuer, Session[] receivers, params object[] args); public delegate void CustomResourceEventHanlder<T>(object issuer, Func<Session, bool> receivers, T argument);// object issuer, Session[] receivers, params object[] args);
// public delegate void CustomReceiversEventHanlder(string[] usernames, DistributedConnection[] connections, params object[] args); // public delegate void CustomReceiversEventHanlder(string[] usernames, DistributedConnection[] connections, params object[] args);

View File

@ -0,0 +1,49 @@
using Esiur.Data;
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace Esiur.Resource.Template
{
public class ArgumentTemplate
{
public string Name { get; set; }
public TemplateDataType Type { get; set; }
public ParameterInfo ParameterInfo { get; set; }
public static (uint, ArgumentTemplate) Parse(byte[] data, uint offset)
{
var cs = (uint)data[offset++];
var name = DC.GetString(data, offset, cs);
offset += cs;
var (size, type) = TemplateDataType.Parse(data, offset);
return (cs + 1 + size, new ArgumentTemplate(name, type));
}
public ArgumentTemplate()
{
}
public ArgumentTemplate(string name, TemplateDataType type)
{
Name = name;
Type = type;
}
public byte[] Compose()
{
var name = DC.ToBytes(Name);
return new BinaryList()
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddUInt8Array(Type.Compose())
.ToArray();
}
}
}

View File

@ -10,7 +10,7 @@ namespace Esiur.Resource.Template
{ {
public class AttributeTemplate : MemberTemplate public class AttributeTemplate : MemberTemplate
{ {
public PropertyInfo Info public PropertyInfo PropertyInfo
{ {
get; get;
set; set;

View File

@ -18,7 +18,9 @@ namespace Esiur.Resource.Template
public bool Listenable { get; set; } public bool Listenable { get; set; }
public EventInfo Info { get; set; } public EventInfo EventInfo { get; set; }
public TemplateDataType ArgumentType { get; set; }
public override byte[] Compose() public override byte[] Compose()
{ {
@ -26,12 +28,12 @@ namespace Esiur.Resource.Template
if (Expansion != null) if (Expansion != null)
{ {
var exp = DC.ToBytes(Expansion); var exp = DC.ToBytes(Expansion);
return new BinaryList() return new BinaryList()
.AddUInt8(Listenable ? (byte) 0x58 : (byte) 0x50) .AddUInt8(Listenable ? (byte) 0x58 : (byte) 0x50)
.AddUInt8((byte)name.Length) .AddUInt8((byte)name.Length)
.AddUInt8Array(name) .AddUInt8Array(name)
.AddUInt8Array(ArgumentType.Compose())
.AddInt32(exp.Length) .AddInt32(exp.Length)
.AddUInt8Array(exp) .AddUInt8Array(exp)
.ToArray(); .ToArray();
@ -41,15 +43,17 @@ namespace Esiur.Resource.Template
.AddUInt8(Listenable ? (byte) 0x48 : (byte) 0x40) .AddUInt8(Listenable ? (byte) 0x48 : (byte) 0x40)
.AddUInt8((byte)name.Length) .AddUInt8((byte)name.Length)
.AddUInt8Array(name) .AddUInt8Array(name)
.AddUInt8Array(ArgumentType.Compose())
.ToArray(); .ToArray();
} }
public EventTemplate(ResourceTemplate template, byte index, string name, string expansion = null, bool listenable=false) public EventTemplate(ResourceTemplate template, byte index, string name, TemplateDataType argumentType, string expansion = null, bool listenable=false)
:base(template, MemberType.Property, index, name) :base(template, MemberType.Property, index, name)
{ {
this.Expansion = expansion; this.Expansion = expansion;
this.Listenable = listenable; this.Listenable = listenable;
this.ArgumentType = argumentType;
} }
} }
} }

View File

@ -2,6 +2,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -16,7 +17,17 @@ namespace Esiur.Resource.Template
set; set;
} }
public bool IsVoid //public bool IsVoid
//{
// get;
// set;
//}
public TemplateDataType ReturnType { get; set; }
public ArgumentTemplate[] Arguments { get; set; }
public MethodInfo MethodInfo
{ {
get; get;
set; set;
@ -25,30 +36,40 @@ namespace Esiur.Resource.Template
public override byte[] Compose() public override byte[] Compose()
{ {
var name = base.Compose(); var name = base.Compose();
var bl = new BinaryList()
//.AddUInt8(Expansion != null ? (byte)0x10 : (byte)0)
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddUInt8Array(ReturnType.Compose())
.AddUInt8((byte)Arguments.Length);
for (var i = 0; i < Arguments.Length; i++)
bl.AddUInt8Array(Arguments[i].Compose());
if (Expansion != null) if (Expansion != null)
{ {
var exp = DC.ToBytes(Expansion); var exp = DC.ToBytes(Expansion);
return new BinaryList().AddUInt8((byte)(0x10 | (IsVoid ? 0x8 : 0x0))) bl.AddInt32(exp.Length)
.AddUInt8((byte)name.Length) .AddUInt8Array(exp);
.AddUInt8Array(name) bl.InsertUInt8(0, 0x10);
.AddInt32(exp.Length)
.AddUInt8Array(exp)
.ToArray();
} }
else else
return new BinaryList().AddUInt8((byte)(IsVoid ? 0x8 : 0x0)) bl.InsertUInt8(0, 0x0);
.AddUInt8((byte)name.Length)
.AddUInt8Array(name) return bl.ToArray();
.ToArray();
} }
public FunctionTemplate(ResourceTemplate template, byte index, string name,bool isVoid, string expansion = null) public FunctionTemplate(ResourceTemplate template, byte index, string name, ArgumentTemplate[] arguments, TemplateDataType returnType, string expansion = null)
:base(template, MemberType.Property, index, name) : base(template, MemberType.Property, index, name)
{ {
this.IsVoid = isVoid; //this.IsVoid = isVoid;
this.Arguments = arguments;
this.ReturnType = returnType;
this.Expansion = expansion; this.Expansion = expansion;
} }
} }

View File

@ -10,7 +10,7 @@ namespace Esiur.Resource.Template
{ {
public class PropertyTemplate : MemberTemplate public class PropertyTemplate : MemberTemplate
{ {
public enum PropertyPermission:byte public enum PropertyPermission : byte
{ {
Read = 1, Read = 1,
Write, Write,
@ -18,12 +18,15 @@ namespace Esiur.Resource.Template
} }
public PropertyInfo Info public PropertyInfo PropertyInfo
{ {
get; get;
set; set;
} }
public TemplateDataType ValueType { get; set; }
/* /*
public bool Serilize public bool Serilize
{ {
@ -32,12 +35,13 @@ namespace Esiur.Resource.Template
*/ */
//bool ReadOnly; //bool ReadOnly;
//IIPTypes::DataType ReturnType; //IIPTypes::DataType ReturnType;
public PropertyPermission Permission { public PropertyPermission Permission
{
get; get;
set; set;
} }
public bool Recordable public bool Recordable
{ {
get; get;
@ -84,6 +88,7 @@ namespace Esiur.Resource.Template
.AddUInt8((byte)(0x38 | pv)) .AddUInt8((byte)(0x38 | pv))
.AddUInt8((byte)name.Length) .AddUInt8((byte)name.Length)
.AddUInt8Array(name) .AddUInt8Array(name)
.AddUInt8Array(ValueType.Compose())
.AddInt32(wexp.Length) .AddInt32(wexp.Length)
.AddUInt8Array(wexp) .AddUInt8Array(wexp)
.AddInt32(rexp.Length) .AddInt32(rexp.Length)
@ -97,6 +102,7 @@ namespace Esiur.Resource.Template
.AddUInt8((byte)(0x30 | pv)) .AddUInt8((byte)(0x30 | pv))
.AddUInt8((byte)name.Length) .AddUInt8((byte)name.Length)
.AddUInt8Array(name) .AddUInt8Array(name)
.AddUInt8Array(ValueType.Compose())
.AddInt32(wexp.Length) .AddInt32(wexp.Length)
.AddUInt8Array(wexp) .AddUInt8Array(wexp)
.ToArray(); .ToArray();
@ -108,25 +114,30 @@ namespace Esiur.Resource.Template
.AddUInt8((byte)(0x28 | pv)) .AddUInt8((byte)(0x28 | pv))
.AddUInt8((byte)name.Length) .AddUInt8((byte)name.Length)
.AddUInt8Array(name) .AddUInt8Array(name)
.AddUInt8Array(ValueType.Compose())
.AddInt32(rexp.Length) .AddInt32(rexp.Length)
.AddUInt8Array(rexp) .AddUInt8Array(rexp)
.ToArray(); .ToArray();
} }
else else
{
return new BinaryList() return new BinaryList()
.AddUInt8((byte)(0x20 | pv)) .AddUInt8((byte)(0x20 | pv))
.AddUInt8((byte)name.Length) .AddUInt8((byte)name.Length)
.AddUInt8Array(name) .AddUInt8Array(name)
.AddUInt8Array(ValueType.Compose())
.ToArray(); .ToArray();
}
} }
public PropertyTemplate(ResourceTemplate template, byte index, string name, string read = null, string write = null, bool recordable = false) public PropertyTemplate(ResourceTemplate template, byte index, string name, TemplateDataType valueType, string read = null, string write = null, bool recordable = false)
:base(template, MemberType.Property, index, name) : base(template, MemberType.Property, index, name)
{ {
this.Recordable = recordable; this.Recordable = recordable;
//this.Storage = storage; //this.Storage = storage;
this.ReadExpansion = read; this.ReadExpansion = read;
this.WriteExpansion = write; this.WriteExpansion = write;
this.ValueType = valueType;
} }
} }
} }

View File

@ -14,6 +14,7 @@ namespace Esiur.Resource.Template
{ {
public class ResourceTemplate public class ResourceTemplate
{ {
Guid classId; Guid classId;
string className; string className;
List<MemberTemplate> members = new List<MemberTemplate>(); List<MemberTemplate> members = new List<MemberTemplate>();
@ -31,6 +32,8 @@ namespace Esiur.Resource.Template
get { return content; } get { return content; }
} }
public Type RuntimeType { get; set; }
public MemberTemplate GetMemberTemplate(MemberInfo member) public MemberTemplate GetMemberTemplate(MemberInfo member)
{ {
if (member is MethodInfo) if (member is MethodInfo)
@ -135,20 +138,137 @@ namespace Esiur.Resource.Template
} }
public static Guid GetTypeGuid(Type type) => GetTypeGuid(type.FullName);
public static Guid GetTypeGuid(string typeName)
{
var tn = Encoding.UTF8.GetBytes(typeName);
var hash = SHA256.Create().ComputeHash(tn).Clip(0, 16);
return new Guid(hash);
}
static Type GetElementType(Type type) => type switch
{
{ IsArray: true } => type.GetElementType(),
{ IsEnum: true } => type.GetEnumUnderlyingType(),
(_) => type
};
public static ResourceTemplate[] GetRuntimeTypes(ResourceTemplate template)
{
var list = new List<ResourceTemplate>();
list.Add(template);
Action<ResourceTemplate, List<ResourceTemplate>> getRuntimeTypes = null;
getRuntimeTypes = (ResourceTemplate tmp, List<ResourceTemplate> bag) =>
{
if (template.RuntimeType == null)
return;
// functions
foreach (var f in tmp.functions)
{
var frtt = Warehouse.GetTemplate(GetElementType(f.MethodInfo.ReturnType));
if (frtt != null)
{
if (!bag.Contains(frtt))
{
list.Add(frtt);
getRuntimeTypes(frtt, bag);
}
}
var args = f.MethodInfo.GetParameters();
for(var i = 0; i < args.Length - 1; i++)
{
var fpt = Warehouse.GetTemplate(GetElementType(args[i].ParameterType));
if (fpt != null)
{
if (!bag.Contains(fpt))
{
bag.Add(fpt);
getRuntimeTypes(fpt, bag);
}
}
}
// skip DistributedConnection argument
if (args.Length > 0)
{
var last = args.Last();
if (last.ParameterType != typeof(DistributedConnection))
{
var fpt = Warehouse.GetTemplate(GetElementType(last.ParameterType));
if (fpt != null)
{
if (!bag.Contains(fpt))
{
bag.Add(fpt);
getRuntimeTypes(fpt, bag);
}
}
}
}
}
// properties
foreach (var p in tmp.properties)
{
var pt = Warehouse.GetTemplate(GetElementType(p.PropertyInfo.PropertyType));
if (pt != null)
{
if (!bag.Contains(pt))
{
bag.Add(pt);
getRuntimeTypes(pt, bag);
}
}
}
// events
foreach (var e in tmp.events)
{
var et = Warehouse.GetTemplate(GetElementType(e.EventInfo.EventHandlerType.GenericTypeArguments[0]));
if (et != null)
{
if (!bag.Contains(et))
{
bag.Add(et);
getRuntimeTypes(et, bag);
}
}
}
};
getRuntimeTypes(template, list);
return list.ToArray();
}
public ResourceTemplate(Type type) public ResourceTemplate(Type type)
{ {
if (!Codec.ImplementsInterface(type, typeof(IResource)))
throw new Exception("Type is not a resource.");
type = ResourceProxy.GetBaseType(type); type = ResourceProxy.GetBaseType(type);
// set guid RuntimeType = type;
var typeName = Encoding.UTF8.GetBytes(type.FullName);
var hash = SHA256.Create().ComputeHash(typeName).Clip(0, 16);
classId = new Guid(hash);
className = type.FullName; className = type.FullName;
//Console.WriteLine($"Creating {className}");
// set guid
classId = GetTypeGuid(className);
#if NETSTANDARD #if NETSTANDARD
PropertyInfo[] propsInfo = type.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly); PropertyInfo[] propsInfo = type.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly);
EventInfo[] eventsInfo = type.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly); EventInfo[] eventsInfo = type.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly);
@ -175,8 +295,9 @@ namespace Esiur.Resource.Template
{ {
var annotationAttr = pi.GetCustomAttribute<AnnotationAttribute>(true); var annotationAttr = pi.GetCustomAttribute<AnnotationAttribute>(true);
var storageAttr = pi.GetCustomAttribute<StorageAttribute>(true); var storageAttr = pi.GetCustomAttribute<StorageAttribute>(true);
var pt = new PropertyTemplate(this, i++, pi.Name, TemplateDataType.FromType(pi.PropertyType));
var pt = new PropertyTemplate(this, i++, pi.Name);
if (storageAttr != null) if (storageAttr != null)
pt.Recordable = storageAttr.Mode == StorageMode.Recordable; pt.Recordable = storageAttr.Mode == StorageMode.Recordable;
@ -185,7 +306,7 @@ namespace Esiur.Resource.Template
else else
pt.ReadExpansion = pi.PropertyType.Name; pt.ReadExpansion = pi.PropertyType.Name;
pt.Info = pi; pt.PropertyInfo = pi;
//pt.Serilize = publicAttr.Serialize; //pt.Serilize = publicAttr.Serialize;
properties.Add(pt); properties.Add(pt);
} }
@ -195,7 +316,7 @@ namespace Esiur.Resource.Template
if (attributeAttr != null) if (attributeAttr != null)
{ {
var at = new AttributeTemplate(this, 0, pi.Name); var at = new AttributeTemplate(this, 0, pi.Name);
at.Info = pi; at.PropertyInfo = pi;
attributes.Add(at); attributes.Add(at);
} }
} }
@ -211,8 +332,9 @@ namespace Esiur.Resource.Template
var annotationAttr = ei.GetCustomAttribute<AnnotationAttribute>(true); var annotationAttr = ei.GetCustomAttribute<AnnotationAttribute>(true);
var listenableAttr = ei.GetCustomAttribute<ListenableAttribute>(true); var listenableAttr = ei.GetCustomAttribute<ListenableAttribute>(true);
var et = new EventTemplate(this, i++, ei.Name); var argType = ei.EventHandlerType.GenericTypeArguments[0];
et.Info = ei; var et = new EventTemplate(this, i++, ei.Name, TemplateDataType.FromType(argType));
et.EventInfo = ei;
if (annotationAttr != null) if (annotationAttr != null)
et.Expansion = annotationAttr.Annotation; et.Expansion = annotationAttr.Annotation;
@ -232,12 +354,32 @@ namespace Esiur.Resource.Template
{ {
var annotationAttr = mi.GetCustomAttribute<AnnotationAttribute>(true); var annotationAttr = mi.GetCustomAttribute<AnnotationAttribute>(true);
var ft = new FunctionTemplate(this, i++, mi.Name, mi.ReturnType == typeof(void)); var returnType = TemplateDataType.FromType(mi.ReturnType);
var args = mi.GetParameters();
if (args.Length > 0)
{
if (args.Last().ParameterType == typeof(DistributedConnection))
args = args.Take(args.Count() - 1).ToArray();
}
var arguments = args.Select(x => new ArgumentTemplate()
{
Name = x.Name,
Type = TemplateDataType.FromType(x.ParameterType),
ParameterInfo = x
})
.ToArray();
var ft = new FunctionTemplate(this, i++, mi.Name, arguments, returnType);// mi.ReturnType == typeof(void));
if (annotationAttr != null) if (annotationAttr != null)
ft.Expansion = annotationAttr.Annotation; ft.Expansion = annotationAttr.Annotation;
else else
ft.Expansion = "(" + String.Join(",", mi.GetParameters().Where(x => x.ParameterType != typeof(DistributedConnection)).Select(x => "[" + x.ParameterType.Name + "] " + x.Name)) + ") -> " + mi.ReturnType.Name; ft.Expansion = "(" + String.Join(",", mi.GetParameters().Where(x => x.ParameterType != typeof(DistributedConnection)).Select(x => "[" + x.ParameterType.Name + "] " + x.Name)) + ") -> " + mi.ReturnType.Name;
ft.MethodInfo = mi;
functions.Add(ft); functions.Add(ft);
} }
} }
@ -253,8 +395,9 @@ namespace Esiur.Resource.Template
{ {
var annotationAttr = pi.GetCustomAttribute<AnnotationAttribute>(true); var annotationAttr = pi.GetCustomAttribute<AnnotationAttribute>(true);
var storageAttr = pi.GetCustomAttribute<StorageAttribute>(true); var storageAttr = pi.GetCustomAttribute<StorageAttribute>(true);
var valueType = TemplateDataType.FromType(pi.PropertyType);
var pt = new PropertyTemplate(this, i++, pi.Name);//, rp.ReadExpansion, rp.WriteExpansion, rp.Storage); var pt = new PropertyTemplate(this, i++, pi.Name, valueType);//, rp.ReadExpansion, rp.WriteExpansion, rp.Storage);
if (storageAttr != null) if (storageAttr != null)
pt.Recordable = storageAttr.Mode == StorageMode.Recordable; pt.Recordable = storageAttr.Mode == StorageMode.Recordable;
@ -263,7 +406,7 @@ namespace Esiur.Resource.Template
else else
pt.ReadExpansion = pi.PropertyType.Name; pt.ReadExpansion = pi.PropertyType.Name;
pt.Info = pi; pt.PropertyInfo = pi;
//pt.Serilize = publicAttr.Serialize; //pt.Serilize = publicAttr.Serialize;
properties.Add(pt); properties.Add(pt);
} }
@ -273,7 +416,7 @@ namespace Esiur.Resource.Template
if (attributeAttr != null) if (attributeAttr != null)
{ {
var at = new AttributeTemplate(this, 0, pi.Name); var at = new AttributeTemplate(this, 0, pi.Name);
at.Info = pi; at.PropertyInfo = pi;
attributes.Add(at); attributes.Add(at);
} }
} }
@ -289,8 +432,10 @@ namespace Esiur.Resource.Template
var annotationAttr = ei.GetCustomAttribute<AnnotationAttribute>(true); var annotationAttr = ei.GetCustomAttribute<AnnotationAttribute>(true);
var listenableAttr = ei.GetCustomAttribute<ListenableAttribute>(true); var listenableAttr = ei.GetCustomAttribute<ListenableAttribute>(true);
var et = new EventTemplate(this, i++, ei.Name); var argType = ei.EventHandlerType.GenericTypeArguments[0];
et.Info = ei;
var et = new EventTemplate(this, i++, ei.Name, TemplateDataType.FromType(argType));
et.EventInfo = ei;
if (annotationAttr != null) if (annotationAttr != null)
et.Expansion = annotationAttr.Annotation; et.Expansion = annotationAttr.Annotation;
@ -309,13 +454,32 @@ namespace Esiur.Resource.Template
if (publicAttr != null) if (publicAttr != null)
{ {
var annotationAttr = mi.GetCustomAttribute<AnnotationAttribute>(true); var annotationAttr = mi.GetCustomAttribute<AnnotationAttribute>(true);
var returnType = TemplateDataType.FromType(mi.ReturnType);
var ft = new FunctionTemplate(this, i++, mi.Name, mi.ReturnType == typeof(void)); var args = mi.GetParameters();
if (args.Length > 0)
{
if (args.Last().ParameterType == typeof(DistributedConnection))
args = args.Take(args.Count() - 1).ToArray();
}
var arguments = args.Select(x => new ArgumentTemplate()
{
Name = x.Name,
Type = TemplateDataType.FromType(x.ParameterType),
ParameterInfo = x
})
.ToArray();
var ft = new FunctionTemplate(this, i++, mi.Name, arguments, returnType);// mi.ReturnType == typeof(void));
if (annotationAttr != null) if (annotationAttr != null)
ft.Expansion = annotationAttr.Annotation; ft.Expansion = annotationAttr.Annotation;
else else
ft.Expansion = "(" + String.Join(",", mi.GetParameters().Where(x=>x.ParameterType != typeof(DistributedConnection)).Select(x=> "[" + x.ParameterType.Name + "] " + x.Name)) + ") -> " + mi.ReturnType.Name; ft.Expansion = "(" + String.Join(",", mi.GetParameters().Where(x=>x.ParameterType != typeof(DistributedConnection)).Select(x=> "[" + x.ParameterType.Name + "] " + x.Name)) + ") -> " + mi.ReturnType.Name;
ft.MethodInfo = mi;
functions.Add(ft); functions.Add(ft);
} }
} }
@ -391,11 +555,27 @@ namespace Esiur.Resource.Template
if (type == 0) // function if (type == 0) // function
{ {
string expansion = null; string expansion = null;
var hasExpansion = ((data[offset] & 0x10) == 0x10); var hasExpansion = ((data[offset++] & 0x10) == 0x10);
var isVoid = ((data[offset++] & 0x08) == 0x08);
var name = data.GetString(offset + 1, data[offset]); var name = data.GetString(offset + 1, data[offset]);
offset += (uint)data[offset] + 1; offset += (uint)data[offset] + 1;
// return type
var (rts, returnType) = TemplateDataType.Parse(data, offset);
offset += rts;
// arguments count
var argsCount = data[offset++];
List<ArgumentTemplate> arguments = new();
for (var a = 0; a < argsCount; a++)
{
var (cs, argType) = ArgumentTemplate.Parse(data, offset);
arguments.Add(argType);
offset += cs;
}
// arguments
if (hasExpansion) // expansion ? if (hasExpansion) // expansion ?
{ {
var cs = data.GetUInt32(offset); var cs = data.GetUInt32(offset);
@ -404,7 +584,7 @@ namespace Esiur.Resource.Template
offset += cs; offset += cs;
} }
var ft = new FunctionTemplate(od, functionIndex++, name, isVoid, expansion); var ft = new FunctionTemplate(od, functionIndex++, name, arguments.ToArray(), returnType, expansion);
od.functions.Add(ft); od.functions.Add(ft);
} }
@ -421,6 +601,10 @@ namespace Esiur.Resource.Template
offset += (uint)data[offset] + 1; offset += (uint)data[offset] + 1;
var (dts, valueType) = TemplateDataType.Parse(data, offset);
offset += dts;
if (hasReadExpansion) // expansion ? if (hasReadExpansion) // expansion ?
{ {
var cs = data.GetUInt32(offset); var cs = data.GetUInt32(offset);
@ -437,7 +621,7 @@ namespace Esiur.Resource.Template
offset += cs; offset += cs;
} }
var pt = new PropertyTemplate(od, propertyIndex++, name, readExpansion, writeExpansion, recordable); var pt = new PropertyTemplate(od, propertyIndex++, name, valueType, readExpansion, writeExpansion, recordable);
od.properties.Add(pt); od.properties.Add(pt);
} }
@ -451,6 +635,10 @@ namespace Esiur.Resource.Template
var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, (int)data[offset]); var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, (int)data[offset]);
offset += (uint)data[offset] + 1; offset += (uint)data[offset] + 1;
var (dts, argType) = TemplateDataType.Parse(data, offset);
offset += dts;
if (hasExpansion) // expansion ? if (hasExpansion) // expansion ?
{ {
var cs = data.GetUInt32(offset); var cs = data.GetUInt32(offset);
@ -459,7 +647,7 @@ namespace Esiur.Resource.Template
offset += cs; offset += cs;
} }
var et = new EventTemplate(od, eventIndex++, name, expansion, listenable); var et = new EventTemplate(od, eventIndex++, name, argType, expansion, listenable);
od.events.Add(et); od.events.Add(et);

View File

@ -0,0 +1,118 @@
using Esiur.Data;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Text;
namespace Esiur.Resource.Template
{
public struct TemplateDataType
{
public DataType Type { get; set; }
//public string TypeName { get; set; }
public ResourceTemplate TypeTemplate => TypeGuid == null ? null : Warehouse.GetTemplate((Guid)TypeGuid);
public Guid? TypeGuid { get; set; }
//public TemplateDataType(DataType type, string typeName)
//{
// Type = type;
// TypeName = typeName;
//}
public static TemplateDataType FromType(Type type)
{
var t = type switch
{
{ IsArray: true } => type.GetElementType(),
{ IsEnum: true } => type.GetEnumUnderlyingType(),
(_) => type
};
DataType dt = t switch
{
_ when t == typeof(bool) => DataType.Bool,
_ when t == typeof(char) => DataType.Char,
_ when t == typeof(byte) => DataType.UInt8,
_ when t == typeof(sbyte) => DataType.Int8,
_ when t == typeof(short) => DataType.Int16,
_ when t == typeof(ushort) => DataType.UInt16,
_ when t == typeof(int) => DataType.Int32,
_ when t == typeof(uint) => DataType.UInt32,
_ when t == typeof(long) => DataType.Int64,
_ when t == typeof(ulong) => DataType.UInt64,
_ when t == typeof(float) => DataType.Float32,
_ when t == typeof(double) => DataType.Float64,
_ when t == typeof(decimal) => DataType.Decimal,
_ when t == typeof(string) => DataType.String,
_ when t == typeof(DateTime) => DataType.DateTime,
_ when t == typeof(IResource) => DataType.Void, // Dynamic resource (unspecified type)
_ when typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject) => DataType.Structure,
_ when Codec.ImplementsInterface(t, typeof(IResource)) => DataType.Resource,
_ => DataType.Void
};
//string tn = dt switch
//{
// DataType.Resource => t.FullName,
// DataType.Structure when t != typeof(Structure) => t.FullName,
// _ => null
//};
Guid? typeGuid = null;
if (dt == DataType.Resource)
typeGuid = ResourceTemplate.GetTypeGuid(t);
if (type.IsArray)
dt = (DataType)((byte)dt | 0x80);
return new TemplateDataType()
{
Type = dt,
TypeGuid = typeGuid
};
}
public byte[] Compose()
{
if (Type == DataType.Resource ||
Type == DataType.ResourceArray)//||
//Type == DataType.DistributedResource ||
//Type == DataType.DistributedResourceArray ||
//Type == DataType.Structure ||
//Type == DataType.StructureArray)
{
var guid = DC.ToBytes((Guid)TypeGuid);
return new BinaryList()
.AddUInt8((byte)Type)
.AddUInt8Array(guid).ToArray();
}
else
return new byte[] { (byte)Type };
}
public override string ToString() => Type.ToString() + TypeTemplate != null ? "<" + TypeTemplate.ClassName + ">" : "";
public static (uint, TemplateDataType) Parse(byte[] data, uint offset)
{
var type = (DataType)data[offset++];
if (type == DataType.Resource ||
type == DataType.ResourceArray)//||
// type == DataType.DistributedResource ||
// type == DataType.DistributedResourceArray)// ||
// type == DataType.Structure ||
// type == DataType.StructureArray)
{
var guid = DC.GetGuid(data, offset);
return (17, new TemplateDataType() { Type = type, TypeGuid = guid });
}
else
return (1, new TemplateDataType() { Type = type });
}
}
}

View File

@ -113,6 +113,22 @@ namespace Esiur.Resource
return new AsyncReply<IResource>(null); return new AsyncReply<IResource>(null);
} }
static void LoadGenerated()
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
var generatedType = assembly.GetType("Esiur.Generated");
if (generatedType != null)
{
var types = (Type[])generatedType.GetProperty("Types").GetValue(null);
foreach (var t in types)
{
PutTemplate(new ResourceTemplate(t));
}
}
}
}
/// <summary> /// <summary>
/// Open the warehouse. /// Open the warehouse.
/// This function issues the initialize trigger to all stores and resources. /// This function issues the initialize trigger to all stores and resources.
@ -123,6 +139,10 @@ namespace Esiur.Resource
if (warehouseIsOpen) if (warehouseIsOpen)
return false; return false;
// Load generated models
LoadGenerated();
warehouseIsOpen = true; warehouseIsOpen = true;
var resSnap = resources.Select(x => var resSnap = resources.Select(x =>
@ -380,7 +400,8 @@ namespace Esiur.Resource
/// </summary> /// </summary>
/// <param name="path"></param> /// <param name="path"></param>
/// <returns>Resource instance.</returns> /// <returns>Resource instance.</returns>
public static async AsyncReply<IResource> Get(string path, object attributes = null, IResource parent = null, IPermissionsManager manager = null) public static async AsyncReply<T> Get<T>(string path, object attributes = null, IResource parent = null, IPermissionsManager manager = null)
where T: IResource
{ {
//var rt = new AsyncReply<IResource>(); //var rt = new AsyncReply<IResource>();
@ -404,9 +425,9 @@ namespace Esiur.Resource
//await Put(store, url[2], null, parent, null, 0, manager, attributes); //await Put(store, url[2], null, parent, null, 0, manager, attributes);
if (url[3].Length > 0 && url[3] != "") if (url[3].Length > 0 && url[3] != "")
return await store.Get(url[3]); return (T)await store.Get(url[3]);
else else
return store; return (T)store;
} }
catch (Exception ex) catch (Exception ex)
@ -471,9 +492,9 @@ namespace Esiur.Resource
var res = await Query(path); var res = await Query(path);
if (res.Length == 0) if (res.Length == 0)
return null; return default(T);
else else
return res.First(); return (T)res.First();
} }
@ -503,7 +524,7 @@ namespace Esiur.Resource
if (parent != null) if (parent != null)
throw new Exception("Parent can't be set when using path in instance name"); throw new Exception("Parent can't be set when using path in instance name");
parent = await Warehouse.Get(string.Join("/", path.Take(path.Length - 1))); parent = await Warehouse.Get<IResource>(string.Join("/", path.Take(path.Length - 1)));
if (parent == null) if (parent == null)
throw new Exception("Can't find parent"); throw new Exception("Can't find parent");
@ -518,27 +539,28 @@ namespace Esiur.Resource
if (store == null) if (store == null)
{ {
// assign parent as a store
if (parent is IStore)
{
store = (IStore)parent;
List<WeakReference<IResource>> list;
if (stores.TryGetValue(store, out list))
lock (((ICollection)list).SyncRoot)
list.Add(resourceReference);
//stores[store].Add(resourceReference);
}
// assign parent's store as a store // assign parent's store as a store
else if (parent != null) if (parent != null)
{ {
store = parent.Instance.Store; // assign parent as a store
if (parent is IStore)
{
store = (IStore)parent;
List<WeakReference<IResource>> list;
if (stores.TryGetValue(store, out list))
lock (((ICollection)list).SyncRoot)
list.Add(resourceReference);
//stores[store].Add(resourceReference);
}
else
{
store = parent.Instance.Store;
List<WeakReference<IResource>> list; List<WeakReference<IResource>> list;
if (stores.TryGetValue(store, out list)) if (stores.TryGetValue(store, out list))
lock (((ICollection)list).SyncRoot) lock (((ICollection)list).SyncRoot)
list.Add(resourceReference); list.Add(resourceReference);
}
//stores[store].Add(resourceReference);
} }
// assign self as a store (root store) // assign self as a store (root store)
else if (resource is IStore) else if (resource is IStore)
@ -722,9 +744,16 @@ namespace Esiur.Resource
/// <returns>Resource template.</returns> /// <returns>Resource template.</returns>
public static ResourceTemplate GetTemplate(Type type) public static ResourceTemplate GetTemplate(Type type)
{ {
if (!Codec.ImplementsInterface(type, typeof(IResource)))
return null;
var baseType = ResourceProxy.GetBaseType(type); var baseType = ResourceProxy.GetBaseType(type);
if (baseType == typeof(IResource) )
return null;
// loaded ? // loaded ?
foreach (var t in templates.Values) foreach (var t in templates.Values)
if (t.ClassName == baseType.FullName) if (t.ClassName == baseType.FullName)
@ -741,10 +770,10 @@ namespace Esiur.Resource
/// </summary> /// </summary>
/// <param name="classId">Class Id.</param> /// <param name="classId">Class Id.</param>
/// <returns>Resource template.</returns> /// <returns>Resource template.</returns>
public static AsyncReply<ResourceTemplate> GetTemplate(Guid classId) public static ResourceTemplate GetTemplate(Guid classId)
{ {
if (templates.ContainsKey(classId)) if (templates.ContainsKey(classId))
return new AsyncReply<ResourceTemplate>(templates[classId]); return templates[classId];
return null; return null;
} }

View File

@ -42,7 +42,7 @@ namespace Esiur.Security.Membership
AsyncReply<byte[]> GetToken(ulong tokenIndex, string domain); AsyncReply<byte[]> GetToken(ulong tokenIndex, string domain);
AsyncReply<bool> Login(Session session); AsyncReply<bool> Login(Session session);
AsyncReply<bool> Logout(Session session); AsyncReply<bool> Logout(Session session);
bool GuestsAllowed { get; }
AsyncReply<string> TokenExists(ulong tokenIndex, string domain); AsyncReply<string> TokenExists(ulong tokenIndex, string domain);
} }
} }

View File

@ -45,6 +45,7 @@ namespace Esiur.Security.Permissions
AddChild, AddChild,
RemoveChild, RemoveChild,
Rename, Rename,
ReceiveEvent ReceiveEvent,
ViewTemplate
} }
} }