mirror of
				https://github.com/esiur/esiur-dotnet.git
				synced 2025-10-30 07:31:35 +00:00 
			
		
		
		
	Added Records
This commit is contained in:
		| @@ -9,7 +9,7 @@ | |||||||
|     <Product>Esiur Entity Framework Extension</Product> |     <Product>Esiur Entity Framework Extension</Product> | ||||||
|     <GeneratePackageOnBuild>true</GeneratePackageOnBuild> |     <GeneratePackageOnBuild>true</GeneratePackageOnBuild> | ||||||
|     <PackageId>Esiur.Stores.EntityCore</PackageId> |     <PackageId>Esiur.Stores.EntityCore</PackageId> | ||||||
|     <Version>1.1.0</Version> |     <Version>1.2.1</Version> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|  |  | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|   | |||||||
| @@ -37,6 +37,7 @@ using Microsoft.EntityFrameworkCore.Metadata.Builders; | |||||||
| using Microsoft.EntityFrameworkCore.Metadata.Conventions; | using Microsoft.EntityFrameworkCore.Metadata.Conventions; | ||||||
| using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; | using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; | ||||||
| using Microsoft.EntityFrameworkCore.Metadata.Internal; | using Microsoft.EntityFrameworkCore.Metadata.Internal; | ||||||
|  | using Esiur.Data; | ||||||
|  |  | ||||||
| namespace Esiur.Stores.EntityCore | namespace Esiur.Stores.EntityCore | ||||||
| { | { | ||||||
| @@ -57,6 +58,7 @@ namespace Esiur.Stores.EntityCore | |||||||
|         public static object CreateInstance( |         public static object CreateInstance( | ||||||
|                                             IDbContextOptions dbContextOptions, |                                             IDbContextOptions dbContextOptions, | ||||||
|                                             IEntityType entityType, |                                             IEntityType entityType, | ||||||
|  |                                             //object id | ||||||
|                                             object[] properties |                                             object[] properties | ||||||
|  |  | ||||||
|         // ILazyLoader loader, |         // ILazyLoader loader, | ||||||
| @@ -64,7 +66,6 @@ namespace Esiur.Stores.EntityCore | |||||||
|         //DbContext context, |         //DbContext context, | ||||||
|         ) |         ) | ||||||
|         { |         { | ||||||
|             ///var id = constructorArguments.Last(); |  | ||||||
|             var id = properties.First(); |             var id = properties.First(); | ||||||
|  |  | ||||||
|             var options = dbContextOptions.FindExtension<EsiurExtensionOptions>(); |             var options = dbContextOptions.FindExtension<EsiurExtensionOptions>(); | ||||||
| @@ -75,15 +76,23 @@ namespace Esiur.Stores.EntityCore | |||||||
|             if (cache != null) |             if (cache != null) | ||||||
|                 return cache; |                 return cache; | ||||||
|  |  | ||||||
|             // check if the object exists |             if (Codec.ImplementsInterface(entityType.ClrType, typeof(IResource))) | ||||||
|             var obj = Warehouse.New(entityType.ClrType).Wait() as IResource;//, "", options.Store, null, manager); |             { | ||||||
|             //obj._PrimaryId = id; |                 // check if the object exists | ||||||
|             options.Store.TypesByType[entityType.ClrType].PrimaryKey.SetValue(obj, id); |                 var obj = Warehouse.New(entityType.ClrType).Wait() as IResource; | ||||||
|             Warehouse.Put(id.ToString(), obj, options.Store, null, null, 0, manager).Wait(); |                 options.Store.TypesByType[entityType.ClrType].PrimaryKey.SetValue(obj, id); | ||||||
|  |                 Warehouse.Put(id.ToString(), obj, options.Store, null, null, 0, manager).Wait(); | ||||||
|  |                 return obj; | ||||||
|  |  | ||||||
|             //            obj.Instance.IntVal = id;//.Variables.Add("eid", id); |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 // record | ||||||
|  |                 var obj = Activator.CreateInstance(entityType.ClrType); | ||||||
|  |                 options.Store.TypesByType[entityType.ClrType].PrimaryKey.SetValue(obj, id); | ||||||
|  |  | ||||||
|             return obj; |                 return obj; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -98,6 +107,10 @@ namespace Esiur.Stores.EntityCore | |||||||
|         { |         { | ||||||
|             foreach (var entityType in modelBuilder.Metadata.GetEntityTypes()) |             foreach (var entityType in modelBuilder.Metadata.GetEntityTypes()) | ||||||
|             { |             { | ||||||
|  |  | ||||||
|  |                 if (!Codec.ImplementsInterface(entityType.ClrType, typeof(IResource))) | ||||||
|  |                     continue; | ||||||
|  |  | ||||||
|                 var proxyType = ResourceProxy.GetProxy(entityType.ClrType); |                 var proxyType = ResourceProxy.GetProxy(entityType.ClrType); | ||||||
|  |  | ||||||
|                 // var ann = entityType.GetAnnotation(CoreAnnotationNames.ConstructorBinding); |                 // var ann = entityType.GetAnnotation(CoreAnnotationNames.ConstructorBinding); | ||||||
| @@ -114,8 +127,14 @@ namespace Esiur.Stores.EntityCore | |||||||
|  |  | ||||||
|  |  | ||||||
|                 try |                 try | ||||||
|  |  | ||||||
|                 { |                 { | ||||||
|  |  | ||||||
|  |                     var key = entityType.FindPrimaryKey().Properties.First(); | ||||||
|  |                     if (key == null) | ||||||
|  |                         continue; | ||||||
|  |  | ||||||
|  |                     //var keys = entityType.FindPrimaryKey().Properties.Select(x=>new PropertyParameterBinding(x)); | ||||||
|  |  | ||||||
|                     entityType.SetAnnotation( |                     entityType.SetAnnotation( | ||||||
| #pragma warning disable EF1001 // Internal EF Core API usage. | #pragma warning disable EF1001 // Internal EF Core API usage. | ||||||
|                         CoreAnnotationNames.ConstructorBinding, |                         CoreAnnotationNames.ConstructorBinding, | ||||||
| @@ -126,12 +145,14 @@ namespace Esiur.Stores.EntityCore | |||||||
|                                 { |                                 { | ||||||
|                                 new DependencyInjectionParameterBinding(typeof(IDbContextOptions), typeof(IDbContextOptions)), |                                 new DependencyInjectionParameterBinding(typeof(IDbContextOptions), typeof(IDbContextOptions)), | ||||||
|                                 new EntityTypeParameterBinding(), |                                 new EntityTypeParameterBinding(), | ||||||
|  |                                 //new PropertyParameterBinding(key) | ||||||
|                                 // constructor arguments  |                                 // constructor arguments  | ||||||
|                                 //new ObjectArrayParameterBinding(binding.ParameterBindings), |                                 //new ObjectArrayParameterBinding(binding.ParameterBindings), | ||||||
|                                  //new ContextParameterBinding(typeof(DbContext)), |                                  //new ContextParameterBinding(typeof(DbContext)), | ||||||
|  |                                  //new ObjectArrayParameterBinding(entityType.FindPrimaryKey().Properties.Select(x=>new PropertyParameterBinding(x)).ToArray()) | ||||||
|                                  new ObjectArrayParameterBinding(new ParameterBinding[]{ |                                  new ObjectArrayParameterBinding(new ParameterBinding[]{ | ||||||
|                                             new PropertyParameterBinding(entityType.FindPrimaryKey().Properties.FirstOrDefault()) |                                             new PropertyParameterBinding(key) }) | ||||||
|                                  }) |                                  //}) | ||||||
|                                 // new Microsoft.EntityFrameworkCore.Metadata.ObjectArrayParameterBinding(), |                                 // new Microsoft.EntityFrameworkCore.Metadata.ObjectArrayParameterBinding(), | ||||||
|                                  //new ObjectArrayParameterBinding()  |                                  //new ObjectArrayParameterBinding()  | ||||||
|  |  | ||||||
| @@ -141,6 +162,7 @@ namespace Esiur.Stores.EntityCore | |||||||
|                 } |                 } | ||||||
|                 catch |                 catch | ||||||
|                 { |                 { | ||||||
|  |  | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -81,6 +81,29 @@ namespace Esiur.Data | |||||||
|             return types; |             return types; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         /// <summary> | ||||||
|  |         /// Compare two records | ||||||
|  |         /// </summary> | ||||||
|  |         /// <param name="initial">Initial record to compare with</param> | ||||||
|  |         /// <param name="next">Next record to compare with the initial</param> | ||||||
|  |         /// <param name="connection">DistributedConnection is required in case a structure holds items at the other end</param> | ||||||
|  |         public static RecordComparisonResult Compare(IRecord initial, IRecord next) | ||||||
|  |         { | ||||||
|  |             if (next == null) | ||||||
|  |                 return RecordComparisonResult.Null; | ||||||
|  |  | ||||||
|  |             if (initial == null) | ||||||
|  |                 return RecordComparisonResult.Record; | ||||||
|  |  | ||||||
|  |             if (next == initial) | ||||||
|  |                 return RecordComparisonResult.Same; | ||||||
|  |  | ||||||
|  |             if (next.GetType() == initial.GetType()) | ||||||
|  |                 return RecordComparisonResult.RecordSameType; | ||||||
|  |  | ||||||
|  |             return RecordComparisonResult.Record; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// Compare two structures |         /// Compare two structures | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @@ -231,6 +254,184 @@ namespace Esiur.Data | |||||||
|             return reply; |             return reply; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         public static AsyncBag<IRecord> ParseRecordArray(byte[] data, uint offset, uint length, DistributedConnection connection) | ||||||
|  |         { | ||||||
|  |  | ||||||
|  |             var reply = new AsyncBag<IRecord>(); | ||||||
|  |             if (length == 0) | ||||||
|  |             { | ||||||
|  |                 reply.Seal(); | ||||||
|  |                 return reply; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             var end = offset + length; | ||||||
|  |  | ||||||
|  |             var result = (RecordComparisonResult)data[offset++]; | ||||||
|  |  | ||||||
|  |             AsyncReply<IRecord> previous = null; | ||||||
|  |             Guid? classId = null; | ||||||
|  |  | ||||||
|  |             if (result == RecordComparisonResult.Null) | ||||||
|  |                 previous = new AsyncReply<IRecord>(null); | ||||||
|  |             else if (result == RecordComparisonResult.Record) | ||||||
|  |             { | ||||||
|  |                 uint cs = data.GetUInt32(offset); | ||||||
|  |                 uint recordLength = cs - 16; | ||||||
|  |                 offset += 4; | ||||||
|  |                 classId = data.GetGuid(offset); | ||||||
|  |                 offset += 16; | ||||||
|  |                 previous = ParseRecord(data, offset, recordLength, connection, classId); | ||||||
|  |                 offset += recordLength; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             reply.Add(previous); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |             while (offset < end) | ||||||
|  |             { | ||||||
|  |                 result = (RecordComparisonResult)data[offset++]; | ||||||
|  |  | ||||||
|  |                 if (result == RecordComparisonResult.Null) | ||||||
|  |                     previous = new AsyncReply<IRecord>(null); | ||||||
|  |                 else if (result == RecordComparisonResult.Record) | ||||||
|  |                 { | ||||||
|  |                     uint cs = data.GetUInt32(offset); | ||||||
|  |                     uint recordLength = cs - 16; | ||||||
|  |                     offset += 4; | ||||||
|  |                     classId = data.GetGuid(offset); | ||||||
|  |                     offset += 16; | ||||||
|  |                     previous = ParseRecord(data, offset, recordLength, connection, classId);  | ||||||
|  |                     offset += recordLength; | ||||||
|  |                 } | ||||||
|  |                 else if (result == RecordComparisonResult.RecordSameType) | ||||||
|  |                 { | ||||||
|  |                     uint cs = data.GetUInt32(offset); | ||||||
|  |                     offset += 4; | ||||||
|  |                     previous = ParseRecord(data, offset, cs, connection, classId); | ||||||
|  |                     offset += cs; | ||||||
|  |                 } | ||||||
|  |                 else if (result == RecordComparisonResult.Same) | ||||||
|  |                 { | ||||||
|  |                     // do nothing | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 reply.Add(previous); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             reply.Seal(); | ||||||
|  |             return reply; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static AsyncReply<IRecord> ParseRecord(byte[] data, uint offset, uint length, DistributedConnection connection, Guid? classId = null) | ||||||
|  |         { | ||||||
|  |             var reply = new AsyncReply<IRecord>(); | ||||||
|  |  | ||||||
|  |             if (classId == null) | ||||||
|  |             { | ||||||
|  |                 classId = data.GetGuid(offset); | ||||||
|  |  | ||||||
|  |                 offset += 16; | ||||||
|  |                 length -= 16; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             var template = Warehouse.GetTemplateByClassId((Guid)classId); | ||||||
|  |  | ||||||
|  |             if (template != null) | ||||||
|  |             { | ||||||
|  |                 ParseVarArray(data, offset, length, connection).Then(ar => | ||||||
|  |                 { | ||||||
|  |                     if (template.ResourceType != null) | ||||||
|  |                     { | ||||||
|  |                         var record = Activator.CreateInstance(template.ResourceType) as IRecord; | ||||||
|  |                         for (var i = 0; i < template.Properties.Length; i++) | ||||||
|  |                            template.Properties[i].PropertyInfo.SetValue(record, ar[i]); | ||||||
|  |  | ||||||
|  |                         reply.Trigger(record); | ||||||
|  |                     } | ||||||
|  |                     else | ||||||
|  |                     { | ||||||
|  |                         var record = new Record(); | ||||||
|  |  | ||||||
|  |                         for (var i = 0; i < template.Properties.Length; i++) | ||||||
|  |                             record.Add(template.Properties[i].Name, ar[i]); | ||||||
|  |  | ||||||
|  |                         reply.Trigger(record); | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 connection.GetTemplate((Guid)classId).Then(tmp => { | ||||||
|  |                     ParseVarArray(data, offset, length, connection).Then(ar => | ||||||
|  |                     { | ||||||
|  |                         var record = new Record(); | ||||||
|  |  | ||||||
|  |                         for (var i = 0; i < tmp.Properties.Length; i++) | ||||||
|  |                             record.Add(tmp.Properties[i].Name, ar[i]); | ||||||
|  |  | ||||||
|  |                         reply.Trigger(record); | ||||||
|  |                     }); | ||||||
|  |                 }).Error(x=>reply.TriggerError(x)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return reply; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static byte[] ComposeRecord(IRecord record, DistributedConnection connection, bool includeClassId = true, bool prependLength = false) | ||||||
|  |         { | ||||||
|  |             var rt = new BinaryList(); | ||||||
|  |  | ||||||
|  |             var template = Warehouse.GetTemplateByType(record.GetType()); | ||||||
|  |  | ||||||
|  |             if (includeClassId) | ||||||
|  |                 rt.AddGuid(template.ClassId); | ||||||
|  |  | ||||||
|  |             foreach (var pt in template.Properties) | ||||||
|  |             { | ||||||
|  |                 var value = pt.PropertyInfo.GetValue(record, null); | ||||||
|  |                 rt.AddUInt8Array(Compose(value, connection)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (prependLength) | ||||||
|  |                 rt.InsertInt32(0, rt.Length); | ||||||
|  |  | ||||||
|  |             return rt.ToArray(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static byte[] ComposeRecordArray(IRecord[] records, DistributedConnection connection, bool prependLength = false) | ||||||
|  |         { | ||||||
|  |              | ||||||
|  |             if (records == null || records?.Length == 0) | ||||||
|  |                 return prependLength ? new byte[] { 0, 0, 0, 0 } : new byte[0]; | ||||||
|  |  | ||||||
|  |             var rt = new BinaryList(); | ||||||
|  |             var comparsion = Compare(null, records[0]); | ||||||
|  |  | ||||||
|  |             rt.AddUInt8((byte)comparsion); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |             if (comparsion == RecordComparisonResult.Record) | ||||||
|  |                 rt.AddUInt8Array(ComposeRecord(records[0], connection, true, true)); | ||||||
|  |  | ||||||
|  |             for (var i = 1; i < records.Length; i++) | ||||||
|  |             { | ||||||
|  |                 comparsion = Compare(records[i - 1], records[i]); | ||||||
|  |                 rt.AddUInt8((byte)comparsion); | ||||||
|  |  | ||||||
|  |                 if (comparsion == RecordComparisonResult.Record) | ||||||
|  |                     rt.AddUInt8Array(ComposeRecord(records[i], connection, true, true)); | ||||||
|  |                 else if (comparsion == RecordComparisonResult.RecordSameType) | ||||||
|  |                     rt.AddUInt8Array(ComposeRecord(records[i], connection, false, true)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (prependLength) | ||||||
|  |                 rt.InsertInt32(0, rt.Length); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |             return rt.ToArray(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// Compose a structure into an array of bytes |         /// Compose a structure into an array of bytes | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @@ -474,6 +675,9 @@ namespace Esiur.Data | |||||||
|  |  | ||||||
|                     case DataType.Structure: |                     case DataType.Structure: | ||||||
|                         return ParseStructureArray(data, offset, contentLength, connection); |                         return ParseStructureArray(data, offset, contentLength, connection); | ||||||
|  |  | ||||||
|  |                     case DataType.Record: | ||||||
|  |                         return ParseRecordArray(data, offset, contentLength, connection); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
| @@ -536,6 +740,9 @@ namespace Esiur.Data | |||||||
|  |  | ||||||
|                     case DataType.Structure: |                     case DataType.Structure: | ||||||
|                         return ParseStructure(data, offset, contentLength, connection); |                         return ParseStructure(data, offset, contentLength, connection); | ||||||
|  |  | ||||||
|  |                     case DataType.Record: | ||||||
|  |                         return ParseRecord(data, offset, contentLength, connection); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -572,22 +779,6 @@ namespace Esiur.Data | |||||||
|             return connection.Fetch(iid);// Warehouse.Get(iid); |             return connection.Fetch(iid);// Warehouse.Get(iid); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public enum ResourceComparisonResult |  | ||||||
|         { |  | ||||||
|             Null, |  | ||||||
|             Distributed, |  | ||||||
|             Local, |  | ||||||
|             Same |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public enum StructureComparisonResult : byte |  | ||||||
|         { |  | ||||||
|             Null, |  | ||||||
|             Structure, |  | ||||||
|             StructureSameKeys, |  | ||||||
|             StructureSameTypes, |  | ||||||
|             Same |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// Check if a resource is local to a given connection. |         /// Check if a resource is local to a given connection. | ||||||
| @@ -648,7 +839,6 @@ namespace Esiur.Data | |||||||
|         /// <param name="connection">DistributedConnection is required to check locality.</param> |         /// <param name="connection">DistributedConnection is required to check locality.</param> | ||||||
|         /// <param name="prependLength">If True, prepend the length of the output at the beginning.</param> |         /// <param name="prependLength">If True, prepend the length of the output at the beginning.</param> | ||||||
|         /// <returns>Array of bytes in the network byte order.</returns> |         /// <returns>Array of bytes in the network byte order.</returns> | ||||||
|  |  | ||||||
|         public static byte[] ComposeResourceArray(IResource[] resources, DistributedConnection connection, bool prependLength = false) |         public static byte[] ComposeResourceArray(IResource[] resources, DistributedConnection connection, bool prependLength = false) | ||||||
|         { |         { | ||||||
|             if (resources == null || resources?.Length == 0) |             if (resources == null || resources?.Length == 0) | ||||||
| @@ -1041,6 +1231,10 @@ namespace Esiur.Data | |||||||
|                     rt.AddUInt8Array(ComposeVarArray((Array)value, connection, true)); |                     rt.AddUInt8Array(ComposeVarArray((Array)value, connection, true)); | ||||||
|                     break; |                     break; | ||||||
|  |  | ||||||
|  |                 case DataType.Record: | ||||||
|  |                     rt.AddUInt8Array(ComposeRecord((IRecord)value, connection, true, true)); | ||||||
|  |                     break; | ||||||
|  |  | ||||||
|                 case DataType.ResourceArray: |                 case DataType.ResourceArray: | ||||||
|                     if (value is IResource[]) |                     if (value is IResource[]) | ||||||
|                         rt.AddUInt8Array(ComposeResourceArray((IResource[])value, connection, true)); |                         rt.AddUInt8Array(ComposeResourceArray((IResource[])value, connection, true)); | ||||||
| @@ -1052,6 +1246,10 @@ namespace Esiur.Data | |||||||
|                     rt.AddUInt8Array(ComposeStructureArray((Structure[])value, connection, true)); |                     rt.AddUInt8Array(ComposeStructureArray((Structure[])value, connection, true)); | ||||||
|                     break; |                     break; | ||||||
|  |  | ||||||
|  |                 case DataType.RecordArray: | ||||||
|  |                     rt.AddUInt8Array(ComposeRecordArray((IRecord[])value, connection, true)); | ||||||
|  |                     break; | ||||||
|  |  | ||||||
|                 default: |                 default: | ||||||
|                     rt.Add(type, value); |                     rt.Add(type, value); | ||||||
|                     if (type.IsArray()) |                     if (type.IsArray()) | ||||||
| @@ -1284,6 +1482,8 @@ namespace Esiur.Data | |||||||
|                     return (IsLocalResource((IResource)value, connection) ? DataType.Resource : DataType.DistributedResource, value); |                     return (IsLocalResource((IResource)value, connection) ? DataType.Resource : DataType.DistributedResource, value); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |             else if (ImplementsInterface(t, typeof(IRecord))) | ||||||
|  |                 type = DataType.Record; | ||||||
|             else |             else | ||||||
|                 type = DataType.Void; |                 type = DataType.Void; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -53,6 +53,7 @@ namespace Esiur.Data | |||||||
|         ResourceLink, |         ResourceLink, | ||||||
|         String, |         String, | ||||||
|         Structure, |         Structure, | ||||||
|  |         Record, | ||||||
|         //Stream, |         //Stream, | ||||||
|         //Array = 0x80, |         //Array = 0x80, | ||||||
|         VarArray = 0x80, |         VarArray = 0x80, | ||||||
| @@ -75,6 +76,7 @@ namespace Esiur.Data | |||||||
|         ResourceLinkArray, |         ResourceLinkArray, | ||||||
|         StringArray, |         StringArray, | ||||||
|         StructureArray, |         StructureArray, | ||||||
|  |         RecordArray, | ||||||
|         NotModified = 0x7f, |         NotModified = 0x7f, | ||||||
|         Unspecified = 0xff, |         Unspecified = 0xff, | ||||||
|     } |     } | ||||||
| @@ -113,7 +115,5 @@ namespace Esiur.Data | |||||||
|                     return -1; |                     return -1; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								Esiur/Data/IRecord.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Esiur/Data/IRecord.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Text; | ||||||
|  |  | ||||||
|  | namespace Esiur.Data | ||||||
|  | { | ||||||
|  |     public interface IRecord | ||||||
|  |     { | ||||||
|  |  | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								Esiur/Data/Record.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Esiur/Data/Record.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Text; | ||||||
|  |  | ||||||
|  | namespace Esiur.Data | ||||||
|  | { | ||||||
|  |     public class Record: KeyList<string, object>, IRecord | ||||||
|  |     { | ||||||
|  |          | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								Esiur/Data/RecordComparisonResult.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								Esiur/Data/RecordComparisonResult.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Text; | ||||||
|  |  | ||||||
|  | namespace Esiur.Data | ||||||
|  | { | ||||||
|  |     public enum RecordComparisonResult : byte | ||||||
|  |     { | ||||||
|  |         Null, | ||||||
|  |         Record, | ||||||
|  |         RecordSameType, | ||||||
|  |         Same | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								Esiur/Data/ResourceComparisonResult.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								Esiur/Data/ResourceComparisonResult.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Text; | ||||||
|  |  | ||||||
|  | namespace Esiur.Data | ||||||
|  | { | ||||||
|  |     public enum ResourceComparisonResult | ||||||
|  |     { | ||||||
|  |         Null, | ||||||
|  |         Distributed, | ||||||
|  |         Local, | ||||||
|  |         Same | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								Esiur/Data/StructureComparisonResult.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								Esiur/Data/StructureComparisonResult.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Text; | ||||||
|  |  | ||||||
|  | namespace Esiur.Data | ||||||
|  | { | ||||||
|  |     public enum StructureComparisonResult : byte | ||||||
|  |     { | ||||||
|  |         Null, | ||||||
|  |         Structure, | ||||||
|  |         StructureSameKeys, | ||||||
|  |         StructureSameTypes, | ||||||
|  |         Same | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -7,7 +7,7 @@ | |||||||
|     <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.8.1</Version> |     <Version>1.8.2.18</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.8.1.0</AssemblyVersion> |     <AssemblyVersion>1.8.1.0</AssemblyVersion> | ||||||
| @@ -41,6 +41,7 @@ | |||||||
|     <Compile Remove="Resource\ResourceEvent.cs" /> |     <Compile Remove="Resource\ResourceEvent.cs" /> | ||||||
|     <Compile Remove="Resource\ResourceFunction.cs" /> |     <Compile Remove="Resource\ResourceFunction.cs" /> | ||||||
|     <Compile Remove="Resource\ResourceProperty.cs" /> |     <Compile Remove="Resource\ResourceProperty.cs" /> | ||||||
|  |     <Compile Remove="Resource\Template\RecordTemplate.cs" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|  |  | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
| @@ -53,6 +54,7 @@ | |||||||
|     <None Include="Resource\ResourceEvent.cs" /> |     <None Include="Resource\ResourceEvent.cs" /> | ||||||
|     <None Include="Resource\ResourceFunction.cs" /> |     <None Include="Resource\ResourceFunction.cs" /> | ||||||
|     <None Include="Resource\ResourceProperty.cs" /> |     <None Include="Resource\ResourceProperty.cs" /> | ||||||
|  |     <None Include="Resource\Template\RecordTemplate.cs" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|  |  | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
| @@ -79,6 +81,10 @@ | |||||||
|     <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 --> |     <!-- 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="$(PkgSystem_Text_Json)\lib\netstandard2.0\*.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" /> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     <None Include="Tools/*" Pack="true" PackagePath="tools/" /> | ||||||
|  |  | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|  |  | ||||||
| </Project>  | </Project>  | ||||||
| @@ -1050,7 +1050,7 @@ namespace Esiur.Net.IIP | |||||||
|                 var host = Instance.Name.Split(':'); |                 var host = Instance.Name.Split(':'); | ||||||
|  |  | ||||||
|                 var address = host[0]; |                 var address = host[0]; | ||||||
|                 var port = ushort.Parse(host[1]); |                 var port = host.Length > 1 ? ushort.Parse(host[1]) : (ushort) 10518; | ||||||
|                 // assign domain from hostname if not provided |                 // assign domain from hostname if not provided | ||||||
|                 var domain = Domain != null ? Domain : address; |                 var domain = Domain != null ? Domain : address; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1079,7 +1079,6 @@ namespace Esiur.Net.IIP | |||||||
|  |  | ||||||
|         void IIPRequestLinkTemplates(uint callback, string resourceLink) |         void IIPRequestLinkTemplates(uint callback, string resourceLink) | ||||||
|         { |         { | ||||||
|             Console.WriteLine("IIPRequestLinkTemplates " + DateTime.UtcNow); |  | ||||||
|             Action<IResource[]> queryCallback = (r) => |             Action<IResource[]> queryCallback = (r) => | ||||||
|             { |             { | ||||||
|                 if (r == null) |                 if (r == null) | ||||||
| @@ -1123,7 +1122,7 @@ namespace Esiur.Net.IIP | |||||||
|  |  | ||||||
|         void IIPRequestTemplateFromClassName(uint callback, string className) |         void IIPRequestTemplateFromClassName(uint callback, string className) | ||||||
|         { |         { | ||||||
|             Warehouse.GetTemplate(className).Then((t) => |             Warehouse.GetTemplateByClassName(className).Then((t) => | ||||||
|             { |             { | ||||||
|                 if (t != null) |                 if (t != null) | ||||||
|                     SendReply(IIPPacket.IIPPacketAction.TemplateFromClassName, callback) |                     SendReply(IIPPacket.IIPPacketAction.TemplateFromClassName, callback) | ||||||
| @@ -1140,7 +1139,7 @@ namespace Esiur.Net.IIP | |||||||
|  |  | ||||||
|         void IIPRequestTemplateFromClassId(uint callback, Guid classId) |         void IIPRequestTemplateFromClassId(uint callback, Guid classId) | ||||||
|         { |         { | ||||||
|             var t = Warehouse.GetTemplate(classId); |             var t = Warehouse.GetTemplateByClassId(classId); | ||||||
|  |  | ||||||
|             if (t != null) |             if (t != null) | ||||||
|                 SendReply(IIPPacket.IIPPacketAction.TemplateFromClassId, callback) |                 SendReply(IIPPacket.IIPPacketAction.TemplateFromClassId, callback) | ||||||
| @@ -2209,7 +2208,7 @@ namespace Esiur.Net.IIP | |||||||
|  |  | ||||||
|                             if (resource == null) |                             if (resource == null) | ||||||
|                             { |                             { | ||||||
|                                 var template = Warehouse.GetTemplate((Guid)rt[0]); |                                 var template = Warehouse.GetTemplateByClassId((Guid)rt[0], true); | ||||||
|                                 if (template?.ResourceType != null) |                                 if (template?.ResourceType != null) | ||||||
|                                     dr = Activator.CreateInstance(template.ResourceType, this, id, (ulong)rt[1], (string)rt[2]) as DistributedResource; |                                     dr = Activator.CreateInstance(template.ResourceType, this, id, (ulong)rt[1], (string)rt[2]) as DistributedResource; | ||||||
|                                 else |                                 else | ||||||
|   | |||||||
| @@ -65,7 +65,7 @@ namespace Esiur.Net.IIP | |||||||
|         { |         { | ||||||
|             get; |             get; | ||||||
|             set; |             set; | ||||||
|         } |         } = 10518; | ||||||
|  |  | ||||||
|  |  | ||||||
|         [Attribute] |         [Attribute] | ||||||
|   | |||||||
| @@ -69,7 +69,7 @@ namespace Esiur.Net | |||||||
|             //sock.OnClose -= Socket_OnClose; |             //sock.OnClose -= Socket_OnClose; | ||||||
|             //sock.OnConnect -= Socket_OnConnect; |             //sock.OnConnect -= Socket_OnConnect; | ||||||
|             //sock.OnReceive -= Socket_OnReceive; |             //sock.OnReceive -= Socket_OnReceive; | ||||||
|             sock.Destroy(); |             sock?.Destroy(); | ||||||
|             //Receiver = null; |             //Receiver = null; | ||||||
|             Close(); |             Close(); | ||||||
|             sock = null; |             sock = null; | ||||||
|   | |||||||
| @@ -21,10 +21,9 @@ namespace Esiur.Proxy | |||||||
|     { |     { | ||||||
|  |  | ||||||
|  |  | ||||||
|         private static Regex urlRegex = new Regex(@"^(?:([\S]*)://([^/]*)/?)"); |  | ||||||
|  |  | ||||||
|         private KeyList<string, ResourceTemplate[]> cache = new(); |         private KeyList<string, ResourceTemplate[]> cache = new(); | ||||||
|        // private List<string> inProgress = new(); |         // private List<string> inProgress = new(); | ||||||
|  |  | ||||||
|         public void Initialize(GeneratorInitializationContext context) |         public void Initialize(GeneratorInitializationContext context) | ||||||
|         { |         { | ||||||
| @@ -33,148 +32,52 @@ namespace Esiur.Proxy | |||||||
|             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) |         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)); |             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) |         void GenerateModel(GeneratorExecutionContext context, ResourceTemplate[] templates) | ||||||
|         { |         { | ||||||
|             foreach (var tmp in templates) |             foreach (var tmp in templates) | ||||||
|             { |             { | ||||||
|                 var source = GenerateClass(tmp, templates); |                 if (tmp.Type == TemplateType.Resource) | ||||||
|                 //File.WriteAllText($@"C:\gen\{tmp.ClassName}.cs", source); |                 { | ||||||
|                 context.AddSource(tmp.ClassName + "_esiur.cs", source); |                     var source = TemplateGenerator.GenerateClass(tmp, templates); | ||||||
|  |                     // File.WriteAllText($@"C:\gen\{tmp.ClassName}.cs", source); | ||||||
|  |                     context.AddSource(tmp.ClassName + ".Generated.cs", source); | ||||||
|  |                 } | ||||||
|  |                 else if (tmp.Type == TemplateType.Record) | ||||||
|  |                 { | ||||||
|  |                     var source = TemplateGenerator.GenerateRecord(tmp, templates); | ||||||
|  |                     // File.WriteAllText($@"C:\gen\{tmp.ClassName}.cs", source); | ||||||
|  |                     context.AddSource(tmp.ClassName + ".Generated.cs", source); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             // generate info class |             // 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})")) |             var typesFile = "using System; \r\n namespace Esiur { public static class Generated { public static Type[] Resources {get;} = new Type[] { " + | ||||||
|                 + " }; \r\n } \r\n}"; |                                 string.Join(",", templates.Where(x => x.Type == TemplateType.Resource).Select(x => $"typeof({x.ClassName})")) | ||||||
|  |                             + " }; \r\n public static Type[] Records { get; } = new Type[] { " + | ||||||
|  |                                 string.Join(",", templates.Where(x => x.Type == TemplateType.Record).Select(x => $"typeof({x.ClassName})")) | ||||||
|  |                             + " }; " + | ||||||
|  |  | ||||||
|  |                             "\r\n } \r\n}"; | ||||||
|  |  | ||||||
|             //File.WriteAllText($@"C:\gen\Esiur.Generated.cs", gen); |             //File.WriteAllText($@"C:\gen\Esiur.Generated.cs", gen); | ||||||
|  |  | ||||||
|             context.AddSource("Esiur.Generated.cs", gen); |             context.AddSource("Esiur.Generated.cs", typesFile); | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |    | ||||||
|         public void Execute(GeneratorExecutionContext context) |         public void Execute(GeneratorExecutionContext context) | ||||||
|         { |         { | ||||||
|  |  | ||||||
| @@ -188,7 +91,7 @@ namespace Esiur.Proxy | |||||||
|  |  | ||||||
|             foreach (var path in receiver.Imports) |             foreach (var path in receiver.Imports) | ||||||
|             { |             { | ||||||
|                 if (!urlRegex.IsMatch(path)) |                 if (!TemplateGenerator.urlRegex.IsMatch(path)) | ||||||
|                     continue; |                     continue; | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -206,7 +109,7 @@ namespace Esiur.Proxy | |||||||
|  |  | ||||||
|                 //inProgress.Add(path); |                 //inProgress.Add(path); | ||||||
|  |  | ||||||
|                 var url = urlRegex.Split(path); |                 var url = TemplateGenerator.urlRegex.Split(path); | ||||||
|  |  | ||||||
|  |  | ||||||
|                 try |                 try | ||||||
| @@ -273,12 +176,12 @@ public virtual void Destroy() {{ OnDestroy?.Invoke(this); }} | |||||||
|                     code += "}}\r\n"; |                     code += "}}\r\n"; | ||||||
|  |  | ||||||
|                     //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 + ".Generated.cs", code); | ||||||
|  |  | ||||||
|                 } |                 } | ||||||
|                 catch (Exception ex) |                 catch (Exception ex) | ||||||
|                 { |                 { | ||||||
|                     System.IO.File.AppendAllText("c:\\gen\\error.log", ci.Name + " " + ex.ToString() + "\r\n"); |                     //System.IO.File.AppendAllText("c:\\gen\\error.log", ci.Name + " " + ex.ToString() + "\r\n"); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| using Esiur.Resource; | using Esiur.Data; | ||||||
|  | using Esiur.Resource; | ||||||
| using System; | using System; | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
| using System.Linq; | using System.Linq; | ||||||
| @@ -56,6 +57,12 @@ namespace Esiur.Proxy | |||||||
|                 return type; |                 return type; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             if (!Codec.ImplementsInterface(type, typeof(IResource))) | ||||||
|  |             { | ||||||
|  |                 cache.Add(type, type); | ||||||
|  |                 return type; | ||||||
|  |             } | ||||||
|  |  | ||||||
| #if NETSTANDARD | #if NETSTANDARD | ||||||
|             var typeInfo = type.GetTypeInfo(); |             var typeInfo = type.GetTypeInfo(); | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										231
									
								
								Esiur/Proxy/TemplateGenerator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										231
									
								
								Esiur/Proxy/TemplateGenerator.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,231 @@ | |||||||
|  | using Esiur.Data; | ||||||
|  | using Esiur.Resource.Template; | ||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.IO; | ||||||
|  | using System.Text; | ||||||
|  | using System.Linq; | ||||||
|  | using System.Text.RegularExpressions; | ||||||
|  | using Esiur.Resource; | ||||||
|  | using Esiur.Net.IIP; | ||||||
|  | using System.Diagnostics; | ||||||
|  |  | ||||||
|  | namespace Esiur.Proxy | ||||||
|  | { | ||||||
|  |     public static class TemplateGenerator | ||||||
|  |     { | ||||||
|  |         internal static Regex urlRegex = new Regex(@"^(?:([\S]*)://([^/]*)/?)"); | ||||||
|  |  | ||||||
|  |         internal static string GenerateRecord(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} : IRecord {{"); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |             foreach (var p in template.Properties) | ||||||
|  |             { | ||||||
|  |                 var ptTypeName = GetTypeName(p.ValueType, templates); | ||||||
|  |                 rt.AppendLine($"public {ptTypeName} {p.Name} {{ get; set; }}"); | ||||||
|  |                 rt.AppendLine(); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             rt.AppendLine("\r\n}\r\n}"); | ||||||
|  |  | ||||||
|  |             return rt.ToString(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         static 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; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static string GetTemplate(string url, string dir = null, string username= null, string password = null) | ||||||
|  |         { | ||||||
|  |             try | ||||||
|  |             { | ||||||
|  |  | ||||||
|  |                 if (!urlRegex.IsMatch(url)) | ||||||
|  |                     throw new Exception("Invalid IIP URL"); | ||||||
|  |  | ||||||
|  |                 var path = urlRegex.Split(url); | ||||||
|  |                 var con = Warehouse.Get<DistributedConnection>(path[1] + "://" + path[2], | ||||||
|  |                         !string.IsNullOrEmpty( username) && !string.IsNullOrEmpty( password) ? new { Username = username, Password = password } : null | ||||||
|  |                     ).Wait(20000); | ||||||
|  |  | ||||||
|  |                 if (con == null) | ||||||
|  |                     throw new Exception("Can't connect to server"); | ||||||
|  |  | ||||||
|  |                 if (string.IsNullOrEmpty(dir)) | ||||||
|  |                     dir = path[2].Replace(":", "_"); | ||||||
|  |  | ||||||
|  |                 var templates = con.GetLinkTemplates(path[3]).Wait(60000); | ||||||
|  |  | ||||||
|  |                 var tempDir = new DirectoryInfo(Path.GetTempPath() + Path.DirectorySeparatorChar | ||||||
|  |                                 + Misc.Global.GenerateCode(20) + Path.DirectorySeparatorChar + dir); | ||||||
|  |  | ||||||
|  |                 if (!tempDir.Exists) | ||||||
|  |                     tempDir.Create(); | ||||||
|  |                 else | ||||||
|  |                 { | ||||||
|  |                     foreach (FileInfo file in tempDir.GetFiles()) | ||||||
|  |                         file.Delete(); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 // make sources | ||||||
|  |                 foreach (var tmp in templates) | ||||||
|  |                 { | ||||||
|  |                     if (tmp.Type == TemplateType.Resource) | ||||||
|  |                     { | ||||||
|  |                         var source = GenerateClass(tmp, templates); | ||||||
|  |                         File.WriteAllText(tempDir.FullName + Path.DirectorySeparatorChar + tmp.ClassName + ".Generated.cs", source); | ||||||
|  |                     } | ||||||
|  |                     else if (tmp.Type == TemplateType.Record) | ||||||
|  |                     { | ||||||
|  |                         var source = GenerateRecord(tmp, templates); | ||||||
|  |                         File.WriteAllText(tempDir.FullName + Path.DirectorySeparatorChar + tmp.ClassName + ".Generated.cs", source); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 // generate info class | ||||||
|  |  | ||||||
|  |                 var typesFile = "using System; \r\n namespace Esiur { public static class Generated { public static Type[] Resources {get;} = new Type[] { " + | ||||||
|  |                         string.Join(",", templates.Where(x => x.Type == TemplateType.Resource).Select(x => $"typeof({x.ClassName})")) | ||||||
|  |                     + " }; \r\n public static Type[] Records { get; } = new Type[] { " + | ||||||
|  |                         string.Join(",", templates.Where(x => x.Type == TemplateType.Record).Select(x => $"typeof({x.ClassName})")) | ||||||
|  |                     + " }; " + | ||||||
|  |  | ||||||
|  |                     "\r\n } \r\n}"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |                 File.WriteAllText(tempDir.FullName + Path.DirectorySeparatorChar + "Esiur.Generated.cs", typesFile); | ||||||
|  |  | ||||||
|  |                 return tempDir.FullName; | ||||||
|  |  | ||||||
|  |             } | ||||||
|  |             catch(Exception ex) | ||||||
|  |             { | ||||||
|  |                 //File.WriteAllText("C:\\gen\\gettemplate.err", ex.ToString()); | ||||||
|  |                 throw ex; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         internal static 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(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -875,7 +875,7 @@ namespace Esiur.Resource | |||||||
|             if (customTemplate != null) |             if (customTemplate != null) | ||||||
|                 this.template = customTemplate; |                 this.template = customTemplate; | ||||||
|             else |             else | ||||||
|                 this.template = Warehouse.GetTemplate(resource.GetType()); |                 this.template = Warehouse.GetTemplateByType(resource.GetType()); | ||||||
|  |  | ||||||
|             // set ages |             // set ages | ||||||
|             for (byte i = 0; i < template.Properties.Length; i++) |             for (byte i = 0; i < template.Properties.Length; i++) | ||||||
|   | |||||||
							
								
								
									
										277
									
								
								Esiur/Resource/Template/RecordTemplate.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										277
									
								
								Esiur/Resource/Template/RecordTemplate.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,277 @@ | |||||||
|  | using Esiur.Data; | ||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Reflection; | ||||||
|  | using System.Text; | ||||||
|  |  | ||||||
|  | namespace Esiur.Resource.Template | ||||||
|  | { | ||||||
|  |     public class RecordTemplate : ResourceTemplate | ||||||
|  |     { | ||||||
|  |         //Guid classId; | ||||||
|  |         //public Guid ClassId => classId; | ||||||
|  |  | ||||||
|  |         //string className; | ||||||
|  |         //public string ClassName => className; | ||||||
|  |  | ||||||
|  |         public RecordTemplate() | ||||||
|  |         { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public new static RecordTemplate Parse(byte[] data, uint offset, uint contentLength) | ||||||
|  |         { | ||||||
|  |  | ||||||
|  |             uint ends = offset + contentLength; | ||||||
|  |  | ||||||
|  |             uint oOffset = offset; | ||||||
|  |  | ||||||
|  |             // start parsing... | ||||||
|  |  | ||||||
|  |             var od = new RecordTemplate(); | ||||||
|  |             od.content = data.Clip(offset, contentLength); | ||||||
|  |  | ||||||
|  |             od.classId = data.GetGuid(offset); | ||||||
|  |             offset += 16; | ||||||
|  |             od.className = data.GetString(offset + 1, data[offset]); | ||||||
|  |             offset += (uint)data[offset] + 1; | ||||||
|  |  | ||||||
|  |             od.version = data.GetInt32(offset); | ||||||
|  |             offset += 4; | ||||||
|  |  | ||||||
|  |             ushort methodsCount = data.GetUInt16(offset); | ||||||
|  |             offset += 2; | ||||||
|  |  | ||||||
|  |              | ||||||
|  |  | ||||||
|  |             for (int i = 0; i < methodsCount; i++) | ||||||
|  |             { | ||||||
|  |                 var type = data[offset] >> 5; | ||||||
|  |  | ||||||
|  |                 if (type == 0) // function | ||||||
|  |                 { | ||||||
|  |                     string expansion = null; | ||||||
|  |                     var hasExpansion = ((data[offset++] & 0x10) == 0x10); | ||||||
|  |  | ||||||
|  |                     var name = data.GetString(offset + 1, data[offset]); | ||||||
|  |                     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 ? | ||||||
|  |                     { | ||||||
|  |                         var cs = data.GetUInt32(offset); | ||||||
|  |                         offset += 4; | ||||||
|  |                         expansion = data.GetString(offset, cs); | ||||||
|  |                         offset += cs; | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     var ft = new FunctionTemplate(od, functionIndex++, name, arguments.ToArray(), returnType, expansion); | ||||||
|  |  | ||||||
|  |                     od.functions.Add(ft); | ||||||
|  |                 } | ||||||
|  |                 else if (type == 1)    // property | ||||||
|  |                 { | ||||||
|  |  | ||||||
|  |                     string readExpansion = null, writeExpansion = null; | ||||||
|  |  | ||||||
|  |                     var hasReadExpansion = ((data[offset] & 0x8) == 0x8); | ||||||
|  |                     var hasWriteExpansion = ((data[offset] & 0x10) == 0x10); | ||||||
|  |                     var recordable = ((data[offset] & 1) == 1); | ||||||
|  |                     var permission = (PropertyTemplate.PropertyPermission)((data[offset++] >> 1) & 0x3); | ||||||
|  |                     var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]); | ||||||
|  |  | ||||||
|  |                     offset += (uint)data[offset] + 1; | ||||||
|  |  | ||||||
|  |                     var (dts, valueType) = TemplateDataType.Parse(data, offset); | ||||||
|  |  | ||||||
|  |                     offset += dts; | ||||||
|  |  | ||||||
|  |                     if (hasReadExpansion) // expansion ? | ||||||
|  |                     { | ||||||
|  |                         var cs = data.GetUInt32(offset); | ||||||
|  |                         offset += 4; | ||||||
|  |                         readExpansion = data.GetString(offset, cs); | ||||||
|  |                         offset += cs; | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     if (hasWriteExpansion) // expansion ? | ||||||
|  |                     { | ||||||
|  |                         var cs = data.GetUInt32(offset); | ||||||
|  |                         offset += 4; | ||||||
|  |                         writeExpansion = data.GetString(offset, cs); | ||||||
|  |                         offset += cs; | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     var pt = new PropertyTemplate(od, propertyIndex++, name, valueType, readExpansion, writeExpansion, recordable); | ||||||
|  |  | ||||||
|  |                     od.properties.Add(pt); | ||||||
|  |                 } | ||||||
|  |                 else if (type == 2) // Event | ||||||
|  |                 { | ||||||
|  |  | ||||||
|  |                     string expansion = null; | ||||||
|  |                     var hasExpansion = ((data[offset] & 0x10) == 0x10); | ||||||
|  |                     var listenable = ((data[offset++] & 0x8) == 0x8); | ||||||
|  |  | ||||||
|  |                     var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, (int)data[offset]); | ||||||
|  |                     offset += (uint)data[offset] + 1; | ||||||
|  |  | ||||||
|  |                     var (dts, argType) = TemplateDataType.Parse(data, offset); | ||||||
|  |  | ||||||
|  |                     offset += dts; | ||||||
|  |  | ||||||
|  |                     if (hasExpansion) // expansion ? | ||||||
|  |                     { | ||||||
|  |                         var cs = data.GetUInt32(offset); | ||||||
|  |                         offset += 4; | ||||||
|  |                         expansion = data.GetString(offset, cs); | ||||||
|  |                         offset += cs; | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     var et = new EventTemplate(od, eventIndex++, name, argType, expansion, listenable); | ||||||
|  |  | ||||||
|  |                     od.events.Add(et); | ||||||
|  |  | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // append signals | ||||||
|  |             for (int i = 0; i < od.events.Count; i++) | ||||||
|  |                 od.members.Add(od.events[i]); | ||||||
|  |             // append slots | ||||||
|  |             for (int i = 0; i < od.functions.Count; i++) | ||||||
|  |                 od.members.Add(od.functions[i]); | ||||||
|  |             // append properties | ||||||
|  |             for (int i = 0; i < od.properties.Count; i++) | ||||||
|  |                 od.members.Add(od.properties[i]); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |             //od.isReady = true; | ||||||
|  |             /* | ||||||
|  |             var oo = owner.Socket.Engine.GetObjectDescription(od.GUID); | ||||||
|  |             if (oo != null) | ||||||
|  |             { | ||||||
|  |                 Console.WriteLine("Already there ! description"); | ||||||
|  |                 return oo; | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 owner.Socket.Engine.AddObjectDescription(od); | ||||||
|  |                 return od; | ||||||
|  |             } | ||||||
|  |             */ | ||||||
|  |  | ||||||
|  |             return od; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public RecordTemplate(Type type) | ||||||
|  |         { | ||||||
|  |             if (!Codec.ImplementsInterface(type, typeof(IRecord))) | ||||||
|  |                 throw new Exception("Type is not a record."); | ||||||
|  |  | ||||||
|  |             className = type.FullName; | ||||||
|  |             classId = ResourceTemplate.GetTypeGuid(className); | ||||||
|  |  | ||||||
|  | #if NETSTANDARD | ||||||
|  |             PropertyInfo[] propsInfo = type.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance); | ||||||
|  | #else | ||||||
|  |             PropertyInfo[] propsInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |             bool classIsPublic = type.GetCustomAttribute<PublicAttribute>() != null; | ||||||
|  |  | ||||||
|  |             byte i = 0; | ||||||
|  |  | ||||||
|  |             if (classIsPublic) | ||||||
|  |             { | ||||||
|  |                 foreach (var pi in propsInfo) | ||||||
|  |                 { | ||||||
|  |                     var privateAttr = pi.GetCustomAttribute<PrivateAttribute>(true); | ||||||
|  |  | ||||||
|  |                     if (privateAttr == null) | ||||||
|  |                         continue; | ||||||
|  |  | ||||||
|  |                     var annotationAttr = pi.GetCustomAttribute<AnnotationAttribute>(true); | ||||||
|  |                     var storageAttr = pi.GetCustomAttribute<StorageAttribute>(true); | ||||||
|  |  | ||||||
|  |                     var pt = new PropertyTemplate(this, i++, pi.Name, TemplateDataType.FromType(pi.PropertyType)); | ||||||
|  |  | ||||||
|  |                     if (storageAttr != null) | ||||||
|  |                         pt.Recordable = storageAttr.Mode == StorageMode.Recordable; | ||||||
|  |  | ||||||
|  |                     if (annotationAttr != null) | ||||||
|  |                         pt.ReadExpansion = annotationAttr.Annotation; | ||||||
|  |                     else | ||||||
|  |                         pt.ReadExpansion = pi.PropertyType.Name; | ||||||
|  |  | ||||||
|  |                     pt.PropertyInfo = pi; | ||||||
|  |                     //pt.Serilize = publicAttr.Serialize; | ||||||
|  |                     properties.Add(pt); | ||||||
|  |                     members.Add(pt); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 foreach (var pi in propsInfo) | ||||||
|  |                 { | ||||||
|  |                     var publicAttr = pi.GetCustomAttribute<PublicAttribute>(true); | ||||||
|  |  | ||||||
|  |                     if (publicAttr == null) | ||||||
|  |                         continue; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |                     var annotationAttr = pi.GetCustomAttribute<AnnotationAttribute>(true); | ||||||
|  |                     var storageAttr = pi.GetCustomAttribute<StorageAttribute>(true); | ||||||
|  |                     var valueType = TemplateDataType.FromType(pi.PropertyType); | ||||||
|  |  | ||||||
|  |                     var pt = new PropertyTemplate(this, i++, pi.Name, valueType);//, rp.ReadExpansion, rp.WriteExpansion, rp.Storage); | ||||||
|  |                     if (storageAttr != null) | ||||||
|  |                         pt.Recordable = storageAttr.Mode == StorageMode.Recordable; | ||||||
|  |  | ||||||
|  |                     if (annotationAttr != null) | ||||||
|  |                         pt.ReadExpansion = annotationAttr.Annotation; | ||||||
|  |                     else | ||||||
|  |                         pt.ReadExpansion = pi.PropertyType.Name; | ||||||
|  |  | ||||||
|  |                     pt.PropertyInfo = pi; | ||||||
|  |                     //pt.Serilize = publicAttr.Serialize; | ||||||
|  |                     properties.Add(pt); | ||||||
|  |                     members.Add(pt); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |             // bake it binarily | ||||||
|  |             var b = new BinaryList(); | ||||||
|  |             b.AddGuid(classId) | ||||||
|  |              .AddUInt8((byte)className.Length) | ||||||
|  |              .AddString(className) | ||||||
|  |              .AddInt32(version) | ||||||
|  |              .AddUInt16((ushort)members.Count); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |             foreach (var pt in properties) | ||||||
|  |                 b.AddUInt8Array(pt.Compose()); | ||||||
|  |  | ||||||
|  |             content = b.ToArray(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -12,28 +12,42 @@ using Esiur.Net.IIP; | |||||||
|  |  | ||||||
| namespace Esiur.Resource.Template | namespace Esiur.Resource.Template | ||||||
| { | { | ||||||
|  |     //public enum TemplateType | ||||||
|  |     //{ | ||||||
|  |     //    Resource, | ||||||
|  |     //    Record | ||||||
|  |     //} | ||||||
|  |  | ||||||
|     public class ResourceTemplate |     public class ResourceTemplate | ||||||
|     { |     { | ||||||
|  |  | ||||||
|         Guid classId; |         protected Guid classId; | ||||||
|         string className; |         protected string className; | ||||||
|         List<MemberTemplate> members = new List<MemberTemplate>(); |         protected List<MemberTemplate> members = new List<MemberTemplate>(); | ||||||
|         List<FunctionTemplate> functions = new List<FunctionTemplate>(); |         protected List<FunctionTemplate> functions = new List<FunctionTemplate>(); | ||||||
|         List<EventTemplate> events = new List<EventTemplate>(); |         protected List<EventTemplate> events = new List<EventTemplate>(); | ||||||
|         List<PropertyTemplate> properties = new List<PropertyTemplate>(); |         protected List<PropertyTemplate> properties = new List<PropertyTemplate>(); | ||||||
|         List<AttributeTemplate> attributes = new List<AttributeTemplate>(); |         protected List<AttributeTemplate> attributes = new List<AttributeTemplate>(); | ||||||
|         int version; |         protected int version; | ||||||
|  |         protected TemplateType templateType; | ||||||
|  |  | ||||||
|  |        // protected TemplateType | ||||||
|         //bool isReady; |         //bool isReady; | ||||||
|  |  | ||||||
|         byte[] content; |         protected byte[] content; | ||||||
|  |  | ||||||
|         public byte[] Content |         public byte[] Content | ||||||
|         { |         { | ||||||
|             get { return content; } |             get { return content; } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         public TemplateType Type => templateType; | ||||||
|  |  | ||||||
|  |  | ||||||
|         public Type ResourceType { get; set; } |         public Type ResourceType { get; set; } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         public MemberTemplate GetMemberTemplate(MemberInfo member) |         public MemberTemplate GetMemberTemplate(MemberInfo member) | ||||||
|         { |         { | ||||||
|             if (member is MethodInfo) |             if (member is MethodInfo) | ||||||
| @@ -174,7 +188,7 @@ namespace Esiur.Resource.Template | |||||||
|                 // functions |                 // functions | ||||||
|                 foreach (var f in tmp.functions) |                 foreach (var f in tmp.functions) | ||||||
|                 { |                 { | ||||||
|                     var frtt = Warehouse.GetTemplate(GetElementType(f.MethodInfo.ReturnType)); |                     var frtt = Warehouse.GetTemplateByType(GetElementType(f.MethodInfo.ReturnType)); | ||||||
|                     if (frtt != null) |                     if (frtt != null) | ||||||
|                     { |                     { | ||||||
|                         if (!bag.Contains(frtt)) |                         if (!bag.Contains(frtt)) | ||||||
| @@ -188,7 +202,7 @@ namespace Esiur.Resource.Template | |||||||
|  |  | ||||||
|                     for(var i = 0; i < args.Length - 1; i++) |                     for(var i = 0; i < args.Length - 1; i++) | ||||||
|                     { |                     { | ||||||
|                         var fpt = Warehouse.GetTemplate(GetElementType(args[i].ParameterType)); |                         var fpt = Warehouse.GetTemplateByType(GetElementType(args[i].ParameterType)); | ||||||
|                         if (fpt != null) |                         if (fpt != null) | ||||||
|                         { |                         { | ||||||
|                             if (!bag.Contains(fpt)) |                             if (!bag.Contains(fpt)) | ||||||
| @@ -205,7 +219,7 @@ namespace Esiur.Resource.Template | |||||||
|                         var last = args.Last(); |                         var last = args.Last(); | ||||||
|                         if (last.ParameterType != typeof(DistributedConnection)) |                         if (last.ParameterType != typeof(DistributedConnection)) | ||||||
|                         { |                         { | ||||||
|                             var fpt = Warehouse.GetTemplate(GetElementType(last.ParameterType)); |                             var fpt = Warehouse.GetTemplateByType(GetElementType(last.ParameterType)); | ||||||
|                             if (fpt != null) |                             if (fpt != null) | ||||||
|                             { |                             { | ||||||
|                                 if (!bag.Contains(fpt)) |                                 if (!bag.Contains(fpt)) | ||||||
| @@ -222,7 +236,7 @@ namespace Esiur.Resource.Template | |||||||
|                 // properties |                 // properties | ||||||
|                 foreach (var p in tmp.properties) |                 foreach (var p in tmp.properties) | ||||||
|                 { |                 { | ||||||
|                     var pt = Warehouse.GetTemplate(GetElementType(p.PropertyInfo.PropertyType)); |                     var pt = Warehouse.GetTemplateByType(GetElementType(p.PropertyInfo.PropertyType)); | ||||||
|                     if (pt != null) |                     if (pt != null) | ||||||
|                     { |                     { | ||||||
|                         if (!bag.Contains(pt)) |                         if (!bag.Contains(pt)) | ||||||
| @@ -236,7 +250,7 @@ namespace Esiur.Resource.Template | |||||||
|                 // events |                 // events | ||||||
|                 foreach (var e in tmp.events) |                 foreach (var e in tmp.events) | ||||||
|                 { |                 { | ||||||
|                     var et = Warehouse.GetTemplate(GetElementType(e.EventInfo.EventHandlerType.GenericTypeArguments[0])); |                     var et = Warehouse.GetTemplateByType(GetElementType(e.EventInfo.EventHandlerType.GenericTypeArguments[0])); | ||||||
|  |  | ||||||
|                     if (et != null) |                     if (et != null) | ||||||
|                     { |                     { | ||||||
| @@ -255,8 +269,18 @@ namespace Esiur.Resource.Template | |||||||
|  |  | ||||||
|         public ResourceTemplate(Type type) |         public ResourceTemplate(Type type) | ||||||
|         { |         { | ||||||
|             if (!Codec.ImplementsInterface(type, typeof(IResource))) |             if (Codec.ImplementsInterface(type, typeof(IRecord))) | ||||||
|                 throw new Exception("Type is not a resource."); |                 templateType = TemplateType.Record; | ||||||
|  |             else if (Codec.ImplementsInterface(type, typeof(IResource))) | ||||||
|  |                 templateType = TemplateType.Resource; | ||||||
|  |             else | ||||||
|  |                 throw new Exception("Type is neither a resource nor a record."); | ||||||
|  |  | ||||||
|  |             //if (isRecord && isResource) | ||||||
|  |             //  throw new Exception("Type can't have both IResource and IRecord interfaces"); | ||||||
|  |  | ||||||
|  |             //if (!(isResource || isRecord)) | ||||||
|  |             //  throw new Exception("Type is neither a resource nor a record."); | ||||||
|  |  | ||||||
|             type = ResourceProxy.GetBaseType(type); |             type = ResourceProxy.GetBaseType(type); | ||||||
|  |  | ||||||
| @@ -322,65 +346,68 @@ namespace Esiur.Resource.Template | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 i = 0; |                 if (templateType == TemplateType.Resource) | ||||||
|  |  | ||||||
|                 foreach (var ei in eventsInfo) |  | ||||||
|                 { |                 { | ||||||
|                     var privateAttr = ei.GetCustomAttribute<PrivateAttribute>(true); |                     i = 0; | ||||||
|                     if (privateAttr == null) |  | ||||||
|  |                     foreach (var ei in eventsInfo) | ||||||
|                     { |                     { | ||||||
|                         var annotationAttr = ei.GetCustomAttribute<AnnotationAttribute>(true); |                         var privateAttr = ei.GetCustomAttribute<PrivateAttribute>(true); | ||||||
|                         var listenableAttr = ei.GetCustomAttribute<ListenableAttribute>(true); |                         if (privateAttr == null) | ||||||
|  |  | ||||||
|                         var argType = ei.EventHandlerType.GenericTypeArguments[0]; |  | ||||||
|                         var et = new EventTemplate(this, i++, ei.Name, TemplateDataType.FromType(argType)); |  | ||||||
|                         et.EventInfo = ei; |  | ||||||
|  |  | ||||||
|                         if (annotationAttr != null) |  | ||||||
|                             et.Expansion = annotationAttr.Annotation; |  | ||||||
|  |  | ||||||
|                         if (listenableAttr != null) |  | ||||||
|                             et.Listenable = true; |  | ||||||
|  |  | ||||||
|                         events.Add(et); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 i = 0; |  | ||||||
|                 foreach (MethodInfo mi in methodsInfo) |  | ||||||
|                 { |  | ||||||
|                     var privateAttr = mi.GetCustomAttribute<PrivateAttribute>(true); |  | ||||||
|                     if (privateAttr == null) |  | ||||||
|                     { |  | ||||||
|                         var annotationAttr = mi.GetCustomAttribute<AnnotationAttribute>(true); |  | ||||||
|  |  | ||||||
|                         var returnType = TemplateDataType.FromType(mi.ReturnType); |  | ||||||
|  |  | ||||||
|                         var args = mi.GetParameters(); |  | ||||||
|  |  | ||||||
|                         if (args.Length > 0) |  | ||||||
|                         { |                         { | ||||||
|                             if (args.Last().ParameterType == typeof(DistributedConnection)) |                             var annotationAttr = ei.GetCustomAttribute<AnnotationAttribute>(true); | ||||||
|                                 args = args.Take(args.Count() - 1).ToArray(); |                             var listenableAttr = ei.GetCustomAttribute<ListenableAttribute>(true); | ||||||
|  |  | ||||||
|  |                             var argType = ei.EventHandlerType.GenericTypeArguments[0]; | ||||||
|  |                             var et = new EventTemplate(this, i++, ei.Name, TemplateDataType.FromType(argType)); | ||||||
|  |                             et.EventInfo = ei; | ||||||
|  |  | ||||||
|  |                             if (annotationAttr != null) | ||||||
|  |                                 et.Expansion = annotationAttr.Annotation; | ||||||
|  |  | ||||||
|  |                             if (listenableAttr != null) | ||||||
|  |                                 et.Listenable = true; | ||||||
|  |  | ||||||
|  |                             events.Add(et); | ||||||
|                         } |                         } | ||||||
|  |                     } | ||||||
|  |  | ||||||
|                         var arguments = args.Select(x => new ArgumentTemplate() |                     i = 0; | ||||||
|                                          { |                     foreach (MethodInfo mi in methodsInfo) | ||||||
|                                              Name = x.Name, |                     { | ||||||
|                                              Type = TemplateDataType.FromType(x.ParameterType), |                         var privateAttr = mi.GetCustomAttribute<PrivateAttribute>(true); | ||||||
|                                              ParameterInfo = x |                         if (privateAttr == null) | ||||||
|                                          }) |                         { | ||||||
|                                          .ToArray(); |                             var annotationAttr = mi.GetCustomAttribute<AnnotationAttribute>(true); | ||||||
|  |  | ||||||
|                         var ft = new FunctionTemplate(this, i++, mi.Name, arguments, returnType);// mi.ReturnType == typeof(void)); |                             var returnType = TemplateDataType.FromType(mi.ReturnType); | ||||||
|  |  | ||||||
|                         if (annotationAttr != null) |                             var args = mi.GetParameters(); | ||||||
|                             ft.Expansion = annotationAttr.Annotation; |  | ||||||
|                         else |  | ||||||
|                             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; |                             if (args.Length > 0) | ||||||
|                         functions.Add(ft); |                             { | ||||||
|  |                                 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) | ||||||
|  |                                 ft.Expansion = annotationAttr.Annotation; | ||||||
|  |                             else | ||||||
|  |                                 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); | ||||||
|  |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @@ -422,65 +449,68 @@ namespace Esiur.Resource.Template | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 i = 0; |                 if (templateType == TemplateType.Resource) | ||||||
|  |  | ||||||
|                 foreach (var ei in eventsInfo) |  | ||||||
|                 { |                 { | ||||||
|                     var publicAttr = ei.GetCustomAttribute<PublicAttribute>(true); |                     i = 0; | ||||||
|                     if (publicAttr != null) |  | ||||||
|  |                     foreach (var ei in eventsInfo) | ||||||
|                     { |                     { | ||||||
|                         var annotationAttr = ei.GetCustomAttribute<AnnotationAttribute>(true); |                         var publicAttr = ei.GetCustomAttribute<PublicAttribute>(true); | ||||||
|                         var listenableAttr = ei.GetCustomAttribute<ListenableAttribute>(true); |                         if (publicAttr != null) | ||||||
|  |  | ||||||
|                         var argType = ei.EventHandlerType.GenericTypeArguments[0]; |  | ||||||
|  |  | ||||||
|                         var et = new EventTemplate(this, i++, ei.Name, TemplateDataType.FromType(argType)); |  | ||||||
|                         et.EventInfo = ei; |  | ||||||
|  |  | ||||||
|                         if (annotationAttr != null) |  | ||||||
|                             et.Expansion = annotationAttr.Annotation; |  | ||||||
|  |  | ||||||
|                         if (listenableAttr != null) |  | ||||||
|                             et.Listenable = true; |  | ||||||
|  |  | ||||||
|                         events.Add(et); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 i = 0; |  | ||||||
|                 foreach (MethodInfo mi in methodsInfo) |  | ||||||
|                 { |  | ||||||
|                     var publicAttr = mi.GetCustomAttribute<PublicAttribute>(true); |  | ||||||
|                     if (publicAttr != null) |  | ||||||
|                     { |  | ||||||
|                         var annotationAttr = mi.GetCustomAttribute<AnnotationAttribute>(true); |  | ||||||
|                         var returnType = TemplateDataType.FromType(mi.ReturnType); |  | ||||||
|  |  | ||||||
|                         var args = mi.GetParameters(); |  | ||||||
|  |  | ||||||
|                         if (args.Length > 0) |  | ||||||
|                         { |                         { | ||||||
|                             if (args.Last().ParameterType == typeof(DistributedConnection)) |                             var annotationAttr = ei.GetCustomAttribute<AnnotationAttribute>(true); | ||||||
|                                 args = args.Take(args.Count() - 1).ToArray(); |                             var listenableAttr = ei.GetCustomAttribute<ListenableAttribute>(true); | ||||||
|  |  | ||||||
|  |                             var argType = ei.EventHandlerType.GenericTypeArguments[0]; | ||||||
|  |  | ||||||
|  |                             var et = new EventTemplate(this, i++, ei.Name, TemplateDataType.FromType(argType)); | ||||||
|  |                             et.EventInfo = ei; | ||||||
|  |  | ||||||
|  |                             if (annotationAttr != null) | ||||||
|  |                                 et.Expansion = annotationAttr.Annotation; | ||||||
|  |  | ||||||
|  |                             if (listenableAttr != null) | ||||||
|  |                                 et.Listenable = true; | ||||||
|  |  | ||||||
|  |                             events.Add(et); | ||||||
|                         } |                         } | ||||||
|  |                     } | ||||||
|  |  | ||||||
|                         var arguments = args.Select(x => new ArgumentTemplate() |                     i = 0; | ||||||
|                                          { |                     foreach (MethodInfo mi in methodsInfo) | ||||||
|                                              Name = x.Name, |                     { | ||||||
|                                              Type = TemplateDataType.FromType(x.ParameterType), |                         var publicAttr = mi.GetCustomAttribute<PublicAttribute>(true); | ||||||
|                                              ParameterInfo = x |                         if (publicAttr != null) | ||||||
|                                          }) |                         { | ||||||
|                                          .ToArray(); |                             var annotationAttr = mi.GetCustomAttribute<AnnotationAttribute>(true); | ||||||
|  |                             var returnType = TemplateDataType.FromType(mi.ReturnType); | ||||||
|  |  | ||||||
|                         var ft = new FunctionTemplate(this, i++, mi.Name, arguments, returnType);// mi.ReturnType == typeof(void)); |                             var args = mi.GetParameters(); | ||||||
|  |  | ||||||
|                         if (annotationAttr != null) |                             if (args.Length > 0) | ||||||
|                             ft.Expansion = annotationAttr.Annotation; |                             { | ||||||
|                         else |                                 if (args.Last().ParameterType == typeof(DistributedConnection)) | ||||||
|                             ft.Expansion = "(" + String.Join(",", mi.GetParameters().Where(x=>x.ParameterType != typeof(DistributedConnection)).Select(x=> "[" + x.ParameterType.Name + "] " + x.Name)) + ") -> " + mi.ReturnType.Name; |                                     args = args.Take(args.Count() - 1).ToArray(); | ||||||
|  |                             } | ||||||
|  |  | ||||||
|                         ft.MethodInfo = mi; |                             var arguments = args.Select(x => new ArgumentTemplate() | ||||||
|                         functions.Add(ft); |                             { | ||||||
|  |                                 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) | ||||||
|  |                                 ft.Expansion = annotationAttr.Annotation; | ||||||
|  |                             else | ||||||
|  |                                 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); | ||||||
|  |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @@ -497,7 +527,8 @@ namespace Esiur.Resource.Template | |||||||
|  |  | ||||||
|             // bake it binarily |             // bake it binarily | ||||||
|             var b = new BinaryList(); |             var b = new BinaryList(); | ||||||
|             b.AddGuid(classId) |             b.AddUInt8((byte)templateType) | ||||||
|  |              .AddGuid(classId) | ||||||
|              .AddUInt8((byte)className.Length) |              .AddUInt8((byte)className.Length) | ||||||
|              .AddString(className) |              .AddString(className) | ||||||
|              .AddInt32(version) |              .AddInt32(version) | ||||||
| @@ -533,6 +564,8 @@ namespace Esiur.Resource.Template | |||||||
|             var od = new ResourceTemplate(); |             var od = new ResourceTemplate(); | ||||||
|             od.content = data.Clip(offset, contentLength); |             od.content = data.Clip(offset, contentLength); | ||||||
|  |  | ||||||
|  |             od.templateType = (TemplateType)data[offset++]; | ||||||
|  |  | ||||||
|             od.classId = data.GetGuid(offset); |             od.classId = data.GetGuid(offset); | ||||||
|             offset += 16; |             offset += 16; | ||||||
|             od.className = data.GetString(offset + 1, data[offset]); |             od.className = data.GetString(offset + 1, data[offset]); | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ namespace Esiur.Resource.Template | |||||||
|     { |     { | ||||||
|         public DataType Type { get; set; } |         public DataType Type { get; set; } | ||||||
|         //public string TypeName { get; set; } |         //public string TypeName { get; set; } | ||||||
|         public  ResourceTemplate TypeTemplate => TypeGuid == null ? null : Warehouse.GetTemplate((Guid)TypeGuid); |         public  ResourceTemplate TypeTemplate => TypeGuid == null ? null : Warehouse.GetTemplateByClassId((Guid)TypeGuid); | ||||||
|  |  | ||||||
|         public Guid? TypeGuid { get; set; } |         public Guid? TypeGuid { get; set; } | ||||||
|         //public TemplateDataType(DataType type, string typeName) |         //public TemplateDataType(DataType type, string typeName) | ||||||
| @@ -51,20 +51,14 @@ namespace Esiur.Resource.Template | |||||||
|                 _ when t == typeof(IResource) => DataType.Void, // Dynamic resource (unspecified type) |                 _ when t == typeof(IResource) => DataType.Void, // Dynamic resource (unspecified type) | ||||||
|                 _ when typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject) => DataType.Structure, |                 _ when typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject) => DataType.Structure, | ||||||
|                 _ when Codec.ImplementsInterface(t, typeof(IResource)) => DataType.Resource, |                 _ when Codec.ImplementsInterface(t, typeof(IResource)) => DataType.Resource, | ||||||
|  |                 _ when Codec.ImplementsInterface(t, typeof(IRecord)) => DataType.Record, | ||||||
|                 _ => DataType.Void |                 _ => DataType.Void | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|  |  | ||||||
|             //string tn = dt switch |  | ||||||
|             //{ |  | ||||||
|             //    DataType.Resource => t.FullName, |  | ||||||
|             //    DataType.Structure when t != typeof(Structure)  => t.FullName, |  | ||||||
|             //    _ => null |  | ||||||
|             //}; |  | ||||||
|  |  | ||||||
|             Guid? typeGuid = null; |             Guid? typeGuid = null; | ||||||
|  |  | ||||||
|             if (dt == DataType.Resource) |             if (dt == DataType.Resource || dt == DataType.Record) | ||||||
|                 typeGuid = ResourceTemplate.GetTypeGuid(t); |                 typeGuid = ResourceTemplate.GetTypeGuid(t); | ||||||
|  |  | ||||||
|             if (type.IsArray) |             if (type.IsArray) | ||||||
| @@ -80,11 +74,9 @@ namespace Esiur.Resource.Template | |||||||
|         public byte[] Compose() |         public byte[] Compose() | ||||||
|         { |         { | ||||||
|             if (Type == DataType.Resource || |             if (Type == DataType.Resource || | ||||||
|                 Type == DataType.ResourceArray)//|| |                 Type == DataType.ResourceArray || | ||||||
|                                                //Type == DataType.DistributedResource || |                 Type == DataType.Record || | ||||||
|                                                //Type == DataType.DistributedResourceArray || |                 Type == DataType.RecordArray) | ||||||
|                                                //Type == DataType.Structure || |  | ||||||
|                                                //Type == DataType.StructureArray) |  | ||||||
|             { |             { | ||||||
|                 var guid = DC.ToBytes((Guid)TypeGuid); |                 var guid = DC.ToBytes((Guid)TypeGuid); | ||||||
|                 return new BinaryList() |                 return new BinaryList() | ||||||
| @@ -102,11 +94,9 @@ namespace Esiur.Resource.Template | |||||||
|         { |         { | ||||||
|             var type = (DataType)data[offset++]; |             var type = (DataType)data[offset++]; | ||||||
|             if (type == DataType.Resource || |             if (type == DataType.Resource || | ||||||
|                 type == DataType.ResourceArray)//|| |                 type == DataType.ResourceArray || | ||||||
|                                                // type == DataType.DistributedResource || |                 type == DataType.Record || | ||||||
|                                                // type == DataType.DistributedResourceArray)// || |                 type == DataType.RecordArray) | ||||||
|                                                // type == DataType.Structure || |  | ||||||
|                                                // type == DataType.StructureArray) |  | ||||||
|             { |             { | ||||||
|                 var guid = data.GetGuid(offset); |                 var guid = data.GetGuid(offset); | ||||||
|                 return (17, new TemplateDataType() { Type = type, TypeGuid = guid }); |                 return (17, new TemplateDataType() { Type = type, TypeGuid = guid }); | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								Esiur/Resource/Template/TemplateType.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								Esiur/Resource/Template/TemplateType.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Text; | ||||||
|  |  | ||||||
|  | namespace Esiur.Resource.Template | ||||||
|  | { | ||||||
|  |     public enum TemplateType:byte | ||||||
|  |     { | ||||||
|  |         Resource, | ||||||
|  |         Record, | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -54,6 +54,7 @@ namespace Esiur.Resource | |||||||
|         static uint resourceCounter = 0; |         static uint resourceCounter = 0; | ||||||
|  |  | ||||||
|         static KeyList<Guid, ResourceTemplate> templates = new KeyList<Guid, ResourceTemplate>(); |         static KeyList<Guid, ResourceTemplate> templates = new KeyList<Guid, ResourceTemplate>(); | ||||||
|  |         static KeyList<Guid, ResourceTemplate> wrapperTemplates = new KeyList<Guid, ResourceTemplate>(); | ||||||
|  |  | ||||||
|         static bool warehouseIsOpen = false; |         static bool warehouseIsOpen = false; | ||||||
|  |  | ||||||
| @@ -120,8 +121,14 @@ namespace Esiur.Resource | |||||||
|                 var generatedType = assembly.GetType("Esiur.Generated"); |                 var generatedType = assembly.GetType("Esiur.Generated"); | ||||||
|                 if (generatedType != null) |                 if (generatedType != null) | ||||||
|                 { |                 { | ||||||
|                     var types = (Type[])generatedType.GetProperty("Types").GetValue(null); |                     var resourceTypes = (Type[])generatedType.GetProperty("Resources").GetValue(null); | ||||||
|                     foreach (var t in types) |                     foreach (var t in resourceTypes) | ||||||
|  |                     { | ||||||
|  |                         PutTemplate(new ResourceTemplate(t), true); | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     var recordTypes = (Type[])generatedType.GetProperty("Records").GetValue(null); | ||||||
|  |                     foreach (var t in recordTypes) | ||||||
|                     { |                     { | ||||||
|                         PutTemplate(new ResourceTemplate(t)); |                         PutTemplate(new ResourceTemplate(t)); | ||||||
|                     } |                     } | ||||||
| @@ -730,9 +737,14 @@ namespace Esiur.Resource | |||||||
|         /// Put a resource template in the templates warehouse. |         /// Put a resource template in the templates warehouse. | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <param name="template">Resource template.</param> |         /// <param name="template">Resource template.</param> | ||||||
|         public static void PutTemplate(ResourceTemplate template) |         public static void PutTemplate(ResourceTemplate template, bool wrapper = false) | ||||||
|         { |         { | ||||||
|             if (!templates.ContainsKey(template.ClassId)) |             if (wrapper) | ||||||
|  |             { | ||||||
|  |                 if (!wrapperTemplates.ContainsKey(template.ClassId)) | ||||||
|  |                     wrapperTemplates.Add(template.ClassId, template); | ||||||
|  |             } | ||||||
|  |             else if (!templates.ContainsKey(template.ClassId)) | ||||||
|                 templates.Add(template.ClassId, template); |                 templates.Add(template.ClassId, template); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -742,18 +754,19 @@ namespace Esiur.Resource | |||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <param name="type">.Net type.</param> |         /// <param name="type">.Net type.</param> | ||||||
|         /// <returns>Resource template.</returns> |         /// <returns>Resource template.</returns> | ||||||
|         public static ResourceTemplate GetTemplate(Type type) |         public static ResourceTemplate GetTemplateByType(Type type) | ||||||
|         { |         { | ||||||
|              |              | ||||||
|             if (!Codec.ImplementsInterface(type, typeof(IResource))) |             if (!(Codec.ImplementsInterface(type, typeof(IResource))  | ||||||
|  |                 || Codec.ImplementsInterface(type, typeof(IRecord)))) | ||||||
|                 return null; |                 return null; | ||||||
|  |  | ||||||
|             var baseType = ResourceProxy.GetBaseType(type); |             var baseType = ResourceProxy.GetBaseType(type); | ||||||
|  |  | ||||||
|             if (baseType == typeof(IResource) ) |             if (baseType == typeof(IResource)  | ||||||
|  |                 || baseType == typeof(IRecord)) | ||||||
|                 return null; |                 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) | ||||||
| @@ -770,10 +783,16 @@ 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 ResourceTemplate GetTemplate(Guid classId) |         public static ResourceTemplate GetTemplateByClassId(Guid classId, bool wrapper = false) | ||||||
|         { |         { | ||||||
|             if (templates.ContainsKey(classId)) |             if (wrapper) | ||||||
|  |             { | ||||||
|  |                 if (wrapperTemplates.ContainsKey(classId)) | ||||||
|  |                     return wrapperTemplates[classId]; | ||||||
|  |             } | ||||||
|  |             else if (templates.ContainsKey(classId)) | ||||||
|                 return templates[classId]; |                 return templates[classId]; | ||||||
|  |  | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -782,7 +801,7 @@ namespace Esiur.Resource | |||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <param name="className">Class name.</param> |         /// <param name="className">Class name.</param> | ||||||
|         /// <returns>Resource template.</returns> |         /// <returns>Resource template.</returns> | ||||||
|         public static AsyncReply<ResourceTemplate> GetTemplate(string className) |         public static AsyncReply<ResourceTemplate> GetTemplateByClassName(string className) | ||||||
|         { |         { | ||||||
|             foreach (var t in templates.Values) |             foreach (var t in templates.Values) | ||||||
|                 if (t.ClassName == className) |                 if (t.ClassName == className) | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								Esiur/Tools/Esiur.psd1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Esiur/Tools/Esiur.psd1
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										115
									
								
								Esiur/Tools/Esiur.psm1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								Esiur/Tools/Esiur.psm1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,115 @@ | |||||||
|  | function Get-Template($url, $dir, $username, $password) | ||||||
|  | { | ||||||
|  |  | ||||||
|  |    $lib = Resolve-Path -Path "$($PSScriptRoot)\..\lib\netstandard2.0\Esiur.dll"             | ||||||
|  |    #write-host "Lib is at $($lib)" | ||||||
|  |  | ||||||
|  |    $assembly =  [Reflection.Assembly]::LoadFile($lib) | ||||||
|  |    $tempPath =  [Esiur.Proxy.TemplateGenerator]::GetTemplate($url, $dir, $username,$password);   | ||||||
|  |    | ||||||
|  |   $startupProject = GetStartupProject | ||||||
|  |    | ||||||
|  | 	$activeConfiguration = $startupProject.ConfigurationManager.ActiveConfiguration | ||||||
|  |     if ($activeConfiguration -eq $null) | ||||||
|  |     { | ||||||
|  |         throw "Unable to read project configuration settings of project '$($startupProject.ProjectName)' for the " + | ||||||
|  |             'active solution configuration. Try closing Package Manager Console and restarting Visual Studio. If the ' + | ||||||
|  |             'problem persists, use Help > Send Feedback > Report a Problem.' | ||||||
|  |     } | ||||||
|  | 	 | ||||||
|  | 	 | ||||||
|  |     $startupProject.ProjectItems.AddFromDirectory($tempPath) | Out-Null	 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function GetStartupProject($name, $fallbackProject) | ||||||
|  | { | ||||||
|  |     if ($name) | ||||||
|  |     { | ||||||
|  |         return Get-Project $name | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $startupProjectPaths = $DTE.Solution.SolutionBuild.StartupProjects | ||||||
|  |     if ($startupProjectPaths) | ||||||
|  |     { | ||||||
|  |         if ($startupProjectPaths.Length -eq 1) | ||||||
|  |         { | ||||||
|  |             $startupProjectPath = $startupProjectPaths[0] | ||||||
|  |             if (![IO.Path]::IsPathRooted($startupProjectPath)) | ||||||
|  |             { | ||||||
|  |                 $solutionPath = Split-Path (GetProperty $DTE.Solution.Properties 'Path') | ||||||
|  |                 $startupProjectPath = [IO.Path]::GetFullPath((Join-Path $solutionPath $startupProjectPath)) | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $startupProject = GetSolutionProjects | ?{ | ||||||
|  |                 try | ||||||
|  |                 { | ||||||
|  |                     $fullName = $_.FullName | ||||||
|  |                 } | ||||||
|  |                 catch [NotImplementedException] | ||||||
|  |                 { | ||||||
|  |                     return $false | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if ($fullName -and $fullName.EndsWith('\')) | ||||||
|  |                 { | ||||||
|  |                     $fullName = $fullName.Substring(0, $fullName.Length - 1) | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 return $fullName -eq $startupProjectPath | ||||||
|  |             } | ||||||
|  |             if ($startupProject) | ||||||
|  |             { | ||||||
|  |                 return $startupProject | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             Write-Warning "Unable to resolve startup project '$startupProjectPath'." | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             Write-Warning 'Multiple startup projects set.' | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         Write-Warning 'No startup project set.' | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Write-Warning "Using project '$($fallbackProject.ProjectName)' as the startup project." | ||||||
|  |  | ||||||
|  |     return $fallbackProject | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function GetProperty($properties, $propertyName) | ||||||
|  | { | ||||||
|  |     try | ||||||
|  |     { | ||||||
|  |         return $properties.Item($propertyName).Value | ||||||
|  |     } | ||||||
|  |     catch | ||||||
|  |     { | ||||||
|  |         return $null | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function GetSolutionProjects() | ||||||
|  | { | ||||||
|  |     $projects = New-Object 'System.Collections.Stack' | ||||||
|  |  | ||||||
|  |     $DTE.Solution.Projects | %{ | ||||||
|  |         $projects.Push($_) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     while ($projects.Count) | ||||||
|  |     { | ||||||
|  |         $project = $projects.Pop(); | ||||||
|  |  | ||||||
|  |         <# yield return #> $project | ||||||
|  |  | ||||||
|  |         if ($project.ProjectItems) | ||||||
|  |         { | ||||||
|  |             $project.ProjectItems | ?{ $_.SubProject } | %{ | ||||||
|  |                 $projects.Push($_.SubProject) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										36
									
								
								Esiur/Tools/init.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								Esiur/Tools/init.ps1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | |||||||
|  |  | ||||||
|  | param($installPath, $toolsPath, $package, $project) | ||||||
|  |  | ||||||
|  | # NB: Not set for scripts in PowerShell 2.0 | ||||||
|  | if (!$PSScriptRoot) | ||||||
|  | { | ||||||
|  |     $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent | ||||||
|  | } | ||||||
|  |  | ||||||
|  | if ($PSVersionTable.PSVersion -lt '3.0') | ||||||
|  | { | ||||||
|  |     # Import a "dummy" module that contains matching functions that throw on PS2 | ||||||
|  |     Import-Module (Join-Path $PSScriptRoot 'Esiur.psd1') -DisableNameChecking | ||||||
|  |  | ||||||
|  |     return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | $importedModule = Get-Module 'Esiur' | ||||||
|  | $moduleToImport = Test-ModuleManifest (Join-Path $PSScriptRoot 'Esiur.psd1') | ||||||
|  | $import = $true | ||||||
|  | if ($importedModule) | ||||||
|  | { | ||||||
|  |     if ($importedModule.Version -le $moduleToImport.Version) | ||||||
|  |     { | ||||||
|  |         Remove-Module 'Esiur' | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         $import = $false | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | if ($import) | ||||||
|  | { | ||||||
|  |     Import-Module $moduleToImport -DisableNameChecking | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user