diff --git a/Esiur.Stores.EntityCore/EntityStore.cs b/Esiur.Stores.EntityCore/EntityStore.cs index f7d38b3..a8ae58e 100644 --- a/Esiur.Stores.EntityCore/EntityStore.cs +++ b/Esiur.Stores.EntityCore/EntityStore.cs @@ -39,6 +39,11 @@ public class EntityStore : IStore { public Instance Instance { get; set; } + bool initialized = false; + + + public bool Initialized => initialized; + public event DestroyedEvent OnDestroy; Dictionary> DB = new Dictionary>(); @@ -92,6 +97,9 @@ public class EntityStore : IStore public IResource GetById(Type type, object id) { + if (!initialized) + throw new Exception("Store not initalized. Make sure the Warehouse is open."); + lock (DBLock) { if (!DB[type].ContainsKey(id)) @@ -136,13 +144,13 @@ public class EntityStore : IStore return this.Instance.Name + "/" + type.Name; } - public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + public bool Record(IResource resource, string propertyName, object value, ulong? age, DateTime? dateTime) { return true; //throw new NotImplementedException(); } - public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + public bool Modify(IResource resource, string propertyName, object value, ulong? age, DateTime? dateTime) { return true; //throw new NotImplementedException(); @@ -201,6 +209,8 @@ public class EntityStore : IStore ReloadModel(); + + initialized = true; } return new AsyncReply(true); diff --git a/Esiur.Stores.EntityCore/Esiur.Stores.EntityCore.csproj b/Esiur.Stores.EntityCore/Esiur.Stores.EntityCore.csproj index e8489f9..932b4ab 100644 --- a/Esiur.Stores.EntityCore/Esiur.Stores.EntityCore.csproj +++ b/Esiur.Stores.EntityCore/Esiur.Stores.EntityCore.csproj @@ -9,7 +9,7 @@ Esiur Entity Framework Extension true Esiur.Stores.EntityCore - 1.2.5 + 1.2.9 latest @@ -22,7 +22,7 @@ - + diff --git a/Esiur.Stores.EntityCore/EsiurExtensions.cs b/Esiur.Stores.EntityCore/EsiurExtensions.cs index fbdaaa9..8f76ec8 100644 --- a/Esiur.Stores.EntityCore/EsiurExtensions.cs +++ b/Esiur.Stores.EntityCore/EsiurExtensions.cs @@ -54,6 +54,8 @@ public static class EsiurExtensions { var store = dbSet.GetInfrastructure().GetService().FindExtension().Store; + if (!store.Initialized) + throw new Exception("Store not initialized. Make sure the Warehouse is open"); var manager = store.Instance.Managers.FirstOrDefault();// > 0 ? store.Instance.Managers.First() : null; @@ -75,7 +77,7 @@ public static class EsiurExtensions else { res = Activator.CreateInstance(proxyType) as IResource; - var ps = Structure.FromObject(resource); + var ps = Map.FromObject(resource); foreach (var p in ps) { diff --git a/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj b/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj index 57a5d85..082f478 100644 --- a/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj +++ b/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj @@ -11,7 +11,7 @@ http://www.esiur.com https://github.com/esiur/esiur-dotnet/ True - 1.5.2 + 1.5.4 Esiur.Stores.MongoDB latest diff --git a/Esiur.Stores.MongoDB/MongoDBStore.cs b/Esiur.Stores.MongoDB/MongoDBStore.cs index 3d72ec7..67567d7 100644 --- a/Esiur.Stores.MongoDB/MongoDBStore.cs +++ b/Esiur.Stores.MongoDB/MongoDBStore.cs @@ -83,7 +83,7 @@ public class MongoDBStore : IStore }*/ - public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime date) + public bool Record(IResource resource, string propertyName, object value, ulong? age, DateTime? date) { var objectId = resource.Instance.Variables["objectId"].ToString(); //var bsonObjectId = new BsonObjectId(new ObjectId(objectId)); @@ -168,7 +168,7 @@ public class MongoDBStore : IStore var attributes = Parse(document["attributes"]).Then(x => { - resource.Instance.SetAttributes(x as Structure); + resource.Instance.SetAttributes(x as Map); }); // var bag = new AsyncBag(); @@ -230,10 +230,10 @@ public class MongoDBStore : IStore else if (doc["type"] == 1) { var bag = new AsyncBag(); - var rt = new AsyncReply(); + var rt = new AsyncReply>(); var bs = (BsonDocument)doc["values"].AsBsonDocument; - var s = new Structure(); + var s = new Map(); foreach (var v in bs) bag.Add(Parse(v.Value)); @@ -414,7 +414,7 @@ public class MongoDBStore : IStore } } - public BsonDocument ComposeStructure(Structure value) + public BsonDocument ComposeStructure(Map value) { var rt = new BsonDocument { { "type", 1 } }; @@ -436,7 +436,7 @@ public class MongoDBStore : IStore return rt; } - BsonArray ComposeStructureArray(Structure[] structures) + BsonArray ComposeStructureArray(Map[] structures) { var rt = new BsonArray(); @@ -466,44 +466,48 @@ public class MongoDBStore : IStore private BsonValue Compose(object valueObj) { - var (type, value) = Codec.GetDataType(valueObj, null); - switch (type) - { - case DataType.Void: - // nothing to do; - return BsonNull.Value; + //@TODO : Rewrite + //var (type, value) = Tra Codec.GetDataType(valueObj, null); - case DataType.String: - return new BsonString((string)value); + //switch (type) + //{ + // case DataType.Void: + // // nothing to do; + // return BsonNull.Value; - case DataType.Resource: - case DataType.DistributedResource: + // case DataType.String: + // return new BsonString((string)value); - return new BsonDocument { { "type", 0 }, { "link", (value as IResource).Instance.Link } }; + // case DataType.Resource: + // case DataType.DistributedResource: - //return new BsonObjectId(new ObjectId((string)(value as IResource).Instance.Variables["objectId"])); + // return new BsonDocument { { "type", 0 }, { "link", (value as IResource).Instance.Link } }; - case DataType.Structure: - return ComposeStructure((Structure)value); + // //return new BsonObjectId(new ObjectId((string)(value as IResource).Instance.Variables["objectId"])); - case DataType.VarArray: - return ComposeVarArray((Array)value); + // case DataType.Structure: + // return ComposeStructure((Structure)value); - case DataType.ResourceArray: - if (value is IResource[]) - return ComposeResourceArray((IResource[])value); - else - return ComposeResourceArray((IResource[])DC.CastConvert(value, typeof(IResource[]))); + // case DataType.VarArray: + // return ComposeVarArray((Array)value); + + // case DataType.ResourceArray: + // if (value is IResource[]) + // return ComposeResourceArray((IResource[])value); + // else + // return ComposeResourceArray((IResource[])DC.CastConvert(value, typeof(IResource[]))); - case DataType.StructureArray: - return ComposeStructureArray((Structure[])value); + // case DataType.StructureArray: + // return ComposeStructureArray((Structure[])value); - default: - return BsonValue.Create(value); - } + // default: + // return BsonValue.Create(value); + //} + + return BsonValue.Create(valueObj); } public AsyncReply Retrieve(uint iid) @@ -776,7 +780,7 @@ public class MongoDBStore : IStore return reply; } - public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + public bool Modify(IResource resource, string propertyName, object value, ulong? age, DateTime? dateTime) { if (resource == this) diff --git a/Esiur.rar b/Esiur.rar new file mode 100644 index 0000000..9390d0e Binary files /dev/null and b/Esiur.rar differ diff --git a/Esiur.sln b/Esiur.sln index 16a18fd..104e119 100644 --- a/Esiur.sln +++ b/Esiur.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29324.140 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31919.166 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Esiur", "Esiur\Esiur.csproj", "{4F74A8C1-D38F-4CC0-ACD1-24459BA0EAFC}" EndProject @@ -8,6 +8,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Esiur.Stores.MongoDB", "Esi EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Esiur.Stores.EntityCore", "Esiur.Stores.EntityCore\Esiur.Stores.EntityCore.csproj", "{53DE5A30-CFA9-4DE7-A840-77CFF519D31B}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{331F82B6-6B90-4533-9718-F7C8090D8F19}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -26,6 +28,10 @@ Global {53DE5A30-CFA9-4DE7-A840-77CFF519D31B}.Debug|Any CPU.Build.0 = Debug|Any CPU {53DE5A30-CFA9-4DE7-A840-77CFF519D31B}.Release|Any CPU.ActiveCfg = Release|Any CPU {53DE5A30-CFA9-4DE7-A840-77CFF519D31B}.Release|Any CPU.Build.0 = Release|Any CPU + {331F82B6-6B90-4533-9718-F7C8090D8F19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {331F82B6-6B90-4533-9718-F7C8090D8F19}.Debug|Any CPU.Build.0 = Debug|Any CPU + {331F82B6-6B90-4533-9718-F7C8090D8F19}.Release|Any CPU.ActiveCfg = Release|Any CPU + {331F82B6-6B90-4533-9718-F7C8090D8F19}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Esiur/Core/AsyncAwaiterGeneric.cs b/Esiur/Core/AsyncAwaiterGeneric.cs index e0d5c2e..394faa8 100644 --- a/Esiur/Core/AsyncAwaiterGeneric.cs +++ b/Esiur/Core/AsyncAwaiterGeneric.cs @@ -32,7 +32,7 @@ public class AsyncAwaiter : INotifyCompletion public T GetResult() { if (exception != null) - throw exception; + throw exception; return result; } diff --git a/Esiur/Core/AsyncBag.cs b/Esiur/Core/AsyncBag.cs index add2c61..ab596e6 100644 --- a/Esiur/Core/AsyncBag.cs +++ b/Esiur/Core/AsyncBag.cs @@ -30,37 +30,42 @@ using System.Threading.Tasks; namespace Esiur.Core; -public class AsyncBag : AsyncReply +interface IAsyncBag +{ + public void Add(AsyncReply reply); +} + +public class AsyncBag : AsyncReply, IAsyncBag { protected List replies = new List(); - List results = new List(); + List results = new(); int count = 0; bool sealedBag = false; - public Type ArrayType { get; set; } + public virtual Type ArrayType { get; set; } = typeof(T); - public AsyncBag Then(Action callback) + public AsyncBag Then(Action callback) { - base.Then(new Action(o => callback((object[])o))); + base.Then(new Action(o => callback((T[])o))); return this; } - public new AsyncBagAwaiter GetAwaiter() + public new AsyncBagAwaiter GetAwaiter() { - return new AsyncBagAwaiter(this); + return new AsyncBagAwaiter(this); } - public new object[] Wait() + public new T[] Wait() { - return (object[])base.Wait(); + return (T[])base.Wait(); } - public new object[] Wait(int timeout) + public new T[] Wait(int timeout) { - return (object[])base.Wait(timeout); + return (T[])base.Wait(timeout); } public void Seal() @@ -71,7 +76,17 @@ public class AsyncBag : AsyncReply sealedBag = true; if (results.Count == 0) - Trigger(new object[0]); + { + if (ArrayType != null) + { + var ar = Array.CreateInstance(ArrayType, 0); + Trigger(ar); + } + else + { + Trigger(new object[0]); + } + } for (var i = 0; i < results.Count; i++) //foreach(var reply in results.Keys) @@ -81,16 +96,24 @@ public class AsyncBag : AsyncReply k.Then((r) => { - results[index] = r; + results[index] = (T)r; count++; if (count == results.Count) { if (ArrayType != null) { - var ar = Array.CreateInstance(ArrayType, count); - for (var i = 0; i < count; i++) - ar.SetValue(results[i], i); - Trigger(ar); + try + { + // @TODO: Safe casting check + var ar = Array.CreateInstance(ArrayType, count); + for (var i = 0; i < count; i++) + ar.SetValue(results[i], i); + Trigger(ar); + } + catch + { + Trigger(results.ToArray()); + } } else Trigger(results.ToArray()); @@ -103,12 +126,12 @@ public class AsyncBag : AsyncReply { if (!sealedBag) { - results.Add(null); + results.Add(default(T)); replies.Add(reply); } } - public void AddBag(AsyncBag bag) + public void AddBag(AsyncBag bag) { foreach (var r in bag.replies) Add(r); @@ -121,10 +144,11 @@ public class AsyncBag : AsyncReply } - public AsyncBag(object[] results) + public AsyncBag(T[] results) : base(results) { } + } diff --git a/Esiur/Core/AsyncBagAwaiter.cs b/Esiur/Core/AsyncBagAwaiter.cs index ec389c6..c60d947 100644 --- a/Esiur/Core/AsyncBagAwaiter.cs +++ b/Esiur/Core/AsyncBagAwaiter.cs @@ -6,15 +6,15 @@ using System.Threading.Tasks; namespace Esiur.Core; -public class AsyncBagAwaiter : INotifyCompletion +public class AsyncBagAwaiter : INotifyCompletion { Action callback = null; AsyncException exception = null; - object[] result; + T[] result; - public AsyncBagAwaiter(AsyncBag reply) + public AsyncBagAwaiter(AsyncBag reply) { reply.Then(x => { @@ -29,7 +29,7 @@ public class AsyncBagAwaiter : INotifyCompletion }); } - public object[] GetResult() + public T[] GetResult() { if (exception != null) throw exception; diff --git a/Esiur/Core/AsyncBagGeneric.cs b/Esiur/Core/AsyncBagGeneric.cs index 240c1a5..f6feddb 100644 --- a/Esiur/Core/AsyncBagGeneric.cs +++ b/Esiur/Core/AsyncBagGeneric.cs @@ -34,10 +34,13 @@ public class AsyncBag : AsyncBag { public AsyncBag Then(Action callback) { - base.Then(new Action((o) => callback(((object[])o).Select(x => (T)x).ToArray()))); + //base.Then(new Action((o) => callback(((object[])o).Select(x => (T)x).ToArray()))); + base.Then(x => callback((T[])x)); + return this; } + public override Type ArrayType => typeof(T); public void Add(AsyncReply reply) { @@ -58,9 +61,15 @@ public class AsyncBag : AsyncBag public new T[] Wait() { - return base.Wait().Select(x => (T)x).ToArray(); + return (T[])base.Wait();// base.Wait().Select(x => (T)x).ToArray(); } + public new T[] Wait(int timeout) + { + return (T[])base.Wait(timeout); + } + + public AsyncBag() { diff --git a/Esiur/Data/BinaryList.cs b/Esiur/Data/BinaryList.cs index f738841..55d2593 100644 --- a/Esiur/Data/BinaryList.cs +++ b/Esiur/Data/BinaryList.cs @@ -47,170 +47,7 @@ public class BinaryList } - /* - /// - /// Converts parameters to binary in same order - /// - /// Variables to convert - public static byte[] ToBytes(params object[] values) - { - var list = new List(); - - foreach (var i in values) - { - if (i is byte) - list.Add((byte)i); - else - { -#if NETSTANDARD - MethodInfo mi = typeof(DC).GetTypeInfo().GetMethod("ToBytes", new Type[] { i.GetType() }); -#else - MethodInfo mi = typeof(DC).GetMethod("ToBytes", new Type[] { i.GetType() }); -#endif - if (mi != null) - { - var b = (byte[])mi.Invoke(null, new object[] { i }); - list.AddRange(b); - } - } - } - - return list.ToArray(); - } - - - /// - /// Create a new instance of BinaryList - /// - /// Populate the list items - public BinaryList(params object[] values) - { - AddRange(values); - } - - /// - /// Add an array of items at the end of the list - /// - /// Array of items - public void AddRange(object[] values) - { - foreach (var i in values) - { - if (i is byte) - list.Add((byte)i); - else - { -#if NETSTANDARD - MethodInfo mi = typeof(DC).GetTypeInfo().GetMethod("ToBytes", new Type[] { i.GetType() }); -#else - MethodInfo mi = typeof(DC).GetMethod("ToBytes", new Type[] { i.GetType() }); -#endif - if (mi != null) - { - var b = (byte[])mi.Invoke(null, new object[] {i}); - list.AddRange(b); - } - } - } - } - - /// - /// Add multiple items at the end of the list - /// - /// Parameters of items - public void Append(params object[] values) - { - AddRange(values); - } - - /// - /// Insert new items to the list at a specified index - /// - /// Position in the list - /// Items to insert - public void Insert(int offset, params object[] values) - { - foreach (var i in values) - { - if (i is byte) - { - list.Insert(offset++, (byte)i); - } - else - { -#if NETSTANDARD - MethodInfo mi = typeof(DC).GetTypeInfo().GetMethod("ToBytes", new Type[] { i.GetType() }); -#else - MethodInfo mi = typeof(DC).GetMethod("ToBytes", new Type[] { i.GetType() }); -#endif - if (mi != null) - { - var b = (byte[])mi.Invoke(null, new object[] { i }); - list.InsertRange(offset, b); - offset += b.Length; - } - } - } - } - - /// - /// Number of the items in the list - /// - public int Length - { - get - { - return list.Count; - } - } - - /* - public void Append(byte data) - { - list.Add(data); - } - - public void Append(byte[] data) - { - list.AddRange(data); - } - - public void Append(int data) - { - list.AddRange(DC.ToBytes(data)); - } - - public void Append(uint data) - { - list.AddRange(DC.ToBytes(data)); - } - - public void Append(float data) - { - list.AddRange(DC.ToBytes(data)); - } - - public void Append(short data) - { - list.AddRange(DC.ToBytes(data)); - } - - public void Append(ushort data) - { - list.AddRange(DC.ToBytes(data)); - } - - public void Append(double data) - { - list.AddRange(DC.ToBytes(data)); - } - - public void Append(sbyte data) - { - list.Add((byte)data); - } - */ - + public Endian Endian { get; set; } = Endian.Little; public int Length => list.Count; @@ -227,18 +64,6 @@ public class BinaryList } - public BinaryList AddDateTimeArray(DateTime[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertDateTimeArray(int position, DateTime[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - public BinaryList AddGuid(Guid value) { list.AddRange(DC.ToBytes(value)); @@ -251,18 +76,7 @@ public class BinaryList return this; } - public BinaryList AddGuidArray(Guid[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertGuidArray(int position, Guid[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - + public BinaryList AddUInt8Array(byte[] value) { @@ -302,18 +116,7 @@ public class BinaryList return this; } - public BinaryList AddStringArray(string[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertStringArray(int position, string[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - + public BinaryList InsertUInt8(int position, byte value) { list.Insert(position, value); @@ -338,17 +141,7 @@ public class BinaryList return this; } - public BinaryList AddInt8Array(sbyte[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - public BinaryList InsertInt8Array(int position, sbyte[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } public BinaryList AddChar(char value) @@ -363,20 +156,7 @@ public class BinaryList return this; } - public BinaryList AddCharArray(char[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertCharArray(int position, char[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - - public BinaryList AddBoolean(bool value) + public BinaryList AddBoolean(bool value) { list.AddRange(DC.ToBytes(value)); return this; @@ -388,314 +168,106 @@ public class BinaryList return this; } - public BinaryList AddBooleanArray(bool[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertBooleanArray(int position, bool[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - public BinaryList AddUInt16(ushort value) { - list.AddRange(DC.ToBytes(value)); + list.AddRange(DC.ToBytes(value, Endian)); return this; } public BinaryList InsertUInt16(int position, ushort value) { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - public BinaryList AddUInt16Array(ushort[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertUInt16Array(int position, ushort[] value) - { - list.InsertRange(position, DC.ToBytes(value)); + list.InsertRange(position, DC.ToBytes(value, Endian)); return this; } public BinaryList AddInt16(short value) { - list.AddRange(DC.ToBytes(value)); + list.AddRange(DC.ToBytes(value, Endian)); return this; } public BinaryList InsertInt16(int position, short value) { - list.InsertRange(position, DC.ToBytes(value)); + list.InsertRange(position, DC.ToBytes(value, Endian)); return this; } - public BinaryList AddInt16Array(short[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertInt16Array(int position, short[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - + public BinaryList AddUInt32(uint value) { - list.AddRange(DC.ToBytes(value)); + list.AddRange(DC.ToBytes(value, Endian)); return this; } public BinaryList InsertUInt32(int position, uint value) { - list.InsertRange(position, DC.ToBytes(value)); + list.InsertRange(position, DC.ToBytes(value, Endian)); return this; } - - public BinaryList AddUInt32Array(uint[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - public BinaryList InsertUInt32Array(int position, uint[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - + public BinaryList AddInt32(int value) { - list.AddRange(DC.ToBytes(value)); + list.AddRange(DC.ToBytes(value, Endian)); return this; } public BinaryList InsertInt32(int position, int value) { - list.InsertRange(position, DC.ToBytes(value)); + list.InsertRange(position, DC.ToBytes(value, Endian)); return this; } - public BinaryList AddInt32Array(int[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - public BinaryList InsertInt32Array(int position, int[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - public BinaryList AddUInt64(ulong value) { - list.AddRange(DC.ToBytes(value)); + list.AddRange(DC.ToBytes(value, Endian)); return this; } public BinaryList InsertUInt64(int position, ulong value) { - list.InsertRange(position, DC.ToBytes(value)); + list.InsertRange(position, DC.ToBytes(value, Endian)); return this; } - public BinaryList AddUInt64Array(ulong[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertUInt64Array(int position, ulong[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - - + public BinaryList AddInt64(long value) { - list.AddRange(DC.ToBytes(value)); + list.AddRange(DC.ToBytes(value, Endian)); return this; } public BinaryList InsertInt64(int position, long value) { - list.InsertRange(position, DC.ToBytes(value)); + list.InsertRange(position, DC.ToBytes(value, Endian)); return this; } - - public BinaryList AddInt64Array(long[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertInt64Array(int position, long[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - + public BinaryList AddFloat32(float value) { - list.AddRange(DC.ToBytes(value)); + list.AddRange(value.ToBytes(Endian)); return this; } public BinaryList InsertFloat32(int position, float value) { - list.InsertRange(position, DC.ToBytes(value)); + list.InsertRange(position, value.ToBytes(Endian)); return this; } - public BinaryList AddFloat32Array(float[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertFloat32Array(int position, float[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - + public BinaryList AddFloat64(double value) { - list.AddRange(DC.ToBytes(value)); + list.AddRange(value.ToBytes(Endian)); return this; } public BinaryList InsertFloat64(int position, double value) { - list.InsertRange(position, DC.ToBytes(value)); + list.InsertRange(position, value.ToBytes(Endian)); return this; } - - public BinaryList AddFloat64Array(double[] value) - { - list.AddRange(DC.ToBytes(value)); - return this; - } - - public BinaryList InsertFloat64Array(int position, double[] value) - { - list.InsertRange(position, DC.ToBytes(value)); - return this; - } - - - - public BinaryList Add(DataType type, object value) - { - switch (type) - { - case DataType.Bool: - AddBoolean((bool)value); - return this; - case DataType.BoolArray: - AddBooleanArray((bool[])value); - return this; - case DataType.UInt8: - AddUInt8((byte)value); - return this; - case DataType.UInt8Array: - AddUInt8Array((byte[])value); - return this; - case DataType.Int8: - AddInt8((sbyte)value); - return this; - case DataType.Int8Array: - AddInt8Array((sbyte[])value); - return this; - case DataType.Char: - AddChar((char)value); - return this; - case DataType.CharArray: - AddCharArray((char[])value); - return this; - case DataType.UInt16: - AddUInt16((ushort)value); - return this; - case DataType.UInt16Array: - AddUInt16Array((ushort[])value); - return this; - case DataType.Int16: - AddInt16((short)value); - return this; - case DataType.Int16Array: - AddInt16Array((short[])value); - return this; - case DataType.UInt32: - AddUInt32((uint)value); - return this; - case DataType.UInt32Array: - AddUInt32Array((uint[])value); - return this; - case DataType.Int32: - AddInt32((int)value); - return this; - case DataType.Int32Array: - AddInt32Array((int[])value); - return this; - case DataType.UInt64: - AddUInt64((ulong)value); - return this; - case DataType.UInt64Array: - AddUInt64Array((ulong[])value); - return this; - case DataType.Int64: - AddInt64((long)value); - return this; - case DataType.Int64Array: - AddInt64Array((long[])value); - return this; - - case DataType.Float32: - AddFloat32((float)value); - return this; - case DataType.Float32Array: - AddFloat32Array((float[])value); - return this; - - case DataType.Float64: - AddFloat64((double)value); - return this; - case DataType.Float64Array: - AddFloat64Array((double[])value); - return this; - - case DataType.String: - AddString((string)value); - return this; - case DataType.StringArray: - AddStringArray((string[])value); - return this; - - case DataType.DateTime: - AddDateTime((DateTime)value); - return this; - case DataType.DateTimeArray: - AddDateTimeArray((DateTime[])value); - return this; - - default: - throw new Exception("Not Implemented " + type.ToString()); - //return this; - } - } + /// /// Convert the list to an array of bytes /// @@ -708,6 +280,5 @@ public class BinaryList public virtual AsyncReply Done() { return null; - // } } diff --git a/Esiur/Data/Codec.cs b/Esiur/Data/Codec.cs index a3fbf27..bb6e708 100644 --- a/Esiur/Data/Codec.cs +++ b/Esiur/Data/Codec.cs @@ -42,631 +42,68 @@ namespace Esiur.Data; public static class Codec { - /// - /// Check if a DataType is an array - /// - /// DataType to check - /// True if DataType is an array, otherwise false - public static bool IsArray(this DataType type) + + delegate AsyncReply Parser(byte[] data, uint offset, uint length, DistributedConnection connection); + + + static Parser[][] FixedParsers = new Parser[][] { - return (((byte)type & 0x80) == 0x80) && (type != DataType.NotModified); - } + new Parser[]{ + DataDeserializer.NullParser, + DataDeserializer.BooleanFalseParser, + DataDeserializer.BooleanTrueParser, + DataDeserializer.NotModifiedParser, + }, + new Parser[]{ + DataDeserializer.ByteParser, + DataDeserializer.SByteParser, + DataDeserializer.Char8Parser, + }, + new Parser[]{ + DataDeserializer.Int16Parser, + DataDeserializer.UInt16Parser, + DataDeserializer.Char16Parser, + }, + new Parser[]{ + DataDeserializer.Int32Parser, + DataDeserializer.UInt32Parser, + DataDeserializer.Float32Parser, + DataDeserializer.ResourceParser, + DataDeserializer.LocalResourceParser, + }, + new Parser[]{ + DataDeserializer.Int64Parser, + DataDeserializer.UInt64Parser, + DataDeserializer.Float64Parser, + DataDeserializer.DateTimeParser, + }, + new Parser[] + { + DataDeserializer.Int128Parser, // int 128 + DataDeserializer.UInt128Parser, // uint 128 + DataDeserializer.Float128Parser, + } + }; - /// - /// Get the element DataType - /// - /// - /// Passing UInt8Array will return UInt8 - /// - /// DataType to get its element DataType - public static DataType GetElementType(this DataType type) + static Parser[] DynamicParsers = new Parser[] { - return (DataType)((byte)type & 0x7F); - } + DataDeserializer.RawDataParser, + DataDeserializer.StringParser, + DataDeserializer.ListParser, + DataDeserializer.ResourceListParser, + DataDeserializer.RecordListParser, + }; - /// - /// Get DataType array of a given Structure - /// - /// Structure to get its DataTypes - /// Distributed connection is required in case a type is at the other end - private static DataType[] GetStructureDateTypes(Structure structure, DistributedConnection connection) + static Parser[] TypedParsers = new Parser[] { - var keys = structure.GetKeys(); - var types = new DataType[keys.Length]; + DataDeserializer.RecordParser, + DataDeserializer.TypedListParser, + DataDeserializer.TypedMapParser, + DataDeserializer.TupleParser, + DataDeserializer.EnumParser, + DataDeserializer.ConstantParser, + }; - for (var i = 0; i < keys.Length; i++) - { - types[i] = Codec.GetDataType(structure[keys[i]], connection).type; - } - return types; - } - - /// - /// Compare two records - /// - /// Initial record to compare with - /// Next record to compare with the initial - /// DistributedConnection is required in case a structure holds items at the other end - 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; - } - - /// - /// Compare two structures - /// - /// Initial structure to compare with - /// Next structure to compare with the initial - /// DistributedConnection is required in case a structure holds items at the other end - public static StructureComparisonResult Compare(Structure initial, Structure next, DistributedConnection connection) - { - if (next == null) - return StructureComparisonResult.Null; - - if (initial == null) - return StructureComparisonResult.Structure; - - if (next == initial) - return StructureComparisonResult.Same; - - if (initial.Length != next.Length) - return StructureComparisonResult.Structure; - - var previousKeys = initial.GetKeys(); - var nextKeys = next.GetKeys(); - - for (var i = 0; i < previousKeys.Length; i++) - if (previousKeys[i] != nextKeys[i]) - return StructureComparisonResult.Structure; - - var previousTypes = GetStructureDateTypes(initial, connection); - var nextTypes = GetStructureDateTypes(next, connection); - - for (var i = 0; i < previousTypes.Length; i++) - if (previousTypes[i] != nextTypes[i]) - return StructureComparisonResult.StructureSameKeys; - - return StructureComparisonResult.StructureSameTypes; - } - - /// - /// Compose an array of structures into an array of bytes - /// - /// Array of Structure to compose - /// DistributedConnection is required in case a structure in the array holds items at the other end - /// If true, prepend the length as UInt32 at the beginning of the returned bytes array - /// Array of bytes in the network byte order - public static byte[] ComposeStructureArray(Structure[] structures, DistributedConnection connection, bool prependLength = false) - { - if (structures == null || structures?.Length == 0) - return prependLength ? new byte[] { 0, 0, 0, 0 } : new byte[0]; - - var rt = new BinaryList(); - var comparsion = StructureComparisonResult.Structure; - - rt.AddUInt8((byte)comparsion) - .AddUInt8Array(ComposeStructure(structures[0], connection, true, true, true)); - - for (var i = 1; i < structures.Length; i++) - { - comparsion = Compare(structures[i - 1], structures[i], connection); - rt.AddUInt8((byte)comparsion); - - if (comparsion == StructureComparisonResult.Structure) - rt.AddUInt8Array(ComposeStructure(structures[i], connection, true, true, true)); - else if (comparsion == StructureComparisonResult.StructureSameKeys) - rt.AddUInt8Array(ComposeStructure(structures[i], connection, false, true, true)); - else if (comparsion == StructureComparisonResult.StructureSameTypes) - rt.AddUInt8Array(ComposeStructure(structures[i], connection, false, false, true)); - } - - if (prependLength) - rt.InsertInt32(0, rt.Length); - - return rt.ToArray(); - } - - /// - /// Parse an array of structures - /// - /// Bytes array - /// Zero-indexed offset - /// Number of bytes to parse - /// DistributedConnection is required in case a structure in the array holds items at the other end - /// Array of structures - public static AsyncBag ParseStructureArray(byte[] data, uint offset, uint length, DistributedConnection connection) - { - var reply = new AsyncBag(); - if (length == 0) - { - reply.Seal(); - return reply; - } - - var end = offset + length; - - var result = (StructureComparisonResult)data[offset++]; - - AsyncReply previous = null; - // string[] previousKeys = null; - // DataType[] previousTypes = null; - - Structure.StructureMetadata metadata = new Structure.StructureMetadata(); - - - if (result == StructureComparisonResult.Null) - previous = new AsyncReply(null); - else if (result == StructureComparisonResult.Structure) - { - uint cs = data.GetUInt32(offset); - offset += 4; - previous = ParseStructure(data, offset, cs, connection, out metadata); - offset += cs; - } - - reply.Add(previous); - - - while (offset < end) - { - result = (StructureComparisonResult)data[offset++]; - - if (result == StructureComparisonResult.Null) - previous = new AsyncReply(null); - else if (result == StructureComparisonResult.Structure) - { - uint cs = data.GetUInt32(offset); - offset += 4; - previous = ParseStructure(data, offset, cs, connection, out metadata);// out previousKeys, out previousTypes); - offset += cs; - } - else if (result == StructureComparisonResult.StructureSameKeys) - { - uint cs = data.GetUInt32(offset); - offset += 4; - previous = ParseStructure(data, offset, cs, connection, out metadata, metadata.Keys); - offset += cs; - } - else if (result == StructureComparisonResult.StructureSameTypes) - { - uint cs = data.GetUInt32(offset); - offset += 4; - previous = ParseStructure(data, offset, cs, connection, out metadata, metadata.Keys, metadata.Types); - offset += cs; - } - - reply.Add(previous); - } - - reply.Seal(); - return reply; - } - - - public static AsyncBag ParseRecordArray(byte[] data, uint offset, uint length, DistributedConnection connection) - { - var reply = new AsyncBag(); - - if (length == 0) - { - reply.Seal(); - return reply; - } - - var end = offset + length; - - var isTyped = (data[offset] & 0x10) == 0x10; - - var result = (RecordComparisonResult)(data[offset++] & 0xF); - - if (isTyped) - { - var classId = data.GetGuid(offset); - offset += 16; - - var template = Warehouse.GetTemplateByClassId(classId, TemplateType.Record); - - reply.ArrayType = template?.DefinedType; - - AsyncReply previous = null; - - if (result == RecordComparisonResult.Null) - previous = new AsyncReply(null); - else if (result == RecordComparisonResult.Record - || result == RecordComparisonResult.RecordSameType) - { - uint cs = data.GetUInt32(offset); - uint recordLength = cs; - offset += 4; - 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(null); - else if (result == RecordComparisonResult.Record - || 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); - } - } - else - { - AsyncReply previous = null; - Guid? classId = null; - - if (result == RecordComparisonResult.Null) - previous = new AsyncReply(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(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 ParseRecord(byte[] data, uint offset, uint length, DistributedConnection connection, Guid? classId = null) - { - var reply = new AsyncReply(); - - if (classId == null) - { - classId = data.GetGuid(offset); - - offset += 16; - length -= 16; - } - - var template = Warehouse.GetTemplateByClassId((Guid)classId, TemplateType.Record); - - if (template != null) - { - ParseVarArray(data, offset, length, connection).Then(ar => - { - if (template.DefinedType != null) - { - var record = Activator.CreateInstance(template.DefinedType) 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(T[] records, DistributedConnection connection, bool prependLength = false) - where T : IRecord - { - - 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]); - - var type = records.GetType().GetElementType(); - var isTyped = type != typeof(IRecord); - - if (isTyped) - { - var template = Warehouse.GetTemplateByType(type); - - if (template != null) - { - // typed array ... no need to add class id , it will be included at the first entry - rt.AddUInt8((byte)(0x10 | (byte)comparsion)); - rt.AddGuid(template.ClassId); - } - else // something wrong - { - throw new Exception($"Template for type `{type.FullName}` not found."); - } - - if (comparsion == RecordComparisonResult.Record) - rt.AddUInt8Array(ComposeRecord(records[0], connection, false, true)); - - for (var i = 1; i < records.Length; i++) - { - comparsion = Compare(records[i - 1], records[i]); - - rt.AddUInt8((byte)comparsion); - - if (comparsion == RecordComparisonResult.RecordSameType - || comparsion == RecordComparisonResult.Record) - rt.AddUInt8Array(ComposeRecord(records[i], connection, false, true)); - } - } - else - { - 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(); - } - - /// - /// Compose a structure into an array of bytes - /// - /// Structure to compose - /// DistributedConnection is required in case an item in the structure is at the other end - /// Whether to include the structure keys - /// Whether to include each item DataType - /// If true, prepend the length as UInt32 at the beginning of the returned bytes array - /// Array of bytes in the network byte order - public static byte[] ComposeStructure(Structure value, DistributedConnection connection, - bool includeKeys = true, bool includeTypes = true, bool prependLength = false) - { - var rt = new BinaryList(); - - if (includeKeys) - { - foreach (var i in value) - { - var key = DC.ToBytes(i.Key); - rt.AddUInt8((byte)key.Length) - .AddUInt8Array(key) - .AddUInt8Array(Compose(i.Value, connection)); - } - } - else - { - foreach (var i in value) - rt.AddUInt8Array(Compose(i.Value, connection, includeTypes)); - } - - if (prependLength) - rt.InsertInt32(0, rt.Length); - - return rt.ToArray(); - } - - /// - /// Parse a structure - /// - /// Bytes array - /// Zero-indexed offset. - /// Number of bytes to parse. - /// DistributedConnection is required in case a structure in the array holds items at the other end. - /// Value - public static AsyncReply ParseStructure(byte[] data, uint offset, uint contentLength, DistributedConnection connection) - { - Structure.StructureMetadata metadata; - return ParseStructure(data, offset, contentLength, connection, out metadata); - } - - /// - /// Parse a structure - /// - /// Bytes array - /// Zero-indexed offset. - /// Number of bytes to parse. - /// DistributedConnection is required in case a structure in the array holds items at the other end. - /// Array to store keys in. - /// Array to store DataTypes in. - /// Array of keys, in case the data doesn't include keys - /// Array of DataTypes, in case the data doesn't include DataTypes - /// Structure - public static AsyncReply ParseStructure(byte[] data, uint offset, uint length, DistributedConnection connection, out Structure.StructureMetadata metadata, string[] keys = null, DataType[] types = null)// out string[] parsedKeys, out DataType[] parsedTypes, string[] keys = null, DataType[] types = null) - { - var reply = new AsyncReply(); - var bag = new AsyncBag(); - var keylist = new List(); - var typelist = new List(); - - if (keys == null) - { - while (length > 0) - { - var len = data[offset++]; - keylist.Add(data.GetString(offset, len)); - offset += len; - - typelist.Add((DataType)data[offset]); - - uint rt; - bag.Add(Codec.Parse(data, offset, out rt, connection)); - length -= rt + len + 1; - offset += rt; - } - } - else if (types == null) - { - keylist.AddRange(keys); - - while (length > 0) - { - typelist.Add((DataType)data[offset]); - - uint rt; - bag.Add(Codec.Parse(data, offset, out rt, connection)); - length -= rt; - offset += rt; - } - } - else - { - keylist.AddRange(keys); - typelist.AddRange(types); - - var i = 0; - while (length > 0) - { - uint rt; - bag.Add(Codec.Parse(data, offset, out rt, connection, types[i])); - length -= rt; - offset += rt; - i++; - } - } - - bag.Seal(); - - bag.Then((res) => - { - // compose the list - var s = new Structure(); - for (var i = 0; i < keylist.Count; i++) - s[keylist[i]] = res[i]; - reply.Trigger(s); - }); - - metadata = new Structure.StructureMetadata() { Keys = keylist.ToArray(), Types = typelist.ToArray() }; - - return reply; - } - - /// - /// Parse a value - /// - /// Bytes array - /// Zero-indexed offset. - /// DistributedConnection is required in case a structure in the array holds items at the other end. - /// DataType, in case the data is not prepended with DataType - /// Structure - public static AsyncReply Parse(byte[] data, uint offset, DistributedConnection connection, DataType dataType = DataType.Unspecified) - { - uint size; - return Parse(data, offset, out size, connection); - } /// /// Parse a value @@ -677,197 +114,34 @@ public static class Codec /// DistributedConnection is required in case a structure in the array holds items at the other end. /// DataType, in case the data is not prepended with DataType /// Value - public static AsyncReply Parse(byte[] data, uint offset, out uint size, DistributedConnection connection, DataType dataType = DataType.Unspecified) + public static (uint, AsyncReply) Parse(byte[] data, uint offset, DistributedConnection connection, TransmissionType? dataType = null) { - bool isArray; - DataType t; + uint len = 0; - if (dataType == DataType.Unspecified) + if (dataType == null) { - size = 1; - dataType = (DataType)data[offset++]; + (var longLen, dataType) = TransmissionType.Parse(data, offset, (uint)data.Length); + len = (uint)longLen; + offset = dataType.Value.Offset; } else - size = 0; + len = (uint)dataType.Value.ContentLength; - t = (DataType)((byte)dataType & 0x7F); + var tt = dataType.Value; - isArray = ((byte)dataType & 0x80) == 0x80; - - var payloadSize = dataType.Size();// SizeOf(); - - - uint contentLength = 0; - - // check if we have the enough data - if (payloadSize == -1) + if (tt.Class == TransmissionTypeClass.Fixed) { - contentLength = data.GetUInt32(offset); - offset += 4; - size += 4 + contentLength; + return (len, FixedParsers[tt.Exponent][tt.Index](data, dataType.Value.Offset, (uint)tt.ContentLength, connection)); } - else - size += (uint)payloadSize; - - if (isArray) + else if (tt.Class == TransmissionTypeClass.Dynamic) { - switch (t) - { - // VarArray ? - case DataType.Void: - return ParseVarArray(data, offset, contentLength, connection); - - case DataType.Bool: - return new AsyncReply(data.GetBooleanArray(offset, contentLength)); - - case DataType.UInt8: - return new AsyncReply(data.GetUInt8Array(offset, contentLength)); - - case DataType.Int8: - return new AsyncReply(data.GetInt8Array(offset, contentLength)); - - case DataType.Char: - return new AsyncReply(data.GetCharArray(offset, contentLength)); - - case DataType.Int16: - return new AsyncReply(data.GetInt16Array(offset, contentLength)); - - case DataType.UInt16: - return new AsyncReply(data.GetUInt16Array(offset, contentLength)); - - case DataType.Int32: - return new AsyncReply(data.GetInt32Array(offset, contentLength)); - - case DataType.UInt32: - return new AsyncReply(data.GetUInt32Array(offset, contentLength)); - - case DataType.Int64: - return new AsyncReply(data.GetInt64Array(offset, contentLength)); - - case DataType.UInt64: - return new AsyncReply(data.GetUInt64Array(offset, contentLength)); - - case DataType.Float32: - return new AsyncReply(data.GetFloat32Array(offset, contentLength)); - - case DataType.Float64: - return new AsyncReply(data.GetFloat64Array(offset, contentLength)); - - case DataType.String: - return new AsyncReply(data.GetStringArray(offset, contentLength)); - - case DataType.Resource: - case DataType.DistributedResource: - return ParseResourceArray(data, offset, contentLength, connection); - - case DataType.DateTime: - return new AsyncReply(data.GetDateTimeArray(offset, contentLength)); - - case DataType.Structure: - return ParseStructureArray(data, offset, contentLength, connection); - - case DataType.Record: - return ParseRecordArray(data, offset, contentLength, connection); - } + return (len, DynamicParsers[tt.Index](data, dataType.Value.Offset, (uint)tt.ContentLength, connection)); } - else + else //if (tt.Class == TransmissionTypeClass.Typed) { - switch (t) - { - case DataType.NotModified: - return new AsyncReply(new NotModified()); - - case DataType.Void: - return new AsyncReply(null); - - case DataType.Bool: - return new AsyncReply(data.GetBoolean(offset)); - - case DataType.UInt8: - return new AsyncReply(data[offset]); - - case DataType.Int8: - return new AsyncReply((sbyte)data[offset]); - - case DataType.Char: - return new AsyncReply(data.GetChar(offset)); - - case DataType.Int16: - return new AsyncReply(data.GetInt16(offset)); - - case DataType.UInt16: - return new AsyncReply(data.GetUInt16(offset)); - - case DataType.Int32: - return new AsyncReply(data.GetInt32(offset)); - - case DataType.UInt32: - return new AsyncReply(data.GetUInt32(offset)); - - case DataType.Int64: - return new AsyncReply(data.GetInt64(offset)); - - case DataType.UInt64: - return new AsyncReply(data.GetUInt64(offset)); - - case DataType.Float32: - return new AsyncReply(data.GetFloat32(offset)); - - case DataType.Float64: - return new AsyncReply(data.GetFloat64(offset)); - - case DataType.String: - return new AsyncReply(data.GetString(offset, contentLength)); - - case DataType.Resource: - return ParseResource(data, offset); - - case DataType.DistributedResource: - return ParseDistributedResource(data, offset, connection); - - case DataType.DateTime: - return new AsyncReply(data.GetDateTime(offset)); - - case DataType.Structure: - return ParseStructure(data, offset, contentLength, connection); - - case DataType.Record: - return ParseRecord(data, offset, contentLength, connection); - } + return (len, TypedParsers[tt.Index](data, dataType.Value.Offset, (uint)tt.ContentLength, connection)); } - - - return null; - } - - /// - /// Parse a resource - /// - /// Bytes array - /// Zero-indexed offset. - /// Resource - public static AsyncReply ParseResource(byte[] data, uint offset) - { - return Warehouse.GetById(data.GetUInt32(offset)); - } - - /// - /// Parse a DistributedResource - /// - /// Bytes array - /// Zero-indexed offset. - /// DistributedConnection is required. - /// DistributedResource - public static AsyncReply ParseDistributedResource(byte[] data, uint offset, DistributedConnection connection) - { - //var g = data.GetGuid(offset); - //offset += 16; - - // find the object - var iid = data.GetUInt32(offset); - - return connection.Fetch(iid);// Warehouse.Get(iid); } @@ -886,449 +160,74 @@ public static class Codec return false; } - /// - /// Compare two resources - /// - /// Initial resource to make comparison with. - /// Next resource to compare with the initial. - /// DistributedConnection is required to check locality. - /// Null, same, local, distributed or same class distributed. + public delegate (TransmissionTypeIdentifier, byte[]) Composer(object value, DistributedConnection connection); - public static ResourceComparisonResult Compare(IResource initial, IResource next, DistributedConnection connection) + public static Dictionary Composers = new Dictionary() { - if (next == null) - return ResourceComparisonResult.Null; - else if (next == initial) - return ResourceComparisonResult.Same; - else if (IsLocalResource(next, connection)) - return ResourceComparisonResult.Local; - else - return ResourceComparisonResult.Distributed; - } + // Fixed + [typeof(bool)] = DataSerializer.BoolComposer, + [typeof(bool?)] = DataSerializer.BoolComposer, + [typeof(NotModified)] = DataSerializer.NotModifiedComposer, + [typeof(byte)] = DataSerializer.UInt8Composer, + [typeof(byte?)] = DataSerializer.UInt8Composer, + [typeof(sbyte)] = DataSerializer.Int8Composer, + [typeof(sbyte?)] = DataSerializer.Int8Composer, + [typeof(char)] = DataSerializer.Char16Composer, + [typeof(char?)] = DataSerializer.Char16Composer, + [typeof(short)] = DataSerializer.Int16Composer, + [typeof(short?)] = DataSerializer.Int16Composer, + [typeof(ushort)] = DataSerializer.UInt16Composer, + [typeof(ushort?)] = DataSerializer.UInt16Composer, + [typeof(int)] = DataSerializer.Int32Composer, + [typeof(int?)] = DataSerializer.Int32Composer, + [typeof(uint)] = DataSerializer.UInt32Composer, + [typeof(uint?)] = DataSerializer.UInt32Composer, + [typeof(float)] = DataSerializer.Float32Composer, + [typeof(float?)] = DataSerializer.Float32Composer, + [typeof(long)] = DataSerializer.Int64Composer, + [typeof(long?)] = DataSerializer.Int64Composer, + [typeof(ulong)] = DataSerializer.UIn64Composer, + [typeof(ulong?)] = DataSerializer.UIn64Composer, + [typeof(double)] = DataSerializer.Float64Composer, + [typeof(double?)] = DataSerializer.Float64Composer, + [typeof(DateTime)] = DataSerializer.DateTimeComposer, + [typeof(DateTime?)] = DataSerializer.DateTimeComposer, + [typeof(decimal)] = DataSerializer.Float128Composer, + [typeof(decimal?)] = DataSerializer.Float128Composer, + [typeof(byte[])] = DataSerializer.RawDataComposerFromArray, + //[typeof(byte?[])] = DataSerializer.RawDataComposerFromArray, + [typeof(List)] = DataSerializer.RawDataComposerFromList, + //[typeof(List)] = DataSerializer.RawDataComposerFromList, + [typeof(string)] = DataSerializer.StringComposer, +#pragma + // Special + [typeof(object[])] = DataSerializer.ListComposer,// DataSerializer.ListComposerFromArray, + [typeof(List)] = DataSerializer.ListComposer,// DataSerializer.ListComposerFromList, + [typeof(IResource[])] = DataSerializer.ResourceListComposer,// (value, con) => (TransmissionTypeIdentifier.ResourceList, DC.ToBytes((decimal)value)), + [typeof(IResource?[])] = DataSerializer.ResourceListComposer,// (value, con) => (TransmissionTypeIdentifier.ResourceList, DC.ToBytes((decimal)value)), + [typeof(List)] = DataSerializer.ResourceListComposer, //(value, con) => (TransmissionTypeIdentifier.ResourceList, DC.ToBytes((decimal)value)), + [typeof(List)] = DataSerializer.ResourceListComposer, //(value, con) => (TransmissionTypeIdentifier.ResourceList, DC.ToBytes((decimal)value)), + [typeof(IRecord[])] = DataSerializer.RecordListComposer,// (value, con) => (TransmissionTypeIdentifier.RecordList, DC.ToBytes((decimal)value)), + [typeof(IRecord?[])] = DataSerializer.RecordListComposer,// (value, con) => (TransmissionTypeIdentifier.RecordList, DC.ToBytes((decimal)value)), + [typeof(List)] = DataSerializer.RecordListComposer, //(value, con) => (TransmissionTypeIdentifier.RecordList, DC.ToBytes((decimal)value)), + [typeof(List)] = DataSerializer.RecordListComposer, //(value, con) => (TransmissionTypeIdentifier.RecordList, DC.ToBytes((decimal)value)), + [typeof(Map)] = DataSerializer.MapComposer, + [typeof(Map)] = DataSerializer.MapComposer, + [typeof(Map)] = DataSerializer.MapComposer, + [typeof(Map)] = DataSerializer.MapComposer, + [typeof(PropertyValue[])] = DataSerializer.PropertyValueArrayComposer + // Typed + // [typeof(bool[])] = (value, con) => DataSerializer.TypedListComposer((IEnumerable)value, typeof(bool), con), + // [typeof(bool?[])] = (value, con) => (TransmissionTypeIdentifier.TypedList, new byte[] { (byte)value }), + // [typeof(List)] = (value, con) => (TransmissionTypeIdentifier.TypedList, new byte[] { (byte)value }), + // [typeof(List)] = (value, con) => (TransmissionTypeIdentifier.TypedList, new byte[] { (byte)value }), + + // [typeof(byte?[])] = (value, con) => (TransmissionTypeIdentifier.TypedList, new byte[] { (byte)value }), + // [typeof(List)] = (value, con) => (TransmissionTypeIdentifier.TypedList, new byte[] { (byte)value }), + + }; - /// - /// Compose a resource - /// - /// Resource to compose. - /// DistributedConnection is required to check locality. - /// Array of bytes in the network byte order. - public static byte[] ComposeResource(IResource resource, DistributedConnection connection) - { - if (IsLocalResource(resource, connection)) - return DC.ToBytes((resource as DistributedResource).Id); - else - { - return new BinaryList().AddGuid(resource.Instance.Template.ClassId).AddUInt32(resource.Instance.Id).ToArray(); - //return BinaryList.ToBytes(resource.Instance.Template.ClassId, resource.Instance.Id); - } - } - /// - /// Compose an array of resources - /// - /// Array of resources. - /// DistributedConnection is required to check locality. - /// If True, prepend the length of the output at the beginning. - /// Array of bytes in the network byte order. - public static byte[] ComposeResourceArray(T[] resources, DistributedConnection connection, bool prependLength = false) - where T : IResource - { - - if (resources == null || resources?.Length == 0) - return prependLength ? new byte[] { 0, 0, 0, 0 } : new byte[0]; - - - foreach (var r in resources) - connection.cache.Add(r, DateTime.UtcNow); - - var rt = new BinaryList(); - var comparsion = Compare(null, resources[0], connection); - - var type = resources.GetType().GetElementType(); - - - if (type != typeof(IResource)) - { - // get template - var tmp = Warehouse.GetTemplateByType(type); - - if (tmp == null) // something wrong - rt.AddUInt8((byte)comparsion); - else - { - // typed array - rt.AddUInt8((byte)((byte)(tmp.Type == TemplateType.Resource ? ResourceArrayType.Static : ResourceArrayType.Wrapper) - | (byte)comparsion)); - // add type - rt.AddGuid(tmp.ClassId); - } - } - else - { - rt.AddUInt8((byte)comparsion); - } - - - if (comparsion == ResourceComparisonResult.Local) - rt.AddUInt32((resources[0] as DistributedResource).Id); - else if (comparsion == ResourceComparisonResult.Distributed) - rt.AddUInt32(resources[0].Instance.Id); - - for (var i = 1; i < resources.Length; i++) - { - comparsion = Compare(resources[i - 1], resources[i], connection); - rt.AddUInt8((byte)comparsion); - if (comparsion == ResourceComparisonResult.Local) - rt.AddUInt32((resources[i] as DistributedResource).Id); - else if (comparsion == ResourceComparisonResult.Distributed) - rt.AddUInt32(resources[i].Instance.Id); - } - - if (prependLength) - rt.InsertInt32(0, rt.Length); - - return rt.ToArray(); - } - - /// - /// Parse an array of bytes into array of resources - /// - /// Array of bytes. - /// Number of bytes to parse. - /// Zero-indexed offset. - /// DistributedConnection is required to fetch resources. - /// Array of resources. - public static AsyncBag ParseResourceArray(byte[] data, uint offset, uint length, DistributedConnection connection) - { - var reply = new AsyncBag(); - if (length == 0) - { - reply.Seal(); - return reply; - } - - var end = offset + length; - - // Is typed array ? - var type = (ResourceArrayType)(data[offset] & 0xF0); - - var result = (ResourceComparisonResult)(data[offset++] & 0xF); - - - if (type == ResourceArrayType.Wrapper) - { - var classId = data.GetGuid(offset); - offset += 16; - var tmp = Warehouse.GetTemplateByClassId(classId, TemplateType.Resource); - // not mine, look if the type is elsewhere - if (tmp == null) - Warehouse.GetTemplateByClassId(classId, TemplateType.Wrapper); - reply.ArrayType = tmp?.DefinedType; - } - else if (type == ResourceArrayType.Static) - { - var classId = data.GetGuid(offset); - offset += 16; - var tmp = Warehouse.GetTemplateByClassId(classId, TemplateType.Wrapper); - reply.ArrayType = tmp?.DefinedType; - } - - AsyncReply previous = null; - - if (result == ResourceComparisonResult.Null) - previous = new AsyncReply(null); - else if (result == ResourceComparisonResult.Local) - { - previous = Warehouse.GetById(data.GetUInt32(offset)); - offset += 4; - } - else if (result == ResourceComparisonResult.Distributed) - { - previous = connection.Fetch(data.GetUInt32(offset)); - offset += 4; - } - - reply.Add(previous); - - - while (offset < end) - { - result = (ResourceComparisonResult)data[offset++]; - - AsyncReply current = null; - - if (result == ResourceComparisonResult.Null) - { - current = new AsyncReply(null); - } - else if (result == ResourceComparisonResult.Same) - { - current = previous; - } - else if (result == ResourceComparisonResult.Local) - { - current = Warehouse.GetById(data.GetUInt32(offset)); - offset += 4; - } - else if (result == ResourceComparisonResult.Distributed) - { - current = connection.Fetch(data.GetUInt32(offset)); - offset += 4; - } - - reply.Add(current); - - previous = current; - } - - reply.Seal(); - return reply; - } - - /// - /// Compose an array of variables - /// - /// Variables. - /// DistributedConnection is required to check locality. - /// If True, prepend the length as UInt32 at the beginning of the output. - /// Array of bytes in the network byte order. - public static byte[] ComposeVarArray(Array array, DistributedConnection connection, bool prependLength = false) - { - var rt = new List(); - - for (var i = 0; i < array.Length; i++) - rt.AddRange(Compose(array.GetValue(i), connection)); - if (prependLength) - rt.InsertRange(0, DC.ToBytes(rt.Count)); - return rt.ToArray(); - } - /// - /// Parse an array of variables. - /// - /// Array of bytes. - /// DistributedConnection is required to fetch resources. - /// Array of variables. - public static AsyncBag ParseVarArray(byte[] data, DistributedConnection connection) - { - return ParseVarArray(data, 0, (uint)data.Length, connection); - } - - /// - /// Parse an array of bytes into an array of varialbes. - /// - /// Array of bytes. - /// Zero-indexed offset. - /// Number of bytes to parse. - /// DistributedConnection is required to fetch resources. - /// Array of variables. - public static AsyncBag ParseVarArray(byte[] data, uint offset, uint length, DistributedConnection connection) - { - var rt = new AsyncBag(); - - while (length > 0) - { - uint cs; - - rt.Add(Parse(data, offset, out cs, connection)); - - if (cs > 0) - { - offset += (uint)cs; - length -= (uint)cs; - } - else - throw new Exception("Error while parsing structured data"); - - } - - rt.Seal(); - return rt; - } - - /// - /// Compose an array of property values. - /// - /// PropertyValue array. - /// DistributedConnection is required to check locality. - /// If True, prepend the length as UInt32 at the beginning of the output. - /// Array of bytes in the network byte order. - /// //, bool includeAge = true - public static byte[] ComposePropertyValueArray(PropertyValue[] array, DistributedConnection connection, bool prependLength = false) - { - var rt = new List(); - for (var i = 0; i < array.Length; i++) - rt.AddRange(ComposePropertyValue(array[i], connection)); - if (prependLength) - rt.InsertRange(0, DC.ToBytes(rt.Count)); - return rt.ToArray(); - } - - /// - /// Compose a property value. - /// - /// Property value - /// DistributedConnection is required to check locality. - /// Array of bytes in the network byte order. - public static byte[] ComposePropertyValue(PropertyValue propertyValue, DistributedConnection connection)//, bool includeAge = true) - { - - return new BinaryList() - .AddUInt64(propertyValue.Age) - .AddDateTime(propertyValue.Date) - .AddUInt8Array(Compose(propertyValue.Value, connection)) - .ToArray(); - - // age, date, value - //if (includeAge) - // return BinaryList.ToBytes(propertyValue.Age, propertyValue.Date, Compose(propertyValue.Value, connection)); - //else - // return BinaryList.ToBytes(propertyValue.Date, Compose(propertyValue.Value, connection)); - - } - - - /// - /// Parse property value. - /// - /// Array of bytes. - /// Zero-indexed offset. - /// DistributedConnection is required to fetch resources. - /// Output content size. - /// PropertyValue. - public static AsyncReply ParsePropertyValue(byte[] data, uint offset, out uint cs, DistributedConnection connection)//, bool ageIncluded = true) - { - var reply = new AsyncReply(); - - var age = data.GetUInt64(offset); - offset += 8; - - DateTime date = data.GetDateTime(offset); - offset += 8; - - uint valueSize; - - Parse(data, offset, out valueSize, connection).Then(value => - { - reply.Trigger(new PropertyValue(value, age, date)); - }); - - cs = 16 + valueSize; - return reply; - } - - /// - /// Parse an array of PropertyValue. - /// - /// Array of bytes. - /// DistributedConnection is required to fetch resources. - /// Array of variables. - public static AsyncBag ParsePropertyValueArray(byte[] data, DistributedConnection connection) - { - return ParsePropertyValueArray(data, 0, (uint)data.Length, connection); - } - - /// - /// Parse resource history - /// - /// Array of bytes. - /// Zero-indexed offset. - /// Number of bytes to parse. - /// Resource - /// Starting age. - /// Ending age. - /// DistributedConnection is required to fetch resources. - /// - public static AsyncReply> ParseHistory(byte[] data, uint offset, uint length, IResource resource, DistributedConnection connection) - { - //var count = (int)toAge - (int)fromAge; - - var list = new KeyList(); - - var reply = new AsyncReply>(); - - var bagOfBags = new AsyncBag(); - - var ends = offset + length; - while (offset < ends) - { - var index = data[offset++]; - var pt = resource.Instance.Template.GetPropertyTemplateByIndex(index); - list.Add(pt, null); - var cs = data.GetUInt32(offset); - offset += 4; - bagOfBags.Add(ParsePropertyValueArray(data, offset, cs, connection)); - offset += cs; - } - - bagOfBags.Seal(); - - bagOfBags.Then(x => - { - for (var i = 0; i < list.Count; i++) - list[list.Keys.ElementAt(i)] = x[i]; - - reply.Trigger(list); - }); - - return reply; - - } - - /// - /// Compose resource history - /// - /// History - /// DistributedConnection is required to fetch resources. - /// - public static byte[] ComposeHistory(KeyList history, - DistributedConnection connection, bool prependLength = false) - { - var rt = new BinaryList(); - - for (var i = 0; i < history.Count; i++) - rt.AddUInt8(history.Keys.ElementAt(i).Index) - .AddUInt8Array(ComposePropertyValueArray(history.Values.ElementAt(i), connection, true)); - - // rt.Append((byte)history.Keys.ElementAt(i).Index, - // ComposePropertyValueArray(history.Values.ElementAt(i), connection, true)); - - if (prependLength) - rt.InsertInt32(0, rt.Length); - - return rt.ToArray(); - } - - /// - /// Parse an array of PropertyValue. - /// - /// Array of bytes. - /// Zero-indexed offset. - /// Number of bytes to parse. - /// DistributedConnection is required to fetch resources. - /// Whether property age is represented in the data. - /// - public static AsyncBag ParsePropertyValueArray(byte[] data, uint offset, uint length, DistributedConnection connection)//, bool ageIncluded = true) - { - var rt = new AsyncBag(); - - while (length > 0) - { - uint cs; - - rt.Add(ParsePropertyValue(data, offset, out cs, connection));//, ageIncluded)); - - if (cs > 0) - { - offset += (uint)cs; - length -= (uint)cs; - } - else - throw new Exception("Error while parsing ValueInfo structured data"); - } - - rt.Seal(); - return rt; - } /// /// Compose a variable @@ -1337,78 +236,118 @@ public static class Codec /// DistributedConnection is required to check locality. /// If True, prepend the DataType at the beginning of the output. /// Array of bytes in the network byte order. - public static byte[] Compose(object valueOrSource, DistributedConnection connection, bool prependType = true) + public static byte[] Compose(object valueOrSource, DistributedConnection connection)//, bool prependType = true) { - var (type, value) = GetDataType(valueOrSource, connection); - var rt = new BinaryList(); - switch (type) + if (valueOrSource == null) + return TransmissionType.Compose(TransmissionTypeIdentifier.Null, null); + + var type = valueOrSource.GetType(); + + if (type.IsGenericType) { - case DataType.Void: - // nothing to do; - break; - case DataType.String: - var st = DC.ToBytes((string)value); - rt.AddInt32(st.Length).AddUInt8Array(st); - break; - - case DataType.Resource: - rt.AddUInt32((value as DistributedResource).Id); - break; - - case DataType.DistributedResource: - //rt.Append((value as IResource).Instance.Template.ClassId, (value as IResource).Instance.Id); - connection.cache.Add(value as IResource, DateTime.UtcNow); - rt.AddUInt32((value as IResource).Instance.Id); - - break; - - case DataType.Structure: - rt.AddUInt8Array(ComposeStructure((Structure)value, connection, true, true, true)); - break; - - case DataType.VarArray: - rt.AddUInt8Array(ComposeVarArray((Array)value, connection, true)); - break; - - case DataType.Record: - rt.AddUInt8Array(ComposeRecord((IRecord)value, connection, true, true)); - break; - - case DataType.ResourceArray: - - rt.AddUInt8Array(ComposeResourceArray((IResource[])value, connection, true)); - break; - //if (value is IResource[]) - // rt.AddUInt8Array(ComposeResourceArray((IResource[])value, connection, true)); - //else - // rt.AddUInt8Array(ComposeResourceArray((IResource[])DC.CastConvert(value, typeof(IResource[])), connection, true)); - //break; - - case DataType.StructureArray: - rt.AddUInt8Array(ComposeStructureArray((Structure[])value, connection, true)); - break; - - case DataType.RecordArray: - rt.AddUInt8Array(ComposeRecordArray((IRecord[])value, connection, true)); - break; - - default: - rt.Add(type, value); - if (type.IsArray()) - rt.InsertInt32(0, rt.Length); - break; + var genericType = type.GetGenericTypeDefinition(); + if (genericType == typeof(DistributedPropertyContext<>)) + { + valueOrSource = ((IDistributedPropertyContext)valueOrSource).GetValue(connection); + } + else if (genericType == typeof(Func<>)) + { + var args = genericType.GetGenericArguments(); + if (args.Length == 2 && args[0] == typeof(DistributedConnection)) + { + //Func a; + //a.Invoke() + } + } } - if (prependType) - rt.InsertUInt8(0, (byte)type); + if (valueOrSource is IUserType) + valueOrSource = (valueOrSource as IUserType).Get(); + + //if (valueOrSource is Func) + // valueOrSource = (valueOrSource as Func)(connection); + + if (valueOrSource == null) + return TransmissionType.Compose(TransmissionTypeIdentifier.Null, null); + + + type = valueOrSource.GetType(); + + + if (Composers.ContainsKey(type)) + { + var (hdr, data) = Composers[type](valueOrSource, connection); + return TransmissionType.Compose(hdr, data); + } + else + { + if (type.IsGenericType) + { + var genericType = type.GetGenericTypeDefinition(); + if (genericType == typeof(List<>)) + { + var args = type.GetGenericArguments(); + //if (Composers.ContainsKey(args[0])) + //{ + var (hdr, data) = DataSerializer.TypedListComposer((IEnumerable)valueOrSource, args[0], connection); + return TransmissionType.Compose(hdr, data); + //} + } + else if (genericType == typeof(Map<,>)) + { + var args = type.GetGenericArguments(); + + var (hdr, data) = DataSerializer.TypedMapComposer(valueOrSource, args[0], args[1], connection); + return TransmissionType.Compose(hdr, data); + + } + else if (genericType == typeof(ValueTuple<,>) + || genericType == typeof(ValueTuple<,,>) + || genericType == typeof(ValueTuple<,,,>) + ) + { + var (hdr, data) = DataSerializer.TupleComposer(valueOrSource, connection); + return TransmissionType.Compose(hdr, data); + } + } + else if (type.IsArray) + { + var elementType = type.GetElementType(); + + //if (Composers.ContainsKey(elementType)) + //{ + var (hdr, data) = DataSerializer.TypedListComposer((IEnumerable)valueOrSource, elementType, connection); + return TransmissionType.Compose(hdr, data); + + //} + } + else if (Codec.ImplementsInterface(type, typeof(IResource))) + { + var (hdr, data) = DataSerializer.ResourceComposer(valueOrSource, connection); + return TransmissionType.Compose(hdr, data); + } + else if (Codec.ImplementsInterface(type, typeof(IRecord))) + { + var (hdr, data) = DataSerializer.RecordComposer(valueOrSource, connection); + return TransmissionType.Compose(hdr, data); + } + else if (type.IsEnum) + { + var (hdr, data) = DataSerializer.EnumComposer(valueOrSource, connection); + return TransmissionType.Compose(hdr, data); + } + + } + + return TransmissionType.Compose(TransmissionTypeIdentifier.Null, null); - return rt.ToArray(); } + public static bool IsAnonymous(Type type) { // Detect anonymous types @@ -1418,6 +357,22 @@ public static class Codec return hasCompilerGeneratedAttribute && nameContainsAnonymousType; } + + public static Type GetGenericType(Type type, Type ifaceType, int argument = 0) + { + if (ifaceType.IsAssignableFrom(type)) + { + var col = type.GetInterfaces().Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == ifaceType) + .FirstOrDefault()? + .GetGenericArguments() + .FirstOrDefault() ?? null; + + return col; + } + else + return null; + } + /// /// Check if a type implements an interface /// @@ -1470,144 +425,4 @@ public static class Codec return false; } - - /// - /// Get the DataType of a given value. - /// This function is needed to compose a value. - /// - /// Value to find its DataType. - /// DistributedConnection is required to check locality of resources. - /// DataType. - public static (DataType type, object value) GetDataType(object value, DistributedConnection connection) - { - - if (value == null) - return (DataType.Void, null); - - if (value is IUserType) - value = (value as IUserType).Get(); - - - // value = (List<>)value.ToArray(); - - if (value is Func) - //if (connection != null) - value = (value as Func)(connection); - //else - // return (DataType.Void, null); - else if (value is DistributedPropertyContext) - { - try - { - //if (connection != null) - value = (value as DistributedPropertyContext).Method(connection); - //else - } - catch (Exception ex) - { - Global.Log(ex); - return (DataType.Void, null); - } - // return (DataType.Void, null); - } - - if (value == null) - return (DataType.Void, null); - - - var t = value.GetType(); - - // Convert ICollection to Array - if (!t.IsArray && typeof(ICollection).IsAssignableFrom(t)) - { - var col = t.GetInterfaces().Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ICollection<>)); - if (col.Count() == 0) - return (DataType.Void, null); - - var elementType = col.First().GetGenericArguments()[0]; - - value = new ArrayList((ICollection)value).ToArray(elementType); - t = value.GetType(); - } - - var isArray = t.IsArray; - - if (isArray) - { - t = t.GetElementType(); - if (t.IsEnum) - { - var src = value as Array; - t = t.GetEnumUnderlyingType(); - var dst = Array.CreateInstance(t, src.Length); - src.CopyTo(dst, 0); - value = dst; - } - } - else if (t.IsEnum) - { - t = t.GetEnumUnderlyingType(); - value = Convert.ChangeType(value, t); - } - - DataType type; - - - - if (t == typeof(bool)) - type = DataType.Bool; - else if (t == typeof(char)) - type = DataType.Char; - else if (t == typeof(byte)) - type = DataType.UInt8; - else if (t == typeof(sbyte)) - type = DataType.Int8; - else if (t == typeof(short)) - type = DataType.Int16; - else if (t == typeof(ushort)) - type = DataType.UInt16; - else if (t == typeof(int)) - type = DataType.Int32; - else if (t == typeof(uint)) - type = DataType.UInt32; - else if (t == typeof(long)) - type = DataType.Int64; - else if (t == typeof(ulong)) - type = DataType.UInt64; - else if (t == typeof(float)) - type = DataType.Float32; - else if (t == typeof(double)) - type = DataType.Float64; - else if (t == typeof(decimal)) - type = DataType.Decimal; - else if (t == typeof(string)) - type = DataType.String; - else if (t == typeof(DateTime)) - type = DataType.DateTime; - else if (typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject)) - type = DataType.Structure; - //else if (t == typeof(DistributedResource)) - // type = DataType.DistributedResource; - else if (ImplementsInterface(t, typeof(IResource))) - { - if (isArray) - return (DataType.ResourceArray, value); - else - { - return (IsLocalResource((IResource)value, connection) ? DataType.Resource : DataType.DistributedResource, value); - } - } - else if (ImplementsInterface(t, typeof(IRecord))) - type = DataType.Record; - else - type = DataType.Void; - - - if (isArray) - return ((DataType)((byte)type | 0x80), value); - else - return (type, value); - - } - } diff --git a/Esiur/Data/DataConverter.cs b/Esiur/Data/DataConverter.cs index 33d6d33..234187d 100644 --- a/Esiur/Data/DataConverter.cs +++ b/Esiur/Data/DataConverter.cs @@ -93,10 +93,10 @@ public static class DC // Data Converter rt.Set(value); return rt; } - else if (sourceType == typeof(Structure) && sourceType.IsAssignableFrom(destinationType)) - { - return Structure.FromStructure((Structure)value, destinationType); - } + //else if (sourceType == typeof(Structure) && sourceType.IsAssignableFrom(destinationType)) + //{ + // return Structure.FromStructure((Structure)value, destinationType); + //} else if (destinationType.IsEnum) { return Enum.ToObject(destinationType, value); @@ -190,45 +190,6 @@ public static class DC // Data Converter return value.ToByteArray(); } - public static byte[] ToBytes(Guid[] value) - { - var rt = new List(); - foreach (var g in value) - rt.AddRange(g.ToByteArray()); - return rt.ToArray(); - } - - public static byte[] ToBytes(char[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - - public static byte[] ToBytes(short[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - - - - public static byte[] ToBytes(ushort[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } public static void Append(ref byte[] dst, byte[] src) { @@ -265,88 +226,6 @@ public static class DC // Data Converter } - public static byte[] ToBytes(this int[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - - public static byte[] ToBytes(this uint[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - - public static byte[] ToBytes(this long[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - - public static byte[] ToBytes(this ulong[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - - public static byte[] ToBytes(this float[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - - public static byte[] ToBytes(this double[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - - - public static byte[] ToBytes(this decimal[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - - - public static byte[] ToBytes(this DateTime[] value) - { - List rt = new List(); - - for (int i = 0; i < value.Length; i++) - rt.AddRange(ToBytes(value[i])); - - return rt.ToArray(); - } - public static byte[] ToBytes(this string[] value) { @@ -356,7 +235,7 @@ public static class DC // Data Converter { byte[] ba = ToBytes(value[i]); // add string length - rt.AddRange(ToBytes(ba.Length)); + rt.AddRange(ToBytes(ba.Length, Endian.Little)); // add encoded string rt.AddRange(ba); } @@ -364,41 +243,68 @@ public static class DC // Data Converter return rt.ToArray(); } - public static unsafe byte[] ToBytes(this int value) + + public static unsafe byte[] ToBytes(this int value, Endian endian) { var rt = new byte[4]; - byte* p = (byte*)&value; - rt[0] = *(p + 3); - rt[1] = *(p + 2); - rt[2] = *(p + 1); - rt[3] = *(p + 0); + if (endian == Endian.Little) + { + fixed (byte* ptr = rt) + *((int*)ptr) = value; + } + else + { + byte* p = (byte*)&value; + + rt[0] = *(p + 3); + rt[1] = *(p + 2); + rt[2] = *(p + 1); + rt[3] = *(p + 0); + + } return rt; } - public static unsafe byte[] ToBytes(this short value) + + + public static unsafe byte[] ToBytes(this short value, Endian endian) { var rt = new byte[2]; - byte* p = (byte*)&value; + if (endian == Endian.Little) + { + fixed (byte* ptr = rt) + *((short*)ptr) = value; + } + else + { + byte* p = (byte*)&value; - rt[0] = *(p + 1); - rt[1] = *(p + 0); + rt[0] = *(p + 1); + rt[1] = *(p + 0); + } return rt; } - public static unsafe byte[] ToBytes(this float value) + public static unsafe byte[] ToBytes(this float value, Endian endian) { var rt = new byte[4]; - - //float rt = 0; - byte* p = (byte*)&value; - rt[0] = *(p + 3); - rt[1] = *(p + 2); - rt[2] = *(p + 1); - rt[3] = *(p); + if (endian == Endian.Little) + { + fixed (byte* ptr = rt) + *((float*)ptr) = value; + } + else + { + byte* p = (byte*)&value; + rt[0] = *(p + 3); + rt[1] = *(p + 2); + rt[2] = *(p + 1); + rt[3] = *(p); + } return rt; } @@ -406,122 +312,153 @@ public static class DC // Data Converter + + + + + + public static byte[] ToBytes(this string value) { return Encoding.UTF8.GetBytes(value); } - public unsafe static byte[] ToBytes(this double value) + public unsafe static byte[] ToBytes(this double value, Endian endian) { var rt = new byte[8]; + if (endian == Endian.Little) + { + fixed (byte* ptr = rt) + *((double*)ptr) = value; + } + else + { + byte* p = (byte*)&value; - byte* p = (byte*)&value; - - rt[0] = *(p + 7); - rt[1] = *(p + 6); - rt[2] = *(p + 5); - rt[3] = *(p + 4); - rt[4] = *(p + 3); - rt[5] = *(p + 2); - rt[6] = *(p + 1); - rt[7] = *(p + 0); + rt[0] = *(p + 7); + rt[1] = *(p + 6); + rt[2] = *(p + 5); + rt[3] = *(p + 4); + rt[4] = *(p + 3); + rt[5] = *(p + 2); + rt[6] = *(p + 1); + rt[7] = *(p + 0); + } return rt; } - public static unsafe byte[] ToBytes(this long value) + public static unsafe byte[] ToBytes(this long value, Endian endian) { var rt = new byte[8]; + if (endian == Endian.Little) + { + fixed (byte* ptr = rt) + *((long*)ptr) = value; + } + else + { + byte* p = (byte*)&value; - byte* p = (byte*)&value; - - rt[0] = *(p + 7); - rt[1] = *(p + 6); - rt[2] = *(p + 5); - rt[3] = *(p + 4); - rt[4] = *(p + 3); - rt[5] = *(p + 2); - rt[6] = *(p + 1); - rt[7] = *(p + 0); + rt[0] = *(p + 7); + rt[1] = *(p + 6); + rt[2] = *(p + 5); + rt[3] = *(p + 4); + rt[4] = *(p + 3); + rt[5] = *(p + 2); + rt[6] = *(p + 1); + rt[7] = *(p + 0); + } return rt; - } - public static unsafe byte[] ToBytes(this DateTime value) { - var rt = new byte[8]; var v = value.ToUniversalTime().Ticks; - byte* p = (byte*)&v; - - rt[0] = *(p + 7); - rt[1] = *(p + 6); - rt[2] = *(p + 5); - rt[3] = *(p + 4); - rt[4] = *(p + 3); - rt[5] = *(p + 2); - rt[6] = *(p + 1); - rt[7] = *(p + 0); - + fixed (byte* ptr = rt) + *((long*)ptr) = v; return rt; - } - public static unsafe byte[] ToBytes(this ulong value) + public static unsafe byte[] ToBytes(this ulong value, Endian endia) { var rt = new byte[8]; + if (endia == Endian.Little) + { + fixed (byte* ptr = rt) + *((ulong*)ptr) = value; + } + else + { - byte* p = (byte*)&value; + byte* p = (byte*)&value; - rt[0] = *(p + 7); - rt[1] = *(p + 6); - rt[2] = *(p + 5); - rt[3] = *(p + 4); - rt[4] = *(p + 3); - rt[5] = *(p + 2); - rt[6] = *(p + 1); - rt[7] = *(p + 0); + rt[0] = *(p + 7); + rt[1] = *(p + 6); + rt[2] = *(p + 5); + rt[3] = *(p + 4); + rt[4] = *(p + 3); + rt[5] = *(p + 2); + rt[6] = *(p + 1); + rt[7] = *(p + 0); + } return rt; } - public static unsafe byte[] ToBytes(this uint value) + public static unsafe byte[] ToBytes(this uint value, Endian endian) { - var rt = new byte[4]; + if (endian == Endian.Little) + { + fixed (byte* ptr = rt) + *((uint*)ptr) = value; + } + else + { - byte* p = (byte*)&value; + byte* p = (byte*)&value; - rt[0] = *(p + 3); - rt[1] = *(p + 2); - rt[2] = *(p + 1); - rt[3] = *(p + 0); + rt[0] = *(p + 3); + rt[1] = *(p + 2); + rt[2] = *(p + 1); + rt[3] = *(p + 0); + } return rt; } - public static unsafe byte[] ToBytes(this ushort value) + public static unsafe byte[] ToBytes(this ushort value, Endian endian) { var rt = new byte[2]; + if (endian == Endian.Little) + { + fixed (byte* ptr = rt) + *((ushort*)ptr) = value; + } + else + { + byte* p = (byte*)&value; - byte* p = (byte*)&value; - - rt[0] = *(p + 1); - rt[1] = *(p); - + rt[0] = *(p + 1); + rt[1] = *(p); + } return rt; } - public static byte[] ToBytes(this decimal value) + public static unsafe byte[] ToBytes(this decimal value, Endian endian) { - byte[] ret = new byte[0];// BitConverter.GetBytes(value); + var rt = new byte[16]; + fixed (byte* ptr = rt) + *((decimal*)ptr) = value; - Array.Reverse(ret); + if (endian == Endian.Big) + Array.Reverse(rt); - return ret; + return rt; } public static string ToHex(this byte[] ba) @@ -533,22 +470,10 @@ public static class DC // Data Converter public static string ToHex(this byte[] ba, uint offset, uint length, string separator = " ") { - if (separator == null) separator = ""; return string.Join(separator, ba.Skip((int)offset).Take((int)length).Select(x => x.ToString("x2")).ToArray()); - - //StringBuilder hex = new StringBuilder((int)length * 2); - - //for (var i = offset; i < offset + length; i++) - //{ - // hex.AppendFormat("{0:x2}", ba[i]); - // if (separator != null) - // hex.Append(separator); - //} - - //return hex.ToString(); } public static byte[] FromHex(string hexString, string separator = " ") @@ -639,240 +564,186 @@ public static class DC // Data Converter return (sbyte)data[offset]; } - public static sbyte[] GetInt8Array(this byte[] data, uint offset, uint length) - { - var rt = new sbyte[length]; - Buffer.BlockCopy(data, (int)offset, rt, 0, (int)length); - return rt; - } + + + + + + + public static byte GetUInt8(this byte[] data, uint offset) { return data[offset]; } - public static byte[] GetUInt8Array(this byte[] data, uint offset, uint length) + public static unsafe short GetInt16(this byte[] data, uint offset, Endian endian) { - var rt = new byte[length]; - Buffer.BlockCopy(data, (int)offset, rt, 0, (int)length); - return rt; - } - - public static Int16 GetInt16(this byte[] data, uint offset) - { - return (Int16)((data[offset] << 8) | data[offset + 1]); - } - - public static Int16[] GetInt16Array(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - - var rt = new Int16[length / 2]; - for (var i = offset; i < end; i += 2) - rt[j++] = GetInt16(data, i); - - return rt; - } - - public static UInt16 GetUInt16(this byte[] data, uint offset) - { - return (UInt16)((data[offset] << 8) | data[offset + 1]); - } - - public static UInt16[] GetUInt16Array(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - var rt = new UInt16[length / 2]; - - for (var i = offset; i < end; i += 2) - rt[j++] = GetUInt16(data, i); - - return rt; - - } - - public static Int32 GetInt32(this byte[] data, uint offset) - { - return (Int32)((data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]); - } - - public static Int32[] GetInt32Array(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - - var rt = new Int32[length / 4]; - for (var i = offset; i < end; i += 4) - rt[j++] = GetInt32(data, i); - - return rt; - } - - public static UInt32 GetUInt32(this byte[] data, uint offset) - { - return (UInt32)((data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]); - } - - public static UInt32[] GetUInt32Array(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - var rt = new UInt32[length / 4]; - - for (var i = offset; i < end; i += 4) - rt[j++] = GetUInt16(data, i); - - return rt; + if (endian == Endian.Little) + { + fixed (byte* ptr = &data[offset]) + return *(short*)ptr; + } + else + { + return (Int16)((data[offset] << 8) | data[offset + 1]); + } } - public static unsafe UInt64 GetUInt64(this byte[] data, uint offset) + + public static unsafe ushort GetUInt16(this byte[] data, uint offset, Endian endian) { - UInt64 rt = 0; - byte* p = (byte*)&rt; - - *(p + 7) = data[offset++]; - *(p + 6) = data[offset++]; - *(p + 5) = data[offset++]; - *(p + 4) = data[offset++]; - *(p + 3) = data[offset++]; - *(p + 2) = data[offset++]; - *(p + 1) = data[offset++]; - *(p) = data[offset++]; - - return rt; - + if (endian == Endian.Little) + { + fixed (byte* ptr = &data[offset]) + return *(ushort*)ptr; + } + else + { + return (UInt16)((data[offset] << 8) | data[offset + 1]); + } } - public static Int64[] GetInt64Array(this byte[] data, uint offset, uint length) + public static unsafe int GetInt32(this byte[] data, uint offset, Endian endian) { - var j = 0; var end = offset + length; - var rt = new Int64[length / 8]; - - for (var i = offset; i < end; i += 8) - rt[j++] = GetInt64(data, i); - - return rt; + if (endian == Endian.Little) + { + fixed (byte* ptr = &data[offset]) + return *(int*)ptr; + } + else + { + return (Int32)((data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]); + } } - public static unsafe Int64 GetInt64(this byte[] data, uint offset) + public static unsafe uint GetUInt32(this byte[] data, uint offset, Endian endian) { - Int64 rt = 0; - byte* p = (byte*)&rt; - *(p + 7) = data[offset++]; - *(p + 6) = data[offset++]; - *(p + 5) = data[offset++]; - *(p + 4) = data[offset++]; - *(p + 3) = data[offset++]; - *(p + 2) = data[offset++]; - *(p + 1) = data[offset++]; - *(p) = data[offset++]; - - return rt; - - /* Or - return (Int64)( - (data[offset] << 56) - | (data[offset + 1] << 48) - | (data[offset + 2] << 40) - | (data[offset + 3] << 32) - | (data[offset + 4] << 24) - | (data[offset + 5] << 16) - | (data[offset + 6] << 8) - | (data[offset + 7]) - ); - */ + if (endian == Endian.Little) + { + fixed (byte* ptr = &data[offset]) + return *(uint*)ptr; + } + else + { + return (uint)((data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]); + } } - public static UInt64[] GetUInt64Array(this byte[] data, uint offset, uint length) + + + + public static unsafe ulong GetUInt64(this byte[] data, uint offset, Endian endian) { - var j = 0; var end = offset + length; - var rt = new UInt64[length / 8]; + if (endian == Endian.Little) + { + fixed (byte* ptr = &data[offset]) + return *(ulong*)ptr; + } + else + { + UInt64 rt = 0; + byte* p = (byte*)&rt; - for (var i = offset; i < end; i += 8) - rt[j++] = GetUInt64(data, i); + *(p + 7) = data[offset++]; + *(p + 6) = data[offset++]; + *(p + 5) = data[offset++]; + *(p + 4) = data[offset++]; + *(p + 3) = data[offset++]; + *(p + 2) = data[offset++]; + *(p + 1) = data[offset++]; + *(p) = data[offset++]; - return rt; + return rt; + } } - public static unsafe float GetFloat32(this byte[] data, uint offset) + + public static unsafe long GetInt64(this byte[] data, uint offset, Endian endian) { - float rt = 0; - byte* p = (byte*)&rt; - *p = data[offset + 3]; - *(p + 1) = data[offset + 2]; - *(p + 2) = data[offset + 1]; - *(p + 3) = data[offset]; - return rt; + if (endian == Endian.Little) + { + fixed (byte* ptr = &data[offset]) + return *(long*)ptr; + } + else + { + Int64 rt = 0; + byte* p = (byte*)&rt; + + *(p + 7) = data[offset++]; + *(p + 6) = data[offset++]; + *(p + 5) = data[offset++]; + *(p + 4) = data[offset++]; + *(p + 3) = data[offset++]; + *(p + 2) = data[offset++]; + *(p + 1) = data[offset++]; + *(p) = data[offset++]; + + return rt; + + } } - public static float[] GetFloat32Array(this byte[] data, uint offset, uint length) + public static unsafe float GetFloat32(this byte[] data, uint offset, Endian endian) { - var j = 0; var end = offset + length; - var rt = new float[length / 4]; + if (endian == Endian.Little) + { + fixed (byte* ptr = &data[offset]) + return *(float*)ptr; + } + else + { + float rt = 0; + byte* p = (byte*)&rt; + *p = data[offset + 3]; + *(p + 1) = data[offset + 2]; + *(p + 2) = data[offset + 1]; + *(p + 3) = data[offset]; + return rt; - for (var i = offset; i < end; i += 4) - rt[j++] = GetFloat32(data, i); - - return rt; + } } - public static unsafe double GetFloat64(this byte[] data, uint offset) + + public static unsafe double GetFloat64(this byte[] data, uint offset, Endian endian) { - double rt = 0; - byte* p = (byte*)&rt; + if (endian == Endian.Little) + { + fixed (byte* ptr = &data[offset]) + return *(double*)ptr; + } + else + { + double rt = 0; + byte* p = (byte*)&rt; - *(p + 7) = data[offset++]; - *(p + 6) = data[offset++]; - *(p + 5) = data[offset++]; - *(p + 4) = data[offset++]; - *(p + 3) = data[offset++]; - *(p + 2) = data[offset++]; - *(p + 1) = data[offset++]; - *(p) = data[offset++]; + *(p + 7) = data[offset++]; + *(p + 6) = data[offset++]; + *(p + 5) = data[offset++]; + *(p + 4) = data[offset++]; + *(p + 3) = data[offset++]; + *(p + 2) = data[offset++]; + *(p + 1) = data[offset++]; + *(p) = data[offset++]; - return rt; + return rt; + } } - public static double[] GetFloat64Array(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - var rt = new double[length / 8]; - - for (var i = offset; i < end; i += 8) - rt[j++] = GetFloat64(data, i); - - return rt; - } public static bool GetBoolean(this byte[] data, uint offset) { return data[offset] > 0; } - public static bool[] GetBooleanArray(this byte[] data, uint offset, uint length) - { - var rt = new bool[length]; - for (var i = 0; i < length; i++) - rt[i] = data[offset + i] > 0; - return rt; - } - public static char GetChar(this byte[] data, uint offset) { return Convert.ToChar(((data[offset] << 8) | data[offset + 1])); } - public static char[] GetCharArray(this byte[] data, uint offset, uint length) - { - - var j = 0; var end = offset + length; - var rt = new char[length / 2]; - - for (var i = offset; i < end; i += 2) - rt[j++] = GetChar(data, i); - - return rt; - } public static string GetString(this byte[] data, uint offset, uint length) { @@ -887,7 +758,7 @@ public static class DC // Data Converter while (i < length) { - var cl = GetUInt32(data, offset + i); + var cl = GetUInt32(data, offset + i, Endian.Little); i += 4; ar.Add(Encoding.UTF8.GetString(data, (int)(offset + i), (int)cl)); i += cl; @@ -901,69 +772,24 @@ public static class DC // Data Converter return new Guid(Clip(data, offset, 16)); } - public static Guid[] GetGuidArray(this byte[] data, uint offset, uint length) + public static DateTime GetDateTime(this byte[] data, uint offset, Endian endian) { - var j = 0; var end = offset + length; - var rt = new Guid[length / 16]; - - for (var i = offset; i < end; i += 16) - rt[j++] = GetGuid(data, i); - - return rt; - } - - public static DateTime GetDateTime(this byte[] data, uint offset) - { - var ticks = GetInt64(data, offset); + var ticks = GetInt64(data, offset, endian); return new DateTime(ticks, DateTimeKind.Utc); } - public static DateTime[] GetDateTimeArray(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - var rt = new DateTime[length / 8]; - - for (var i = offset; i < end; i += 8) - rt[j++] = GetDateTime(data, i); - - return rt; - } public static IPAddress GetIPv4Address(this byte[] data, uint offset) { - return new IPAddress((long)GetUInt32(data, offset)); + return new IPAddress((long)GetUInt32(data, offset, Endian.Little)); } - public static IPAddress[] GetIPv4AddressArray(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - var rt = new IPAddress[length / 4]; - - for (var i = offset; i < end; i += 4) - rt[j++] = GetIPv6Address(data, i); - - return rt; - } public static IPAddress GetIPv6Address(this byte[] data, uint offset) { return new IPAddress(Clip(data, offset, 16)); } - public static IPAddress[] GetIPv6AddressArray(this byte[] data, uint offset, uint length) - { - var j = 0; var end = offset + length; - var rt = new IPAddress[length / 16]; - - for (var i = offset; i < end; i += 16) - rt[j++] = GetIPv6Address(data, i); - - return rt; - - } - - - public static byte[] Clip(this byte[] data, uint offset, uint length) { if (data.Length < offset + length) diff --git a/Esiur/Data/DataDeserializer.cs b/Esiur/Data/DataDeserializer.cs new file mode 100644 index 0000000..c454acc --- /dev/null +++ b/Esiur/Data/DataDeserializer.cs @@ -0,0 +1,554 @@ +using Esiur.Core; +using Esiur.Net.IIP; +using Esiur.Resource; +using System; +using System.Collections.Generic; +using System.Text; +using Esiur.Data; +using Esiur.Resource.Template; +using System.Linq; + +namespace Esiur.Data; + +public static class DataDeserializer +{ + public static AsyncReply NullParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + return new AsyncReply(null); + } + + public static AsyncReply BooleanTrueParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + return new AsyncReply(true); + } + + public static AsyncReply BooleanFalseParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + return new AsyncReply(false); + } + + public static AsyncReply NotModifiedParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + return new AsyncReply(new NotModified()); + } + + public static AsyncReply ByteParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + return new AsyncReply(data[offset]); + } + public static AsyncReply SByteParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + return new AsyncReply((sbyte)data[offset]); + } + public static unsafe AsyncReply Char16Parser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + fixed (byte* ptr = &data[offset]) + return new AsyncReply(*(char*)ptr); + } + + public static AsyncReply Char8Parser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + return new AsyncReply((char)data[offset]); + } + + + public static unsafe AsyncReply Int16Parser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + fixed (byte* ptr = &data[offset]) + return new AsyncReply(*(short*)ptr); + } + + public static unsafe AsyncReply UInt16Parser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + fixed (byte* ptr = &data[offset]) + return new AsyncReply(*(ushort*)ptr); + } + + public static unsafe AsyncReply Int32Parser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + fixed (byte* ptr = &data[offset]) + return new AsyncReply(*(int*)ptr); + } + + public static unsafe AsyncReply UInt32Parser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + fixed (byte* ptr = &data[offset]) + return new AsyncReply(*(uint*)ptr); + } + + public static unsafe AsyncReply Float32Parser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + fixed (byte* ptr = &data[offset]) + return new AsyncReply(*(float*)ptr); + } + + public static unsafe AsyncReply Float64Parser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + fixed (byte* ptr = &data[offset]) + return new AsyncReply(*(double*)ptr); + } + + public static unsafe AsyncReply Float128Parser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + fixed (byte* ptr = &data[offset]) + return new AsyncReply(*(decimal*)ptr); + } + + public static unsafe AsyncReply Int128Parser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + fixed (byte* ptr = &data[offset]) + return new AsyncReply(*(decimal*)ptr); + } + + + public static unsafe AsyncReply UInt128Parser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + fixed (byte* ptr = &data[offset]) + return new AsyncReply(*(decimal*)ptr); + } + + + public static unsafe AsyncReply Int64Parser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + fixed (byte* ptr = &data[offset]) + return new AsyncReply(*(long*)ptr); + } + + public static unsafe AsyncReply UInt64Parser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + fixed (byte* ptr = &data[offset]) + return new AsyncReply(*(ulong*)ptr); + } + + public static unsafe AsyncReply DateTimeParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + fixed (byte* ptr = &data[offset]) + return new AsyncReply(new DateTime(*(long*)ptr, DateTimeKind.Utc)); + + } + + + public static unsafe AsyncReply ResourceParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + fixed (byte* ptr = &data[offset]) + return connection.Fetch(*(uint*)ptr); + + } + + public static unsafe AsyncReply LocalResourceParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + fixed (byte* ptr = &data[offset]) + return Warehouse.GetById(*(uint*)ptr); + + } + + + public static unsafe AsyncReply RawDataParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + return new AsyncReply(data.Clip(offset, length)); + } + + public static unsafe AsyncReply StringParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + return new AsyncReply(data.GetString(offset, length)); + } + + public static unsafe AsyncReply RecordParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + + var reply = new AsyncReply(); + + var classId = data.GetGuid(offset); + offset += 16; + length -= 16; + + + var template = Warehouse.GetTemplateByClassId((Guid)classId, TemplateType.Record); + + if (template != null) + { + //ListParser(data, offset, length, connection) + ListParser(data, offset, length, connection).Then(r => + { + var ar = (object[])r; + + if (template.DefinedType != null) + { + var record = Activator.CreateInstance(template.DefinedType) as IRecord; + for (var i = 0; i < template.Properties.Length; i++) + { + try + { + var v = Convert.ChangeType(ar[i], template.Properties[i].PropertyInfo.PropertyType); + template.Properties[i].PropertyInfo.SetValue(record, v); + } catch ( Exception ex) + { + Console.WriteLine(ex); + } + } + + 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 => + { + ListParser(data, offset, length, connection).Then(r => + { + var ar = (object[])r; + + 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 unsafe AsyncReply ConstantParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + throw new NotImplementedException(); + } + + public static unsafe AsyncReply EnumParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + + var classId = data.GetGuid(offset); + offset += 16; + var index = data[offset++]; + + var template = Warehouse.GetTemplateByClassId((Guid)classId, TemplateType.Enum); + + if (template != null) + { + return new AsyncReply(template.Constants[index].Value); + } + else + { + var reply = new AsyncReply(); + + connection.GetTemplate((Guid)classId).Then(tmp => + { + reply.Trigger(tmp.Constants[index].Value); + }).Error(x => reply.TriggerError(x)); + + return reply; + } + } + + + + public static AsyncReply RecordListParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + var rt = new AsyncBag(); + + while (length > 0) + { + var (cs, reply) = Codec.Parse(data, offset, connection); + + rt.Add(reply); + + if (cs > 0) + { + offset += (uint)cs; + length -= (uint)cs; + } + else + throw new Exception("Error while parsing structured data"); + + } + + rt.Seal(); + return rt; + } + + public static AsyncReply ResourceListParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + var rt = new AsyncBag(); + + while (length > 0) + { + var (cs, reply) = Codec.Parse(data, offset, connection); + + rt.Add(reply); + + if (cs > 0) + { + offset += (uint)cs; + length -= (uint)cs; + } + else + throw new Exception("Error while parsing structured data"); + + } + + rt.Seal(); + return rt; + } + + + public static AsyncBag ListParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + var rt = new AsyncBag(); + + while (length > 0) + { + var (cs, reply) = Codec.Parse(data, offset, connection); + + rt.Add(reply); + + if (cs > 0) + { + offset += (uint)cs; + length -= (uint)cs; + } + else + throw new Exception("Error while parsing structured data"); + + } + + rt.Seal(); + return rt; + } + + public static AsyncReply TypedMapParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + // get key type + var (keyCs, keyRepType) = RepresentationType.Parse(data, offset); + offset += keyCs; + length -= keyCs; + + var (valueCs, valueRepType) = RepresentationType.Parse(data, offset); + offset += valueCs; + length -= valueCs; + + var map = (IMap)Activator.CreateInstance(typeof(Map<,>).MakeGenericType(keyRepType.GetRuntimeType(), valueRepType.GetRuntimeType())); + + var rt = new AsyncReply(); + + var results = new AsyncBag(); + + while (length > 0) + { + var (cs, reply) = Codec.Parse(data, offset, connection); + + + results.Add(reply); + + if (cs > 0) + { + offset += (uint)cs; + length -= (uint)cs; + } + else + throw new Exception("Error while parsing structured data"); + + } + + results.Seal(); + + results.Then(ar => + { + for (var i = 0; i < ar.Length; i += 2) + map.Add(ar[i], ar[i + 1]); + + rt.Trigger(map); + }); + + + return rt; + + } + + public static AsyncReply TupleParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + var results = new AsyncBag(); + var rt = new AsyncReply(); + + var tupleSize = data[offset++]; + length--; + + var types = new List(); + + for (var i = 0; i < tupleSize; i++) + { + var (cs, rep) = RepresentationType.Parse(data, offset); + types.Add(rep.GetRuntimeType()); + offset += cs; + length -= cs; + } + + while (length > 0) + { + var (cs, reply) = Codec.Parse(data, offset, connection); + + results.Add(reply); + + if (cs > 0) + { + offset += (uint)cs; + length -= (uint)cs; + } + else + throw new Exception("Error while parsing structured data"); + + } + + results.Seal(); + + + results.Then(ar => + { + if (ar.Length == 2) + { + var type = typeof(ValueTuple<,>).MakeGenericType(types.ToArray()); + rt.Trigger(Activator.CreateInstance(type, ar[0], ar[1])); + } + else if (ar.Length == 3) + { + var type = typeof(ValueTuple<,,>).MakeGenericType(types.ToArray()); + rt.Trigger(Activator.CreateInstance(type, ar[0], ar[1], ar[2])); + } + else if (ar.Length == 4) + { + var type = typeof(ValueTuple<,,,>).MakeGenericType(types.ToArray()); + rt.Trigger(Activator.CreateInstance(type, ar[0], ar[1], ar[2], ar[3])); + } + }); + + return rt; + } + + public static AsyncReply TypedListParser(byte[] data, uint offset, uint length, DistributedConnection connection) + { + var rt = new AsyncBag(); + + // get the type + var (hdrCs, rep) = RepresentationType.Parse(data, offset); + + offset += hdrCs; + length -= hdrCs; + + var runtimeType = rep.GetRuntimeType(); + + rt.ArrayType = runtimeType; + + while (length > 0) + { + var (cs, reply) = Codec.Parse(data, offset, connection); + + rt.Add(reply); + + if (cs > 0) + { + offset += (uint)cs; + length -= (uint)cs; + } + else + throw new Exception("Error while parsing structured data"); + + } + + rt.Seal(); + return rt; + } + + + public static AsyncBag PropertyValueArrayParser(byte[] data, uint offset, uint length, DistributedConnection connection)//, bool ageIncluded = true) + { + var rt = new AsyncBag(); + + + ListParser(data, offset, length, connection).Then(x => + { + var ar = (object[])x; + var pvs = new List(); + + for (var i = 0; i < ar.Length; i += 3) + pvs.Add(new PropertyValue(ar[2], (ulong?)ar[0], (DateTime?)ar[1])); + + + rt.Trigger(pvs.ToArray()); + }); + + return rt; + + } + + public static (uint, AsyncReply) PropertyValueParser(byte[] data, uint offset, DistributedConnection connection)//, bool ageIncluded = true) + { + var reply = new AsyncReply(); + + var age = data.GetUInt64(offset, Endian.Little); + offset += 8; + + DateTime date = data.GetDateTime(offset, Endian.Little); + offset += 8; + + + var (valueSize, results) = Codec.Parse(data, offset, connection); + + results.Then(value => + { + reply.Trigger(new PropertyValue(value, age, date)); + }); + + return (16 + valueSize, reply); + } + + public static AsyncReply> HistoryParser(byte[] data, uint offset, uint length, IResource resource, DistributedConnection connection) + { + //var count = (int)toAge - (int)fromAge; + + var list = new KeyList(); + + var reply = new AsyncReply>(); + + var bagOfBags = new AsyncBag(); + + var ends = offset + length; + while (offset < ends) + { + var index = data[offset++]; + var pt = resource.Instance.Template.GetPropertyTemplateByIndex(index); + list.Add(pt, null); + var cs = data.GetUInt32(offset, Endian.Little); + offset += 4; + + var (len, pv) = PropertyValueParser(data, offset, connection); + + bagOfBags.Add(pv);// ParsePropertyValueArray(data, offset, cs, connection)); + offset += len; + } + + bagOfBags.Seal(); + + bagOfBags.Then(x => + { + for (var i = 0; i < list.Count; i++) + list[list.Keys.ElementAt(i)] = x[i]; + + reply.Trigger(list); + }); + + return reply; + + } + +} diff --git a/Esiur/Data/DataSerializer.cs b/Esiur/Data/DataSerializer.cs new file mode 100644 index 0000000..31ef2eb --- /dev/null +++ b/Esiur/Data/DataSerializer.cs @@ -0,0 +1,416 @@ +using Esiur.Core; +using Esiur.Net.IIP; +using Esiur.Resource; +using Esiur.Resource.Template; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Esiur.Data; + +public static class DataSerializer +{ + public delegate byte[] Serializer(object value); + + public static unsafe (TransmissionTypeIdentifier, byte[]) Int32Composer(object value, DistributedConnection connection) + { + var v = (int)value; + var rt = new byte[4]; + fixed (byte* ptr = rt) + *((int*)ptr) = v; + return (TransmissionTypeIdentifier.Int32, rt); + } + + public static unsafe (TransmissionTypeIdentifier, byte[]) UInt32Composer(object value, DistributedConnection connection) + { + var v = (uint)value; + var rt = new byte[4]; + fixed (byte* ptr = rt) + *((uint*)ptr) = v; + return (TransmissionTypeIdentifier.UInt32, rt); + } + + public static unsafe (TransmissionTypeIdentifier, byte[]) Int16Composer(object value, DistributedConnection connection) + { + var v = (short)value; + var rt = new byte[2]; + fixed (byte* ptr = rt) + *((short*)ptr) = v; + return (TransmissionTypeIdentifier.Int16, rt); + } + + public static unsafe (TransmissionTypeIdentifier, byte[]) UInt16Composer(object value, DistributedConnection connection) + { + var v = (ushort)value; + var rt = new byte[2]; + fixed (byte* ptr = rt) + *((ushort*)ptr) = v; + return (TransmissionTypeIdentifier.UInt16, rt); + } + + public static unsafe (TransmissionTypeIdentifier, byte[]) Float32Composer(object value, DistributedConnection connection) + { + var v = (float)value; + var rt = new byte[4]; + fixed (byte* ptr = rt) + *((float*)ptr) = v; + return (TransmissionTypeIdentifier.Float32, rt); + } + + public static unsafe (TransmissionTypeIdentifier, byte[]) Float64Composer(object value, DistributedConnection connection) + { + var v = (double)value; + var rt = new byte[8]; + fixed (byte* ptr = rt) + *((double*)ptr) = v; + return (TransmissionTypeIdentifier.Float64, rt); + } + + public static unsafe (TransmissionTypeIdentifier, byte[]) Int64Composer(object value, DistributedConnection connection) + { + var v = (long)value; + var rt = new byte[8]; + fixed (byte* ptr = rt) + *((long*)ptr) = v; + return (TransmissionTypeIdentifier.Int64, rt); + } + + public static unsafe (TransmissionTypeIdentifier, byte[]) UIn64Composer(object value, DistributedConnection connection) + { + var v = (ulong)value; + var rt = new byte[8]; + fixed (byte* ptr = rt) + *((ulong*)ptr) = v; + return (TransmissionTypeIdentifier.UInt64, rt); + } + + + public static unsafe (TransmissionTypeIdentifier, byte[]) DateTimeComposer(object value, DistributedConnection connection) + { + var v = ((DateTime)value).ToUniversalTime().Ticks; + var rt = new byte[8]; + fixed (byte* ptr = rt) + *((long*)ptr) = v; + return (TransmissionTypeIdentifier.DateTime, rt); + } + + public static unsafe (TransmissionTypeIdentifier, byte[]) Float128Composer(object value, DistributedConnection connection) + { + var v = (decimal)value; + var rt = new byte[16]; + fixed (byte* ptr = rt) + *((decimal*)ptr) = v; + return (TransmissionTypeIdentifier.Float128, rt); + } + + + + public static (TransmissionTypeIdentifier, byte[]) StringComposer(object value, DistributedConnection connection) + { + return (TransmissionTypeIdentifier.String, Encoding.UTF8.GetBytes((string)value)); + } + + public static (TransmissionTypeIdentifier, byte[]) EnumComposer(object value, DistributedConnection connection) + { + if (value == null) + return (TransmissionTypeIdentifier.Null, new byte[0]); + + var template = Warehouse.GetTemplateByType(value.GetType()); + + var intVal = Convert.ChangeType(value, (value as Enum).GetTypeCode()); + + var ct = template.Constants.FirstOrDefault(x => x.Value.Equals(intVal)); + + if (ct == null) + return (TransmissionTypeIdentifier.Null, new byte[0]); + + + var rt = new List(); + rt.AddRange(template.ClassId.ToByteArray()); + rt.Add(ct.Index); + + return (TransmissionTypeIdentifier.Enum, rt.ToArray()); + } + + public static (TransmissionTypeIdentifier, byte[]) UInt8Composer(object value, DistributedConnection connection) + { + return (TransmissionTypeIdentifier.UInt8, new byte[] { (byte)value }); + } + + public static (TransmissionTypeIdentifier, byte[]) Int8Composer(object value, DistributedConnection connection) + { + return (TransmissionTypeIdentifier.Int8, new byte[] { (byte)(sbyte)value }); + } + + public static unsafe (TransmissionTypeIdentifier, byte[]) Char8Composer(object value, DistributedConnection connection) + { + return (TransmissionTypeIdentifier.Char8, new byte[] { (byte)(char)value }); + } + + public static unsafe (TransmissionTypeIdentifier, byte[]) Char16Composer(object value, DistributedConnection connection) + { + + var v = (char)value; + var rt = new byte[2]; + fixed (byte* ptr = rt) + *((char*)ptr) = v; + return (TransmissionTypeIdentifier.Char16, rt); + + } + + public static (TransmissionTypeIdentifier, byte[]) BoolComposer(object value, DistributedConnection connection) + { + return ((bool)value ? TransmissionTypeIdentifier.True : TransmissionTypeIdentifier.False, new byte[0]); + } + + + public static (TransmissionTypeIdentifier, byte[]) NotModifiedComposer(object value, DistributedConnection connection) + { + return (TransmissionTypeIdentifier.NotModified, new byte[0]); + } + + public static (TransmissionTypeIdentifier, byte[]) RawDataComposerFromArray(object value, DistributedConnection connection) + { + return (TransmissionTypeIdentifier.RawData, (byte[])value); + } + + public static (TransmissionTypeIdentifier, byte[]) RawDataComposerFromList(dynamic value, DistributedConnection connection) + { + return (TransmissionTypeIdentifier.RawData, (value as List).ToArray()); + } + + //public static (TransmissionTypeIdentifier, byte[]) ListComposerFromArray(dynamic value, DistributedConnection connection) + //{ + // var rt = new List(); + // var array = (object[])value; + + // for (var i = 0; i < array.Length; i++) + // rt.AddRange(Codec.Compose(array[i], connection)); + + // return (TransmissionTypeIdentifier.List, rt.ToArray()); + //} + + public static (TransmissionTypeIdentifier, byte[]) ListComposer(object value, DistributedConnection connection) + { + + var rt = ArrayComposer((IEnumerable)value, connection); + + if (rt == null) + return (TransmissionTypeIdentifier.Null, new byte[0]); + else + return (TransmissionTypeIdentifier.List, rt); + + + //var rt = new List(); + //var list = (IEnumerable)value;// ((List)value); + + //foreach (var o in list) + // rt.AddRange(Codec.Compose(o, connection)); + + //return (TransmissionTypeIdentifier.List, rt.ToArray()); + } + + + public static (TransmissionTypeIdentifier, byte[]) TypedListComposer(IEnumerable value, Type type, DistributedConnection connection) + { + var composed = ArrayComposer((IEnumerable)value, connection); + + if (composed == null) + return (TransmissionTypeIdentifier.Null, new byte[0]); + + var header = RepresentationType.FromType(type).Compose(); + + var rt = new List(); + + rt.AddRange(header); + rt.AddRange(composed); + + return (TransmissionTypeIdentifier.TypedList, rt.ToArray()); + } + + //public static byte[] PropertyValueComposer(PropertyValue propertyValue, DistributedConnection connection)//, bool includeAge = true) + //{ + // var rt = new BinaryList(); + + // return + // .AddUInt64(propertyValue.Age) + // .AddDateTime(propertyValue.Date) + // .AddUInt8Array(Codec.Compose(propertyValue.Value, connection)) + // .ToArray(); + //} + + public static (TransmissionTypeIdentifier, byte[]) PropertyValueArrayComposer(object value, DistributedConnection connection) + { + if (value == null) + return (TransmissionTypeIdentifier.Null, new byte[0]); + + var rt = new List(); + var ar = value as PropertyValue[]; + + foreach (var pv in ar) + { + rt.AddRange(Codec.Compose(pv.Age, connection)); + rt.AddRange(Codec.Compose(pv.Date, connection)); + rt.AddRange(Codec.Compose(pv.Value, connection)); + } + + return (TransmissionTypeIdentifier.List, rt.ToArray()); + } + + public static (TransmissionTypeIdentifier, byte[]) TypedMapComposer(object value, Type keyType, Type valueType, DistributedConnection connection) + { + if (value == null) + return (TransmissionTypeIdentifier.Null, new byte[0]); + + var kt = RepresentationType.FromType(keyType).Compose(); + var vt = RepresentationType.FromType(valueType).Compose(); + + var rt = new List(); + + rt.AddRange(kt); + rt.AddRange(vt); + + var map = (IMap)value; + + foreach(var el in map.Serialize()) + rt.AddRange(Codec.Compose(el, connection)); + + return (TransmissionTypeIdentifier.TypedMap, rt.ToArray()); + } + + public static byte[] ArrayComposer(IEnumerable value, DistributedConnection connection) + { + if (value == null) + return null; + + var rt = new List(); + + foreach (var i in value) + rt.AddRange(Codec.Compose(i, connection)); + + return rt.ToArray(); + } + + public static (TransmissionTypeIdentifier, byte[]) ResourceListComposer(object value, DistributedConnection connection) + { + if (value == null) + return (TransmissionTypeIdentifier.Null, new byte[0]); + + + return (TransmissionTypeIdentifier.ResourceList, ArrayComposer((IEnumerable)value, connection)); + } + + public static (TransmissionTypeIdentifier, byte[]) RecordListComposer(object value, DistributedConnection connection) + { + if (value == null) + return (TransmissionTypeIdentifier.Null, new byte[0]); + + + return (TransmissionTypeIdentifier.RecordList, ArrayComposer((IEnumerable)value, connection)); + } + + + public static unsafe (TransmissionTypeIdentifier, byte[]) ResourceComposer(object value, DistributedConnection connection) + { + var resource = (IResource)value; + var rt = new byte[4]; + + if (Codec.IsLocalResource(resource, connection)) + { + + fixed (byte* ptr = rt) + *((uint*)ptr) = (resource as DistributedResource).Id; + + return (TransmissionTypeIdentifier.ResourceLocal, rt); + } + else + { + //rt.Append((value as IResource).Instance.Template.ClassId, (value as IResource).Instance.Id); + connection.cache.Add(value as IResource, DateTime.UtcNow); + + fixed (byte* ptr = rt) + *((uint*)ptr) = resource.Instance.Id; + + return (TransmissionTypeIdentifier.Resource, rt); + } + } + + public static unsafe (TransmissionTypeIdentifier, byte[]) MapComposer(object value, DistributedConnection connection) + { + if (value == null) + return (TransmissionTypeIdentifier.Null, new byte[0]); + + var rt = new List(); + var map = (IMap)value; + + foreach (var el in map.Serialize()) + rt.AddRange(Codec.Compose(el, connection)); + + return (TransmissionTypeIdentifier.Map, rt.ToArray()); + } + + public static unsafe (TransmissionTypeIdentifier, byte[]) RecordComposer(object value, DistributedConnection connection) + { + var rt = new List();// BinaryList(); + var record = (IRecord)value; + + var template = Warehouse.GetTemplateByType(record.GetType()); + + + rt.AddRange(template.ClassId.ToByteArray()); + + foreach (var pt in template.Properties) + { + var propValue = pt.PropertyInfo.GetValue(record, null); + rt.AddRange(Codec.Compose(propValue, connection)); + } + + return (TransmissionTypeIdentifier.Record, rt.ToArray()); + } + public static byte[] HistoryComposer(KeyList history, + DistributedConnection connection, bool prependLength = false) + { + //@TODO:Test + var rt = new BinaryList(); + + for (var i = 0; i < history.Count; i++) + rt.AddUInt8(history.Keys.ElementAt(i).Index) + .AddUInt8Array(Codec.Compose(history.Values.ElementAt(i), connection)); + + if (prependLength) + rt.InsertInt32(0, rt.Length); + + return rt.ToArray(); + } + + public static (TransmissionTypeIdentifier, byte[]) TupleComposer(object value, DistributedConnection connection) + { + if (value == null) + return (TransmissionTypeIdentifier.Null, new byte[0]); + + var rt = new List(); + + var fields = value.GetType().GetFields(); + var list = fields.Select(x => x.GetValue(value)).ToArray(); + var types = fields.Select(x => RepresentationType.FromType(x.FieldType).Compose()).ToArray(); + + rt.Add((byte)list.Length); + + foreach (var t in types) + rt.AddRange(t); + + var composed = ArrayComposer(list, connection); + + if (composed == null) + return (TransmissionTypeIdentifier.Null, new byte[0]); + else + { + rt.AddRange(composed); + return (TransmissionTypeIdentifier.Tuple, rt.ToArray()); + } + } +} + + diff --git a/Esiur/Data/Endian.cs b/Esiur/Data/Endian.cs new file mode 100644 index 0000000..1300968 --- /dev/null +++ b/Esiur/Data/Endian.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Data +{ + public enum Endian + { + Big, + Little + } +} diff --git a/Esiur/Data/KeyList.cs b/Esiur/Data/KeyList.cs index c88903d..c50da5a 100644 --- a/Esiur/Data/KeyList.cs +++ b/Esiur/Data/KeyList.cs @@ -229,7 +229,7 @@ public class KeyList : IEnumerable> #if NETSTANDARD removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())); #else - removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T))); + removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T))); #endif this.Owner = owner; diff --git a/Esiur/Data/Map.cs b/Esiur/Data/Map.cs new file mode 100644 index 0000000..e216ea5 --- /dev/null +++ b/Esiur/Data/Map.cs @@ -0,0 +1,248 @@ +/* + +Copyright (c) 2017 Ahmed Kh. Zamil + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Esiur.Data; +using Esiur.Misc; +using Esiur.Core; +using System.Reflection; +using System.Dynamic; + +namespace Esiur.Data; + +//public class Map : IEnumerable> +//{ +// private Dictionary dic = new(); + +// public IEnumerator> GetEnumerator() +// { +// return dic.GetEnumerator(); +// } + +// IEnumerator IEnumerable.GetEnumerator() +// { +// return dic.GetEnumerator(); +// } +//} + +public interface IMap +{ + public void Add(object key, object value); + public void Remove(object key); + public void Clear(); + public bool ContainsKey(object key); + public object[] Serialize(); +} + +public class Map : IEnumerable>, IMap +{ + + //public struct StructureMetadata + //{ + // public KT[] Keys; + // public VT[] Types; + //} + + private Dictionary dic = new Dictionary();// StringComparer.OrdinalIgnoreCase); + private object syncRoot = new object(); + + + public bool ContainsKey(KT key) + { + return dic.ContainsKey(key); + } + + public override string ToString() + { + var rt = ""; + foreach (var kv in dic) + rt += kv.Key + ": " + kv.Value.ToString() + " \r\n"; + + return rt.TrimEnd('\r', '\n'); + } + + public Map(Map source) + { + dic = source.dic; + } + public Map() + { + + } + + public static Map FromMap(Map source, Type destinationType) + { + var rt = Activator.CreateInstance(destinationType) as Map; + rt.dic = source.dic; + return rt; + } + + //public static T FromStructure(Map source) where T : Map + //{ + // var rt = Activator.CreateInstance(); + // rt.dic = source.dic; + // return rt; + //} + + // public static explicit operator Map(ExpandoObject obj) => FromDynamic(obj); + + public static Map FromDynamic(ExpandoObject obj) + { + var rt = new Map(); + foreach (var kv in obj) + rt[kv.Key] = kv.Value; + return rt; + } + + public static Map FromObject(object obj) + { + var type = obj.GetType(); + + var st = new Map(); + + var pi = type.GetTypeInfo().GetProperties().Where(x => x.CanRead); + foreach (var p in pi) + st[p.Name] = p.GetValue(obj); + + var fi = type.GetTypeInfo().GetFields().Where(x => x.IsPublic); + foreach (var f in fi) + st[f.Name] = f.GetValue(obj); + + return st; + + + // if (obj is Structure) + // return obj as Structure; + // else //if (Codec.IsAnonymous(type)) + // { + // var st = new Structure(); + + // var pi = type.GetTypeInfo().GetProperties().Where(x => x.CanRead); + // foreach (var p in pi) + // st[p.Name] = p.GetValue(obj); + + // var fi = type.GetTypeInfo().GetFields().Where(x => x.IsPublic); + // foreach (var f in fi) + // st[f.Name] = f.GetValue(obj); + + // return st; + // } + // //else + // // return null; + } + + public IEnumerator> GetEnumerator() + { + return dic.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return dic.GetEnumerator(); + } + + public int Length + { + get { return dic.Count; } + } + + public KeyValuePair At(int index) + { + return dic.ElementAt(index); + } + + public object SyncRoot + { + get { return syncRoot; } + } + + public KT[] GetKeys() => dic.Keys.ToArray();//GetKeys() + //{ + // return dic.Keys.ToArray(); + //} + + public void Add(KT key, VT value) + { + if (dic.ContainsKey(key)) + dic[key] = value; + else + dic.Add(key, value); + } + + public void Add(object key, object value) + { + Add((KT)key, (VT)value); + } + + public void Remove(object key) + { + Remove((KT)key); + } + + public void Clear() + { + dic.Clear(); + } + + public bool ContainsKey(object key) + { + return ContainsKey((KT)key); + } + + public object[] Serialize() + { + var rt = new List(); + foreach(var kv in dic) + { + rt.Add(kv.Key); + rt.Add(kv.Value); + } + + return rt.ToArray(); + } + + public VT this[KT index] + { + get + { + if (dic.ContainsKey(index)) + return dic[index]; + else + return default; + } + set + { + if (dic.ContainsKey(index)) + dic[index] = value; + else + dic.Add(index, value); + } + } + +} diff --git a/Esiur/Data/PropertyValue.cs b/Esiur/Data/PropertyValue.cs index d91d219..e9ec6f2 100644 --- a/Esiur/Data/PropertyValue.cs +++ b/Esiur/Data/PropertyValue.cs @@ -13,11 +13,11 @@ public class PropertyValue /// /// Get or set date of modification or occurrence. /// - public DateTime Date { get; set; } + public DateTime? Date { get; set; } /// /// Get or set property age. /// - public ulong Age { get; set; } + public ulong? Age { get; set; } /// /// Create an instance of PropertyValue. @@ -25,7 +25,7 @@ public class PropertyValue /// Value. /// Age. /// Date. - public PropertyValue(object value, ulong age, DateTime date) + public PropertyValue(object value, ulong? age, DateTime? date) { Value = value; Age = age; diff --git a/Esiur/Data/RecordComparisonResult.cs b/Esiur/Data/RecordComparisonResult.cs deleted file mode 100644 index 9e78b1b..0000000 --- a/Esiur/Data/RecordComparisonResult.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Esiur.Data; - -public enum RecordComparisonResult : byte -{ - Null, - Record, - RecordSameType, - Same -} diff --git a/Esiur/Data/RepresentationType.cs b/Esiur/Data/RepresentationType.cs new file mode 100644 index 0000000..c1fb14e --- /dev/null +++ b/Esiur/Data/RepresentationType.cs @@ -0,0 +1,372 @@ +using Esiur.Net.IIP; +using Esiur.Resource; +using Esiur.Resource.Template; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Dynamic; +using System.Text; + +namespace Esiur.Data +{ + public enum RepresentationTypeIdentifier + { + Void, + Dynamic, + Bool, + UInt8, + Int8, + Char, + Int16, + UInt16, + Int32, + UInt32, + Float32, + Int64, + UInt64, + Float64, + DateTime, + Int128, + UInt128, + Decimal, + String, + RawData, + Resource, + Record, + List, + Map, + Enum = 0x44, + TypedResource = 0x45, // Followed by UUID + TypedRecord = 0x46, // Followed by UUID + TypedList = 0x48, // Followed by element type + Tuple2 = 0x50, // Followed by element type + TypedMap = 0x51, // Followed by key type and value type + Tuple3 = 0x58, + Tuple4 = 0x60, + Tuple5 = 0x68, + Tuple6 = 0x70, + Tuple7 = 0x78 + } + + public class RepresentationType + { + public Type? GetRuntimeType() + { + return Identifier switch + { + (RepresentationTypeIdentifier.Void) => typeof(void), + (RepresentationTypeIdentifier.Dynamic) => typeof(object), + (RepresentationTypeIdentifier.Bool) => Nullable ? typeof(bool?) : typeof(bool), + (RepresentationTypeIdentifier.Char) => Nullable ? typeof(char?) : typeof(char), + (RepresentationTypeIdentifier.UInt8) => Nullable ? typeof(byte?) : typeof(byte), + (RepresentationTypeIdentifier.Int8) => Nullable ? typeof(sbyte?) : typeof(sbyte), + (RepresentationTypeIdentifier.Int16) => Nullable ? typeof(short?) : typeof(short), + (RepresentationTypeIdentifier.UInt16) => Nullable ? typeof(ushort?) : typeof(ushort), + (RepresentationTypeIdentifier.Int32) => Nullable ? typeof(int?) : typeof(int), + (RepresentationTypeIdentifier.UInt32) => Nullable ? typeof(uint?) : typeof(uint), + (RepresentationTypeIdentifier.Int64) => Nullable ? typeof(ulong?) : typeof(long), + (RepresentationTypeIdentifier.UInt64) => Nullable ? typeof(ulong?) : typeof(ulong), + (RepresentationTypeIdentifier.Float32) => Nullable ? typeof(float?) : typeof(float), + (RepresentationTypeIdentifier.Float64) => Nullable ? typeof(double?) : typeof(double), + (RepresentationTypeIdentifier.Decimal) => Nullable ? typeof(decimal?) : typeof(decimal), + (RepresentationTypeIdentifier.String) => typeof(string), //Nullable ? typeof(Nullable) : typeof(string), + (RepresentationTypeIdentifier.DateTime) => Nullable ? typeof(DateTime?) : typeof(DateTime), + (RepresentationTypeIdentifier.Resource) => typeof(IResource), + (RepresentationTypeIdentifier.Record) => typeof(IRecord), + (RepresentationTypeIdentifier.TypedRecord) => Warehouse.GetTemplateByClassId((Guid)GUID, TemplateType.Record).DefinedType, + (RepresentationTypeIdentifier.TypedResource) => Warehouse.GetTemplateByClassId((Guid)GUID, TemplateType.Unspecified).DefinedType, + (RepresentationTypeIdentifier.Enum) => Warehouse.GetTemplateByClassId((Guid)GUID, TemplateType.Enum).DefinedType, + _ => null + }; + } + + public RepresentationTypeIdentifier Identifier; + public bool Nullable; + public Guid? GUID; + //public RepresentationType? SubType1; // List + Map + //public RepresentationType? SubType2; // Map + //public RepresentationType? SubType3; // No types yet + + public RepresentationType?[] SubTypes = new RepresentationType[3]; + + public static RepresentationType? FromType(Type type) + { + var nullType = System.Nullable.GetUnderlyingType(type); + var nullable = false; + + if (nullType != null) { + type = nullType; + nullable = true; + } + + if (type.IsGenericType) + { + var genericType = type.GetGenericTypeDefinition(); + if (genericType == typeof(List<>)) + { + var args = type.GetGenericArguments(); + if (args[0] == typeof(object)) + { + return new RepresentationType(RepresentationTypeIdentifier.List, nullable); + } + else + { + var subType = FromType(args[0]); + if (subType == null) // unrecongnized type + return null; + + return new RepresentationType(RepresentationTypeIdentifier.TypedList, nullable, null, subType); + + } + } + else if (genericType == typeof(Map<,>)) + { + var args = type.GetGenericArguments(); + if (args[0] == typeof(object) && args[1] == typeof(object)) + { + return new RepresentationType(RepresentationTypeIdentifier.Map, nullable); + } + else + { + var subType1 = FromType(args[0]); + if (subType1 == null) + return null; + + var subType2 = FromType(args[1]); + if (subType2 == null) + return null; + + return new RepresentationType(RepresentationTypeIdentifier.TypedMap, nullable, null, subType1, subType2); + } + } + else if (genericType == typeof(DistributedPropertyContext<>)) + { + var args = type.GetGenericArguments(); + return FromType(args[0]); + } + else if (genericType == typeof(ValueTuple<,>)) + { + var args = type.GetGenericArguments(); + var subTypes = new RepresentationType[args.Length]; + for (var i = 0; i < args.Length; i++) + { + subTypes[i] = FromType(args[i]); + if (subTypes[i] == null) + return null; + } + + return new RepresentationType(RepresentationTypeIdentifier.Tuple2, nullable, null, subTypes); + } + else if (genericType == typeof(ValueTuple<,,>)) + { + var args = type.GetGenericArguments(); + var subTypes = new RepresentationType[args.Length]; + for(var i = 0; i < args.Length; i++) + { + subTypes[i] = FromType(args[i]); + if (subTypes[i] == null) + return null; + } + + return new RepresentationType(RepresentationTypeIdentifier.Tuple3, nullable, null, subTypes); + } + else if (genericType == typeof(ValueTuple<,,,>)) + { + + var args = type.GetGenericArguments(); + var subTypes = new RepresentationType[args.Length]; + for (var i = 0; i < args.Length; i++) + { + subTypes[i] = FromType(args[i]); + if (subTypes[i] == null) + return null; + } + + return new RepresentationType(RepresentationTypeIdentifier.Tuple4, nullable, null, subTypes); + } + else if (genericType == typeof(ValueTuple<,,,,>)) + { + var args = type.GetGenericArguments(); + var subTypes = new RepresentationType[args.Length]; + for (var i = 0; i < args.Length; i++) + { + subTypes[i] = FromType(args[i]); + if (subTypes[i] == null) + return null; + } + + return new RepresentationType(RepresentationTypeIdentifier.Tuple5, nullable, null, subTypes); + } + else if (genericType == typeof(ValueTuple<,,,,,>)) + { + var args = type.GetGenericArguments(); + var subTypes = new RepresentationType[args.Length]; + for (var i = 0; i < args.Length; i++) + { + subTypes[i] = FromType(args[i]); + if (subTypes[i] == null) + return null; + } + + return new RepresentationType(RepresentationTypeIdentifier.Tuple6, nullable, null, subTypes); + } + else if (genericType == typeof(ValueTuple<,,,,,,>)) + { + var args = type.GetGenericArguments(); + var subTypes = new RepresentationType[args.Length]; + for (var i = 0; i < args.Length; i++) + { + subTypes[i] = FromType(args[i]); + if (subTypes[i] == null) + return null; + } + + return new RepresentationType(RepresentationTypeIdentifier.Tuple7, nullable, null, subTypes); + } + else + return null; + } + else if (type.IsArray) + { + var elementType = type.GetElementType(); + if (elementType == typeof(object)) + return new RepresentationType(RepresentationTypeIdentifier.List, nullable); + else + { + var subType = FromType(elementType); + + if (subType == null) + return null; + + return new RepresentationType(RepresentationTypeIdentifier.TypedList, nullable, null, subType); + + } + } + else if (type == typeof(IResource)) + return new RepresentationType(RepresentationTypeIdentifier.Resource, nullable); + else if (type == typeof(IRecord) || type == typeof(Record)) + return new RepresentationType(RepresentationTypeIdentifier.Record, nullable); + else if (type == typeof(Map)) + return new RepresentationType(RepresentationTypeIdentifier.Map, nullable); + else if (Codec.ImplementsInterface(type, typeof(IResource))) + { + return new RepresentationType( + RepresentationTypeIdentifier.TypedResource, + nullable, + TypeTemplate.GetTypeGuid(type) + ); + } + else if (Codec.ImplementsInterface(type, typeof(IRecord))) + { + return new RepresentationType( + RepresentationTypeIdentifier.TypedRecord, + nullable, + TypeTemplate.GetTypeGuid(type) + ); + } + else if (type.IsEnum) + { + return new RepresentationType(RepresentationTypeIdentifier.Enum, nullable, TypeTemplate.GetTypeGuid(type)); + } + //else if (typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject) => RepresentationTypeIdentifier.Structure) + //{ + + //} + + return type switch + { + _ when type == typeof(void) => new RepresentationType(RepresentationTypeIdentifier.Void, nullable), + _ when type == typeof(object) => new RepresentationType(RepresentationTypeIdentifier.Dynamic, nullable), + _ when type == typeof(bool) => new RepresentationType(RepresentationTypeIdentifier.Bool, nullable), + _ when type == typeof(char) => new RepresentationType(RepresentationTypeIdentifier.Char, nullable), + _ when type == typeof(byte) => new RepresentationType(RepresentationTypeIdentifier.UInt8, nullable), + _ when type == typeof(sbyte) => new RepresentationType(RepresentationTypeIdentifier.Int8, nullable), + _ when type == typeof(short) => new RepresentationType(RepresentationTypeIdentifier.Int16, nullable), + _ when type == typeof(ushort) => new RepresentationType(RepresentationTypeIdentifier.UInt16, nullable), + _ when type == typeof(int) => new RepresentationType(RepresentationTypeIdentifier.Int32, nullable), + _ when type == typeof(uint) => new RepresentationType(RepresentationTypeIdentifier.UInt32, nullable), + _ when type == typeof(long) => new RepresentationType(RepresentationTypeIdentifier.Int64, nullable), + _ when type == typeof(ulong) => new RepresentationType(RepresentationTypeIdentifier.UInt64, nullable), + _ when type == typeof(float) => new RepresentationType(RepresentationTypeIdentifier.Float32, nullable), + _ when type == typeof(double) => new RepresentationType(RepresentationTypeIdentifier.Float64, nullable), + _ when type == typeof(decimal) => new RepresentationType(RepresentationTypeIdentifier.Decimal, nullable), + _ when type == typeof(string) => new RepresentationType(RepresentationTypeIdentifier.String, nullable), + _ when type == typeof(DateTime) => new RepresentationType(RepresentationTypeIdentifier.DateTime, nullable), + _ => null + }; + + } + + public RepresentationType(RepresentationTypeIdentifier identifier, bool nullable, Guid? guid = null, params RepresentationType[] subTypes) + { + Nullable = nullable; + Identifier = identifier; + GUID = guid; + SubTypes = subTypes; + } + + public byte[] Compose() + { + var rt = new BinaryList(); + + if (Nullable) + rt.AddUInt8((byte)(0x80 | (byte)Identifier)); + else + rt.AddUInt8((byte)Identifier); + + if (GUID != null) + rt.AddUInt8Array(DC.ToBytes((Guid)GUID)); + + if (SubTypes != null) + for (var i = 0; i < SubTypes.Length; i++) + rt.AddUInt8Array(SubTypes[i].Compose()); + + return rt.ToArray(); + } + + + //public override string ToString() => Identifier.ToString() + (Nullable ? "?" : "") + // + TypeTemplate != null ? "<" + TypeTemplate.ClassName + ">" : ""; + + + public static (uint, RepresentationType) Parse(byte[] data, uint offset) + { + var oOffset = offset; + + var header = data[offset++]; + bool nullable = (header & 0x80) > 0; + var identifier = (RepresentationTypeIdentifier)(header & 0x7F); + + + if ((header & 0x40) > 0) + { + + var hasGUID = (header & 0x4) > 0; + var subsCount = (header >> 3) & 0x7; + + Guid? guid = null; + + if (hasGUID) + { + guid = data.GetGuid(offset); + offset += 16; + } + + var subs = new RepresentationType[subsCount]; + + for (var i = 0; i < subsCount; i++) + { + (var len, subs[i]) = RepresentationType.Parse(data, offset); + offset += len; + } + + return (offset - oOffset, new RepresentationType(identifier, nullable, guid, subs)); + } + else + { + return (1, new RepresentationType(identifier, nullable)); + } + } + + } +} \ No newline at end of file diff --git a/Esiur/Data/ResourceComparisonResult.cs b/Esiur/Data/ResourceComparisonResult.cs deleted file mode 100644 index c173f8c..0000000 --- a/Esiur/Data/ResourceComparisonResult.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Esiur.Data; - -public enum ResourceComparisonResult -{ - Null, // null - Distributed, // resource is distributed - Local, // resource is local - Same, // Same as previous -} diff --git a/Esiur/Data/ResourceJsonConverter.cs b/Esiur/Data/ResourceJsonConverter.cs index d13b132..b8c7792 100644 --- a/Esiur/Data/ResourceJsonConverter.cs +++ b/Esiur/Data/ResourceJsonConverter.cs @@ -55,7 +55,7 @@ class ResourceJsonConverter : JsonConverter foreach (var pt in resource.Instance.Template.Properties) { var rt = pt.PropertyInfo.GetValue(resource, null); - if (rt is DistributedPropertyContext) + if (rt != null && rt.GetType().IsGenericType) continue; writer.WritePropertyName(options.PropertyNamingPolicy?.ConvertName(pt.Name) ?? pt.Name); diff --git a/Esiur/Data/Structure.cs b/Esiur/Data/Structure.cs deleted file mode 100644 index 72729c4..0000000 --- a/Esiur/Data/Structure.cs +++ /dev/null @@ -1,180 +0,0 @@ -/* - -Copyright (c) 2017 Ahmed Kh. Zamil - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Esiur.Data; -using Esiur.Misc; -using Esiur.Core; -using System.Reflection; -using System.Dynamic; - -namespace Esiur.Data; - -public class Structure : IEnumerable> -{ - - public struct StructureMetadata - { - public string[] Keys; - public DataType[] Types; - } - - private Dictionary dic = new Dictionary(StringComparer.OrdinalIgnoreCase); - private object syncRoot = new object(); - - - public bool ContainsKey(string key) - { - return dic.ContainsKey(key); - } - - public override string ToString() - { - var rt = ""; - foreach (var kv in dic) - rt += kv.Key + ": " + kv.Value.ToString() + " \r\n"; - - return rt.TrimEnd('\r', '\n'); - } - - public Structure(Structure source) - { - dic = source.dic; - } - public Structure() - { - - } - - public static Structure FromStructure(Structure source, Type destinationType) - { - var rt = Activator.CreateInstance(destinationType) as Structure; - rt.dic = source.dic; - return rt; - } - - public static T FromStructure(Structure source) where T : Structure - { - var rt = Activator.CreateInstance(); - rt.dic = source.dic; - return rt; - } - - public static explicit operator Structure(ExpandoObject obj) => FromDynamic(obj); - - public static Structure FromDynamic(ExpandoObject obj) - { - var rt = new Structure(); - foreach (var kv in obj) - rt[kv.Key] = kv.Value; - return rt; - } - - public static Structure FromObject(object obj) - { - var type = obj.GetType(); - - if (obj is Structure) - return obj as Structure; - else //if (Codec.IsAnonymous(type)) - { - var st = new Structure(); - - var pi = type.GetTypeInfo().GetProperties().Where(x => x.CanRead); - foreach (var p in pi) - st[p.Name] = p.GetValue(obj); - - var fi = type.GetTypeInfo().GetFields().Where(x => x.IsPublic); - foreach (var f in fi) - st[f.Name] = f.GetValue(obj); - - return st; - } - //else - // return null; - } - public IEnumerator> GetEnumerator() - { - return dic.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return dic.GetEnumerator(); - } - - public int Length - { - get { return dic.Count; } - } - - public KeyValuePair At(int index) - { - return dic.ElementAt(index); - } - - public object SyncRoot - { - get { return syncRoot; } - } - - public string[] GetKeys() => dic.Keys.ToArray();//GetKeys() - //{ - // return dic.Keys.ToArray(); - //} - - public Structure Add(string key, object value) - { - if (dic.ContainsKey(key)) - dic[key] = value; - else - dic.Add(key, value); - - return this; - } - - public object this[string index] - { - get - { - if (dic.ContainsKey(index)) - return dic[index]; - else - return null; - } - set - { - if (dic.ContainsKey(index)) - dic[index] = value; - else - dic.Add(index, value); - } - } - -} diff --git a/Esiur/Data/StructureComparisonResult.cs b/Esiur/Data/StructureComparisonResult.cs deleted file mode 100644 index 6d150ad..0000000 --- a/Esiur/Data/StructureComparisonResult.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Esiur.Data; - -public enum StructureComparisonResult : byte -{ - Null, - Structure, - StructureSameKeys, - StructureSameTypes, - Same -} diff --git a/Esiur/Data/TransmissionType.cs b/Esiur/Data/TransmissionType.cs new file mode 100644 index 0000000..d016c4a --- /dev/null +++ b/Esiur/Data/TransmissionType.cs @@ -0,0 +1,247 @@ +using Esiur.Net.IIP; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Data; + +public enum TransmissionTypeIdentifier : byte +{ + Null = 0x0, + False = 0x1, + True = 0x2, + NotModified = 0x3, + UInt8 = 0x8, + Int8 = 0x9, + Char8 = 0xA, + Int16 = 0x10, + UInt16 = 0x11, + Char16 = 0x12, + Int32 = 0x18, + UInt32 = 0x19, + Float32 = 0x1A, + Resource = 0x1B, + ResourceLocal = 0x1C, + Int64 = 0x20, + UInt64 = 0x21, + Float64 = 0x22, + DateTime = 0x23, + Int128 = 0x28, + UInt128 = 0x29, + Float128 = 0x2A, + + RawData = 0x40, + String = 0x41, + List = 0x42, + ResourceList = 0x43, + RecordList = 0x44, + Map = 0x45, + MapList = 0x46, + //Tuple = 0x47, + + Record = 0x80, + TypedList = 0x81, + TypedMap = 0x82, + Tuple = 0x83, + Enum = 0x84, + Constant = 0x85 + //TypedResourceList = 0x81, + //TypedRecordList = 0x82, + +} + +public enum TransmissionTypeClass +{ + Fixed = 0, + Dynamic = 1, + Typed = 2 +} + +public struct TransmissionType +{ + public TransmissionTypeIdentifier Identifier; + public int Index; + public TransmissionTypeClass Class; + public uint Offset; + public ulong ContentLength; + public byte Exponent; + + + public TransmissionType(TransmissionTypeIdentifier identifier, TransmissionTypeClass cls, int index, uint offset, ulong contentLength, byte exponent = 0) + { + Identifier = identifier; + Index = index; + Class = cls; + Offset=offset; + ContentLength = contentLength; + Exponent = exponent; + } + + public static byte[] Compose(TransmissionTypeIdentifier identifier, byte[] data) + { + + if (data == null || data.Length == 0) + return new byte[] { (byte)identifier }; + + var cls = (TransmissionTypeClass)((int)identifier >> 6); + if (cls == TransmissionTypeClass.Fixed) + { + return DC.Combine(new byte[] { (byte)identifier }, 0, 1, data, 0, (uint)data.Length); + } + else + { + var len = (ulong)data.LongLength; + + if (len == 0) + { + return new byte[1] { (byte) identifier }; + } + else if (len <= 0xFF) + { + var rt = new byte[2 + len]; + rt[0] = (byte)((byte)identifier | 0x8); + rt[1] = (byte)len; + Buffer.BlockCopy(data, 0, rt, 2, (int)len); + return rt; + } + else if (len <= 0xFF_FF) + { + var rt = new byte[3 + len]; + rt[0] = (byte)((byte)identifier | 0x10); + rt[1] = (byte)((len >> 8) & 0xFF); + rt[2] = (byte)(len & 0xFF); + Buffer.BlockCopy(data, 0, rt, 3, (int)len); + return rt; + } + else if (len <= 0xFF_FF_FF) + { + var rt = new byte[4 + len]; + rt[0] = (byte)((byte)identifier | 0x18); + rt[1] = (byte)((len >> 16) & 0xFF); + rt[2] = (byte)((len >> 8) & 0xFF); + rt[3] = (byte)(len & 0xFF); + Buffer.BlockCopy(data, 0, rt, 4, (int)len); + return rt; + } + else if (len <= 0xFF_FF_FF_FF) + { + var rt = new byte[5 + len]; + rt[0] = (byte)((byte)identifier | 0x20); + rt[1] = (byte)((len >> 24) & 0xFF); + rt[2] = (byte)((len >> 16) & 0xFF); + rt[3] = (byte)((len >> 8) & 0xFF); + rt[4] = (byte)(len & 0xFF); + Buffer.BlockCopy(data, 0, rt, 5, (int)len); + return rt; + } + else if (len <= 0xFF_FF_FF_FF_FF) + { + var rt = new byte[6 + len]; + rt[0] = (byte)((byte)identifier | 0x28); + rt[1] = (byte)((len >> 32) & 0xFF); + rt[2] = (byte)((len >> 24) & 0xFF); + rt[3] = (byte)((len >> 16) & 0xFF); + rt[4] = (byte)((len >> 8) & 0xFF); + rt[5] = (byte)(len & 0xFF); + Buffer.BlockCopy(data, 0, rt, 6, (int)len); + return rt; + } + else if (len <= 0xFF_FF_FF_FF_FF_FF) + { + var rt = new byte[7 + len]; + rt[0] = (byte)((byte)identifier | 0x30); + rt[1] = (byte)((len >> 40) & 0xFF); + rt[2] = (byte)((len >> 32) & 0xFF); + rt[3] = (byte)((len >> 24) & 0xFF); + rt[4] = (byte)((len >> 16) & 0xFF); + rt[5] = (byte)((len >> 8) & 0xFF); + rt[6] = (byte)(len & 0xFF); + Buffer.BlockCopy(data, 0, rt, 7, (int)len); + return rt; + } + else //if (len <= 0xFF_FF_FF_FF_FF_FF_FF) + { + var rt = new byte[8 + len]; + rt[0] = (byte)((byte)identifier | 0x38); + rt[1] = (byte)((len >> 48) & 0xFF); + rt[2] = (byte)((len >> 40) & 0xFF); + rt[3] = (byte)((len >> 32) & 0xFF); + rt[4] = (byte)((len >> 24) & 0xFF); + rt[5] = (byte)((len >> 16) & 0xFF); + rt[6] = (byte)((len >> 8) & 0xFF); + rt[7] = (byte)(len & 0xFF); + Buffer.BlockCopy(data, 0, rt, 8, (int)len); + return rt; + } + //else // if (len <= 0xFF_FF_FF_FF_FF_FF_FF_FF) + //{ + // var rt = new byte[9 + len]; + // rt[0] = (byte)((byte)identifier | 0x8); + // rt[1] = (byte)((len >> 56) & 0xFF); + // rt[2] = (byte)((len >> 48) & 0xFF); + // rt[3] = (byte)((len >> 40) & 0xFF); + // rt[4] = (byte)((len >> 32) & 0xFF); + // rt[5] = (byte)((len >> 24) & 0xFF); + // rt[6] = (byte)((len >> 16) & 0xFF); + // rt[7] = (byte)((len >> 8) & 0xFF); + // rt[8] = (byte)(len & 0xFF); + // Buffer.BlockCopy(data, 0, rt, 9, (int)len); + // return rt; + //} + + + // // add length + // int bytes = 1; + //for (var i = 56; i > 0; i -= 8, bytes++) + // if (len <= (0xFF_FF_FF_FF_FF_FF_FF_FF >> i)) + // break; + + //var rt = new byte[1 + bytes + data.Length]; + //rt[0] = (byte)((byte)identifier | (bytes << 3)); + + //for (var i = 1; i <= bytes; i++) + // rt[i] = data.LongLength >> i * 8; + + //Buffer.BlockCopy(data, 0, rt, 1 + bytes, data.Length); + } + } + + public static (ulong, TransmissionType?) Parse(byte[] data, uint offset, uint ends) + { + var h = data[offset++]; + + var cls = (TransmissionTypeClass)(h >> 6); + + if (cls == TransmissionTypeClass.Fixed) + { + var exp = (h & 0x38) >> 3; + + if (exp == 0) + return (1, new TransmissionType((TransmissionTypeIdentifier)h, cls, h & 0x7, 0, (byte)exp)); + + ulong cl = (ulong)(1 << (exp -1)); + + if (ends - offset < cl) + return (ends - offset - (uint)cl, null); + + //offset += (uint)cl; + + return (1 + cl, new TransmissionType((TransmissionTypeIdentifier)h, cls, h & 0x7, offset, cl, (byte)exp)); + } + else + { + ulong cll = (ulong)(h >> 3) & 0x7; + + if (ends - offset < cll) + return (ends - offset - (uint)cll, null); + + ulong cl = 0; + + for (uint i = 0; i < cll; i++) + cl = cl << 8 | data[offset++]; + + return (1 + cl + cll, new TransmissionType((TransmissionTypeIdentifier)(h & 0xC7), cls, h & 0x7, offset, cl)); + } + } + +} diff --git a/Esiur/Esiur.csproj b/Esiur/Esiur.csproj index 0ca824f..09e175c 100644 --- a/Esiur/Esiur.csproj +++ b/Esiur/Esiur.csproj @@ -6,12 +6,12 @@ Ahmed Kh. Zamil http://www.esiur.com true - 2.0.0-alpha + 2.1.1 https://github.com/esiur/esiur-dotnet Ahmed Kh. Zamil - 2.0.0.0 + Esiur Foundation - 2.0.0.0 + Esiur Esiur Esiur @@ -36,11 +36,15 @@ + + + + @@ -48,29 +52,31 @@ + + - + - + - + - - + + @@ -83,9 +89,22 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/Esiur/Net/DataLink/PacketFilter.cs b/Esiur/Net/DataLink/PacketFilter.cs index dad670e..835e166 100644 --- a/Esiur/Net/DataLink/PacketFilter.cs +++ b/Esiur/Net/DataLink/PacketFilter.cs @@ -42,6 +42,7 @@ public abstract class PacketFilter : IResource } public event DestroyedEvent OnDestroy; + public abstract AsyncReply Trigger(ResourceTrigger trigger); @@ -51,4 +52,6 @@ public abstract class PacketFilter : IResource { OnDestroy?.Invoke(this); } + + } diff --git a/Esiur/Net/DataLink/PacketServer.cs b/Esiur/Net/DataLink/PacketServer.cs index aff14fb..a7723b4 100644 --- a/Esiur/Net/DataLink/PacketServer.cs +++ b/Esiur/Net/DataLink/PacketServer.cs @@ -61,6 +61,7 @@ public class PacketServer : IResource } public event DestroyedEvent OnDestroy; + public event PropertyModifiedEvent PropertyModified; public void Destroy() { diff --git a/Esiur/Net/HTTP/HTTPConnection.cs b/Esiur/Net/HTTP/HTTPConnection.cs index 4e104d7..1cd1db8 100644 --- a/Esiur/Net/HTTP/HTTPConnection.cs +++ b/Esiur/Net/HTTP/HTTPConnection.cs @@ -103,26 +103,36 @@ public class HTTPConnection : NetworkConnection public bool Upgrade() { - if (IsWebsocketRequest()) + var ok = Upgrade(Request, Response); + + if (ok) + { + WSMode = true; + Send(); + } + + return ok; + } + + public static bool Upgrade(HTTPRequestPacket request, HTTPResponsePacket response) + { + if (IsWebsocketRequest(request)) { string magicString = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - string ret = Request.Headers["Sec-WebSocket-Key"] + magicString; + string ret = request.Headers["Sec-WebSocket-Key"] + magicString; // Compute the SHA1 hash SHA1 sha = SHA1.Create(); byte[] sha1Hash = sha.ComputeHash(Encoding.UTF8.GetBytes(ret)); - Response.Headers["Upgrade"] = Request.Headers["Upgrade"]; - Response.Headers["Connection"] = Request.Headers["Connection"];// "Upgrade"; - Response.Headers["Sec-WebSocket-Accept"] = Convert.ToBase64String(sha1Hash); + response.Headers["Upgrade"] = request.Headers["Upgrade"]; + response.Headers["Connection"] = request.Headers["Connection"];// "Upgrade"; + response.Headers["Sec-WebSocket-Accept"] = Convert.ToBase64String(sha1Hash); - if (Request.Headers.ContainsKey("Sec-WebSocket-Protocol")) - Response.Headers["Sec-WebSocket-Protocol"] = Request.Headers["Sec-WebSocket-Protocol"]; + if (request.Headers.ContainsKey("Sec-WebSocket-Protocol")) + response.Headers["Sec-WebSocket-Protocol"] = request.Headers["Sec-WebSocket-Protocol"]; - Response.Number = HTTPResponsePacket.ResponseCode.Switching; - Response.Text = "Switching Protocols"; - WSMode = true; - - Send(); + response.Number = HTTPResponsePacket.ResponseCode.Switching; + response.Text = "Switching Protocols"; return true; } @@ -212,13 +222,18 @@ public class HTTPConnection : NetworkConnection public bool IsWebsocketRequest() { - if (Request.Headers.ContainsKey("connection") - && Request.Headers["connection"].ToLower().Contains("upgrade") - && Request.Headers.ContainsKey("upgrade") - && Request.Headers["upgrade"].ToLower() == "websocket" - && Request.Headers.ContainsKey("Sec-WebSocket-Version") - && Request.Headers["Sec-WebSocket-Version"] == "13" - && Request.Headers.ContainsKey("Sec-WebSocket-Key")) + return IsWebsocketRequest(this.Request); + } + + public static bool IsWebsocketRequest(HTTPRequestPacket request) + { + if (request.Headers.ContainsKey("connection") + && request.Headers["connection"].ToLower().Contains("upgrade") + && request.Headers.ContainsKey("upgrade") + && request.Headers["upgrade"].ToLower() == "websocket" + && request.Headers.ContainsKey("Sec-WebSocket-Version") + && request.Headers["Sec-WebSocket-Version"] == "13" + && request.Headers.ContainsKey("Sec-WebSocket-Key")) //&& Request.Headers.ContainsKey("Sec-WebSocket-Protocol")) { return true; @@ -284,7 +299,7 @@ public class HTTPConnection : NetworkConnection - if (IsWebsocketRequest() & !WSMode) + if (IsWebsocketRequest(Request) & !WSMode) { Upgrade(); //return; diff --git a/Esiur/Net/HTTP/HTTPFilter.cs b/Esiur/Net/HTTP/HTTPFilter.cs index 8819eb6..3270b16 100644 --- a/Esiur/Net/HTTP/HTTPFilter.cs +++ b/Esiur/Net/HTTP/HTTPFilter.cs @@ -46,7 +46,6 @@ public abstract class HTTPFilter : IResource } public event DestroyedEvent OnDestroy; - public abstract AsyncReply Trigger(ResourceTrigger trigger); /* diff --git a/Esiur/Net/HTTP/HTTPServer.cs b/Esiur/Net/HTTP/HTTPServer.cs index 31fb944..9444d43 100644 --- a/Esiur/Net/HTTP/HTTPServer.cs +++ b/Esiur/Net/HTTP/HTTPServer.cs @@ -155,7 +155,12 @@ public class HTTPServer : NetworkServer, IResource return false; } + //public delegate void HTTPGetHandler(HTTPConnection connection, object[] params values); + public void MapGet(string pattern, Delegate handler) + { + // if (p) + } /* diff --git a/Esiur/Net/IIP/DistributedConnection.cs b/Esiur/Net/IIP/DistributedConnection.cs index c6815bb..f8bf7f1 100644 --- a/Esiur/Net/IIP/DistributedConnection.cs +++ b/Esiur/Net/IIP/DistributedConnection.cs @@ -39,6 +39,7 @@ using Esiur.Resource.Template; using System.Linq; using System.Diagnostics; using static Esiur.Net.Packets.IIPPacket; +using Esiur.Net.HTTP; namespace Esiur.Net.IIP; public partial class DistributedConnection : NetworkConnection, IStore @@ -56,6 +57,8 @@ public partial class DistributedConnection : NetworkConnection, IStore /// public event ErrorEvent OnError; + + IIPPacket packet = new IIPPacket(); IIPAuthPacket authPacket = new IIPAuthPacket(); @@ -71,8 +74,12 @@ public partial class DistributedConnection : NetworkConnection, IStore string _hostname; ushort _port; + bool initialPacket = true; + DateTime loginDate; + + /// /// Local username to authenticate ourselves. /// @@ -350,7 +357,7 @@ public partial class DistributedConnection : NetworkConnection, IStore if (ready) { var rt = packet.Parse(msg, offset, ends); - //Console.WriteLine("Rec: " + chunkId + " " + packet.ToString()); + Console.WriteLine("Rec: " + chunkId + " " + packet.ToString()); /* if (packet.Command == IIPPacketCommand.Event) @@ -394,10 +401,10 @@ public partial class DistributedConnection : NetworkConnection, IStore IIPEventResourceDestroyed(packet.ResourceId); break; case IIPPacket.IIPPacketEvent.PropertyUpdated: - IIPEventPropertyUpdated(packet.ResourceId, packet.MethodIndex, packet.Content); + IIPEventPropertyUpdated(packet.ResourceId, packet.MethodIndex, (TransmissionType)packet.DataType, msg);// packet.Content); break; case IIPPacket.IIPPacketEvent.EventOccurred: - IIPEventEventOccurred(packet.ResourceId, packet.MethodIndex, packet.Content); + IIPEventEventOccurred(packet.ResourceId, packet.MethodIndex, (TransmissionType)packet.DataType, msg);//packet.Content); break; case IIPPacketEvent.ChildAdded: @@ -407,10 +414,11 @@ public partial class DistributedConnection : NetworkConnection, IStore IIPEventChildRemoved(packet.ResourceId, packet.ChildId); break; case IIPPacketEvent.Renamed: - IIPEventRenamed(packet.ResourceId, packet.Content); + IIPEventRenamed(packet.ResourceId, packet.ResourceLink); break; case IIPPacketEvent.AttributesUpdated: - IIPEventAttributesUpdated(packet.ResourceId, packet.Content); + // @TODO: fix this + //IIPEventAttributesUpdated(packet.ResourceId, packet.Content); break; } } @@ -429,7 +437,8 @@ public partial class DistributedConnection : NetworkConnection, IStore IIPRequestDetachResource(packet.CallbackId, packet.ResourceId); break; case IIPPacket.IIPPacketAction.CreateResource: - IIPRequestCreateResource(packet.CallbackId, packet.StoreId, packet.ResourceId, packet.Content); + //@TODO : fix this + //IIPRequestCreateResource(packet.CallbackId, packet.StoreId, packet.ResourceId, packet.Content); break; case IIPPacket.IIPPacketAction.DeleteResource: IIPRequestDeleteResource(packet.CallbackId, packet.ResourceId); @@ -441,7 +450,7 @@ public partial class DistributedConnection : NetworkConnection, IStore IIPRequestRemoveChild(packet.CallbackId, packet.ResourceId, packet.ChildId); break; case IIPPacketAction.RenameResource: - IIPRequestRenameResource(packet.CallbackId, packet.ResourceId, packet.Content); + IIPRequestRenameResource(packet.CallbackId, packet.ResourceId, packet.ResourceName); break; // Inquire @@ -474,13 +483,13 @@ public partial class DistributedConnection : NetworkConnection, IStore break; // Invoke - case IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments: - IIPRequestInvokeFunctionArrayArguments(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content); + case IIPPacket.IIPPacketAction.InvokeFunction: + IIPRequestInvokeFunction(packet.CallbackId, packet.ResourceId, packet.MethodIndex, (TransmissionType)packet.DataType, msg); break; - case IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments: - IIPRequestInvokeFunctionNamedArguments(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content); - break; + //case IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments: + // IIPRequestInvokeFunctionNamedArguments(packet.CallbackId, packet.ResourceId, packet.MethodIndex, (TransmissionType)packet.DataType, msg); + // break; //case IIPPacket.IIPPacketAction.GetProperty: // IIPRequestGetProperty(packet.CallbackId, packet.ResourceId, packet.MethodIndex); @@ -498,27 +507,33 @@ public partial class DistributedConnection : NetworkConnection, IStore break; case IIPPacket.IIPPacketAction.SetProperty: - IIPRequestSetProperty(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content); + IIPRequestSetProperty(packet.CallbackId, packet.ResourceId, packet.MethodIndex, (TransmissionType)packet.DataType, msg); break; // Attribute case IIPPacketAction.GetAllAttributes: - IIPRequestGetAttributes(packet.CallbackId, packet.ResourceId, packet.Content, true); + // @TODO : fix this + //IIPRequestGetAttributes(packet.CallbackId, packet.ResourceId, packet.Content, true); break; case IIPPacketAction.UpdateAllAttributes: - IIPRequestUpdateAttributes(packet.CallbackId, packet.ResourceId, packet.Content, true); + // @TODO : fix this + //IIPRequestUpdateAttributes(packet.CallbackId, packet.ResourceId, packet.Content, true); break; case IIPPacketAction.ClearAllAttributes: - IIPRequestClearAttributes(packet.CallbackId, packet.ResourceId, packet.Content, true); + // @TODO : fix this + //IIPRequestClearAttributes(packet.CallbackId, packet.ResourceId, packet.Content, true); break; case IIPPacketAction.GetAttributes: - IIPRequestGetAttributes(packet.CallbackId, packet.ResourceId, packet.Content, false); + // @TODO : fix this + //IIPRequestGetAttributes(packet.CallbackId, packet.ResourceId, packet.Content, false); break; case IIPPacketAction.UpdateAttributes: - IIPRequestUpdateAttributes(packet.CallbackId, packet.ResourceId, packet.Content, false); + // @TODO : fix this + //IIPRequestUpdateAttributes(packet.CallbackId, packet.ResourceId, packet.Content, false); break; case IIPPacketAction.ClearAttributes: - IIPRequestClearAttributes(packet.CallbackId, packet.ResourceId, packet.Content, false); + // @TODO : fix this + //IIPRequestClearAttributes(packet.CallbackId, packet.ResourceId, packet.Content, false); break; } } @@ -528,11 +543,11 @@ public partial class DistributedConnection : NetworkConnection, IStore { // Manage case IIPPacket.IIPPacketAction.AttachResource: - IIPReply(packet.CallbackId, packet.ClassId, packet.ResourceAge, packet.ResourceLink, packet.Content); + IIPReply(packet.CallbackId, packet.ClassId, packet.ResourceAge, packet.ResourceLink, packet.DataType, msg); break; case IIPPacket.IIPPacketAction.ReattachResource: - IIPReply(packet.CallbackId, packet.ResourceAge, packet.Content); + IIPReply(packet.CallbackId, packet.ResourceAge, packet.DataType, msg); break; case IIPPacket.IIPPacketAction.DetachResource: @@ -555,7 +570,9 @@ public partial class DistributedConnection : NetworkConnection, IStore case IIPPacket.IIPPacketAction.TemplateFromClassName: case IIPPacket.IIPPacketAction.TemplateFromClassId: case IIPPacket.IIPPacketAction.TemplateFromResourceId: - IIPReply(packet.CallbackId, TypeTemplate.Parse(packet.Content)); + + var content = msg.Clip(packet.DataType.Value.Offset, (uint)packet.DataType.Value.ContentLength); + IIPReply(packet.CallbackId, TypeTemplate.Parse(content)); break; case IIPPacketAction.QueryLink: @@ -563,13 +580,12 @@ public partial class DistributedConnection : NetworkConnection, IStore case IIPPacketAction.ResourceParents: case IIPPacketAction.ResourceHistory: case IIPPacketAction.LinkTemplates: - IIPReply(packet.CallbackId, packet.Content); + IIPReply(packet.CallbackId, (TransmissionType)packet.DataType, msg);// packet.Content); break; // Invoke - case IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments: - case IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments: - IIPReplyInvoke(packet.CallbackId, packet.Content); + case IIPPacket.IIPPacketAction.InvokeFunction: + IIPReplyInvoke(packet.CallbackId, (TransmissionType)packet.DataType, msg);// packet.Content); break; //case IIPPacket.IIPPacketAction.GetProperty: @@ -589,7 +605,7 @@ public partial class DistributedConnection : NetworkConnection, IStore // Attribute case IIPPacketAction.GetAllAttributes: case IIPPacketAction.GetAttributes: - IIPReply(packet.CallbackId, packet.Content); + IIPReply(packet.CallbackId, (TransmissionType)packet.DataType, msg);// packet.Content); break; case IIPPacketAction.UpdateAllAttributes: @@ -616,7 +632,7 @@ public partial class DistributedConnection : NetworkConnection, IStore IIPReportProgress(packet.CallbackId, ProgressType.Execution, packet.ProgressValue, packet.ProgressMax); break; case IIPPacketReport.ChunkStream: - IIPReportChunk(packet.CallbackId, packet.Content); + IIPReportChunk(packet.CallbackId, (TransmissionType)packet.DataType, msg);// packet.Content); break; } @@ -626,6 +642,62 @@ public partial class DistributedConnection : NetworkConnection, IStore else { + + // check if the reqeust through websockets + + if (initialPacket) + { + initialPacket = false; + + if (msg.Length > 3 && Encoding.Default.GetString(msg, 0, 3) == "GET") + { + // Parse with http packet + var req = new HTTPRequestPacket(); + var pSize = req.Parse(msg, 0, (uint)msg.Length); + if (pSize > 0) + { + // check for WS upgrade + + if (HTTPConnection.IsWebsocketRequest(req)) + { + + Socket?.Unhold(); + + var res = new HTTPResponsePacket(); + + HTTPConnection.Upgrade(req, res); + + + res.Compose(HTTPResponsePacket.ComposeOptions.AllCalculateLength); + Send(res.Data); + // replace my socket with websockets + var tcpSocket = this.Unassign(); + var wsSocket = new WSocket(tcpSocket); + this.Assign(wsSocket); + } + else + { + + var res = new HTTPResponsePacket(); + res.Number = HTTPResponsePacket.ResponseCode.BadRequest; + res.Compose(HTTPResponsePacket.ComposeOptions.AllCalculateLength); + Send(res.Data); + //@TODO: kill the connection + } + } + else + { + // packet incomplete + return (uint)pSize; + } + + // switching completed + return (uint)msg.Length; + } + } + + Console.WriteLine(msg.GetString(offset, ends - offset)); + var rt = authPacket.Parse(msg, offset, ends); //Console.WriteLine(session.LocalAuthentication.Type.ToString() + " " + offset + " " + ends + " " + rt + " " + authPacket.ToString()); @@ -649,7 +721,16 @@ public partial class DistributedConnection : NetworkConnection, IStore { try { - Server.Membership.UserExists(authPacket.RemoteUsername, authPacket.Domain).Then(x => + if (Server.Membership == null) + { + var errMsg = DC.ToBytes("Membership not set."); + + SendParams().AddUInt8(0xc0) + .AddUInt8((byte)ExceptionCode.GeneralFailure) + .AddUInt16((ushort)errMsg.Length) + .AddUInt8Array(errMsg).Done(); + } + else Server.Membership.UserExists(authPacket.RemoteUsername, authPacket.Domain).Then(x => { if (x) { @@ -660,15 +741,15 @@ public partial class DistributedConnection : NetworkConnection, IStore .AddUInt8(0xa0) .AddUInt8Array(localNonce) .Done(); - //SendParams((byte)0xa0, localNonce); - } + //SendParams((byte)0xa0, localNonce); + } else { - //Console.WriteLine("User not found"); - SendParams().AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.UserOrTokenNotFound) - .AddUInt16(14) - .AddString("User not found").Done(); + //Console.WriteLine("User not found"); + SendParams().AddUInt8(0xc0) + .AddUInt8((byte)ExceptionCode.UserOrTokenNotFound) + .AddUInt16(14) + .AddString("User not found").Done(); } }); } @@ -686,31 +767,43 @@ public partial class DistributedConnection : NetworkConnection, IStore { try { - // Check if user and token exists - Server.Membership.TokenExists(authPacket.RemoteTokenIndex, authPacket.Domain).Then(x => + if (Server.Membership == null) { - if (x != null) - { - session.RemoteAuthentication.Username = x; - session.RemoteAuthentication.TokenIndex = authPacket.RemoteTokenIndex; - remoteNonce = authPacket.RemoteNonce; - session.RemoteAuthentication.Domain = authPacket.Domain; - SendParams() - .AddUInt8(0xa0) - .AddUInt8Array(localNonce) - .Done(); - } - else - { - //Console.WriteLine("User not found"); - SendParams() + SendParams() .AddUInt8(0xc0) .AddUInt8((byte)ExceptionCode.UserOrTokenNotFound) .AddUInt16(15) .AddString("Token not found") .Done(); - } - }); + } + // Check if user and token exists + else + { + Server.Membership.TokenExists(authPacket.RemoteTokenIndex, authPacket.Domain).Then(x => + { + if (x != null) + { + session.RemoteAuthentication.Username = x; + session.RemoteAuthentication.TokenIndex = authPacket.RemoteTokenIndex; + remoteNonce = authPacket.RemoteNonce; + session.RemoteAuthentication.Domain = authPacket.Domain; + SendParams() + .AddUInt8(0xa0) + .AddUInt8Array(localNonce) + .Done(); + } + else + { + //Console.WriteLine("User not found"); + SendParams() + .AddUInt8(0xc0) + .AddUInt8((byte)ExceptionCode.UserOrTokenNotFound) + .AddUInt16(15) + .AddString("Token not found") + .Done(); + } + }); + } } catch (Exception ex) { @@ -729,7 +822,7 @@ public partial class DistributedConnection : NetworkConnection, IStore try { // Check if guests are allowed - if (Server.Membership.GuestsAllowed) + if (Server.Membership?.GuestsAllowed ?? true) { session.RemoteAuthentication.Username = "g-" + Global.GenerateCode(); session.RemoteAuthentication.Domain = authPacket.Domain; @@ -789,31 +882,31 @@ public partial class DistributedConnection : NetworkConnection, IStore if (pw != null) { var hashFunc = SHA256.Create(); - //var hash = hashFunc.ComputeHash(BinaryList.ToBytes(pw, remoteNonce, localNonce)); - var hash = hashFunc.ComputeHash((new BinaryList()) - .AddUInt8Array(pw) - .AddUInt8Array(remoteNonce) - .AddUInt8Array(localNonce) - .ToArray()); + //var hash = hashFunc.ComputeHash(BinaryList.ToBytes(pw, remoteNonce, localNonce)); + var hash = hashFunc.ComputeHash((new BinaryList()) + .AddUInt8Array(pw) + .AddUInt8Array(remoteNonce) + .AddUInt8Array(localNonce) + .ToArray()); if (hash.SequenceEqual(remoteHash)) { - // send our hash - //var localHash = hashFunc.ComputeHash(BinaryList.ToBytes(localNonce, remoteNonce, pw)); - //SendParams((byte)0, localHash); + // send our hash + //var localHash = hashFunc.ComputeHash(BinaryList.ToBytes(localNonce, remoteNonce, pw)); + //SendParams((byte)0, localHash); - var localHash = hashFunc.ComputeHash((new BinaryList()).AddUInt8Array(localNonce).AddUInt8Array(remoteNonce).AddUInt8Array(pw).ToArray()); + var localHash = hashFunc.ComputeHash((new BinaryList()).AddUInt8Array(localNonce).AddUInt8Array(remoteNonce).AddUInt8Array(pw).ToArray()); SendParams().AddUInt8(0).AddUInt8Array(localHash).Done(); readyToEstablish = true; } else { - //Global.Log("auth", LogType.Warning, "U:" + RemoteUsername + " IP:" + Socket.RemoteEndPoint.Address.ToString() + " S:DENIED"); - SendParams().AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.AccessDenied) - .AddUInt16(13) - .AddString("Access Denied") - .Done(); + //Global.Log("auth", LogType.Warning, "U:" + RemoteUsername + " IP:" + Socket.RemoteEndPoint.Address.ToString() + " S:DENIED"); + SendParams().AddUInt8(0xc0) + .AddUInt8((byte)ExceptionCode.AccessDenied) + .AddUInt16(13) + .AddString("Access Denied") + .Done(); } } }); @@ -849,7 +942,7 @@ public partial class DistributedConnection : NetworkConnection, IStore openReply?.Trigger(true); OnReady?.Invoke(this); - Server?.Membership.Login(session); + Server?.Membership?.Login(session); loginDate = DateTime.Now; }).Error(x => @@ -862,7 +955,7 @@ public partial class DistributedConnection : NetworkConnection, IStore ready = true; openReply?.Trigger(true); OnReady?.Invoke(this); - Server?.Membership.Login(session); + Server?.Membership?.Login(session); } //Global.Log("auth", LogType.Warning, "U:" + RemoteUsername + " IP:" + Socket.RemoteEndPoint.Address.ToString() + " S:AUTH"); @@ -988,7 +1081,7 @@ public partial class DistributedConnection : NetworkConnection, IStore protected override void DataReceived(NetworkBuffer data) { - // Console.WriteLine("DR " + hostType + " " + data.Available + " " + RemoteEndPoint.ToString()); + //Console.WriteLine("DR " + data.Available + " " + RemoteEndPoint.ToString()); var msg = data.Read(); uint offset = 0; uint ends = (uint)msg.Length; @@ -997,7 +1090,7 @@ public partial class DistributedConnection : NetworkConnection, IStore var chunkId = (new Random()).Next(1000, 1000000); - var list = new List();// double, IIPPacketCommand>(); + //var list = new List>();// double, IIPPacketCommand>(); this.Socket.Hold(); @@ -1127,7 +1220,7 @@ public partial class DistributedConnection : NetworkConnection, IStore { try { - var bag = new AsyncBag(); + var bag = new AsyncBag(); for (var i = 0; i < resources.Keys.Count; i++) { @@ -1168,13 +1261,13 @@ public partial class DistributedConnection : NetworkConnection, IStore return new AsyncReply(true); } - public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + public bool Record(IResource resource, string propertyName, object value, ulong? age, DateTime? dateTime) { // nothing to do return true; } - public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + public bool Modify(IResource resource, string propertyName, object value, ulong? age, DateTime? dateTime) { // nothing to do return true; @@ -1202,9 +1295,10 @@ public partial class DistributedConnection : NetworkConnection, IStore throw new NotImplementedException(); } + public AsyncBag Children(IResource resource, string name) where T : IResource { - throw new Exception("SS"); + throw new Exception("Not implemented"); //if (Codec.IsLocalResource(resource, this)) // return new AsyncBag((resource as DistributedResource).children.Where(x => x.GetType() == typeof(T)).Select(x => (T)x)); @@ -1214,7 +1308,7 @@ public partial class DistributedConnection : NetworkConnection, IStore public AsyncBag Parents(IResource resource, string name) where T : IResource { - throw new Exception("SS"); + throw new Exception("Not implemented"); //if (Codec.IsLocalResource(resource, this)) // return (resource as DistributedResource).parents.Where(x => x.GetType() == typeof(T)).Select(x => (T)x); @@ -1253,7 +1347,7 @@ public partial class DistributedConnection : NetworkConnection, IStore Warehouse.Remove(this); if (ready) - Server?.Membership.Logout(session); + Server?.Membership?.Logout(session); ready = false; } diff --git a/Esiur/Net/IIP/DistributedConnectionProtocol.cs b/Esiur/Net/IIP/DistributedConnectionProtocol.cs index 919b72c..7e0f8be 100644 --- a/Esiur/Net/IIP/DistributedConnectionProtocol.cs +++ b/Esiur/Net/IIP/DistributedConnectionProtocol.cs @@ -148,15 +148,15 @@ partial class DistributedConnection } - internal AsyncReply SendInvokeByArrayArguments(uint instanceId, byte index, object[] parameters) + internal AsyncReply SendInvoke(uint instanceId, byte index, Map parameters) { - var pb = Codec.ComposeVarArray(parameters, this, true); + var pb = Codec.Compose(parameters, this);// Codec.ComposeVarArray(parameters, this, true); var reply = new AsyncReply(); var c = callbackCounter++; requests.Add(c, reply); - SendParams().AddUInt8((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments)) + SendParams().AddUInt8((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunction)) .AddUInt32(c) .AddUInt32(instanceId) .AddUInt8(index) @@ -182,35 +182,6 @@ partial class DistributedConnection } } - internal AsyncReply SendInvokeByNamedArguments(uint instanceId, byte index, Structure parameters) - { - var pb = Codec.ComposeStructure(parameters, this, true, true, true); - - /* - var reply = new AsyncReply(); - callbackCounter++; - var bl = new BinaryList((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments), - callbackCounter, instanceId, index, pb); - Send(bl.ToArray()); - requests.Add(callbackCounter, reply); - - return reply; - */ - - var reply = new AsyncReply(); - var c = callbackCounter++; - requests.Add(c, reply); - - SendParams().AddUInt8((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments)) - .AddUInt32(c) - .AddUInt32(instanceId) - .AddUInt8(index) - .AddUInt8Array(pb) - .Done(); - return reply; - } - - void SendError(ErrorType type, uint callbackId, ushort errorCode, string errorMessage = "") { var msg = DC.ToBytes(errorMessage); @@ -243,7 +214,7 @@ partial class DistributedConnection void SendChunk(uint callbackId, object chunk) { - var c = Codec.Compose(chunk, this, true); + var c = Codec.Compose(chunk, this); SendParams() .AddUInt8((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ChunkStream)) .AddUInt32(callbackId) @@ -257,11 +228,12 @@ partial class DistributedConnection req?.Trigger(results); } - void IIPReplyInvoke(uint callbackId, byte[] result) + void IIPReplyInvoke(uint callbackId, TransmissionType transmissionType, byte[] content) { var req = requests.Take(callbackId); - Codec.Parse(result, 0, this).Then((rt) => + var (_, parsed) = Codec.Parse(content, 0, this, transmissionType); + parsed.Then((rt) => { req?.Trigger(rt); }); @@ -279,12 +251,13 @@ partial class DistributedConnection req?.TriggerProgress(type, value, max); } - void IIPReportChunk(uint callbackId, byte[] data) + void IIPReportChunk(uint callbackId, TransmissionType dataType, byte[] data) { if (requests.ContainsKey(callbackId)) { var req = requests[callbackId]; - Codec.Parse(data, 0, this).Then((x) => + var (_, parsed) = Codec.Parse(data, dataType.Offset, this, dataType); + parsed.Then((x) => { req.TriggerChunk(x); }); @@ -306,7 +279,7 @@ partial class DistributedConnection } } - void IIPEventPropertyUpdated(uint resourceId, byte index, byte[] content) + void IIPEventPropertyUpdated(uint resourceId, byte index, TransmissionType dataType, byte[] data) { Fetch(resourceId).Then(r => @@ -314,7 +287,8 @@ partial class DistributedConnection var item = new AsyncReply(); queue.Add(item); - Codec.Parse(content, 0, this).Then((arguments) => + var (_, parsed) = Codec.Parse(data, dataType.Offset, this, dataType);// 0, this); + parsed.Then((arguments) => { var pt = r.Instance.Template.GetPropertyTemplateByIndex(index); if (pt != null) @@ -325,7 +299,7 @@ partial class DistributedConnection } else { // ft found, fi not found, this should never happen - queue.Remove(item); + queue.Remove(item); } }); @@ -369,15 +343,16 @@ partial class DistributedConnection } - void IIPEventEventOccurred(uint resourceId, byte index, byte[] content) + void IIPEventEventOccurred(uint resourceId, byte index, TransmissionType dataType, byte[] data) { Fetch(resourceId).Then(r => { - // push to the queue to gaurantee serialization - var item = new AsyncReply(); + // push to the queue to gaurantee serialization + var item = new AsyncReply(); queue.Add(item); - Codec.Parse(content, 0, this).Then((arguments) => + var (_, parsed) = Codec.Parse(data, dataType.Offset, this, dataType);//, 0, this); + parsed.Then((arguments) => { var et = r.Instance.Template.GetEventTemplateByIndex(index); if (et != null) @@ -387,7 +362,7 @@ partial class DistributedConnection } else { // ft found, fi not found, this should never happen - queue.Remove(item); + queue.Remove(item); } }); @@ -438,8 +413,8 @@ partial class DistributedConnection parent.children.Add(child); child.parents.Add(parent); - //parent.Instance.Children.Add(child); - }); + //parent.Instance.Children.Add(child); + }); }); } @@ -452,16 +427,16 @@ partial class DistributedConnection parent.children.Remove(child); child.parents.Remove(parent); - // parent.Instance.Children.Remove(child); - }); + // parent.Instance.Children.Remove(child); + }); }); } - void IIPEventRenamed(uint resourceId, byte[] name) + void IIPEventRenamed(uint resourceId, string name) { Fetch(resourceId).Then(resource => { - resource.Instance.Variables["name"] = name.GetString(0, (uint)name.Length); + resource.Instance.Variables["name"] = name; }); } @@ -494,72 +469,74 @@ partial class DistributedConnection var r = res as IResource; - // unsubscribe - Unsubscribe(r); + // unsubscribe + Unsubscribe(r); - //r.Instance.ResourceEventOccurred -= Instance_EventOccurred; - //r.Instance.CustomResourceEventOccurred -= Instance_CustomEventOccurred; - //r.Instance.ResourceModified -= Instance_PropertyModified; - //r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed; + //r.Instance.ResourceEventOccurred -= Instance_EventOccurred; + //r.Instance.CustomResourceEventOccurred -= Instance_CustomEventOccurred; + //r.Instance.ResourceModified -= Instance_PropertyModified; + //r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed; - // r.Instance.Children.OnAdd -= Children_OnAdd; - // r.Instance.Children.OnRemoved -= Children_OnRemoved; + // r.Instance.Children.OnAdd -= Children_OnAdd; + // r.Instance.Children.OnRemoved -= Children_OnRemoved; - //r.Instance.Attributes.OnModified -= Attributes_OnModified; + //r.Instance.Attributes.OnModified -= Attributes_OnModified; - // Console.WriteLine("Attach {0} {1}", r.Instance.Link, r.Instance.Id); + // Console.WriteLine("Attach {0} {1}", r.Instance.Link, r.Instance.Id); - // add it to attached resources so GC won't remove it from memory - ///attachedResources.Add(r); + // add it to attached resources so GC won't remove it from memory + ///attachedResources.Add(r); - var link = DC.ToBytes(r.Instance.Link); + var link = DC.ToBytes(r.Instance.Link); if (r is DistributedResource) { - // reply ok - SendReply(IIPPacket.IIPPacketAction.AttachResource, callback) - .AddGuid(r.Instance.Template.ClassId) - .AddUInt64(r.Instance.Age) - .AddUInt16((ushort)link.Length) - .AddUInt8Array(link) - .AddUInt8Array(Codec.ComposePropertyValueArray((r as DistributedResource)._Serialize(), this, true)) - .Done(); + // reply ok + SendReply(IIPPacket.IIPPacketAction.AttachResource, callback) + .AddGuid(r.Instance.Template.ClassId) + .AddUInt64(r.Instance.Age) + .AddUInt16((ushort)link.Length) + .AddUInt8Array(link) + //.AddUInt8Array(DataSerializer.PropertyValueArrayComposer((r as DistributedResource)._Serialize(), this, true)) + .AddUInt8Array(Codec.Compose((r as DistributedResource)._Serialize(), this)) + .Done(); } else { - // reply ok - SendReply(IIPPacket.IIPPacketAction.AttachResource, callback) - .AddGuid(r.Instance.Template.ClassId) - .AddUInt64(r.Instance.Age) - .AddUInt16((ushort)link.Length) - .AddUInt8Array(link) - .AddUInt8Array(Codec.ComposePropertyValueArray(r.Instance.Serialize(), this, true)) - .Done(); + // reply ok + SendReply(IIPPacket.IIPPacketAction.AttachResource, callback) + .AddGuid(r.Instance.Template.ClassId) + .AddUInt64(r.Instance.Age) + .AddUInt16((ushort)link.Length) + .AddUInt8Array(link) + .AddUInt8Array(Codec.Compose(r.Instance.Serialize(), this)) + //.AddUInt8Array(DataSerializer.PropertyValueArrayComposer(r.Instance.Serialize(), this, true)) + .Done(); } - // subscribe - //r.Instance.ResourceEventOccurred += Instance_EventOccurred; - //r.Instance.CustomResourceEventOccurred += Instance_CustomEventOccurred; - //r.Instance.ResourceModified += Instance_PropertyModified; - //r.Instance.ResourceDestroyed += Instance_ResourceDestroyed; + // subscribe + //r.Instance.ResourceEventOccurred += Instance_EventOccurred; + //r.Instance.CustomResourceEventOccurred += Instance_CustomEventOccurred; + //r.Instance.ResourceModified += Instance_PropertyModified; + //r.Instance.ResourceDestroyed += Instance_ResourceDestroyed; - Subscribe(r); + Subscribe(r); - //r.Instance.Children.OnAdd += Children_OnAdd; - //r.Instance.Children.OnRemoved += Children_OnRemoved; + //r.Instance.Children.OnAdd += Children_OnAdd; + //r.Instance.Children.OnRemoved += Children_OnRemoved; - //r.Instance.Attributes.OnModified += Attributes_OnModified; + //r.Instance.Attributes.OnModified += Attributes_OnModified; - } + } else { - // reply failed - //SendParams(0x80, r.Instance.Id, r.Instance.Age, r.Instance.Serialize(false, this)); - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + // reply failed + //SendParams(0x80, r.Instance.Id, r.Instance.Age, r.Instance.Serialize(false, this)); + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); } }); } @@ -624,41 +601,41 @@ partial class DistributedConnection if (res != null) { var r = res as IResource; - // unsubscribe - Unsubscribe(r); + // unsubscribe + Unsubscribe(r); Subscribe(r); - //r.Instance.ResourceEventOccurred -= Instance_EventOccurred; - //r.Instance.CustomResourceEventOccurred -= Instance_CustomEventOccurred; - //r.Instance.ResourceModified -= Instance_PropertyModified; - //r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed; + //r.Instance.ResourceEventOccurred -= Instance_EventOccurred; + //r.Instance.CustomResourceEventOccurred -= Instance_CustomEventOccurred; + //r.Instance.ResourceModified -= Instance_PropertyModified; + //r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed; - //r.Instance.Children.OnAdd -= Children_OnAdd; - //r.Instance.Children.OnRemoved -= Children_OnRemoved; + //r.Instance.Children.OnAdd -= Children_OnAdd; + //r.Instance.Children.OnRemoved -= Children_OnRemoved; - //r.Instance.Attributes.OnModified -= Attributes_OnModified; + //r.Instance.Attributes.OnModified -= Attributes_OnModified; - // subscribe - //r.Instance.ResourceEventOccurred += Instance_EventOccurred; - //r.Instance.CustomResourceEventOccurred += Instance_CustomEventOccurred; - //r.Instance.ResourceModified += Instance_PropertyModified; - //r.Instance.ResourceDestroyed += Instance_ResourceDestroyed; + // subscribe + //r.Instance.ResourceEventOccurred += Instance_EventOccurred; + //r.Instance.CustomResourceEventOccurred += Instance_CustomEventOccurred; + //r.Instance.ResourceModified += Instance_PropertyModified; + //r.Instance.ResourceDestroyed += Instance_ResourceDestroyed; - //r.Instance.Children.OnAdd += Children_OnAdd; - //r.Instance.Children.OnRemoved += Children_OnRemoved; + //r.Instance.Children.OnAdd += Children_OnAdd; + //r.Instance.Children.OnRemoved += Children_OnRemoved; - //r.Instance.Attributes.OnModified += Attributes_OnModified; + //r.Instance.Attributes.OnModified += Attributes_OnModified; - // reply ok - SendReply(IIPPacket.IIPPacketAction.ReattachResource, callback) - .AddUInt64(r.Instance.Age) - .AddUInt8Array(Codec.ComposePropertyValueArray(r.Instance.Serialize(), this, true)) + // reply ok + SendReply(IIPPacket.IIPPacketAction.ReattachResource, callback) + .AddUInt64(r.Instance.Age) + .AddUInt8Array(Codec.Compose(r.Instance.Serialize(), this)) .Done(); } else { - // reply failed - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + // reply failed + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); } }); } @@ -669,24 +646,24 @@ partial class DistributedConnection { if (res != null) { - //var r = res as IResource; - //r.Instance.ResourceEventOccurred -= Instance_EventOccurred; - //r.Instance.CustomResourceEventOccurred -= Instance_CustomEventOccurred; - //r.Instance.ResourceModified -= Instance_PropertyModified; - //r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed; + //var r = res as IResource; + //r.Instance.ResourceEventOccurred -= Instance_EventOccurred; + //r.Instance.CustomResourceEventOccurred -= Instance_CustomEventOccurred; + //r.Instance.ResourceModified -= Instance_PropertyModified; + //r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed; - Unsubscribe(res); + Unsubscribe(res); - // remove from attached resources - //attachedResources.Remove(res); + // remove from attached resources + //attachedResources.Remove(res); - // reply ok - SendReply(IIPPacket.IIPPacketAction.DetachResource, callback).Done(); + // reply ok + SendReply(IIPPacket.IIPPacketAction.DetachResource, callback).Done(); } else { - // reply failed - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + // reply failed + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); } }); } @@ -708,8 +685,8 @@ partial class DistributedConnection return; } - // check security - if (store.Instance.Applicable(session, ActionType.CreateResource, null) != Ruling.Allowed) + // check security + if (store.Instance.Applicable(session, ActionType.CreateResource, null) != Ruling.Allowed) { SendError(ErrorType.Management, callback, (ushort)ExceptionCode.CreateDenied); return; @@ -718,9 +695,9 @@ partial class DistributedConnection Warehouse.GetById(parentId).Then(parent => { - // check security + // check security - if (parent != null) + if (parent != null) if (parent.Instance.Applicable(session, ActionType.AddChild, null) != Ruling.Allowed) { SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AddChildDenied); @@ -732,11 +709,11 @@ partial class DistributedConnection var className = content.GetString(offset + 1, content[0]); offset += 1 + (uint)content[0]; - var nameLength = content.GetUInt16(offset); + var nameLength = content.GetUInt16(offset, Endian.Little); offset += 2; var name = content.GetString(offset, nameLength); - var cl = content.GetUInt32(offset); + var cl = content.GetUInt32(offset, Endian.Little); offset += 4; var type = Type.GetType(className); @@ -747,25 +724,28 @@ partial class DistributedConnection return; } - Codec.ParseVarArray(content, offset, cl, this).Then(parameters => + DataDeserializer.ListParser(content, offset, cl, this).Then(parameters => { offset += cl; - cl = content.GetUInt32(offset); - Codec.ParseStructure(content, offset, cl, this).Then(attributes => + cl = content.GetUInt32(offset, Endian.Little); + + //Codec.ParseStructure(content, offset, cl, this).Then(attributes => + DataDeserializer.TypedMapParser(content, offset, cl, this).Then(attributes => { offset += cl; cl = (uint)content.Length - offset; - Codec.ParseStructure(content, offset, cl, this).Then(values => + //Codec.ParseStructure(content, offset, cl, this).Then(values => + DataDeserializer.TypedMapParser(content, offset, cl, this).Then(values => { #if NETSTANDARD - var constructors = Type.GetType(className).GetTypeInfo().GetConstructors(); + var constructors = Type.GetType(className).GetTypeInfo().GetConstructors(); #else var constructors = Type.GetType(className).GetConstructors(); #endif - var matching = constructors.Where(x => + var matching = constructors.Where(x => { var ps = x.GetParameters(); if (ps.Length > 0 && ps.Length == parameters.Length + 1) @@ -778,8 +758,8 @@ partial class DistributedConnection var pi = matching[0].GetParameters(); - // cast arguments - object[] args = null; + // cast arguments + object[] args = null; if (pi.Length > 0) { @@ -800,8 +780,8 @@ partial class DistributedConnection } } - // create the resource - var resource = Activator.CreateInstance(type, args) as IResource; + // create the resource + var resource = Activator.CreateInstance(type, args) as IResource; Warehouse.Put(name, resource, store as IStore, parent).Then(ok => { @@ -839,8 +819,8 @@ partial class DistributedConnection if (Warehouse.Remove(r)) SendReply(IIPPacket.IIPPacketAction.DeleteResource, callback).Done(); - //SendParams((byte)0x84, callback); - else + //SendParams((byte)0x84, callback); + else SendError(ErrorType.Management, callback, (ushort)ExceptionCode.DeleteFailed); }); } @@ -855,8 +835,8 @@ partial class DistributedConnection return; } - // if (!r.Instance.Store.Instance.Applicable(r, session, ActionType.InquireAttributes, null)) - if (r.Instance.Applicable(session, ActionType.InquireAttributes, null) != Ruling.Allowed) + // if (!r.Instance.Store.Instance.Applicable(r, session, ActionType.InquireAttributes, null)) + if (r.Instance.Applicable(session, ActionType.InquireAttributes, null) != Ruling.Allowed) { SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ViewAttributeDenied); return; @@ -871,7 +851,7 @@ partial class DistributedConnection if (st != null) SendReply(all ? IIPPacket.IIPPacketAction.GetAllAttributes : IIPPacket.IIPPacketAction.GetAttributes, callback) - .AddUInt8Array(Codec.ComposeStructure(st, this, true, true, true)) + .AddUInt8Array(Codec.Compose(st, this)) .Done(); else SendError(ErrorType.Management, callback, (ushort)ExceptionCode.GetAttributesFailed); @@ -912,8 +892,8 @@ partial class DistributedConnection parent.Instance.Store.AddChild(parent, child); SendReply(IIPPacket.IIPPacketAction.AddChild, callback).Done(); - //child.Instance.Parents - }); + //child.Instance.Parents + }); }); } @@ -950,14 +930,14 @@ partial class DistributedConnection parent.Instance.Store.RemoveChild(parent, child);// Children.Remove(child); - SendReply(IIPPacket.IIPPacketAction.RemoveChild, callback).Done(); - //child.Instance.Parents - }); + SendReply(IIPPacket.IIPPacketAction.RemoveChild, callback).Done(); + //child.Instance.Parents + }); }); } - void IIPRequestRenameResource(uint callback, uint resourceId, byte[] name) + void IIPRequestRenameResource(uint callback, uint resourceId, string name) { Warehouse.GetById(resourceId).Then(resource => { @@ -974,7 +954,7 @@ partial class DistributedConnection } - resource.Instance.Name = name.GetString(0, (uint)name.Length); + resource.Instance.Name = name; SendReply(IIPPacket.IIPPacketAction.RenameResource, callback).Done(); }); } @@ -992,7 +972,7 @@ partial class DistributedConnection resource.Instance.Children().Then(children => { SendReply(IIPPacket.IIPPacketAction.ResourceChildren, callback) - .AddUInt8Array(Codec.ComposeResourceArray(children, this, true)) + .AddUInt8Array(Codec.Compose(children, this))// Codec.ComposeResourceArray(children, this, true)) .Done(); }); @@ -1014,7 +994,8 @@ partial class DistributedConnection resource.Instance.Parents().Then(parents => { SendReply(IIPPacket.IIPPacketAction.ResourceParents, callback) - .AddUInt8Array(Codec.ComposeResourceArray(parents, this, true)) + .AddUInt8Array(Codec.Compose(parents, this)) + //.AddUInt8Array(Codec.ComposeResourceArray(parents, this, true)) .Done(); }); @@ -1067,9 +1048,10 @@ partial class DistributedConnection return; } - Codec.ParseStructure(attributes, 0, (uint)attributes.Length, this).Then(attrs => + + DataDeserializer.TypedMapParser(attributes, 0, (uint)attributes.Length, this).Then(attrs => { - if (r.Instance.SetAttributes(attrs, clearAttributes)) + if (r.Instance.SetAttributes((Map)attrs, clearAttributes)) SendReply(clearAttributes ? IIPPacket.IIPPacketAction.ClearAllAttributes : IIPPacket.IIPPacketAction.ClearAttributes, callback).Done(); else @@ -1094,9 +1076,9 @@ partial class DistributedConnection SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); else { - // get all templates related to this resource + // get all templates related to this resource - var msg = new BinaryList(); + var msg = new BinaryList(); var templates = new List(); foreach (var resource in list) @@ -1108,11 +1090,12 @@ partial class DistributedConnection .AddUInt8Array(t.Content); } - // digggg - SendReply(IIPPacket.IIPPacketAction.LinkTemplates, callback) - .AddInt32(msg.Length) - .AddUInt8Array(msg.ToArray()) - .Done(); + // digggg + SendReply(IIPPacket.IIPPacketAction.LinkTemplates, callback) + //.AddInt32(msg.Length) + //.AddUInt8Array(msg.ToArray()) + .AddUInt8Array(TransmissionType.Compose(TransmissionTypeIdentifier.RawData, msg.ToArray())) + .Done(); } } }; @@ -1129,8 +1112,9 @@ partial class DistributedConnection if (t != null) SendReply(IIPPacket.IIPPacketAction.TemplateFromClassName, callback) - .AddInt32(t.Content.Length) - .AddUInt8Array(t.Content) + .AddUInt8Array(TransmissionType.Compose(TransmissionTypeIdentifier.RawData, t.Content)) + //.AddInt32(t.Content.Length) + //.AddUInt8Array(t.Content) .Done(); else { @@ -1145,8 +1129,9 @@ partial class DistributedConnection if (t != null) SendReply(IIPPacket.IIPPacketAction.TemplateFromClassId, callback) - .AddInt32(t.Content.Length) - .AddUInt8Array(t.Content) + .AddUInt8Array(TransmissionType.Compose(TransmissionTypeIdentifier.RawData, t.Content)) + //.AddInt32(t.Content.Length) + //.AddUInt8Array(t.Content) .Done(); else { @@ -1168,8 +1153,8 @@ partial class DistributedConnection .Done(); else { - // reply failed - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound); + // reply failed + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound); } }); } @@ -1192,7 +1177,8 @@ partial class DistributedConnection SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); else SendReply(IIPPacket.IIPPacketAction.QueryLink, callback) - .AddUInt8Array(Codec.ComposeResourceArray(list, this, true)) + .AddUInt8Array(Codec.Compose(list, this)) + //.AddUInt8Array(Codec.ComposeResourceArray(list, this, true)) .Done(); } }; @@ -1224,303 +1210,147 @@ partial class DistributedConnection return new Tuple((ushort)code, $"{source}: {msg}\n{trace}"); } - void IIPRequestInvokeFunctionArrayArguments(uint callback, uint resourceId, byte index, byte[] content) + void IIPRequestInvokeFunction(uint callback, uint resourceId, byte index, TransmissionType transmissionType, byte[] content) { //Console.WriteLine("IIPRequestInvokeFunction " + callback + " " + resourceId + " " + index); Warehouse.GetById(resourceId).Then((r) => { - if (r != null) + if (r == null) { - Codec.ParseVarArray(content, this).Then((arguments) => + // no resource with this id + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + var ft = r.Instance.Template.GetFunctionTemplateByIndex(index); + + if (ft == null) + { + // no function at this index + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); + return; + } + + var (_, parsed) = Codec.Parse(content, 0, this, transmissionType); + + parsed.Then(results => + { + var arguments = (Map)results ;// (object[])results; + + // un hold the socket to send data immediately + this.Socket.Unhold(); + + if (r is DistributedResource) { - var ft = r.Instance.Template.GetFunctionTemplateByIndex(index); - if (ft != null) + var rt = (r as DistributedResource)._Invoke(index, arguments); + if (rt != null) { - - // un hold the socket to send data immediately - this.Socket.Unhold(); - - if (r is DistributedResource) + rt.Then(res => { - var rt = (r as DistributedResource)._InvokeByArrayArguments(index, arguments); - if (rt != null) - { - rt.Then(res => - { - SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback) - .AddUInt8Array(Codec.Compose(res, this)) - .Done(); - }); - } - else - { - - // function not found on a distributed object - } - } - else - { -#if NETSTANDARD - var fi = r.GetType().GetTypeInfo().GetMethod(ft.Name); -#else - var fi = r.GetType().GetMethod(ft.Name); -#endif - - if (fi != null) - { - if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied) - { - SendError(ErrorType.Management, callback, - (ushort)ExceptionCode.InvokeDenied); - return; - } - - // cast arguments - ParameterInfo[] pi = fi.GetParameters(); - object[] args = null; - - if (pi.Length > 0) - { - int argsCount = pi.Length; - args = new object[pi.Length]; - - if (pi[pi.Length - 1].ParameterType == typeof(DistributedConnection)) - { - args[--argsCount] = this; - } - - if (arguments != null) - { - for (int i = 0; i < argsCount && i < arguments.Length; i++) - { - args[i] = DC.CastConvert(arguments[i], pi[i].ParameterType); - } - } - } - - object rt; - - try - { - rt = fi.Invoke(r, args); - } - catch (Exception ex) - { - var (code, msg) = SummerizeException(ex); - SendError(ErrorType.Exception, callback, code, msg); - return; - } - - if (rt is System.Collections.IEnumerable && !(rt is Array || rt is Structure || rt is string)) - { - var enu = rt as System.Collections.IEnumerable; - - try - { - foreach (var v in enu) - SendChunk(callback, v); - SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback) - .AddUInt8((byte)DataType.Void) + SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback) + .AddUInt8Array(Codec.Compose(res, this)) .Done(); - } - catch (Exception ex) - { - var (code, msg) = SummerizeException(ex); - SendError(ErrorType.Exception, callback, code, msg); - } - - } - else if (rt is Task) - { - (rt as Task).ContinueWith(t => - { -#if NETSTANDARD - var res = t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t); -#else - var res = t.GetType().GetProperty("Result").GetValue(t); -#endif - SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback) - .AddUInt8Array(Codec.Compose(res, this)) - .Done(); - }); - - //await t; - //SendParams((byte)0x90, callback, Codec.Compose(res, this)); - } - else if (rt is AsyncReply)// Codec.ImplementsInterface(rt.GetType(), typeof(IAsyncReply<>)))// rt.GetType().GetTypeInfo().IsGenericType - //&& rt.GetType().GetGenericTypeDefinition() == typeof(IAsyncReply<>)) - { - (rt as AsyncReply).Then(res => - { - SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback) - .AddUInt8Array(Codec.Compose(res, this)) - .Done(); - }).Error(ex => - { - var (code, msg) = SummerizeException(ex); - SendError(ErrorType.Exception, callback, code, msg); - }).Progress((pt, pv, pm) => - { - SendProgress(callback, pv, pm); - }).Chunk(v => - { - SendChunk(callback, v); - }); - } - else - { - SendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback) - .AddUInt8Array(Codec.Compose(rt, this)) - .Done(); - } - } - else - { - // ft found, fi not found, this should never happen - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); - } - } + }); } else { - // no function at this index - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); + // function not found on a distributed object + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); } - }); - } - else - { - // no resource with this id - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - } - }); - } + } + else + { + var fi = r.GetType().GetMethod(ft.Name); + if (fi != null) + { + if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied) + { + SendError(ErrorType.Management, callback, + (ushort)ExceptionCode.InvokeDenied); + return; + } - void IIPRequestInvokeFunctionNamedArguments(uint callback, uint resourceId, byte index, byte[] content) - { + // cast arguments + ParameterInfo[] pis = fi.GetParameters(); - Warehouse.GetById(resourceId).Then((r) => - { - if (r != null) - { - Codec.ParseStructure(content, 0, (uint)content.Length, this).Then((namedArgs) => - { - var ft = r.Instance.Template.GetFunctionTemplateByIndex(index); - if (ft != null) - { - // un hold the socket to send data immediately - this.Socket.Unhold(); + object[] args = new object[pis.Length]; - if (r is DistributedResource) - { - var rt = (r as DistributedResource)._InvokeByNamedArguments(index, namedArgs); - if (rt != null) - { - rt.Then(res => - { - SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback) - .AddUInt8Array(Codec.Compose(res, this)) - .Done(); - }); - } - else - { + if (pis.Length > 0) + { + if (pis.Last().ParameterType == typeof(DistributedConnection)) + { + for(byte i = 0; i< pis.Length - 1; i++) + args[i] = arguments.ContainsKey(i) ? + DC.CastConvert(arguments[i], pis[i].ParameterType) : Type.Missing; + args[args.Length - 1] = this; + } + else + { + for (byte i = 0; i < pis.Length ; i++) + args[i] = arguments.ContainsKey(i) ? + DC.CastConvert(arguments[i], pis[i].ParameterType) : Type.Missing; + } + } - // function not found on a distributed object - } - } - else - { + object rt; + + try + { + rt = fi.Invoke(r, args); + } + catch (Exception ex) + { + var (code, msg) = SummerizeException(ex); + SendError(ErrorType.Exception, callback, code, msg); + return; + } + + if (rt is System.Collections.IEnumerable && !(rt is Array || rt is Map || rt is string)) + { + var enu = rt as System.Collections.IEnumerable; + + try + { + foreach (var v in enu) + SendChunk(callback, v); + SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback) + .AddUInt8((byte)TransmissionTypeIdentifier.Null) + .Done(); + } + catch (Exception ex) + { + var (code, msg) = SummerizeException(ex); + SendError(ErrorType.Exception, callback, code, msg); + } + + } + else if (rt is Task) + { + (rt as Task).ContinueWith(t => + { #if NETSTANDARD - var fi = r.GetType().GetTypeInfo().GetMethod(ft.Name); -#else - var fi = r.GetType().GetMethod(ft.Name); -#endif - - if (fi != null) - { - if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied) - { - SendError(ErrorType.Management, callback, - (ushort)ExceptionCode.InvokeDenied); - return; - } - - // cast arguments - ParameterInfo[] pi = fi.GetParameters(); - - object[] args = new object[pi.Length]; - - for (var i = 0; i < pi.Length; i++) - { - if (pi[i].ParameterType == typeof(DistributedConnection)) - { - args[i] = this; - } - else if (namedArgs.ContainsKey(pi[i].Name)) - { - args[i] = DC.CastConvert(namedArgs[pi[i].Name], pi[i].ParameterType); - } - } - - - object rt; - - try - { - rt = fi.Invoke(r, args); - } - catch (Exception ex) - { - var (code, msg) = SummerizeException(ex); - SendError(ErrorType.Exception, callback, code, msg); - return; - } - - if (rt is System.Collections.IEnumerable && !(rt is Array || rt is Structure || rt is string)) - { - var enu = rt as System.Collections.IEnumerable; - - try - { - foreach (var v in enu) - SendChunk(callback, v); - - SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback) - .AddUInt8((byte)DataType.Void) - .Done(); - } - catch (Exception ex) - { - var (code, msg) = SummerizeException(ex); - SendError(ErrorType.Exception, callback, code, msg); - } - } - else if (rt is Task) - { - (rt as Task).ContinueWith(t => - { -#if NETSTANDARD - var res = t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t); + var res = t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t); #else var res = t.GetType().GetProperty("Result").GetValue(t); #endif - SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback) - .AddUInt8Array(Codec.Compose(res, this)) - .Done(); - }); + SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback) + .AddUInt8Array(Codec.Compose(res, this)) + .Done(); + }); - } - else if (rt is AsyncReply) - { - (rt as AsyncReply).Then(res => + //await t; + //SendParams((byte)0x90, callback, Codec.Compose(res, this)); + } + else if (rt is AsyncReply)// Codec.ImplementsInterface(rt.GetType(), typeof(IAsyncReply<>)))// rt.GetType().GetTypeInfo().IsGenericType + //&& rt.GetType().GetGenericTypeDefinition() == typeof(IAsyncReply<>)) + { + (rt as AsyncReply).Then(res => { - SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback) + SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback) .AddUInt8Array(Codec.Compose(res, this)) .Done(); - }).Error(ex => { var (code, msg) = SummerizeException(ex); @@ -1532,38 +1362,28 @@ partial class DistributedConnection { SendChunk(callback, v); }); - } - else - { - SendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback) - .AddUInt8Array(Codec.Compose(rt, this)) - .Done(); - } - } - else - { - // ft found, fi not found, this should never happen - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); + } + else + { + SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback) + .AddUInt8Array(Codec.Compose(rt, this)) + .Done(); + } + } + else + { + // ft found, fi not found, this should never happen + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); + } + } + }); - } - } - } - else - { - // no function at this index - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); - - } - }); - } - else - { - // no resource with this id - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); - } }); } + + + void IIPRequestListen(uint callback, uint resourceId, byte index) { Warehouse.GetById(resourceId).Then((r) => @@ -1605,14 +1425,14 @@ partial class DistributedConnection } else { - // pt not found - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); + // pt not found + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); } } else { - // resource not found - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + // resource not found + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); } }); @@ -1659,14 +1479,14 @@ partial class DistributedConnection } else { - // pt not found - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); + // pt not found + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.MethodNotFound); } } else { - // resource not found - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + // resource not found + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); } }); @@ -1727,24 +1547,24 @@ partial class DistributedConnection { r.Instance.Store.GetRecord(r, fromDate, toDate).Then((results) => { - var history = Codec.ComposeHistory(results, this, true); + var history = DataSerializer.HistoryComposer(results, this, true); - /* - ulong fromAge = 0; - ulong toAge = 0; + /* + ulong fromAge = 0; + ulong toAge = 0; - if (results.Count > 0) + if (results.Count > 0) + { + var firstProp = results.Values.First(); + //var lastProp = results.Values.Last(); + + if (firstProp.Length > 0) { - var firstProp = results.Values.First(); - //var lastProp = results.Values.Last(); + fromAge = firstProp[0].Age; + toAge = firstProp.Last().Age; + } - if (firstProp.Length > 0) - { - fromAge = firstProp[0].Age; - toAge = firstProp.Last().Age; - } - - }*/ + }*/ SendReply(IIPPacket.IIPPacketAction.ResourceHistory, callback) .AddUInt8Array(history) @@ -1801,38 +1621,38 @@ partial class DistributedConnection // }); // } - void IIPRequestSetProperty(uint callback, uint resourceId, byte index, byte[] content) + void IIPRequestSetProperty(uint callback, uint resourceId, byte index, TransmissionType transmissionType, byte[] content) { Warehouse.GetById(resourceId).Then((r) => { if (r != null) { - var pt = r.Instance.Template.GetPropertyTemplateByIndex(index); if (pt != null) { - Codec.Parse(content, 0, this).Then((value) => + var (_, parsed) = Codec.Parse(content, 0, this, transmissionType); + parsed.Then((value) => { if (r is DistributedResource) { - // propagation - (r as DistributedResource)._Set(index, value).Then((x) => - { - SendReply(IIPPacket.IIPPacketAction.SetProperty, callback).Done(); - }).Error(x => - { - SendError(x.Type, callback, (ushort)x.Code, x.Message); - }); + // propagation + (r as DistributedResource)._Set(index, value).Then((x) => + { + SendReply(IIPPacket.IIPPacketAction.SetProperty, callback).Done(); + }).Error(x => + { + SendError(x.Type, callback, (ushort)x.Code, x.Message); + }); } else { - /* + /* #if NETSTANDARD - var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name); + var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name); #else - var pi = r.GetType().GetProperty(pt.Name); + var pi = r.GetType().GetProperty(pt.Name); #endif*/ var pi = pt.PropertyInfo; @@ -1853,14 +1673,16 @@ partial class DistributedConnection } - if (pi.PropertyType == typeof(DistributedPropertyContext)) + if (pi.PropertyType.IsGenericType && pi.PropertyType.GetGenericTypeDefinition() + == typeof(DistributedPropertyContext<>)) { - value = new DistributedPropertyContext(this, value); + value = Activator.CreateInstance(pi.PropertyType, this, value); + //value = new DistributedPropertyContext(this, value); } else { - // cast new value type to property type - value = DC.CastConvert(value, pi.PropertyType); + // cast new value type to property type + value = DC.CastConvert(value, pi.PropertyType); } @@ -1877,8 +1699,8 @@ partial class DistributedConnection } else { - // pt found, pi not found, this should never happen - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.PropertyNotFound); + // pt found, pi not found, this should never happen + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.PropertyNotFound); } } @@ -1886,14 +1708,14 @@ partial class DistributedConnection } else { - // property not found - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.PropertyNotFound); + // property not found + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.PropertyNotFound); } } else { - // resource not found - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + // resource not found + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); } }); } @@ -2080,11 +1902,11 @@ partial class DistributedConnection Query(path).Then(ar => { - //if (filter != null) - // ar = ar?.Where(filter).ToArray(); + //if (filter != null) + // ar = ar?.Where(filter).ToArray(); - // MISSING: should dispatch the unused resources. - if (ar?.Length > 0) + // MISSING: should dispatch the unused resources. + if (ar?.Length > 0) rt.Trigger(ar[0]); else rt.Trigger(null); @@ -2150,13 +1972,13 @@ partial class DistributedConnection { var templates = new List(); - // parse templates - - var data = (byte[])rt[0]; - //var offset = 0; - for (uint offset = 0; offset < data.Length;) + // parse templates + var tt = (TransmissionType)rt[0]; + var data = (byte[])rt[1]; + //var offset = 0; + for (var offset = tt.Offset; offset < tt.ContentLength;) { - var cs = data.GetUInt32(offset); + var cs = data.GetUInt32(offset, Endian.Little); offset += 4; templates.Add(TypeTemplate.Parse(data, offset, cs)); offset += cs; @@ -2219,32 +2041,51 @@ partial class DistributedConnection else dr = resource; + var transmissionType = (TransmissionType)rt[3]; + var content = (byte[])rt[4]; GetTemplate((Guid)rt[0]).Then((tmp) => { - // ClassId, ResourceAge, ResourceLink, Content - if (resource == null) + // ClassId, ResourceAge, ResourceLink, Content + if (resource == null) { Warehouse.Put(id.ToString(), dr, this, null, tmp).Then((ok) => { - Codec.ParsePropertyValueArray((byte[])rt[3], this).Then((ar) => + var (_, parsed) = Codec.Parse(content, 0, this, transmissionType); + parsed.Then(results => { - dr._Attach(ar); + var ar = results as object[]; + + var pvs = new List(); + + for (var i = 0; i < ar.Length; i += 3) + pvs.Add(new PropertyValue(ar[i + 2], (ulong?)ar[i], (DateTime?)ar[i + 1])); + + dr._Attach(pvs.ToArray());// (PropertyValue[])pvs); resourceRequests.Remove(id); reply.Trigger(dr); - }); + }).Error(ex => reply.TriggerError(ex)); + }).Error(ex => reply.TriggerError(ex)); } else { - Codec.ParsePropertyValueArray((byte[])rt[3], this).Then((ar) => + var (_, parsed) = Codec.Parse(content, 0, this, transmissionType); + parsed.Then((results) => { - dr._Attach(ar); - resourceRequests.Remove(id); + var ar = results as object[]; + + var pvs = new List(); + + for (var i = 0; i < ar.Length; i += 3) + pvs.Add(new PropertyValue(ar[i + 2], (ulong?)ar[i], (DateTime?)ar[i + 1])); + + dr._Attach(pvs.ToArray());// (PropertyValue[])pvs); + + // resourceRequests.Remove(id); reply.Trigger(dr); }).Error(ex => reply.TriggerError(ex)); } - }).Error((ex) => { reply.TriggerError(ex); @@ -2267,11 +2108,18 @@ partial class DistributedConnection .Done() .Then(ar => { - var d = (byte[])ar[0]; - Codec.ParseResourceArray(d, 0, (uint)d.Length, this).Then(resources => - { - rt.Trigger(resources); - }).Error(ex => rt.TriggerError(ex)); + var dataType = (TransmissionType)ar[0]; + var data = (byte[])ar[1]; + + var (_, parsed) = Codec.Parse(data, dataType.Offset, this, dataType); + + parsed.Then(resources => rt.Trigger(resources)) + .Error(ex => rt.TriggerError(ex)); + + //Codec.ParseResourceArray(d, 0, (uint)d.Length, this).Then(resources => + //{ + // rt.Trigger(resources); + //}).Error(ex => rt.TriggerError(ex)); }); return rt; @@ -2286,11 +2134,17 @@ partial class DistributedConnection .Done() .Then(ar => { - var d = (byte[])ar[0]; - Codec.ParseResourceArray(d, 0, (uint)d.Length, this).Then(resources => - { - rt.Trigger(resources); - }).Error(ex => rt.TriggerError(ex)); + var dataType = (TransmissionType)ar[0]; + var data = (byte[])ar[1]; + var (_, parsed) = Codec.Parse(data, dataType.Offset, this, dataType); + + parsed.Then(resources => rt.Trigger(resources)) + .Error(ex => rt.TriggerError(ex)); + + //Codec.ParseResourceArray(d, 0, (uint)d.Length, this).Then(resources => + //{ + // rt.Trigger(resources); + //}).Error(ex => rt.TriggerError(ex)); }); return rt; @@ -2321,13 +2175,14 @@ partial class DistributedConnection return rt; } - public AsyncReply SetAttributes(IResource resource, Structure attributes, bool clearAttributes = false) + public AsyncReply SetAttributes(IResource resource, Map attributes, bool clearAttributes = false) { var rt = new AsyncReply(); SendRequest(clearAttributes ? IIPPacket.IIPPacketAction.UpdateAllAttributes : IIPPacket.IIPPacketAction.UpdateAttributes) .AddUInt32(resource.Instance.Id) - .AddUInt8Array(Codec.ComposeStructure(attributes, this, true, true, true)) + //.AddUInt8Array(Codec.ComposeStructure(attributes, this, true, true, true)) + .AddUInt8Array(Codec.Compose(attributes, this)) .Done() .Then(ar => rt.Trigger(true)) .Error(ex => rt.TriggerError(ex)); @@ -2335,9 +2190,9 @@ partial class DistributedConnection return rt; } - public AsyncReply GetAttributes(IResource resource, string[] attributes = null) + public AsyncReply> GetAttributes(IResource resource, string[] attributes = null) { - var rt = new AsyncReply(); + var rt = new AsyncReply>(); if (attributes == null) { @@ -2346,11 +2201,14 @@ partial class DistributedConnection .Done() .Then(ar => { - var d = ar[0] as byte[]; - Codec.ParseStructure(d, 0, (uint)d.Length, this).Then(st => + var dataType = (TransmissionType)ar[0]; + var data = (byte[])ar[1]; + //Codec.Parse(d, ) + var (_, parsed) = Codec.Parse(data, 0, this, dataType); + parsed.Then(st => { - resource.Instance.SetAttributes(st); + resource.Instance.SetAttributes(st as Map); rt.Trigger(st); }).Error(ex => rt.TriggerError(ex)); @@ -2366,11 +2224,14 @@ partial class DistributedConnection .Done() .Then(ar => { - var d = ar[0] as byte[]; - Codec.ParseStructure(d, 0, (uint)d.Length, this).Then(st => + var dataType = (TransmissionType)ar[0]; + var data = (byte[])ar[1]; + + var (_, parsed) = Codec.Parse(data, 0, this, dataType); + parsed.Then(st => { - resource.Instance.SetAttributes(st); + resource.Instance.SetAttributes((Map)st); rt.Trigger(st); }).Error(ex => rt.TriggerError(ex)); @@ -2407,7 +2268,7 @@ partial class DistributedConnection { var content = (byte[])rt[0]; - Codec.ParseHistory(content, 0, (uint)content.Length, resource, this) + DataDeserializer.HistoryParser(content, 0, (uint)content.Length, resource, this) .Then((history) => reply.Trigger(history)); }).Error((ex) => reply.TriggerError(ex)); @@ -2432,12 +2293,18 @@ partial class DistributedConnection .AddUInt16((ushort)str.Length) .AddUInt8Array(str) .Done() - .Then(args => + .Then(ar => { - var content = args[0] as byte[]; + var dataType = (TransmissionType)ar[0]; + var data = ar[1] as byte[]; - Codec.ParseResourceArray(content, 0, (uint)content.Length, this) - .Then(resources => reply.Trigger(resources)); + var (_, parsed) = Codec.Parse(data, dataType.Offset, this, dataType); + + parsed.Then(resources => reply.Trigger(resources)) + .Error(ex => reply.TriggerError(ex)); + + //Codec.ParseResourceArray(content, 0, (uint)content.Length, this) + // .Then(resources => reply.Trigger(resources)); }).Error(ex => reply.TriggerError(ex)); @@ -2454,7 +2321,7 @@ partial class DistributedConnection /// Resource attributeds. /// Values for the resource properties. /// New resource instance - public AsyncReply Create(IStore store, IResource parent, string className, object[] parameters, Structure attributes, Structure values) + public AsyncReply Create(IStore store, IResource parent, string className, object[] parameters, Map attributes, Map values) { var reply = new AsyncReply(); var pkt = new BinaryList() @@ -2462,9 +2329,9 @@ partial class DistributedConnection .AddUInt32(parent.Instance.Id) .AddUInt8((byte)className.Length) .AddString(className) - .AddUInt8Array(Codec.ComposeVarArray(parameters, this, true)) - .AddUInt8Array(Codec.ComposeStructure(attributes, this, true, true, true)) - .AddUInt8Array(Codec.ComposeStructure(values, this)); + .AddUInt8Array(Codec.Compose(parameters, this)) + .AddUInt8Array(Codec.Compose(attributes, this)) + .AddUInt8Array(Codec.Compose(values, this)); pkt.InsertInt32(8, pkt.Length); @@ -2489,10 +2356,10 @@ partial class DistributedConnection { lock (subscriptionsLock) { - resource.Instance.ResourceEventOccurred += Instance_EventOccurred; - resource.Instance.CustomResourceEventOccurred += Instance_CustomEventOccurred; - resource.Instance.ResourceModified += Instance_PropertyModified; - resource.Instance.ResourceDestroyed += Instance_ResourceDestroyed; + resource.Instance.EventOccurred += Instance_EventOccurred; + resource.Instance.CustomEventOccurred += Instance_CustomEventOccurred; + resource.Instance.PropertyModified += Instance_PropertyModified; + resource.Instance.Destroyed += Instance_ResourceDestroyed; subscriptions.Add(resource, new List()); } @@ -2503,10 +2370,10 @@ partial class DistributedConnection lock (subscriptionsLock) { // do something with the list... - resource.Instance.ResourceEventOccurred -= Instance_EventOccurred; - resource.Instance.CustomResourceEventOccurred -= Instance_CustomEventOccurred; - resource.Instance.ResourceModified -= Instance_PropertyModified; - resource.Instance.ResourceDestroyed -= Instance_ResourceDestroyed; + resource.Instance.EventOccurred -= Instance_EventOccurred; + resource.Instance.CustomEventOccurred -= Instance_CustomEventOccurred; + resource.Instance.PropertyModified -= Instance_PropertyModified; + resource.Instance.Destroyed -= Instance_ResourceDestroyed; subscriptions.Remove(resource); } @@ -2519,10 +2386,10 @@ partial class DistributedConnection { foreach (var resource in subscriptions.Keys) { - resource.Instance.ResourceEventOccurred -= Instance_EventOccurred; - resource.Instance.CustomResourceEventOccurred -= Instance_CustomEventOccurred; - resource.Instance.ResourceModified -= Instance_PropertyModified; - resource.Instance.ResourceDestroyed -= Instance_ResourceDestroyed; + resource.Instance.EventOccurred -= Instance_EventOccurred; + resource.Instance.CustomEventOccurred -= Instance_CustomEventOccurred; + resource.Instance.PropertyModified -= Instance_PropertyModified; + resource.Instance.Destroyed -= Instance_ResourceDestroyed; } subscriptions.Clear(); @@ -2541,86 +2408,75 @@ partial class DistributedConnection } - private void Instance_PropertyModified(IResource resource, string name, object newValue) + private void Instance_PropertyModified(PropertyModificationInfo info) { - var pt = resource.Instance.Template.GetPropertyTemplateByName(name); - - if (pt == null) - return; + //var pt = resource.Instance.Template.GetPropertyTemplateByName(name); + // if (pt == null) + // return; SendEvent(IIPPacket.IIPPacketEvent.PropertyUpdated) - .AddUInt32(resource.Instance.Id) - .AddUInt8(pt.Index) - .AddUInt8Array(Codec.Compose(newValue, this)) + .AddUInt32(info.Resource.Instance.Id) + .AddUInt8(info.PropertyTemplate.Index) + .AddUInt8Array(Codec.Compose(info.Value, this)) .Done(); } // private void Instance_EventOccurred(IResource resource, string name, string[] users, DistributedConnection[] connections, object[] args) - private void Instance_CustomEventOccurred(IResource resource, object issuer, Func receivers, string name, object args) + private void Instance_CustomEventOccurred(CustomEventOccurredInfo info) { - var et = resource.Instance.Template.GetEventTemplateByName(name); - - if (et == null) - return; - - if (et.Listenable) + if (info.EventTemplate.Listenable) { lock (subscriptionsLock) { // check the client requested listen - if (!subscriptions.ContainsKey(resource)) + if (!subscriptions.ContainsKey(info.Resource)) return; - if (!subscriptions[resource].Contains(et.Index)) + if (!subscriptions[info.Resource].Contains(info.EventTemplate.Index)) return; } } - if (!receivers(this.session)) + if (!info.Receivers(this.session)) return; - if (resource.Instance.Applicable(this.session, ActionType.ReceiveEvent, et, issuer) == Ruling.Denied) + if (info.Resource.Instance.Applicable(this.session, ActionType.ReceiveEvent, info.EventTemplate, info.Issuer) == Ruling.Denied) return; // compose the packet SendEvent(IIPPacket.IIPPacketEvent.EventOccurred) - .AddUInt32(resource.Instance.Id) - .AddUInt8((byte)et.Index) - .AddUInt8Array(Codec.Compose(args, this, true)) + .AddUInt32(info.Resource.Instance.Id) + .AddUInt8((byte)info.EventTemplate.Index) + .AddUInt8Array(Codec.Compose(info.Value, this)) .Done(); } - private void Instance_EventOccurred(IResource resource, string name, object args) + private void Instance_EventOccurred(EventOccurredInfo info) { - var et = resource.Instance.Template.GetEventTemplateByName(name); - - if (et == null) - return; - - if (et.Listenable) + if (info.EventTemplate.Listenable) { lock (subscriptionsLock) { // check the client requested listen - if (!subscriptions.ContainsKey(resource)) + if (!subscriptions.ContainsKey(info.Resource)) return; - if (!subscriptions[resource].Contains(et.Index)) + if (!subscriptions[info.Resource].Contains(info.EventTemplate.Index)) return; } } - if (resource.Instance.Applicable(this.session, ActionType.ReceiveEvent, et, null) == Ruling.Denied) + if (info.Resource.Instance.Applicable(this.session, ActionType.ReceiveEvent, info.EventTemplate, null) == Ruling.Denied) return; // compose the packet SendEvent(IIPPacket.IIPPacketEvent.EventOccurred) - .AddUInt32(resource.Instance.Id) - .AddUInt8((byte)et.Index) - .AddUInt8Array(Codec.Compose(args, this, true)) + .AddUInt32(info.Resource.Instance.Id) + .AddUInt8((byte)info.EventTemplate.Index) + .AddUInt8Array(Codec.Compose(info.Value, this)) .Done(); } } diff --git a/Esiur/Net/IIP/DistributedPropertyContext.cs b/Esiur/Net/IIP/DistributedPropertyContext.cs index f1e390c..ddd800e 100644 --- a/Esiur/Net/IIP/DistributedPropertyContext.cs +++ b/Esiur/Net/IIP/DistributedPropertyContext.cs @@ -3,23 +3,34 @@ using System.Collections.Generic; using System.Text; namespace Esiur.Net.IIP; -public class DistributedPropertyContext -{ - public object Value { get; private set; } - public DistributedConnection Connection { get; private set; } - public Func Method { get; private set; } - public DistributedPropertyContext(DistributedConnection connection, object value) +public interface IDistributedPropertyContext +{ + object GetValue(DistributedConnection connection); +} + +public class DistributedPropertyContext : IDistributedPropertyContext +{ + public T Value { get; private set; } + public DistributedConnection Connection { get; private set; } + public Func Method { get; private set; } + + public DistributedPropertyContext(DistributedConnection connection, T value) { this.Value = value; this.Connection = connection; } - public DistributedPropertyContext(Func method) + public DistributedPropertyContext(Func method) { this.Method = method; } - public static implicit operator DistributedPropertyContext(Func method) - => new DistributedPropertyContext(method); + public static implicit operator DistributedPropertyContext(Func method) + => new DistributedPropertyContext(method); + + public object GetValue(DistributedConnection connection) + { + return Method.Invoke(connection); + } } diff --git a/Esiur/Net/IIP/DistributedResource.cs b/Esiur/Net/IIP/DistributedResource.cs index 522f8ca..9d129b4 100644 --- a/Esiur/Net/IIP/DistributedResource.cs +++ b/Esiur/Net/IIP/DistributedResource.cs @@ -52,7 +52,8 @@ public class DistributedResource : DynamicObject, IResource /// Raised when the distributed resource is destroyed. /// public event DestroyedEvent OnDestroy; - public event Instance.ResourceModifiedEvent OnModified; + public event PropertyModifiedEvent PropertyModified; + uint instanceId; DistributedConnection connection; @@ -83,6 +84,8 @@ public class DistributedResource : DynamicObject, IResource //} + + /// /// Connection responsible for the distributed resource. /// @@ -214,12 +217,10 @@ public class DistributedResource : DynamicObject, IResource { var et = Instance.Template.GetEventTemplateByIndex(index); events[index]?.Invoke(this, args); - Instance.EmitResourceEvent(et.Name, args); + Instance.EmitResourceEvent(et, args); } - - - public AsyncReply _InvokeByNamedArguments(byte index, Structure namedArgs) + public AsyncReply _Invoke(byte index, Map args) { if (destroyed) throw new Exception("Trying to access destroyed object"); @@ -231,23 +232,7 @@ public class DistributedResource : DynamicObject, IResource throw new Exception("Function index is incorrect"); - return connection.SendInvokeByNamedArguments(instanceId, index, namedArgs); - } - - - public AsyncReply _InvokeByArrayArguments(byte index, object[] args) - { - if (destroyed) - throw new Exception("Trying to access destroyed object"); - - if (suspended) - throw new Exception("Trying to access suspended object"); - - if (index >= Instance.Template.Functions.Length) - throw new Exception("Function index is incorrect"); - - - return connection.SendInvokeByArrayArguments(instanceId, index, args); + return connection.SendInvoke(instanceId, index, args); } @@ -294,31 +279,43 @@ public class DistributedResource : DynamicObject, IResource var ft = Instance.Template.GetFunctionTemplateByName(binder.Name); var reply = new AsyncReply(); - + if (attached && ft != null) { + var indexedArgs = new Map(); + if (args.Length == 1) { // Detect anonymous types var type = args[0].GetType(); + + if (Codec.IsAnonymous(type)) { - var namedArgs = new Structure(); - var pi = type.GetTypeInfo().GetProperties(); - foreach (var p in pi) - namedArgs[p.Name] = p.GetValue(args[0]); - result = _InvokeByNamedArguments(ft.Index, namedArgs); + var pis = type.GetProperties(); + + for (byte i = 0; i < ft.Arguments.Length; i++) + { + var pi = pis.FirstOrDefault(x => x.Name == ft.Arguments[i].Name); + if (pi != null) + indexedArgs.Add(i, pi.GetValue(args[0])); + } + + result =_Invoke(ft.Index, indexedArgs); } else { - result = _InvokeByArrayArguments(ft.Index, args); + indexedArgs.Add((byte)0, args[0]); + result = _Invoke(ft.Index, indexedArgs); } - } else { - result = _InvokeByArrayArguments(ft.Index, args); + for (byte i = 0; i < args.Length; i++) + indexedArgs.Add(i, args[i]); + + result = _Invoke(ft.Index, indexedArgs); } return true; } @@ -341,6 +338,20 @@ public class DistributedResource : DynamicObject, IResource return properties[index]; } + public bool TryGetPropertyValue(byte index, out object value) + { + if (index >= properties.Length) + { + value = null; + return false; + } + else + { + value = properties[index]; + return true; + } + } + public override bool TryGetMember(GetMemberBinder binder, out object result) { if (destroyed) @@ -409,6 +420,7 @@ public class DistributedResource : DynamicObject, IResource return reply; } + public override bool TrySetMember(SetMemberBinder binder, object value) { if (destroyed) @@ -496,7 +508,7 @@ public class DistributedResource : DynamicObject, IResource { if (trigger == ResourceTrigger.Initialize) - this.Instance.ResourceModified += this.OnModified; + this.Instance.PropertyModified += this.PropertyModified; // do nothing. return new AsyncReply(true); diff --git a/Esiur/Net/IIP/DistributedServer.cs b/Esiur/Net/IIP/DistributedServer.cs index 35d2cdd..2c00590 100644 --- a/Esiur/Net/IIP/DistributedServer.cs +++ b/Esiur/Net/IIP/DistributedServer.cs @@ -38,6 +38,9 @@ using Esiur.Security.Membership; namespace Esiur.Net.IIP; public class DistributedServer : NetworkServer, IResource { + + + [Attribute] public string IP { @@ -81,6 +84,8 @@ public class DistributedServer : NetworkServer, IResource set; } + public event PropertyModifiedEvent PropertyModified; + public AsyncReply Trigger(ResourceTrigger trigger) { if (trigger == ResourceTrigger.Initialize) diff --git a/Esiur/Net/NetworkBuffer.cs b/Esiur/Net/NetworkBuffer.cs index 6f9b741..54a32b8 100644 --- a/Esiur/Net/NetworkBuffer.cs +++ b/Esiur/Net/NetworkBuffer.cs @@ -170,6 +170,7 @@ public class NetworkBuffer { rt = data; data = new byte[0]; + return rt; } else { @@ -200,7 +201,6 @@ public class NetworkBuffer } } - return rt; } } } diff --git a/Esiur/Net/NetworkServer.cs b/Esiur/Net/NetworkServer.cs index 1604e7f..a0fb3b1 100644 --- a/Esiur/Net/NetworkServer.cs +++ b/Esiur/Net/NetworkServer.cs @@ -121,6 +121,8 @@ public abstract class NetworkServer : IDestructible where TConnecti return; } + Console.WriteLine("New Socket ... " + DateTime.Now); + var c = new TConnection(); //c.OnClose += ClientDisconnectedEventReceiver; c.Assign(s); diff --git a/Esiur/Net/Packets/IIPAuthPacket.cs b/Esiur/Net/Packets/IIPAuthPacket.cs index a53aa21..3faf5e7 100644 --- a/Esiur/Net/Packets/IIPAuthPacket.cs +++ b/Esiur/Net/Packets/IIPAuthPacket.cs @@ -222,7 +222,7 @@ class IIPAuthPacket : Packet if (NotEnough(offset, ends, 2)) return -dataLengthNeeded; - var length = data.GetUInt16(offset); + var length = data.GetUInt16(offset, Endian.Little); offset += 2; @@ -311,7 +311,7 @@ class IIPAuthPacket : Packet offset += 32; - RemoteTokenIndex = data.GetUInt64(offset); + RemoteTokenIndex = data.GetUInt64(offset, Endian.Little); offset += 8; } } @@ -321,7 +321,7 @@ class IIPAuthPacket : Packet if (NotEnough(offset, ends, 2)) return -dataLengthNeeded; - var keyLength = data.GetUInt16(offset); + var keyLength = data.GetUInt16(offset, Endian.Little); offset += 2; @@ -369,7 +369,7 @@ class IIPAuthPacket : Packet if (NotEnough(offset, ends, 2)) return -dataLengthNeeded; - var keyLength = data.GetUInt16(offset); + var keyLength = data.GetUInt16(offset, Endian.Little); offset += 2; @@ -394,7 +394,7 @@ class IIPAuthPacket : Packet ErrorCode = data[offset++]; - var cl = data.GetUInt16(offset); + var cl = data.GetUInt16(offset, Endian.Little); offset += 2; if (NotEnough(offset, ends, cl)) diff --git a/Esiur/Net/Packets/IIPPacket.cs b/Esiur/Net/Packets/IIPPacket.cs index 8890206..32860ce 100644 --- a/Esiur/Net/Packets/IIPPacket.cs +++ b/Esiur/Net/Packets/IIPPacket.cs @@ -109,8 +109,8 @@ class IIPPacket : Packet LinkTemplates, // Request Invoke - InvokeFunctionArrayArguments = 0x10, - InvokeFunctionNamedArguments, + InvokeFunction = 0x10, + Reserved, Listen, Unlisten, SetProperty, @@ -173,6 +173,7 @@ class IIPPacket : Packet set; } + public TransmissionType? DataType { get; set; } public uint ResourceId { get; set; } public uint NewResourceId { get; set; } @@ -181,11 +182,13 @@ class IIPPacket : Packet public uint StoreId { get; set; } public ulong ResourceAge { get; set; } - public byte[] Content { get; set; } + //public byte[] Content { get; set; } public ushort ErrorCode { get; set; } public string ErrorMessage { get; set; } public string ClassName { get; set; } public string ResourceLink { get; set; } + + public string ResourceName { get; set; } public Guid ClassId { get; set; } public byte MethodIndex { get; set; } public string MethodName { get; set; } @@ -236,7 +239,7 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 4)) return -dataLengthNeeded; - ResourceId = data.GetUInt32(offset); + ResourceId = data.GetUInt32(offset, Endian.Little); offset += 4; } else if (Command == IIPPacketCommand.Report) @@ -246,7 +249,7 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 4)) return -dataLengthNeeded; - CallbackId = data.GetUInt32(offset); + CallbackId = data.GetUInt32(offset, Endian.Little); offset += 4; } else @@ -257,7 +260,7 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 4)) return -dataLengthNeeded; - CallbackId = data.GetUInt32(offset); + CallbackId = data.GetUInt32(offset, Endian.Little); offset += 4; } @@ -268,7 +271,7 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 4)) return -dataLengthNeeded; - NewResourceId = data.GetUInt32(offset); + NewResourceId = data.GetUInt32(offset, Endian.Little); offset += 4; } @@ -282,7 +285,7 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 4)) return -dataLengthNeeded; - ChildId = data.GetUInt32(offset); + ChildId = data.GetUInt32(offset, Endian.Little); offset += 4; } else if (Event == IIPPacketEvent.Renamed) @@ -290,13 +293,15 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 2)) return -dataLengthNeeded; - var cl = data.GetUInt16(offset); + var cl = data.GetUInt16(offset, Endian.Little); offset += 2; if (NotEnough(offset, ends, cl)) return -dataLengthNeeded; - Content = data.Clip(offset, cl); + ResourceName = data.GetString(offset, cl); + + //Content = data.Clip(offset, cl); offset += cl; } @@ -308,31 +313,19 @@ class IIPPacket : Packet MethodIndex = data[offset++]; - var dt = (DataType)data[offset++]; - var size = dt.Size();// Codec.SizeOf(dt); + (var size, DataType) = TransmissionType.Parse(data, offset, ends); - if (size < 0) - { - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; - var cl = data.GetUInt32(offset); - offset += 4; + //var dt = (DataType)data[offset++]; + //var size = dt.Size();// Codec.SizeOf(dt); - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; + if (DataType == null) + return -(int)size; - Content = data.Clip(offset - 5, cl + 5); - offset += cl; - } - else - { - if (NotEnough(offset, ends, (uint)size)) - return -dataLengthNeeded; + //Content = data.Clip(DataType.Value.Offset, (uint)DataType.Value.ContentLength); + + offset += (uint)size; - Content = data.Clip(offset - 1, (uint)size + 1); - offset += (uint)size; - } } //else if (Event == IIPPacketEvent.EventOccurred) //{ @@ -357,13 +350,14 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 4)) return -dataLengthNeeded; - var cl = data.GetUInt32(offset); + var cl = data.GetUInt32(offset, Endian.Little); offset += 4; if (NotEnough(offset, ends, cl)) return -dataLengthNeeded; - Content = data.Clip(offset, cl); + //@TODO: Fix this + //Content = data.Clip(offset, cl); offset += cl; } @@ -375,7 +369,7 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 4)) return -dataLengthNeeded; - ResourceId = data.GetUInt32(offset); + ResourceId = data.GetUInt32(offset, Endian.Little); offset += 4; } else if (Action == IIPPacketAction.ReattachResource) @@ -383,10 +377,10 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 12)) return -dataLengthNeeded; - ResourceId = data.GetUInt32(offset); + ResourceId = data.GetUInt32(offset, Endian.Little); offset += 4; - ResourceAge = data.GetUInt64(offset); + ResourceAge = data.GetUInt64(offset, Endian.Little); offset += 8; } @@ -395,7 +389,7 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 4)) return -dataLengthNeeded; - ResourceId = data.GetUInt32(offset); + ResourceId = data.GetUInt32(offset, Endian.Little); offset += 4; } @@ -404,25 +398,26 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 12)) return -dataLengthNeeded; - StoreId = data.GetUInt32(offset); + StoreId = data.GetUInt32(offset, Endian.Little); offset += 4; - ResourceId = data.GetUInt32(offset); + ResourceId = data.GetUInt32(offset, Endian.Little); offset += 4; - var cl = data.GetUInt32(offset); + var cl = data.GetUInt32(offset, Endian.Little); offset += 4; if (NotEnough(offset, ends, cl)) return -dataLengthNeeded; - this.Content = data.Clip(offset, cl); + // @TODO: fix this + //this.Content = data.Clip(offset, cl); } else if (Action == IIPPacketAction.DeleteResource) { if (NotEnough(offset, ends, 4)) return -dataLengthNeeded; - ResourceId = data.GetUInt32(offset); + ResourceId = data.GetUInt32(offset, Endian.Little); offset += 4; } @@ -432,9 +427,9 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 8)) return -dataLengthNeeded; - ResourceId = data.GetUInt32(offset); + ResourceId = data.GetUInt32(offset, Endian.Little); offset += 4; - ChildId = data.GetUInt32(offset); + ChildId = data.GetUInt32(offset, Endian.Little); offset += 4; } else if (Action == IIPPacketAction.RenameResource) @@ -442,15 +437,16 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 6)) return -dataLengthNeeded; - ResourceId = data.GetUInt32(offset); + ResourceId = data.GetUInt32(offset, Endian.Little); offset += 4; - var cl = data.GetUInt16(offset); + var cl = data.GetUInt16(offset, Endian.Little); offset += 2; if (NotEnough(offset, ends, cl)) return -dataLengthNeeded; - Content = data.Clip(offset, cl); + ResourceName = data.GetString(offset, cl); + //Content = data.Clip(offset, cl); offset += cl; } else if (Action == IIPPacketAction.TemplateFromClassName) @@ -481,7 +477,7 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 4)) return -dataLengthNeeded; - ResourceId = data.GetUInt32(offset); + ResourceId = data.GetUInt32(offset, Endian.Little); offset += 4; } else if (Action == IIPPacketAction.QueryLink @@ -490,7 +486,7 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 2)) return -dataLengthNeeded; - var cl = data.GetUInt16(offset); + var cl = data.GetUInt16(offset, Endian.Little); offset += 2; if (NotEnough(offset, ends, cl)) @@ -505,7 +501,7 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 4)) return -dataLengthNeeded; - ResourceId = data.GetUInt32(offset); + ResourceId = data.GetUInt32(offset, Endian.Little); offset += 4; } else if (Action == IIPPacketAction.ResourceHistory) @@ -513,35 +509,42 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 20)) return -dataLengthNeeded; - ResourceId = data.GetUInt32(offset); + ResourceId = data.GetUInt32(offset, Endian.Little); offset += 4; - FromDate = data.GetDateTime(offset); + FromDate = data.GetDateTime(offset, Endian.Little); offset += 8; - ToDate = data.GetDateTime(offset); + ToDate = data.GetDateTime(offset, Endian.Little); offset += 8; } - else if (Action == IIPPacketAction.InvokeFunctionArrayArguments - || Action == IIPPacketAction.InvokeFunctionNamedArguments) + else if (Action == IIPPacketAction.InvokeFunction) { - if (NotEnough(offset, ends, 9)) + if (NotEnough(offset, ends, 6)) return -dataLengthNeeded; - ResourceId = data.GetUInt32(offset); + ResourceId = data.GetUInt32(offset, Endian.Little); offset += 4; MethodIndex = data[offset++]; - var cl = data.GetUInt32(offset); - offset += 4; - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; + (var size, DataType) = TransmissionType.Parse(data, offset, ends); - Content = data.Clip(offset, cl); - offset += cl; + if (DataType == null) + return -(int)size; + + offset += (uint)size; + + //var cl = data.GetUInt32(offset); + //offset += 4; + + //if (NotEnough(offset, ends, cl)) + // return -dataLengthNeeded; + + //Content = data.Clip(offset, cl); + //offset += cl; } else if (Action == IIPPacketAction.Listen @@ -550,7 +553,7 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 5)) return -dataLengthNeeded; - ResourceId = data.GetUInt32(offset); + ResourceId = data.GetUInt32(offset, Endian.Little); offset += 4; MethodIndex = data[offset++]; @@ -575,37 +578,21 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 6)) return -dataLengthNeeded; - ResourceId = data.GetUInt32(offset); + ResourceId = data.GetUInt32(offset, Endian.Little); offset += 4; MethodIndex = data[offset++]; + (var size, DataType) = TransmissionType.Parse(data, offset, ends); - var dt = (DataType)data[offset++]; - var size = dt.Size();// Codec.SizeOf(dt); + if (DataType == null) + return -(int)size; - if (size < 0) - { - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; - var cl = data.GetUInt32(offset); - offset += 4; + //Content = data.Clip(DataType.Value.Offset, (uint)DataType.Value.ContentLength); - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; + offset += (uint)size; - Content = data.Clip(offset - 5, cl + 5); - offset += cl; - } - else - { - if (NotEnough(offset, ends, (uint)size)) - return -dataLengthNeeded; - - Content = data.Clip(offset - 1, (uint)size + 1); - offset += (uint)size; - } } // Attributes else if (Action == IIPPacketAction.UpdateAllAttributes @@ -616,15 +603,16 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 8)) return -dataLengthNeeded; - ResourceId = data.GetUInt32(offset); + ResourceId = data.GetUInt32(offset, Endian.Little); offset += 4; - var cl = data.GetUInt32(offset); + var cl = data.GetUInt32(offset, Endian.Little); offset += 4; if (NotEnough(offset, ends, cl)) return -dataLengthNeeded; - Content = data.Clip(offset, cl); + // @TODO: fix this + //Content = data.Clip(offset, cl); offset += cl; } } @@ -640,10 +628,10 @@ class IIPPacket : Packet ClassId = data.GetGuid(offset); offset += 16; - ResourceAge = data.GetUInt64(offset); + ResourceAge = data.GetUInt64(offset, Endian.Little); offset += 8; - uint cl = data.GetUInt16(offset); + uint cl = data.GetUInt16(offset, Endian.Little); offset += 2; if (NotEnough(offset, ends, cl)) @@ -652,17 +640,19 @@ class IIPPacket : Packet ResourceLink = data.GetString(offset, cl); offset += cl; - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; + //if (NotEnough(offset, ends, 4)) + // return -dataLengthNeeded; - cl = data.GetUInt32(offset); - offset += 4; - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; + (var size, DataType) = TransmissionType.Parse(data, offset, ends); + + if (DataType == null) + return -(int)size; + + offset += (uint)size; + + //Content = data.Clip(DataType.Value.Offset, (uint)DataType.Value.ContentLength); - Content = data.Clip(offset, cl); - offset += cl; } else if (Action == IIPPacketAction.DetachResource) { @@ -676,7 +666,7 @@ class IIPPacket : Packet //ClassId = data.GetGuid(offset); //offset += 16; - ResourceId = data.GetUInt32(offset); + ResourceId = data.GetUInt32(offset, Endian.Little); offset += 4; } @@ -697,51 +687,40 @@ class IIPPacket : Packet || Action == IIPPacketAction.GetAllAttributes || Action == IIPPacketAction.GetAttributes) { - if (NotEnough(offset, ends, 4)) + if (NotEnough(offset, ends, 1)) return -dataLengthNeeded; - var cl = data.GetUInt32(offset); - offset += 4; + (var size, DataType) = TransmissionType.Parse(data, offset, ends ); - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; + if (DataType == null) + return -(int)size; - Content = data.Clip(offset, cl); - offset += cl; + offset += (uint)size; + + //var cl = data.GetUInt32(offset); + //offset += 4; + + //if (NotEnough(offset, ends, cl)) + // return -dataLengthNeeded; + + //Content = data.Clip(offset, cl); + //offset += cl; } - else if (Action == IIPPacketAction.InvokeFunctionArrayArguments - || Action == IIPPacketAction.InvokeFunctionNamedArguments) + else if (Action == IIPPacketAction.InvokeFunction) //|| Action == IIPPacketAction.GetProperty //|| Action == IIPPacketAction.GetPropertyIfModified) { if (NotEnough(offset, ends, 1)) return -dataLengthNeeded; - var dt = (DataType)data[offset++]; - var size = dt.Size();// Codec.SizeOf(dt); + (var size, DataType) = TransmissionType.Parse(data, offset, ends); - if (size < 0) - { - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; + if (DataType == null) + return -(int)size; - var cl = data.GetUInt32(offset); - offset += 4; + offset += (uint)size; - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; - - Content = data.Clip(offset - 5, cl + 5); - offset += cl; - } - else - { - if (NotEnough(offset, ends, (uint)size)) - return -dataLengthNeeded; - - Content = data.Clip(offset - 1, (uint)size + 1); - offset += (uint)size; - } + //Content = data.Clip(DataType.Value.Offset, (uint)DataType.Value.ContentLength); } else if (Action == IIPPacketAction.SetProperty || Action == IIPPacketAction.Listen @@ -757,7 +736,7 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 2)) return -dataLengthNeeded; - ErrorCode = data.GetUInt16(offset); + ErrorCode = data.GetUInt16(offset, Endian.Little); offset += 2; } else if (Report == IIPPacketReport.ExecutionError) @@ -765,13 +744,13 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 2)) return -dataLengthNeeded; - ErrorCode = data.GetUInt16(offset); + ErrorCode = data.GetUInt16(offset, Endian.Little); offset += 2; if (NotEnough(offset, ends, 2)) return -dataLengthNeeded; - var cl = data.GetUInt16(offset); + var cl = data.GetUInt16(offset, Endian.Little); offset += 2; if (NotEnough(offset, ends, cl)) @@ -785,9 +764,9 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 8)) return -dataLengthNeeded; - ProgressValue = data.GetInt32(offset); + ProgressValue = data.GetInt32(offset, Endian.Little); offset += 4; - ProgressMax = data.GetInt32(offset); + ProgressMax = data.GetInt32(offset, Endian.Little); offset += 4; } else if (Report == IIPPacketReport.ChunkStream) @@ -795,31 +774,16 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 1)) return -dataLengthNeeded; - var dt = (DataType)data[offset++]; - var size = dt.Size();// Codec.SizeOf(dt); - if (size < 0) - { - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; + (var size, DataType) = TransmissionType.Parse(Data, offset, ends ); - var cl = data.GetUInt32(offset); - offset += 4; + if (DataType == null) + return -(int)size; - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; + offset += (uint)size; - Content = data.Clip(offset - 5, cl + 5); - offset += cl; - } - else - { - if (NotEnough(offset, ends, (uint)size)) - return -dataLengthNeeded; + //Content = data.Clip(DataType.Value.Offset, (uint)DataType.Value.ContentLength); - Content = data.Clip(offset - 1, (uint)size + 1); - offset += (uint)size; - } } } diff --git a/Esiur/Net/Packets/WebsocketPacket.cs b/Esiur/Net/Packets/WebsocketPacket.cs index c7e314a..5650f00 100644 --- a/Esiur/Net/Packets/WebsocketPacket.cs +++ b/Esiur/Net/Packets/WebsocketPacket.cs @@ -88,13 +88,13 @@ public class WebsocketPacket : Packet // 4 bytes { pkt.Add((byte)((Mask ? 0x80 : 0x0) | 127)); - pkt.AddRange(DC.ToBytes((UInt64)Message.LongCount())); + pkt.AddRange(DC.ToBytes((UInt64)Message.LongCount(), Endian.Big)); } else if (Message.Length > 125) // 2 bytes { pkt.Add((byte)((Mask ? 0x80 : 0x0) | 126)); - pkt.AddRange(DC.ToBytes((UInt16)Message.Length)); + pkt.AddRange(DC.ToBytes((UInt16)Message.Length, Endian.Big)); } else { @@ -145,7 +145,7 @@ public class WebsocketPacket : Packet //Console.WriteLine("stage 2 " + needed); return length - needed; } - PayloadLength = data.GetUInt16(offset); + PayloadLength = data.GetUInt16(offset, Endian.Big); offset += 2; } else if (PayloadLength == 127) @@ -157,7 +157,7 @@ public class WebsocketPacket : Packet return length - needed; } - PayloadLength = data.GetInt64(offset); + PayloadLength = data.GetInt64(offset, Endian.Big); offset += 8; } diff --git a/Esiur/Net/TCP/TCPFilter.cs b/Esiur/Net/TCP/TCPFilter.cs index 1091afc..591bb5e 100644 --- a/Esiur/Net/TCP/TCPFilter.cs +++ b/Esiur/Net/TCP/TCPFilter.cs @@ -36,6 +36,7 @@ namespace Esiur.Net.TCP; public abstract class TCPFilter : IResource { + public Instance Instance { get; @@ -43,6 +44,7 @@ public abstract class TCPFilter : IResource } public event DestroyedEvent OnDestroy; + public abstract AsyncReply Trigger(ResourceTrigger trigger); diff --git a/Esiur/Net/TCP/TCPServer.cs b/Esiur/Net/TCP/TCPServer.cs index acfdad5..eb93eed 100644 --- a/Esiur/Net/TCP/TCPServer.cs +++ b/Esiur/Net/TCP/TCPServer.cs @@ -66,7 +66,6 @@ public class TCPServer : NetworkServer, IResource TCPFilter[] filters = null; - public AsyncReply Trigger(ResourceTrigger trigger) { if (trigger == ResourceTrigger.Initialize) diff --git a/Esiur/Net/UDP/UDPFilter.cs b/Esiur/Net/UDP/UDPFilter.cs index 7a48e4d..b1ef087 100644 --- a/Esiur/Net/UDP/UDPFilter.cs +++ b/Esiur/Net/UDP/UDPFilter.cs @@ -35,6 +35,9 @@ using Esiur.Resource; namespace Esiur.Net.UDP; public abstract class UDPFilter : IResource { + + + public Instance Instance { get; diff --git a/Esiur/Net/UDP/UDPServer.cs b/Esiur/Net/UDP/UDPServer.cs index 0dc9573..ec48d24 100644 --- a/Esiur/Net/UDP/UDPServer.cs +++ b/Esiur/Net/UDP/UDPServer.cs @@ -47,6 +47,7 @@ public class UDPServer : IResource UDPFilter[] filters = new UDPFilter[0]; public event DestroyedEvent OnDestroy; + public Instance Instance { diff --git a/Esiur/Proxy/ResourceGenerator.cs b/Esiur/Proxy/ResourceGenerator.cs index 027b00e..754bda6 100644 --- a/Esiur/Proxy/ResourceGenerator.cs +++ b/Esiur/Proxy/ResourceGenerator.cs @@ -74,6 +74,15 @@ public class ResourceGenerator : ISourceGenerator + static string SuggestPropertyName(string propertyName) + { + if (Char.IsUpper(propertyName[0])) + return propertyName.Substring(0, 1).ToLower() + propertyName.Substring(1); + else + return propertyName.Substring(0, 1).ToUpper() + propertyName.Substring(1); + + } + public void Execute(GeneratorExecutionContext context) { @@ -146,27 +155,30 @@ namespace { ci.ClassSymbol.ContainingNamespace.ToDisplayString() } {{ "; if (ci.HasInterface) - code += $"public partial class {ci.Name} {{"; + code += $"public partial class {ci.Name} {{\r\n"; else { - code += @$"public partial class {ci.Name} : IResource {{ -public Instance Instance {{ get; set; }} -public event DestroyedEvent OnDestroy; -public virtual void Destroy() {{ OnDestroy?.Invoke(this); }} + code += +@$" public partial class {ci.Name} : IResource {{ + public Instance Instance {{ get; set; }} + public event DestroyedEvent OnDestroy; + + public virtual void Destroy() {{ OnDestroy?.Invoke(this); }} "; if (!ci.HasTrigger) - code += "public AsyncReply Trigger(ResourceTrigger trigger) => new AsyncReply(true);\r\n"; + code += +" public AsyncReply Trigger(ResourceTrigger trigger) => new AsyncReply(true);\r\n"; } //Debugger.Launch(); foreach (var f in ci.Fields) { - var givenName = f.GetAttributes().Where(x => x.AttributeClass.Name == "PublicAttribute").FirstOrDefault()?.ConstructorArguments.FirstOrDefault().Value; + var givenName = f.GetAttributes().Where(x => x.AttributeClass.Name == "PublicAttribute").FirstOrDefault()?.ConstructorArguments.FirstOrDefault().Value as string; var fn = f.Name; - var pn = givenName ?? fn.Substring(0, 1).ToUpper() + fn.Substring(1); + var pn =string.IsNullOrEmpty(givenName) ? SuggestPropertyName(fn): givenName; //System.IO.File.AppendAllText("c:\\gen\\fields.txt", fn + " -> " + pn + "\r\n"); diff --git a/Esiur/Proxy/ResourceGeneratorReceiver.cs b/Esiur/Proxy/ResourceGeneratorReceiver.cs index 2ae715b..f00cb13 100644 --- a/Esiur/Proxy/ResourceGeneratorReceiver.cs +++ b/Esiur/Proxy/ResourceGeneratorReceiver.cs @@ -29,10 +29,11 @@ public class ResourceGeneratorReceiver : ISyntaxContextReceiver { // Debugger.Launch(); - var url = import.ConstructorArguments.First().Value.ToString(); + var urls = import.ConstructorArguments.Select(x => x.Value.ToString());//.ToString(); - if (!Imports.Contains(url)) - Imports.Add(url); + foreach(var url in urls) + if (!Imports.Contains(url)) + Imports.Add(url); } if (attrs.Any(a => a.AttributeClass.ToDisplayString() == "Esiur.Resource.ResourceAttribute")) @@ -48,6 +49,7 @@ public class ResourceGeneratorReceiver : ISyntaxContextReceiver var fields = cds.Members.Where(x => x is FieldDeclarationSyntax) .Select(x => context.SemanticModel.GetDeclaredSymbol((x as FieldDeclarationSyntax).Declaration.Variables.First()) as IFieldSymbol) + .Where(x => !x.IsConst) .Where(x => x.GetAttributes().Any(a => a.AttributeClass.ToDisplayString() == "Esiur.Resource.PublicAttribute")) .ToArray(); diff --git a/Esiur/Proxy/TemplateGenerator.cs b/Esiur/Proxy/TemplateGenerator.cs index 639f043..ef54093 100644 --- a/Esiur/Proxy/TemplateGenerator.cs +++ b/Esiur/Proxy/TemplateGenerator.cs @@ -26,7 +26,7 @@ public static class TemplateGenerator 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 {{"); + rt.AppendLine($"[Public] public class {className} : IRecord {{"); foreach (var p in template.Properties) @@ -41,58 +41,81 @@ public static class TemplateGenerator return rt.ToString(); } - static string GetTypeName(TemplateDataType templateDataType, TypeTemplate[] templates) + internal static string GenerateEnum(TypeTemplate template, TypeTemplate[] templates) { + var cls = template.ClassName.Split('.'); - if (templateDataType.Type == DataType.Resource) - return templates.First(x => x.ClassId == templateDataType.TypeGuid && (x.Type == TemplateType.Resource || x.Type == TemplateType.Wrapper)).ClassName; - else if (templateDataType.Type == DataType.ResourceArray) - return templates.First(x => x.ClassId == templateDataType.TypeGuid && (x.Type == TemplateType.Resource || x.Type == TemplateType.Wrapper)).ClassName + "[]"; - else if (templateDataType.Type == DataType.Record) - return templates.First(x => x.ClassId == templateDataType.TypeGuid && x.Type == TemplateType.Record).ClassName; - else if (templateDataType.Type == DataType.RecordArray) - return templates.First(x => x.ClassId == templateDataType.TypeGuid && x.Type == TemplateType.Record).ClassName + "[]"; + var nameSpace = string.Join(".", cls.Take(cls.Length - 1)); + var className = cls.Last(); - var name = templateDataType.Type switch + 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] public enum {className} {{"); + + rt.AppendLine(String.Join(",\r\n", template.Constants.Select(x => $"{x.Name}={x.Value}"))); + + rt.AppendLine("\r\n}\r\n}"); + + return rt.ToString(); + } + + + static string GetTypeName(RepresentationType representationType, TypeTemplate[] templates) + { + string name; + + if (representationType.Identifier == RepresentationTypeIdentifier.TypedResource)// == DataType.Resource) + name = templates.First(x => x.ClassId == representationType.GUID && (x.Type == TemplateType.Resource || x.Type == TemplateType.Wrapper)).ClassName; + else if (representationType.Identifier == RepresentationTypeIdentifier.TypedRecord) + name = templates.First(x => x.ClassId == representationType.GUID && x.Type == TemplateType.Record).ClassName; + else if (representationType.Identifier == RepresentationTypeIdentifier.Enum) + name = templates.First(x => x.ClassId == representationType.GUID && x.Type == TemplateType.Enum).ClassName; + else if (representationType.Identifier == RepresentationTypeIdentifier.TypedList) + name = GetTypeName(representationType.SubTypes[0], templates) + "[]"; + else if (representationType.Identifier == RepresentationTypeIdentifier.TypedMap) + name = "Map<" + GetTypeName(representationType.SubTypes[0], templates) + + "," + GetTypeName(representationType.SubTypes[1], templates) + + ">"; + else if (representationType.Identifier == RepresentationTypeIdentifier.Tuple2 || + representationType.Identifier == RepresentationTypeIdentifier.Tuple3 || + representationType.Identifier == RepresentationTypeIdentifier.Tuple4 || + representationType.Identifier == RepresentationTypeIdentifier.Tuple5 || + representationType.Identifier == RepresentationTypeIdentifier.Tuple6 || + representationType.Identifier == RepresentationTypeIdentifier.Tuple7) + name = "(" + String.Join(",", representationType.SubTypes.Select(x=> GetTypeName(x, templates))) + + ")"; + else { - 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; + name = representationType.Identifier switch + { + RepresentationTypeIdentifier.Dynamic => "object", + RepresentationTypeIdentifier.Bool => "bool", + RepresentationTypeIdentifier.Char => "char", + RepresentationTypeIdentifier.DateTime => "DateTime", + RepresentationTypeIdentifier.Decimal => "decimal", + RepresentationTypeIdentifier.Float32 => "float", + RepresentationTypeIdentifier.Float64 => "double", + RepresentationTypeIdentifier.Int16 => "short", + RepresentationTypeIdentifier.Int32 => "int", + RepresentationTypeIdentifier.Int64 => "long", + RepresentationTypeIdentifier.Int8 => "sbyte", + RepresentationTypeIdentifier.String => "string", + RepresentationTypeIdentifier.Map => "Map", + RepresentationTypeIdentifier.UInt16 => "ushort", + RepresentationTypeIdentifier.UInt32 => "uint", + RepresentationTypeIdentifier.UInt64 => "ulong", + RepresentationTypeIdentifier.UInt8 => "byte", + RepresentationTypeIdentifier.List => "object[]", + RepresentationTypeIdentifier.Resource => "IResource", + RepresentationTypeIdentifier.Record => "IRecord", + _ => "object" + }; + } + + return (representationType.Nullable) ? name + "?" : name; } public static string GetTemplate(string url, string dir = null, string username = null, string password = null) @@ -142,16 +165,27 @@ public static class TemplateGenerator var source = GenerateRecord(tmp, templates); File.WriteAllText(tempDir.FullName + Path.DirectorySeparatorChar + tmp.ClassName + ".Generated.cs", source); } + else if (tmp.Type == TemplateType.Enum) + { + var source = GenerateEnum(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[] { " + + var typesFile = @"using System; + 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[] { " + + + @" }; + public static Type[] Records { get; } = new Type[] { " + string.Join(",", templates.Where(x => x.Type == TemplateType.Record).Select(x => $"typeof({x.ClassName})")) - + " }; " + - + + @" }; + public static Type[] Enums { get; } = new Type[] { " + + string.Join(",", templates.Where(x => x.Type == TemplateType.Enum).Select(x => $"typeof({x.ClassName})")) + + @" };" + "\r\n } \r\n}"; @@ -163,7 +197,6 @@ public static class TemplateGenerator } catch (Exception ex) { - //File.WriteAllText("C:\\gen\\gettemplate.err", ex.ToString()); throw ex; } } @@ -179,13 +212,22 @@ public static class TemplateGenerator 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 {{"); + + // extends + if (template.ParentId == null) + rt.AppendLine($"public class {className} : DistributedResource {{"); + else + rt.AppendLine($"public class {className} : {templates.First(x => x.ClassId == template.ParentId && x.Type == TemplateType.Resource).ClassName} {{"); + 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) { + if (f.Inherited) + continue; + 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))); @@ -201,6 +243,9 @@ public static class TemplateGenerator foreach (var p in template.Properties) { + if (p.Inherited) + continue; + var ptTypeName = GetTypeName(p.ValueType, templates); rt.AppendLine($"public {ptTypeName} {p.Name} {{"); rt.AppendLine($"get => ({ptTypeName})properties[{p.Index}];"); @@ -208,8 +253,19 @@ public static class TemplateGenerator rt.AppendLine("}"); } + foreach (var c in template.Constants) + { + if (c.Inherited) + continue; + + var ctTypeName = GetTypeName(c.ValueType, templates); + rt.AppendLine($"public const {ctTypeName} {c.Name} = {c.Value};"); + } + + if (template.Events.Length > 0) { + rt.AppendLine("protected override void _EmitEventByIndex(byte index, object args) {"); rt.AppendLine("switch (index) {"); diff --git a/Esiur/Resource/CustomEventOccurredEvent.cs b/Esiur/Resource/CustomEventOccurredEvent.cs new file mode 100644 index 0000000..48882eb --- /dev/null +++ b/Esiur/Resource/CustomEventOccurredEvent.cs @@ -0,0 +1,7 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Resource; + +public delegate void CustomEventOccurredEvent(CustomEventOccurredInfo info); diff --git a/Esiur/Resource/CustomEventOccurredInfo.cs b/Esiur/Resource/CustomEventOccurredInfo.cs new file mode 100644 index 0000000..3857bf9 --- /dev/null +++ b/Esiur/Resource/CustomEventOccurredInfo.cs @@ -0,0 +1,27 @@ +using Esiur.Resource.Template; +using Esiur.Security.Authority; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Resource; + +public class CustomEventOccurredInfo +{ + public readonly EventTemplate EventTemplate; + public readonly IResource Resource; + public readonly object Value; + public readonly object Issuer; + public readonly Func Receivers; + + public string Name => EventTemplate.Name; + + public CustomEventOccurredInfo(IResource resource, EventTemplate eventTemplate, Func receivers, object issuer, object value) + { + Resource = resource; + EventTemplate = eventTemplate; + Receivers = receivers; + Issuer = issuer; + Value = value; + } +} diff --git a/Esiur/Resource/EventOccurredEvent.cs b/Esiur/Resource/EventOccurredEvent.cs new file mode 100644 index 0000000..da3a998 --- /dev/null +++ b/Esiur/Resource/EventOccurredEvent.cs @@ -0,0 +1,8 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Resource +{ + public delegate void EventOccurredEvent(EventOccurredInfo info); +} diff --git a/Esiur/Resource/EventOccurredInfo.cs b/Esiur/Resource/EventOccurredInfo.cs new file mode 100644 index 0000000..4ad931e --- /dev/null +++ b/Esiur/Resource/EventOccurredInfo.cs @@ -0,0 +1,26 @@ +using Esiur.Resource.Template; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Resource +{ + + public class EventOccurredInfo + { + + public readonly EventTemplate EventTemplate; + + public string Name => EventTemplate.Name; + + public readonly IResource Resource; + public readonly object Value; + + public EventOccurredInfo(IResource resource, EventTemplate eventTemplate, object value) + { + Resource = resource; + Value = value; + EventTemplate = eventTemplate; + } + } +} diff --git a/Esiur/Resource/IResource.cs b/Esiur/Resource/IResource.cs index 348ff42..0e9bd75 100644 --- a/Esiur/Resource/IResource.cs +++ b/Esiur/Resource/IResource.cs @@ -40,7 +40,6 @@ public delegate bool QueryFilter(T value); public interface IResource : IDestructible///, INotifyPropertyChanged { - AsyncReply Trigger(ResourceTrigger trigger); [NotMapped] @@ -50,5 +49,5 @@ public interface IResource : IDestructible///, INotifyPropertyChanged set; } - + } diff --git a/Esiur/Resource/IStore.cs b/Esiur/Resource/IStore.cs index c956b96..b974c17 100644 --- a/Esiur/Resource/IStore.cs +++ b/Esiur/Resource/IStore.cs @@ -40,8 +40,8 @@ public interface IStore : IResource //AsyncReply Retrieve(uint iid); AsyncReply Put(IResource resource); string Link(IResource resource); - bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime); - bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime); + bool Record(IResource resource, string propertyName, object value, ulong? age, DateTime? dateTime); + bool Modify(IResource resource, string propertyName, object value, ulong? age, DateTime? dateTime); bool Remove(IResource resource); //bool RemoveAttributes(IResource resource, string[] attributes = null); diff --git a/Esiur/Resource/ImportAttribute.cs b/Esiur/Resource/ImportAttribute.cs index e40a600..2ca2bc8 100644 --- a/Esiur/Resource/ImportAttribute.cs +++ b/Esiur/Resource/ImportAttribute.cs @@ -7,7 +7,7 @@ namespace Esiur.Resource; [AttributeUsage(AttributeTargets.Class)] public class ImportAttribute : Attribute { - public ImportAttribute(string url) + public ImportAttribute(params string[] urls) { } diff --git a/Esiur/Resource/Instance.cs b/Esiur/Resource/Instance.cs index 3e1c8c4..7c240c1 100644 --- a/Esiur/Resource/Instance.cs +++ b/Esiur/Resource/Instance.cs @@ -32,24 +32,20 @@ public class Instance AutoList managers; - public delegate void ResourceModifiedEvent(IResource resource, string propertyName, object newValue); - public delegate void ResourceEventOccurredEvent(IResource resource, string eventName, object args); + public event PropertyModifiedEvent PropertyModified; - public delegate void CustomResourceEventOccurredEvent(IResource resource, object issuer, Func receivers, string eventName, object args); - - public delegate void ResourceDestroyedEvent(IResource resource); - - public event ResourceModifiedEvent ResourceModified; - public event ResourceEventOccurredEvent ResourceEventOccurred; - public event CustomResourceEventOccurredEvent CustomResourceEventOccurred; - public event ResourceDestroyedEvent ResourceDestroyed; + + + public event EventOccurredEvent EventOccurred; + public event CustomEventOccurredEvent CustomEventOccurred; + public event ResourceDestroyedEvent Destroyed; bool loading = false; //KeyList attributes; - List ages = new List(); - List modificationDates = new List(); + List ages = new(); + List modificationDates = new (); private ulong instanceAge; private DateTime instanceModificationDate; @@ -100,10 +96,10 @@ public class Instance */ } - public Structure GetAttributes(string[] attributes = null) + public Map GetAttributes(string[] attributes = null) { // @TODO - Structure rt = new Structure(); + var rt = new Map(); if (attributes != null) { @@ -172,7 +168,7 @@ public class Instance */ } - public bool SetAttributes(Structure attributes, bool clearAttributes = false) + public bool SetAttributes(Map attributes, bool clearAttributes = false) { // @ TODO @@ -274,7 +270,7 @@ public class Instance /// /// Zero-based property index. /// Age. - public ulong GetAge(byte index) + public ulong? GetAge(byte index) { if (index < ages.Count) return ages[index]; @@ -287,13 +283,13 @@ public class Instance /// /// Zero-based property index. /// Age. - public void SetAge(byte index, ulong value) + public void SetAge(byte index, ulong? value) { if (index < ages.Count) { ages[index] = value; if (value > instanceAge) - instanceAge = value; + instanceAge = (ulong)value; } } @@ -302,13 +298,13 @@ public class Instance /// /// Zero-based property index. /// Modification date. - public void SetModificationDate(byte index, DateTime value) + public void SetModificationDate(byte index, DateTime? value) { if (index < modificationDates.Count) { modificationDates[index] = value; if (value > instanceModificationDate) - instanceModificationDate = value; + instanceModificationDate = (DateTime) value; } } @@ -317,7 +313,7 @@ public class Instance /// /// Zero-based property index /// Modification date. - public DateTime GetModificationDate(byte index) + public DateTime? GetModificationDate(byte index) { if (index < modificationDates.Count) return modificationDates[index]; @@ -333,7 +329,7 @@ public class Instance /// Property age /// Property value /// - public bool LoadProperty(string name, ulong age, DateTime modificationDate, object value) + public bool LoadProperty(string name, ulong? age, DateTime? modificationDate, object value) { IResource res; @@ -354,7 +350,8 @@ public class Instance #endif */ - if (pt.PropertyInfo.PropertyType == typeof(DistributedPropertyContext)) + if (pt.PropertyInfo.PropertyType.IsGenericType + && pt.PropertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(DistributedPropertyContext<>)) return false; @@ -394,7 +391,7 @@ public class Instance /// /// Last modification date. /// - public DateTime ModificationDate + public DateTime? ModificationDate { get { @@ -559,14 +556,15 @@ public class Instance if (pt.Recordable) { store.Record(res, pt.Name, value, ages[pt.Index], now); - } else //if (pt.Storage == StorageMode.Recordable) { store.Modify(res, pt.Name, value, ages[pt.Index], now); } - ResourceModified?.Invoke(res, pt.Name, value); + //ResourceModified?.Invoke(res, pt.Name, value); + + PropertyModified?.Invoke(new PropertyModificationInfo(res, pt, value, instanceAge)); } } @@ -591,21 +589,21 @@ public class Instance // internal void EmitResourceEvent(string name, string[] users, DistributedConnection[] connections, object[] args) - internal void EmitCustomResourceEvent(object issuer, Func receivers, string name, object args) + internal void EmitCustomResourceEvent(object issuer, Func receivers, EventTemplate eventTemplate, object value) { IResource res; if (this.resource.TryGetTarget(out res)) { - CustomResourceEventOccurred?.Invoke(res, issuer, receivers, name, args); + CustomEventOccurred?.Invoke(new CustomEventOccurredInfo(res, eventTemplate, receivers, issuer, value)); } } - internal void EmitResourceEvent(string name, object args) + internal void EmitResourceEvent(EventTemplate eventTemplate, object value) { IResource res; if (this.resource.TryGetTarget(out res)) { - ResourceEventOccurred?.Invoke(res, name, args); + EventOccurred?.Invoke(new EventOccurredInfo(res, eventTemplate, value)); } } @@ -912,7 +910,7 @@ public class Instance // if (ca.Length == 0) // continue; - ResourceEventHandler proxyDelegate = (args) => EmitResourceEvent(evt.Name, args); + ResourceEventHandler proxyDelegate = (args) => EmitResourceEvent(evt, args); evt.EventInfo.AddEventHandler(resource, proxyDelegate); } @@ -922,7 +920,7 @@ public class Instance //if (ca.Length == 0) // continue; - CustomResourceEventHandler proxyDelegate = (issuer, receivers, args) => EmitCustomResourceEvent(issuer, receivers, evt.Name, args); + CustomResourceEventHandler proxyDelegate = (issuer, receivers, args) => EmitCustomResourceEvent(issuer, receivers, evt, args); evt.EventInfo.AddEventHandler(resource, proxyDelegate); } @@ -991,6 +989,6 @@ public class Instance private void Resource_OnDestroy(object sender) { - ResourceDestroyed?.Invoke((IResource)sender); + Destroyed?.Invoke((IResource)sender); } } diff --git a/Esiur/Resource/PropertyModificationInfo.cs b/Esiur/Resource/PropertyModificationInfo.cs new file mode 100644 index 0000000..6c31b71 --- /dev/null +++ b/Esiur/Resource/PropertyModificationInfo.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Esiur.Resource; +using Esiur.Resource.Template; + +namespace Esiur.Resource; + +public struct PropertyModificationInfo +{ + public readonly IResource Resource; + public readonly PropertyTemplate PropertyTemplate; + public string Name => PropertyTemplate.Name; + public readonly ulong Age; + public object Value; + + public PropertyModificationInfo(IResource resource, PropertyTemplate propertyTemplate, object value, ulong age) + { + Resource = resource; + PropertyTemplate = propertyTemplate; + Age = age; + Value = value; + } + +} + diff --git a/Esiur/Resource/PropertyModifiedEvent.cs b/Esiur/Resource/PropertyModifiedEvent.cs new file mode 100644 index 0000000..41fb4f0 --- /dev/null +++ b/Esiur/Resource/PropertyModifiedEvent.cs @@ -0,0 +1,7 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Resource; + +public delegate void PropertyModifiedEvent(PropertyModificationInfo data); \ No newline at end of file diff --git a/Esiur/Resource/PublicAttribute.cs b/Esiur/Resource/PublicAttribute.cs index e24d47c..fe6ead6 100644 --- a/Esiur/Resource/PublicAttribute.cs +++ b/Esiur/Resource/PublicAttribute.cs @@ -4,7 +4,7 @@ using System.Text; namespace Esiur.Resource; -[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Event | AttributeTargets.Class)] +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Event | AttributeTargets.Class | AttributeTargets.Enum)] public class PublicAttribute : Attribute { diff --git a/Esiur/Resource/Resource.cs b/Esiur/Resource/Resource.cs index 03709e2..a71a2bd 100644 --- a/Esiur/Resource/Resource.cs +++ b/Esiur/Resource/Resource.cs @@ -32,7 +32,7 @@ public class Resource : IResource public Instance Instance { get; set; } public event DestroyedEvent OnDestroy; - + public virtual void Destroy() { OnDestroy?.Invoke(this); @@ -52,6 +52,7 @@ public class Resource : IResource return true; } + ~Resource() { Destroy(); diff --git a/Esiur/Resource/ResourceDestroyedEvent.cs b/Esiur/Resource/ResourceDestroyedEvent.cs new file mode 100644 index 0000000..b42fc36 --- /dev/null +++ b/Esiur/Resource/ResourceDestroyedEvent.cs @@ -0,0 +1,8 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Resource +{ + public delegate void ResourceDestroyedEvent(IResource resource); +} diff --git a/Esiur/Resource/ResourceProperty.cs b/Esiur/Resource/ResourceProperty.cs index 10049ba..4aec31f 100644 --- a/Esiur/Resource/ResourceProperty.cs +++ b/Esiur/Resource/ResourceProperty.cs @@ -34,42 +34,21 @@ namespace Esiur.Resource; [AttributeUsage(AttributeTargets.Property)] public class ResourceProperty : System.Attribute { - bool serialize; - string readExpansion; - string writeExpansion; - // bool recordable; - //bool storable; - //public bool Recordable => recordable; - //public bool Storable => storable; - StorageMode storage; + public readonly bool Nullable; + public readonly StorageMode Storage; + public readonly bool Serialize; + public readonly string ReadExpansion; + public readonly string WriteExpansion; - public StorageMode Storage => storage; - public bool Serialize => serialize; - - public string ReadExpansion + public ResourceProperty(StorageMode storage = StorageMode.NonVolatile, bool serialize = true, + string readExpansion = null, string writeExpansion = null) { - get - { - return readExpansion; - } - } - - public string WriteExpansion - { - get - { - return writeExpansion; - } - } - - public ResourceProperty(StorageMode storage = StorageMode.NonVolatile, bool serialize = true, string readExpansion = null, string writeExpansion = null) - { - this.readExpansion = readExpansion; - this.writeExpansion = writeExpansion; - this.storage = storage; - this.serialize = serialize; + this.ReadExpansion = readExpansion; + this.WriteExpansion = writeExpansion; + this.Storage = storage; + this.Serialize = serialize; } } diff --git a/Esiur/Resource/Storable.cs b/Esiur/Resource/Storable.cs index 44f8c76..7e7216d 100644 --- a/Esiur/Resource/Storable.cs +++ b/Esiur/Resource/Storable.cs @@ -40,11 +40,11 @@ public class Storable : global::System.Attribute SerializerFunction serializer; DeserializerFunction deserializer; - DataType type; + RepresentationType dataType; public Storable() { - type = DataType.Void; + //dataType = = DataType.Void; } public DeserializerFunction Deserializer @@ -57,14 +57,14 @@ public class Storable : global::System.Attribute get { return serializer; } } - public Storable(DataType type) + public Storable(RepresentationType type) { - this.type = type; + this.dataType = type; } - public Storable(DataType type, SerializerFunction serializer, DeserializerFunction deserializer) + public Storable(RepresentationType type, SerializerFunction serializer, DeserializerFunction deserializer) { - this.type = type; + this.dataType = type; this.serializer = serializer; this.deserializer = deserializer; } diff --git a/Esiur/Resource/StoreGeneric.cs b/Esiur/Resource/StoreGeneric.cs index 1568b27..cc804b2 100644 --- a/Esiur/Resource/StoreGeneric.cs +++ b/Esiur/Resource/StoreGeneric.cs @@ -11,6 +11,7 @@ public abstract class Store : IStore where T : IResource public Instance Instance { get; set; } public event DestroyedEvent OnDestroy; + public abstract AsyncReply AddChild(IResource parent, IResource child); @@ -30,13 +31,13 @@ public abstract class Store : IStore where T : IResource public abstract string Link(IResource resource); - public abstract bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime); + public abstract bool Modify(IResource resource, string propertyName, object value, ulong? age, DateTime? dateTime); public abstract AsyncBag Parents(IResource resource, string name) where T1 : IResource; public abstract AsyncReply Put(IResource resource); - public abstract bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime); + public abstract bool Record(IResource resource, string propertyName, object value, ulong? age, DateTime? dateTime); public abstract bool Remove(IResource resource); diff --git a/Esiur/Resource/Template/ArgumentTemplate.cs b/Esiur/Resource/Template/ArgumentTemplate.cs index 538491f..b3e4f2c 100644 --- a/Esiur/Resource/Template/ArgumentTemplate.cs +++ b/Esiur/Resource/Template/ArgumentTemplate.cs @@ -9,18 +9,24 @@ public class ArgumentTemplate { public string Name { get; set; } - public TemplateDataType Type { get; set; } + public bool Optional { get; set; } + + public RepresentationType Type { get; set; } public ParameterInfo ParameterInfo { get; set; } - public static (uint, ArgumentTemplate) Parse(byte[] data, uint offset) + public int Index { get; set; } + + public static (uint, ArgumentTemplate) Parse(byte[] data, uint offset, int index) { + var optional = (data[offset++] & 0x1) == 0x1; + var cs = (uint)data[offset++]; var name = data.GetString(offset, cs); offset += cs; - var (size, type) = TemplateDataType.Parse(data, offset); + var (size, type) = RepresentationType.Parse(data, offset); - return (cs + 1 + size, new ArgumentTemplate(name, type)); + return (cs + 2 + size, new ArgumentTemplate(name, index, type, optional)); } public ArgumentTemplate() @@ -28,10 +34,12 @@ public class ArgumentTemplate } - public ArgumentTemplate(string name, TemplateDataType type) + public ArgumentTemplate(string name, int index, RepresentationType type, bool optional) { Name = name; + Index = index; Type = type; + Optional = optional; } public byte[] Compose() @@ -39,6 +47,7 @@ public class ArgumentTemplate var name = DC.ToBytes(Name); return new BinaryList() + .AddUInt8(Optional ? (byte)1 : (byte)0) .AddUInt8((byte)name.Length) .AddUInt8Array(name) .AddUInt8Array(Type.Compose()) diff --git a/Esiur/Resource/Template/AttributeTemplate.cs b/Esiur/Resource/Template/AttributeTemplate.cs index 2d2f767..d4d8ac5 100644 --- a/Esiur/Resource/Template/AttributeTemplate.cs +++ b/Esiur/Resource/Template/AttributeTemplate.cs @@ -16,8 +16,8 @@ public class AttributeTemplate : MemberTemplate } - public AttributeTemplate(TypeTemplate template, byte index, string name) - : base(template, MemberType.Attribute, index, name) + public AttributeTemplate(TypeTemplate template, byte index, string name, bool inherited) + : base(template, index, name, inherited) { } diff --git a/Esiur/Resource/Template/ConstantTemplate.cs b/Esiur/Resource/Template/ConstantTemplate.cs new file mode 100644 index 0000000..e8841df --- /dev/null +++ b/Esiur/Resource/Template/ConstantTemplate.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Esiur.Data; + +namespace Esiur.Resource.Template; + +public class ConstantTemplate : MemberTemplate +{ + public readonly object Value; + //public readonly byte[] ValueData; + public readonly string Expansion; + public readonly RepresentationType ValueType; + + public ConstantTemplate(TypeTemplate template, byte index, string name, bool inherited, RepresentationType valueType, object value, string expansion) + : base(template, index, name, inherited) + { + Expansion = expansion; + ValueType = valueType; + Value = value; + //try + //{ + // Codec.Compose(value, null); + // Value = value; + //} + //catch + //{ + // throw new Exception($"Constant `{template.ClassName}.{name}` can't be serialized."); + //} + } + + public override byte[] Compose() + { + var name = base.Compose(); + + var hdr = Inherited ? (byte)0x80 : (byte)0; + + + if (Expansion != null) + { + var exp = DC.ToBytes(Expansion); + hdr |= 0x70; + return new BinaryList() + .AddUInt8(hdr) + .AddUInt8((byte)name.Length) + .AddUInt8Array(name) + .AddUInt8Array(ValueType.Compose()) + .AddUInt8Array(Codec.Compose(Value, null)) + .AddInt32(exp.Length) + .AddUInt8Array(exp) + .ToArray(); + } + else + { + hdr |= 0x60; + + return new BinaryList() + .AddUInt8(hdr) + .AddUInt8((byte)name.Length) + .AddUInt8Array(name) + .AddUInt8Array(ValueType.Compose()) + .AddUInt8Array(Codec.Compose(Value, null)) + .ToArray(); + } + } +} + diff --git a/Esiur/Resource/Template/CustomEventOccurredEvent.cs b/Esiur/Resource/Template/CustomEventOccurredEvent.cs new file mode 100644 index 0000000..b0da4f7 --- /dev/null +++ b/Esiur/Resource/Template/CustomEventOccurredEvent.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Resource.Template +{ + internal class CustomEventOccurredEvent + { + } +} diff --git a/Esiur/Resource/Template/EventTemplate.cs b/Esiur/Resource/Template/EventTemplate.cs index d81ee7f..d3da606 100644 --- a/Esiur/Resource/Template/EventTemplate.cs +++ b/Esiur/Resource/Template/EventTemplate.cs @@ -19,17 +19,23 @@ public class EventTemplate : MemberTemplate public EventInfo EventInfo { get; set; } - public TemplateDataType ArgumentType { get; set; } + public RepresentationType ArgumentType { get; set; } public override byte[] Compose() { var name = base.Compose(); + var hdr = Inherited ? (byte)0x80 : (byte)0; + + if (Listenable) + hdr |= 0x8; + if (Expansion != null) { var exp = DC.ToBytes(Expansion); + hdr |= 0x50; return new BinaryList() - .AddUInt8(Listenable ? (byte)0x58 : (byte)0x50) + .AddUInt8(hdr) .AddUInt8((byte)name.Length) .AddUInt8Array(name) .AddUInt8Array(ArgumentType.Compose()) @@ -38,17 +44,17 @@ public class EventTemplate : MemberTemplate .ToArray(); } else + hdr |= 0x40; return new BinaryList() - .AddUInt8(Listenable ? (byte)0x48 : (byte)0x40) + .AddUInt8(hdr) .AddUInt8((byte)name.Length) .AddUInt8Array(name) .AddUInt8Array(ArgumentType.Compose()) .ToArray(); } - - public EventTemplate(TypeTemplate template, byte index, string name, TemplateDataType argumentType, string expansion = null, bool listenable = false) - : base(template, MemberType.Property, index, name) + public EventTemplate(TypeTemplate template, byte index, string name,bool inherited, RepresentationType argumentType, string expansion = null, bool listenable = false) + : base(template, index, name, inherited) { this.Expansion = expansion; this.Listenable = listenable; diff --git a/Esiur/Resource/Template/FunctionTemplate.cs b/Esiur/Resource/Template/FunctionTemplate.cs index 668c61a..53ccf15 100644 --- a/Esiur/Resource/Template/FunctionTemplate.cs +++ b/Esiur/Resource/Template/FunctionTemplate.cs @@ -22,7 +22,7 @@ public class FunctionTemplate : MemberTemplate // set; //} - public TemplateDataType ReturnType { get; set; } + public RepresentationType ReturnType { get; set; } public ArgumentTemplate[] Arguments { get; set; } @@ -54,17 +54,16 @@ public class FunctionTemplate : MemberTemplate var exp = DC.ToBytes(Expansion); bl.AddInt32(exp.Length) .AddUInt8Array(exp); - bl.InsertUInt8(0, 0x10); + bl.InsertUInt8(0, Inherited ? (byte)0x90 : (byte)0x10); } else - bl.InsertUInt8(0, 0x0); + bl.InsertUInt8(0, Inherited ? (byte)0x80 : (byte)0x0); return bl.ToArray(); } - - public FunctionTemplate(TypeTemplate template, byte index, string name, ArgumentTemplate[] arguments, TemplateDataType returnType, string expansion = null) - : base(template, MemberType.Property, index, name) + public FunctionTemplate(TypeTemplate template, byte index, string name, bool inherited, ArgumentTemplate[] arguments, RepresentationType returnType, string expansion = null) + : base(template, index, name, inherited) { //this.IsVoid = isVoid; this.Arguments = arguments; diff --git a/Esiur/Resource/Template/MemberTemplate.cs b/Esiur/Resource/Template/MemberTemplate.cs index 78a504c..9c43b31 100644 --- a/Esiur/Resource/Template/MemberTemplate.cs +++ b/Esiur/Resource/Template/MemberTemplate.cs @@ -8,34 +8,21 @@ using System.Threading.Tasks; namespace Esiur.Resource.Template; public class MemberTemplate { - public enum MemberType + + public readonly byte Index; + public readonly string Name; + public readonly bool Inherited; + public readonly TypeTemplate Template; + + public MemberTemplate(TypeTemplate template, byte index, string name, bool inherited) { - Function = 0, - Property = 1, - Event = 2, - Attribute = 3 + Template = template; + Index = index; + Name = name; + Inherited = inherited; } - public byte Index => index; - public string Name => name; - public MemberType Type => type; - - TypeTemplate template; - string name; - MemberType type; - byte index; - - public TypeTemplate Template => template; - - public MemberTemplate(TypeTemplate template, MemberType type, byte index, string name) - { - this.template = template; - this.type = type; - this.index = index; - this.name = name; - } - - public string Fullname => template.ClassName + "." + Name; + public string Fullname => Template.ClassName + "." + Name; public virtual byte[] Compose() { diff --git a/Esiur/Resource/Template/PropertyTemplate.cs b/Esiur/Resource/Template/PropertyTemplate.cs index 38e33ad..c4dcde2 100644 --- a/Esiur/Resource/Template/PropertyTemplate.cs +++ b/Esiur/Resource/Template/PropertyTemplate.cs @@ -23,7 +23,7 @@ public class PropertyTemplate : MemberTemplate set; } - public TemplateDataType ValueType { get; set; } + public RepresentationType ValueType { get; set; } /* @@ -40,6 +40,7 @@ public class PropertyTemplate : MemberTemplate set; } + public bool IsNullable { get; set; } public bool Recordable { @@ -79,6 +80,9 @@ public class PropertyTemplate : MemberTemplate var name = base.Compose(); var pv = ((byte)(Permission) << 1) | (Recordable ? 1 : 0); + if (Inherited) + pv |= 0x80; + if (WriteExpansion != null && ReadExpansion != null) { var rexp = DC.ToBytes(ReadExpansion); @@ -129,12 +133,14 @@ public class PropertyTemplate : MemberTemplate } } - public PropertyTemplate(TypeTemplate template, byte index, string name, TemplateDataType valueType, string read = null, string write = null, bool recordable = false) - : base(template, MemberType.Property, index, name) + public PropertyTemplate(TypeTemplate template, byte index, string name, bool inherited, + RepresentationType valueType, string read = null, string write = null, bool recordable = false) + : base(template, index, name, inherited) { this.Recordable = recordable; //this.Storage = storage; - this.ReadExpansion = read; + if (read != null) + this.ReadExpansion = read; this.WriteExpansion = write; this.ValueType = valueType; } diff --git a/Esiur/Resource/Template/TemplateDataType.cs b/Esiur/Resource/Template/TemplateDataType.cs index 136f31e..0cdb457 100644 --- a/Esiur/Resource/Template/TemplateDataType.cs +++ b/Esiur/Resource/Template/TemplateDataType.cs @@ -1,107 +1,131 @@ -using Esiur.Data; -using System; -using System.Collections.Generic; -using System.Dynamic; -using System.Text; +//using Esiur.Data; +//using System; +//using System.Collections; +//using System.Collections.Generic; +//using System.Dynamic; +//using System.Linq; +//using System.Text; -namespace Esiur.Resource.Template; -public struct TemplateDataType -{ - public DataType Type { get; set; } - //public string TypeName { get; set; } - public TypeTemplate TypeTemplate => TypeGuid == null ? null : Warehouse.GetTemplateByClassId((Guid)TypeGuid); +//namespace Esiur.Resource.Template; +//public struct TemplateDataType +//{ +// public DataType Type { get; set; } +// //public string TypeName { get; set; } +// public TypeTemplate TypeTemplate => TypeGuid == null ? null : Warehouse.GetTemplateByClassId((Guid)TypeGuid); - public Guid? TypeGuid { get; set; } - //public TemplateDataType(DataType type, string typeName) - //{ - // Type = type; - // TypeName = typeName; - //} +// public Guid? TypeGuid { get; set; } + +// public bool IsNullable { get; set; } +// //public TemplateDataType(DataType type, string typeName) +// //{ +// // Type = type; +// // TypeName = typeName; +// //} - public static TemplateDataType FromType(Type type) - { - - var t = type switch - { - { IsArray: true } => type.GetElementType(), - { IsEnum: true } => type.GetEnumUnderlyingType(), - (_) => type - }; - - DataType dt = t switch - { - _ when t == typeof(bool) => DataType.Bool, - _ when t == typeof(char) => DataType.Char, - _ when t == typeof(byte) => DataType.UInt8, - _ when t == typeof(sbyte) => DataType.Int8, - _ when t == typeof(short) => DataType.Int16, - _ when t == typeof(ushort) => DataType.UInt16, - _ when t == typeof(int) => DataType.Int32, - _ when t == typeof(uint) => DataType.UInt32, - _ when t == typeof(long) => DataType.Int64, - _ when t == typeof(ulong) => DataType.UInt64, - _ when t == typeof(float) => DataType.Float32, - _ when t == typeof(double) => DataType.Float64, - _ when t == typeof(decimal) => DataType.Decimal, - _ when t == typeof(string) => DataType.String, - _ when t == typeof(DateTime) => DataType.DateTime, - _ when t == typeof(IResource) => DataType.Void, // Dynamic resource (unspecified type) - _ when t == typeof(IRecord) => DataType.Void, // Dynamic record (unspecified type) - _ when typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject) => DataType.Structure, - _ when Codec.ImplementsInterface(t, typeof(IResource)) => DataType.Resource, - _ when Codec.ImplementsInterface(t, typeof(IRecord)) => DataType.Record, - _ => DataType.Void - }; +// public static TemplateDataType FromType(Type type) +// { - Guid? typeGuid = null; +// bool isList = typeof(ICollection).IsAssignableFrom(type); - if (dt == DataType.Resource || dt == DataType.Record) - typeGuid = TypeTemplate.GetTypeGuid(t); +// var t = type switch +// { - if (type.IsArray) - dt = (DataType)((byte)dt | 0x80); +// { IsArray: true } => type.GetElementType(), +// { IsEnum: true } => type.GetEnumUnderlyingType(), +// _ when isList => Codec.GetGenericListType(type), +// (_) => type +// }; - return new TemplateDataType() - { - Type = dt, - TypeGuid = typeGuid - }; - } - - public byte[] Compose() - { - if (Type == DataType.Resource || - Type == DataType.ResourceArray || - Type == DataType.Record || - Type == DataType.RecordArray) - { - var guid = DC.ToBytes((Guid)TypeGuid); - return new BinaryList() - .AddUInt8((byte)Type) - .AddUInt8Array(guid).ToArray(); - } - else - return new byte[] { (byte)Type }; - } - - public override string ToString() => Type.ToString() + TypeTemplate != null ? "<" + TypeTemplate.ClassName + ">" : ""; +// DataType dt = t switch +// { +// _ when t == typeof(bool) => DataType.Bool, +// _ when t == typeof(char) => DataType.Char, +// _ when t == typeof(byte) => DataType.UInt8, +// _ when t == typeof(sbyte) => DataType.Int8, +// _ when t == typeof(short) => DataType.Int16, +// _ when t == typeof(ushort) => DataType.UInt16, +// _ when t == typeof(int) => DataType.Int32, +// _ when t == typeof(uint) => DataType.UInt32, +// _ when t == typeof(long) => DataType.Int64, +// _ when t == typeof(ulong) => DataType.UInt64, +// _ when t == typeof(float) => DataType.Float32, +// _ when t == typeof(double) => DataType.Float64, +// _ when t == typeof(decimal) => DataType.Decimal, +// _ when t == typeof(string) => DataType.String, +// _ when t == typeof(DateTime) => DataType.DateTime, +// _ when t == typeof(IResource) => DataType.Void, // Dynamic resource (unspecified type) +// _ when t == typeof(IRecord) => DataType.Void, // Dynamic record (unspecified type) +// _ when typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject) => DataType.Structure, +// _ when Codec.ImplementsInterface(t, typeof(IResource)) => DataType.Resource, +// _ when Codec.ImplementsInterface(t, typeof(IRecord)) => DataType.Record, +// _ => DataType.Void +// }; - public static (uint, TemplateDataType) Parse(byte[] data, uint offset) - { - var type = (DataType)data[offset++]; - if (type == DataType.Resource || - type == DataType.ResourceArray || - type == DataType.Record || - type == DataType.RecordArray) - { - var guid = data.GetGuid(offset); - return (17, new TemplateDataType() { Type = type, TypeGuid = guid }); - } - else - return (1, new TemplateDataType() { Type = type }); - } -} +// Guid? typeGuid = null; + +// if (dt == DataType.Resource || dt == DataType.Record) +// typeGuid = TypeTemplate.GetTypeGuid(t); + +// if (type.IsArray || isList) +// dt = (DataType)((byte)dt | 0x80); + + +// return new TemplateDataType() +// { +// Type = dt, +// TypeGuid = typeGuid, +// IsNullable = Nullable.GetUnderlyingType(type) != null +// }; +// } + +// public byte[] Compose() +// { +// if (Type == DataType.Resource || +// Type == DataType.ResourceArray || +// Type == DataType.Record || +// Type == DataType.RecordArray) +// { +// var guid = DC.ToBytes((Guid)TypeGuid); +// if (IsNullable) +// { +// return new BinaryList() +// .AddUInt8((byte)((byte)Type | 0x40)) +// .AddUInt8Array(guid).ToArray(); +// } else +// { +// return new BinaryList() +// .AddUInt8((byte)Type) +// .AddUInt8Array(guid).ToArray(); +// } +// } +// else if (IsNullable) +// return new byte[] { (byte)((byte)Type | 0x40) }; +// else +// return new byte[] { (byte)Type }; +// } + +// public override string ToString() => Type.ToString() + (IsNullable ? "?":"" ) +// + TypeTemplate != null ? "<" + TypeTemplate.ClassName + ">" : ""; + + +// public static (uint, TemplateDataType) Parse(byte[] data, uint offset) +// { +// bool isNullable = (data[offset] & 0x40) > 0; +// var type = (DataType)(data[offset++] & 0xBF); + +// if (type == DataType.Resource || +// type == DataType.ResourceArray || +// type == DataType.Record || +// type == DataType.RecordArray) +// { +// var guid = data.GetGuid(offset); +// return (17, new TemplateDataType() { Type = type, TypeGuid = guid , IsNullable = isNullable}); +// } +// else +// return (1, new TemplateDataType() { Type = type, IsNullable = isNullable }); +// } +//} diff --git a/Esiur/Resource/Template/TemplateType.cs b/Esiur/Resource/Template/TemplateType.cs index 4542866..a1e19c8 100644 --- a/Esiur/Resource/Template/TemplateType.cs +++ b/Esiur/Resource/Template/TemplateType.cs @@ -9,4 +9,5 @@ public enum TemplateType : byte Resource, Record, Wrapper, + Enum } diff --git a/Esiur/Resource/Template/TypeTemplate.cs b/Esiur/Resource/Template/TypeTemplate.cs index 228dea0..d4bfaa2 100644 --- a/Esiur/Resource/Template/TypeTemplate.cs +++ b/Esiur/Resource/Template/TypeTemplate.cs @@ -22,20 +22,26 @@ public class TypeTemplate { protected Guid classId; - protected string className; - protected List members = new List(); - protected List functions = new List(); - protected List events = new List(); - protected List properties = new List(); - protected List attributes = new List(); - protected int version; - protected TemplateType templateType; + protected Guid? parentId; + + string className; + List members = new List(); + List functions = new List(); + List events = new List(); + List properties = new List(); + List attributes = new List(); + List constants = new(); + int version; + TemplateType templateType; + // protected TemplateType //bool isReady; protected byte[] content; + public Guid? ParentId => parentId; + public byte[] Content { get { return content; } @@ -45,9 +51,7 @@ public class TypeTemplate public Type DefinedType { get; set; } - - - + public Type ParentDefinedType { get; set; } //public MemberTemplate GetMemberTemplate(MemberInfo member) //{ @@ -145,7 +149,7 @@ public class TypeTemplate get { return properties.ToArray(); } } - + public ConstantTemplate[] Constants => constants.ToArray(); public TypeTemplate() { @@ -166,7 +170,7 @@ public class TypeTemplate static Type GetElementType(Type type) => type switch { { IsArray: true } => type.GetElementType(), - { IsEnum: true } => type.GetEnumUnderlyingType(), + // { IsEnum: true } => type.GetEnumUnderlyingType(), (_) => type }; @@ -177,8 +181,20 @@ public class TypeTemplate var list = new List(); + // Add self list.Add(template); + // Add parents + var parentType = template.ParentDefinedType; + + // Get parents + while (parentType != null) + { + var parentTemplate = Warehouse.GetTemplateByType(parentType); + list.Add(parentTemplate); + parentType = parentTemplate.ParentDefinedType; + } + Action> getDependenciesFunc = null; getDependenciesFunc = (TypeTemplate tmp, List bag) => @@ -186,8 +202,8 @@ public class TypeTemplate if (template.DefinedType == null) return; - // functions - foreach (var f in tmp.functions) + // functions + foreach (var f in tmp.functions) { var frtt = Warehouse.GetTemplateByType(GetElementType(f.MethodInfo.ReturnType)); if (frtt != null) @@ -214,8 +230,8 @@ public class TypeTemplate } } - // skip DistributedConnection argument - if (args.Length > 0) + // skip DistributedConnection argument + if (args.Length > 0) { var last = args.Last(); if (last.ParameterType != typeof(DistributedConnection)) @@ -234,8 +250,8 @@ public class TypeTemplate } - // properties - foreach (var p in tmp.properties) + // properties + foreach (var p in tmp.properties) { var pt = Warehouse.GetTemplateByType(GetElementType(p.PropertyInfo.PropertyType)); if (pt != null) @@ -248,8 +264,8 @@ public class TypeTemplate } } - // events - foreach (var e in tmp.events) + // events + foreach (var e in tmp.events) { var et = Warehouse.GetTemplateByType(GetElementType(e.EventInfo.EventHandlerType.GenericTypeArguments[0])); @@ -268,6 +284,15 @@ public class TypeTemplate return list.ToArray(); } + public string GetTypeAnnotationName(Type type) + { + var nullType = Nullable.GetUnderlyingType(type); + if (nullType == null) + return type.Name; + else + return type.Name + "?"; + } + public TypeTemplate(Type type, bool addToWarehouse = false) { if (Codec.InheritsClass(type, typeof(DistributedResource))) @@ -276,6 +301,8 @@ public class TypeTemplate templateType = TemplateType.Resource; else if (Codec.ImplementsInterface(type, typeof(IRecord))) templateType = TemplateType.Record; + else if (type.IsEnum) + templateType = TemplateType.Enum; else throw new Exception("Type must implement IResource, IRecord or inherit from DistributedResource."); @@ -291,32 +318,56 @@ public class TypeTemplate className = type.FullName; - //Console.WriteLine($"Creating {className}"); - // set guid classId = GetTypeGuid(className); if (addToWarehouse) Warehouse.PutTemplate(this); + -#if NETSTANDARD - PropertyInfo[] propsInfo = type.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly); - EventInfo[] eventsInfo = type.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly); - MethodInfo[] methodsInfo = type.GetTypeInfo().GetMethods(BindingFlags.Public | BindingFlags.Instance); // | BindingFlags.DeclaredOnly); - -#else - PropertyInfo[] propsInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly); - EventInfo[] eventsInfo = type.GetEvents(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly); - MethodInfo[] methodsInfo = type.GetMethods(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly); -#endif + PropertyInfo[] propsInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly); + EventInfo[] eventsInfo = type.GetEvents(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly); + MethodInfo[] methodsInfo = type.GetMethods(BindingFlags.Public | BindingFlags.Instance); // | BindingFlags.DeclaredOnly); + FieldInfo[] constantsInfo = type.GetFields(BindingFlags.Public | BindingFlags.Static); + + + bool classIsPublic = type.IsEnum || (type.GetCustomAttribute() != null); - bool classIsPublic = type.GetCustomAttribute() != null; byte i = 0; if (classIsPublic) { + + foreach (var ci in constantsInfo) + { + var privateAttr = ci.GetCustomAttribute(true); + var annotationAttr = ci.GetCustomAttribute(true); + + if (privateAttr != null) + continue; + + + var valueType = RepresentationType.FromType(ci.FieldType); + + if (valueType == null) + throw new Exception($"Unsupported type `{ci.FieldType}` in constant `{type.Name}.{ci.Name}`"); + + var value = ci.GetValue(null); + + if (templateType == TemplateType.Enum) + value = Convert.ChangeType(value, ci.FieldType.GetEnumUnderlyingType()); + + var ct = new ConstantTemplate(this, i++, ci.Name, ci.DeclaringType != type, valueType, value, annotationAttr?.Annotation); + + + constants.Add(ct); + + } + + i = 0; + foreach (var pi in propsInfo) { var privateAttr = pi.GetCustomAttribute(true); @@ -326,7 +377,12 @@ public class TypeTemplate var annotationAttr = pi.GetCustomAttribute(true); var storageAttr = pi.GetCustomAttribute(true); - var pt = new PropertyTemplate(this, i++, pi.Name, TemplateDataType.FromType(pi.PropertyType)); + var attrType = RepresentationType.FromType(pi.PropertyType); + + if (attrType == null) + throw new Exception($"Unsupported type `{pi.PropertyType}` in property `{type.Name}.{pi.Name}`"); + + var pt = new PropertyTemplate(this, i++, pi.Name, pi.DeclaringType != type, attrType); if (storageAttr != null) pt.Recordable = storageAttr.Mode == StorageMode.Recordable; @@ -334,7 +390,7 @@ public class TypeTemplate if (annotationAttr != null) pt.ReadExpansion = annotationAttr.Annotation; else - pt.ReadExpansion = pi.PropertyType.Name; + pt.ReadExpansion = GetTypeAnnotationName(pi.PropertyType); pt.PropertyInfo = pi; //pt.Serilize = publicAttr.Serialize; @@ -346,7 +402,7 @@ public class TypeTemplate if (attributeAttr != null) { var an = attributeAttr.Name ?? pi.Name; - var at = new AttributeTemplate(this, 0, an); + var at = new AttributeTemplate(this, 0, an, pi.DeclaringType != type); at.PropertyInfo = pi; attributes.Add(at); } @@ -356,69 +412,109 @@ public class TypeTemplate if (templateType == TemplateType.Resource) { i = 0; - foreach (var ei in eventsInfo) { var privateAttr = ei.GetCustomAttribute(true); - if (privateAttr == null) - { - var annotationAttr = ei.GetCustomAttribute(true); - var listenableAttr = ei.GetCustomAttribute(true); + if (privateAttr != null) + continue; - var argType = ei.EventHandlerType.GenericTypeArguments[0]; - var et = new EventTemplate(this, i++, ei.Name, TemplateDataType.FromType(argType)); - et.EventInfo = ei; + var annotationAttr = ei.GetCustomAttribute(true); + var listenableAttr = ei.GetCustomAttribute(true); - if (annotationAttr != null) - et.Expansion = annotationAttr.Annotation; + var argType = ei.EventHandlerType.GenericTypeArguments[0]; + var evtType = RepresentationType.FromType(argType); - if (listenableAttr != null) - et.Listenable = true; + if (evtType == null) + throw new Exception($"Unsupported type `{argType}` in event `{type.Name}.{ei.Name}`"); - events.Add(et); - } + var et = new EventTemplate(this, i++, ei.Name, ei.DeclaringType != type, evtType); + 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(true); - if (privateAttr == null) + if (privateAttr != null) + continue; + + var annotationAttr = mi.GetCustomAttribute(true); + + var returnType = RepresentationType.FromType(mi.ReturnType); + + if (returnType == null) + throw new Exception($"Unsupported type {mi.ReturnType} in method {type.Name}.{mi.Name} return"); + + var args = mi.GetParameters(); + + if (args.Length > 0) { - var annotationAttr = mi.GetCustomAttribute(true); + if (args.Last().ParameterType == typeof(DistributedConnection)) + args = args.Take(args.Count() - 1).ToArray(); + } - var returnType = TemplateDataType.FromType(mi.ReturnType); + var arguments = args.Select(x => + { + var argType = RepresentationType.FromType(x.ParameterType); + if (argType == null) + throw new Exception($"Unsupported type `{x.ParameterType}` in method `{type.Name}.{mi.Name}` parameter `{x.Name}`"); - var args = mi.GetParameters(); - - if (args.Length > 0) - { - if (args.Last().ParameterType == typeof(DistributedConnection)) - args = args.Take(args.Count() - 1).ToArray(); - } - - var arguments = args.Select(x => new ArgumentTemplate() + return new ArgumentTemplate() { Name = x.Name, - Type = TemplateDataType.FromType(x.ParameterType), - ParameterInfo = x - }).ToArray(); + Type = argType, + ParameterInfo = x, + Optional = x.IsOptional + }; + }).ToArray(); - var ft = new FunctionTemplate(this, i++, mi.Name, arguments, returnType);// mi.ReturnType == typeof(void)); + var ft = new FunctionTemplate(this, i++, mi.Name, mi.DeclaringType != type, 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; + 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); - } + ft.MethodInfo = mi; + functions.Add(ft); } + } } else { + foreach (var ci in constantsInfo) + { + var publicAttr = ci.GetCustomAttribute(true); + var annotationAttr = ci.GetCustomAttribute(true); + + if (publicAttr == null) + continue; + + + var valueType = RepresentationType.FromType(ci.FieldType); + + if (valueType == null) + throw new Exception($"Unsupported type `{ci.FieldType}` in constant `{type.Name}.{ci.Name}`"); + + var value = ci.GetValue(null); + + var ct = new ConstantTemplate(this, i++, ci.Name, ci.DeclaringType != type, valueType, value, annotationAttr?.Annotation); + + + constants.Add(ct); + + } + + i = 0; foreach (var pi in propsInfo) { @@ -428,17 +524,22 @@ public class TypeTemplate { var annotationAttr = pi.GetCustomAttribute(true); var storageAttr = pi.GetCustomAttribute(true); - var valueType = TemplateDataType.FromType(pi.PropertyType); + var valueType = RepresentationType.FromType(pi.PropertyType); + + if (valueType == null) + throw new Exception($"Unsupported type `{pi.PropertyType}` in property `{type.Name}.{pi.Name}`"); + + var pn = publicAttr.Name ?? pi.Name; - var pt = new PropertyTemplate(this, i++, pn, valueType);//, rp.ReadExpansion, rp.WriteExpansion, rp.Storage); + var pt = new PropertyTemplate(this, i++, pn, pi.DeclaringType != type, 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.ReadExpansion = GetTypeAnnotationName(pi.PropertyType); pt.PropertyInfo = pi; //pt.Serilize = publicAttr.Serialize; @@ -450,7 +551,7 @@ public class TypeTemplate if (attributeAttr != null) { var pn = attributeAttr.Name ?? pi.Name; - var at = new AttributeTemplate(this, 0, pn); + var at = new AttributeTemplate(this, 0, pn, pi.DeclaringType != type); at.PropertyInfo = pi; attributes.Add(at); } @@ -464,65 +565,85 @@ public class TypeTemplate foreach (var ei in eventsInfo) { var publicAttr = ei.GetCustomAttribute(true); - if (publicAttr != null) - { - var annotationAttr = ei.GetCustomAttribute(true); - var listenableAttr = ei.GetCustomAttribute(true); - var argType = ei.EventHandlerType.GenericTypeArguments[0]; + if (publicAttr == null) + continue; - var en = publicAttr.Name ?? ei.Name; - var et = new EventTemplate(this, i++, en, TemplateDataType.FromType(argType)); - et.EventInfo = ei; + var annotationAttr = ei.GetCustomAttribute(true); + var listenableAttr = ei.GetCustomAttribute(true); - if (annotationAttr != null) - et.Expansion = annotationAttr.Annotation; + var argType = ei.EventHandlerType.GenericTypeArguments[0]; - if (listenableAttr != null) - et.Listenable = true; + var en = publicAttr.Name ?? ei.Name; - events.Add(et); - } + var evtType = RepresentationType.FromType(argType); + + if (evtType == null) + throw new Exception($"Unsupported type `{argType}` in event `{type.Name}.{ei.Name}`"); + + var et = new EventTemplate(this, i++, en, ei.DeclaringType != type, evtType); + 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(true); - if (publicAttr != null) + if (publicAttr == null) + continue; + + + var annotationAttr = mi.GetCustomAttribute(true); + var returnType = RepresentationType.FromType(mi.ReturnType); + + if (returnType == null) + throw new Exception($"Unsupported type `{mi.ReturnType}` in method `{type.Name}.{mi.Name}` return"); + + var args = mi.GetParameters(); + + if (args.Length > 0) { - var annotationAttr = mi.GetCustomAttribute(true); - var returnType = TemplateDataType.FromType(mi.ReturnType); + if (args.Last().ParameterType == typeof(DistributedConnection)) + args = args.Take(args.Count() - 1).ToArray(); + } - var args = mi.GetParameters(); + var arguments = args.Select(x => + { + var argType = RepresentationType.FromType(x.ParameterType); + if (argType == null) + throw new Exception($"Unsupported type `{x.ParameterType}` in method `{type.Name}.{mi.Name}` parameter `{x.Name}`"); - if (args.Length > 0) - { - if (args.Last().ParameterType == typeof(DistributedConnection)) - args = args.Take(args.Count() - 1).ToArray(); - } - - var arguments = args.Select(x => new ArgumentTemplate() + return new ArgumentTemplate() { Name = x.Name, - Type = TemplateDataType.FromType(x.ParameterType), - ParameterInfo = x - }) - .ToArray(); + Type = argType, + ParameterInfo = x, + Optional = x.IsOptional + }; + }) + .ToArray(); - var fn = publicAttr.Name ?? mi.Name; + var fn = publicAttr.Name ?? mi.Name; - var ft = new FunctionTemplate(this, i++, fn, arguments, returnType);// mi.ReturnType == typeof(void)); + var ft = new FunctionTemplate(this, i++, fn, mi.DeclaringType != type, 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; + 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); - ft.MethodInfo = mi; - functions.Add(ft); - } } } } @@ -537,15 +658,41 @@ public class TypeTemplate for (i = 0; i < properties.Count; i++) members.Add(properties[i]); + // append constants + for (i = 0; i < constants.Count; i++) + members.Add(constants[i]); + // bake it binarily var b = new BinaryList(); - b.AddUInt8((byte)templateType) - .AddGuid(classId) - .AddUInt8((byte)className.Length) - .AddString(className) - .AddInt32(version) - .AddUInt16((ushort)members.Count); + // find the first parent type that implements IResource + + + + + if (HasParent(type)) + { + // find the first parent type that implements IResource + var ParentDefinedType = ResourceProxy.GetBaseType(type.BaseType); + var parentId = GetTypeGuid(ParentDefinedType.FullName); + + b.AddUInt8((byte)(0x80 | (byte)templateType)) + .AddGuid(classId) + .AddUInt8((byte)className.Length) + .AddString(className) + .AddGuid(parentId) + .AddInt32(version) + .AddUInt16((ushort)members.Count); + } + else + { + b.AddUInt8((byte)templateType) + .AddGuid(classId) + .AddUInt8((byte)className.Length) + .AddString(className) + .AddInt32(version) + .AddUInt16((ushort)members.Count); + } foreach (var ft in functions) b.AddUInt8Array(ft.Compose()); @@ -553,11 +700,32 @@ public class TypeTemplate b.AddUInt8Array(pt.Compose()); foreach (var et in events) b.AddUInt8Array(et.Compose()); + foreach (var ct in constants) + b.AddUInt8Array(ct.Compose()); content = b.ToArray(); } + public static bool HasParent (Type type) + { + var parent = type.BaseType; + + if (parent == typeof(Resource) + || parent == typeof(Record)) + return false; + + while (parent != null) + { + if (parent.GetInterfaces().Contains(typeof(IResource)) + || parent.GetInterfaces().Contains(typeof(IRecord))) + return true; + parent = parent.BaseType; + } + + return false; + } + public static TypeTemplate Parse(byte[] data) { return Parse(data, 0, (uint)data.Length); @@ -576,17 +744,27 @@ public class TypeTemplate var od = new TypeTemplate(); od.content = data.Clip(offset, contentLength); - od.templateType = (TemplateType)data[offset++]; + var hasParent = (data[offset] & 0x80) > 0; + od.templateType = (TemplateType)(data[offset++] & 0xF); 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); + if (od.className == "Test.MyChildRecord") + Console.WriteLine(); + + if (hasParent) + { + od.parentId = data.GetGuid(offset); + offset += 16; + } + + od.version = data.GetInt32(offset, Endian.Little); offset += 4; - ushort methodsCount = data.GetUInt16(offset); + ushort methodsCount = data.GetUInt16(offset, Endian.Little); offset += 2; byte functionIndex = 0; @@ -595,7 +773,8 @@ public class TypeTemplate for (int i = 0; i < methodsCount; i++) { - var type = data[offset] >> 5; + var inherited = (data[offset] & 0x80) > 0; + var type = (data[offset] >> 5) & 0x3; if (type == 0) // function { @@ -606,7 +785,7 @@ public class TypeTemplate offset += (uint)data[offset] + 1; // return type - var (rts, returnType) = TemplateDataType.Parse(data, offset); + var (rts, returnType) = RepresentationType.Parse(data, offset); offset += rts; // arguments count @@ -615,7 +794,7 @@ public class TypeTemplate for (var a = 0; a < argsCount; a++) { - var (cs, argType) = ArgumentTemplate.Parse(data, offset); + var (cs, argType) = ArgumentTemplate.Parse(data, offset, a); arguments.Add(argType); offset += cs; } @@ -623,13 +802,13 @@ public class TypeTemplate // arguments if (hasExpansion) // expansion ? { - var cs = data.GetUInt32(offset); + var cs = data.GetUInt32(offset, Endian.Little); offset += 4; expansion = data.GetString(offset, cs); offset += cs; } - var ft = new FunctionTemplate(od, functionIndex++, name, arguments.ToArray(), returnType, expansion); + var ft = new FunctionTemplate(od, functionIndex++, name, inherited, arguments.ToArray(), returnType, expansion); od.functions.Add(ft); } @@ -646,13 +825,13 @@ public class TypeTemplate offset += (uint)data[offset] + 1; - var (dts, valueType) = TemplateDataType.Parse(data, offset); + var (dts, valueType) = RepresentationType.Parse(data, offset); offset += dts; if (hasReadExpansion) // expansion ? { - var cs = data.GetUInt32(offset); + var cs = data.GetUInt32(offset, Endian.Little); offset += 4; readExpansion = data.GetString(offset, cs); offset += cs; @@ -660,13 +839,13 @@ public class TypeTemplate if (hasWriteExpansion) // expansion ? { - var cs = data.GetUInt32(offset); + var cs = data.GetUInt32(offset, Endian.Little); offset += 4; writeExpansion = data.GetString(offset, cs); offset += cs; } - var pt = new PropertyTemplate(od, propertyIndex++, name, valueType, readExpansion, writeExpansion, recordable); + var pt = new PropertyTemplate(od, propertyIndex++, name, inherited, valueType, readExpansion, writeExpansion, recordable); od.properties.Add(pt); } @@ -680,23 +859,52 @@ public class TypeTemplate 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); + var (dts, argType) = RepresentationType.Parse(data, offset); offset += dts; if (hasExpansion) // expansion ? { - var cs = data.GetUInt32(offset); + var cs = data.GetUInt32(offset, Endian.Little); offset += 4; expansion = data.GetString(offset, cs); offset += cs; } - var et = new EventTemplate(od, eventIndex++, name, argType, expansion, listenable); + var et = new EventTemplate(od, eventIndex++, name, inherited, argType, expansion, listenable); od.events.Add(et); } + // constant + else if (type == 3) + { + string expansion = null; + var hasExpansion = ((data[offset++] & 0x10) == 0x10); + + var name = data.GetString(offset + 1, data[offset]); + offset += (uint)data[offset] + 1; + + var (dts, valueType) = RepresentationType.Parse(data, offset); + + offset += dts; + + (dts, var value) = Codec.Parse(data, offset, null); + + offset += dts; + + if (hasExpansion) // expansion ? + { + var cs = data.GetUInt32(offset, Endian.Little); + offset += 4; + expansion = data.GetString(offset, cs); + offset += cs; + } + + var ct = new ConstantTemplate(od, eventIndex++, name, inherited, valueType, value.Result, expansion); + + od.constants.Add(ct); + } } // append signals @@ -708,22 +916,9 @@ public class TypeTemplate // 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; - } - */ + // append constants + for (int i = 0; i < od.constants.Count; i++) + od.members.Add(od.constants[i]); return od; } diff --git a/Esiur/Resource/Warehouse.cs b/Esiur/Resource/Warehouse.cs index aed3c72..9568253 100644 --- a/Esiur/Resource/Warehouse.cs +++ b/Esiur/Resource/Warehouse.cs @@ -53,9 +53,7 @@ public static class Warehouse static uint resourceCounter = 0; - //static KeyList templates = new KeyList(); - //static KeyList wrapperTemplates = new KeyList(); - + static KeyList> templates = new KeyList>() { @@ -63,6 +61,7 @@ public static class Warehouse [TemplateType.Resource] = new KeyList(), [TemplateType.Record] = new KeyList(), [TemplateType.Wrapper] = new KeyList(), + [TemplateType.Enum] = new KeyList(), }; static bool warehouseIsOpen = false; @@ -141,6 +140,12 @@ public static class Warehouse { PutTemplate(new TypeTemplate(t)); } + + var enumsTypes = (Type[])generatedType.GetProperty("Enums").GetValue(null); + foreach (var t in recordTypes) + { + PutTemplate(new TypeTemplate(t)); + } } } } @@ -590,7 +595,7 @@ public static class Warehouse resource.Instance = new Instance(resourceCounter++, instanceName, resource, store, customTemplate, age); if (attributes != null) - resource.Instance.SetAttributes(Structure.FromObject(attributes)); + resource.Instance.SetAttributes(Map.FromObject(attributes)); if (manager != null) resource.Instance.Managers.Add(manager); @@ -686,7 +691,7 @@ public static class Warehouse if (properties != null) { - var ps = Structure.FromObject(properties); + var ps = Map.FromObject(properties); foreach (var p in ps) { @@ -768,6 +773,8 @@ public static class Warehouse templateType = TemplateType.Resource; else if (Codec.ImplementsInterface(type, typeof(IRecord))) templateType = TemplateType.Record; + else if (type.IsEnum) + templateType = TemplateType.Enum; else return null; @@ -781,7 +788,10 @@ public static class Warehouse // loaded ? if (template == null) + { template = new TypeTemplate(baseType, true); + TypeTemplate.GetDependencies(template); + } return template; } @@ -805,6 +815,12 @@ public static class Warehouse if (template != null) return template; + // look in enums + template = templates[TemplateType.Enum][classId]; + if (template != null) + return template; + + // look in wrappers template = templates[TemplateType.Wrapper][classId]; return template; diff --git a/Esiur/Security/Authority/CACertificate.cs b/Esiur/Security/Authority/CACertificate.cs index 2ff0d08..709beb2 100644 --- a/Esiur/Security/Authority/CACertificate.cs +++ b/Esiur/Security/Authority/CACertificate.cs @@ -53,11 +53,11 @@ public class CACertificate : Certificate uint oOffset = offset; - this.id = DC.GetUInt64(data, offset); + this.id = DC.GetUInt64(data, offset, Endian.Little); offset += 8; - this.issueDate = DC.GetDateTime(data, offset); + this.issueDate = DC.GetDateTime(data, offset, Endian.Little); offset += 8; - this.expireDate = DC.GetDateTime(data, offset); + this.expireDate = DC.GetDateTime(data, offset, Endian.Little); offset += 8; this.hashFunction = (HashFunctionType)(data[offset++] >> 4); @@ -77,7 +77,7 @@ public class CACertificate : Certificate offset += exponentLength; - uint keySize = DC.GetUInt16(data, offset); + uint keySize = DC.GetUInt16(data, offset, Endian.Little); offset += 2; key.Modulus = DC.Clip(data, offset, keySize); diff --git a/Esiur/Security/Authority/DomainCertificate.cs b/Esiur/Security/Authority/DomainCertificate.cs index 42882c3..1f12e05 100644 --- a/Esiur/Security/Authority/DomainCertificate.cs +++ b/Esiur/Security/Authority/DomainCertificate.cs @@ -79,19 +79,19 @@ public class DomainCertificate : Certificate { var oOffset = offset; - this.id = DC.GetUInt64(data, offset); + this.id = DC.GetUInt64(data, offset, Endian.Little); offset += 8; // load IPs - this.ip = DC.GetUInt32(data, offset); + this.ip = DC.GetUInt32(data, offset, Endian.Little); offset += 4; this.ip6 = DC.Clip(data, offset, 16); offset += 16; - this.issueDate = DC.GetDateTime(data, offset); + this.issueDate = DC.GetDateTime(data, offset, Endian.Little); offset += 8; - this.expireDate = DC.GetDateTime(data, offset); + this.expireDate = DC.GetDateTime(data, offset, Endian.Little); offset += 8; this.domain = Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]); @@ -100,7 +100,7 @@ public class DomainCertificate : Certificate this.authorityName = (Encoding.ASCII.GetString(data, (int)offset + 1, data[offset])); offset += (uint)data[offset] + 1; - caId = DC.GetUInt64(data, offset); + caId = DC.GetUInt64(data, offset, Endian.Little); offset += 8; var aea = (AsymetricEncryptionAlgorithmType)(data[offset] >> 5); @@ -113,7 +113,7 @@ public class DomainCertificate : Certificate key.Exponent = DC.Clip(data, offset, exponentLength); offset += exponentLength; - uint keySize = DC.GetUInt16(data, offset); + uint keySize = DC.GetUInt16(data, offset, Endian.Little); offset += 2; key.Modulus = DC.Clip(data, offset, keySize); diff --git a/Esiur/Security/Authority/UserCertificate.cs b/Esiur/Security/Authority/UserCertificate.cs index 0feb33c..419ee62 100644 --- a/Esiur/Security/Authority/UserCertificate.cs +++ b/Esiur/Security/Authority/UserCertificate.cs @@ -79,21 +79,21 @@ public class UserCertificate : Certificate { var oOffset = offset; - this.id = DC.GetUInt64(data, offset); + this.id = DC.GetUInt64(data, offset, Endian.Little); offset += 8; // load IPs - this.ip = DC.GetUInt32(data, offset); + this.ip = DC.GetUInt32(data, offset, Endian.Little); offset += 4; ip6 = DC.Clip(data, offset, 16); offset += 16; - this.issueDate = DC.GetDateTime(data, offset); + this.issueDate = DC.GetDateTime(data, offset, Endian.Little); offset += 8; - this.expireDate = DC.GetDateTime(data, offset); + this.expireDate = DC.GetDateTime(data, offset, Endian.Little); offset += 8; - this.domainId = DC.GetUInt64(data, offset); + this.domainId = DC.GetUInt64(data, offset, Endian.Little); offset += 8; this.domain = Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]); @@ -119,7 +119,7 @@ public class UserCertificate : Certificate offset += exponentLength; - uint keySize = DC.GetUInt16(data, offset); + uint keySize = DC.GetUInt16(data, offset, Endian.Little); offset += 2; key.Modulus = DC.Clip(data, offset, keySize); diff --git a/Esiur/Security/Integrity/SHA256.cs b/Esiur/Security/Integrity/SHA256.cs index 887e1b3..3637821 100644 --- a/Esiur/Security/Integrity/SHA256.cs +++ b/Esiur/Security/Integrity/SHA256.cs @@ -76,7 +76,7 @@ public static class SHA256 var w = new uint[64]; for (var i = 0; i < 16; i++) - w[i] = data.GetUInt32((uint)(chunk + (i * 4))); + w[i] = data.GetUInt32((uint)(chunk + (i * 4)), Endian.Big); //for(var i = 16; i < 64; i++) // w[i] = 0; diff --git a/Esiur/Security/Permissions/IPermissionsManager.cs b/Esiur/Security/Permissions/IPermissionsManager.cs index 7e2efde..b4ede30 100644 --- a/Esiur/Security/Permissions/IPermissionsManager.cs +++ b/Esiur/Security/Permissions/IPermissionsManager.cs @@ -49,7 +49,7 @@ public interface IPermissionsManager /// Allowed or denined. Ruling Applicable(IResource resource, Session session, ActionType action, MemberTemplate member, object inquirer = null); - bool Initialize(Structure settings, IResource resource); + bool Initialize(Map settings, IResource resource); - Structure Settings { get; } + Map Settings { get; } } diff --git a/Esiur/Security/Permissions/StorePermissionsManager.cs b/Esiur/Security/Permissions/StorePermissionsManager.cs index 190661a..4bec070 100644 --- a/Esiur/Security/Permissions/StorePermissionsManager.cs +++ b/Esiur/Security/Permissions/StorePermissionsManager.cs @@ -35,16 +35,16 @@ namespace Esiur.Security.Permissions; public class StorePermissionsManager : IPermissionsManager { - Structure settings; + Map settings; - public Structure Settings => settings; + public Map Settings => settings; public Ruling Applicable(IResource resource, Session session, ActionType action, MemberTemplate member, object inquirer = null) { return resource.Instance.Store.Instance.Applicable(session, action, member, inquirer); } - public bool Initialize(Structure settings, IResource resource) + public bool Initialize(Map settings, IResource resource) { this.settings = settings; return true; diff --git a/Esiur/Security/Permissions/UserPermissionsManager.cs b/Esiur/Security/Permissions/UserPermissionsManager.cs index 3ddb23e..536483f 100644 --- a/Esiur/Security/Permissions/UserPermissionsManager.cs +++ b/Esiur/Security/Permissions/UserPermissionsManager.cs @@ -36,18 +36,18 @@ namespace Esiur.Security.Permissions; public class UserPermissionsManager : IPermissionsManager { IResource resource; - Structure settings; + Map settings; - public Structure Settings => settings; + public Map Settings => settings; public Ruling Applicable(IResource resource, Session session, ActionType action, MemberTemplate member, object inquirer) { - Structure userPermissions = null; + Map userPermissions = null; if (settings.ContainsKey(session.RemoteAuthentication.FullName)) - userPermissions = settings[session.RemoteAuthentication.FullName] as Structure; + userPermissions = settings[session.RemoteAuthentication.FullName] as Map; else if (settings.ContainsKey("public")) - userPermissions = settings["public"] as Structure; + userPermissions = settings["public"] as Map; else return Ruling.Denied; @@ -98,7 +98,7 @@ public class UserPermissionsManager : IPermissionsManager } else if (userPermissions.ContainsKey(member?.Name)) { - Structure methodPermissions = userPermissions[member.Name] as Structure; + Map methodPermissions = userPermissions[member.Name] as Map; if ((string)methodPermissions[action.ToString()] != "yes") return Ruling.Denied; } @@ -111,12 +111,12 @@ public class UserPermissionsManager : IPermissionsManager } - public UserPermissionsManager(Structure settings) + public UserPermissionsManager(Map settings) { this.settings = settings; } - public bool Initialize(Structure settings, IResource resource) + public bool Initialize(Map settings, IResource resource) { this.resource = resource; this.settings = settings; diff --git a/Esiur/Stores/MemoryStore.cs b/Esiur/Stores/MemoryStore.cs index 67f50e5..43c23d3 100644 --- a/Esiur/Stores/MemoryStore.cs +++ b/Esiur/Stores/MemoryStore.cs @@ -15,6 +15,7 @@ public class MemoryStore : IStore public Instance Instance { get; set; } public event DestroyedEvent OnDestroy; + KeyList resources = new KeyList(); @@ -69,7 +70,7 @@ public class MemoryStore : IStore return new AsyncReply(true); } - public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + public bool Record(IResource resource, string propertyName, object value, ulong? age, DateTime? dateTime) { throw new NotImplementedException(); } @@ -85,7 +86,7 @@ public class MemoryStore : IStore return true; } - public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + public bool Modify(IResource resource, string propertyName, object value, ulong? age, DateTime? dateTime) { return true; } diff --git a/Esiur/Stores/TemporaryStore.cs b/Esiur/Stores/TemporaryStore.cs index b3e74d1..424f3bb 100644 --- a/Esiur/Stores/TemporaryStore.cs +++ b/Esiur/Stores/TemporaryStore.cs @@ -14,7 +14,7 @@ public class TemporaryStore : IStore public Instance Instance { get; set; } public event DestroyedEvent OnDestroy; - + Dictionary resources = new Dictionary(); public void Destroy() @@ -64,7 +64,7 @@ public class TemporaryStore : IStore return new AsyncReply(true); } - public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + public bool Record(IResource resource, string propertyName, object value, ulong? age, DateTime? dateTime) { throw new NotImplementedException(); } @@ -80,7 +80,7 @@ public class TemporaryStore : IStore return true; } - public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + public bool Modify(IResource resource, string propertyName, object value, ulong? age, DateTime? dateTime) { return true; } diff --git a/Esiur/TODO b/Esiur/TODO new file mode 100644 index 0000000..48008c5 --- /dev/null +++ b/Esiur/TODO @@ -0,0 +1,3 @@ + +1- Bin +2- clean \ No newline at end of file diff --git a/Test.Client/Program.cs b/Test.Client/Program.cs new file mode 100644 index 0000000..c932df2 --- /dev/null +++ b/Test.Client/Program.cs @@ -0,0 +1,21 @@ + + +using Esiur.Resource; + +namespace Test.Client; + +public class App +{ + static async Task Main(string[] args) + { + + var remote = await Warehouse.Get("iip://localhost/mem/service"); + var (i, s) = await remote.Tuple2(22, "ZZZZ"); + remote.ArrayEvent += (x) => Console.WriteLine(x); + remote.StringEvent += (x)=>Console.WriteLine(x); + await remote.InvokeEvents("Client"); + + Console.WriteLine(remote); + } + + } \ No newline at end of file diff --git a/Test.Client/Test.Client.csproj b/Test.Client/Test.Client.csproj new file mode 100644 index 0000000..601efa3 --- /dev/null +++ b/Test.Client/Test.Client.csproj @@ -0,0 +1,14 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + diff --git a/Test.Client/Test.Client.sln b/Test.Client/Test.Client.sln new file mode 100644 index 0000000..c6c7bbd --- /dev/null +++ b/Test.Client/Test.Client.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31919.166 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.Client", "Test.Client.csproj", "{EDDCB21B-5929-4218-912A-64B115CBF625}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EDDCB21B-5929-4218-912A-64B115CBF625}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EDDCB21B-5929-4218-912A-64B115CBF625}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EDDCB21B-5929-4218-912A-64B115CBF625}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EDDCB21B-5929-4218-912A-64B115CBF625}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E70DC657-E2B7-466C-BC0E-9ADC92F62831} + EndGlobalSection +EndGlobal diff --git a/Test.Client/localhost/Esiur.Generated.cs b/Test.Client/localhost/Esiur.Generated.cs new file mode 100644 index 0000000..c179af0 --- /dev/null +++ b/Test.Client/localhost/Esiur.Generated.cs @@ -0,0 +1,8 @@ +using System; + namespace Esiur { + public static class Generated { + public static Type[] Resources {get;} = new Type[] { typeof(Test.MyService),typeof(Test.MyResource),typeof(Test.MyChildResource),typeof(Test.MyService) }; + public static Type[] Records { get; } = new Type[] { typeof(Test.MyRecord) }; + public static Type[] Enums { get; } = new Type[] { typeof(Test.SizeEnum) }; + } +} \ No newline at end of file diff --git a/Test.Client/localhost/Test.MyChildResource.Generated.cs b/Test.Client/localhost/Test.MyChildResource.Generated.cs new file mode 100644 index 0000000..7eae6ae --- /dev/null +++ b/Test.Client/localhost/Test.MyChildResource.Generated.cs @@ -0,0 +1,23 @@ +using System; +using Esiur.Resource; +using Esiur.Core; +using Esiur.Data; +using Esiur.Net.IIP; +namespace Test { +public class MyChildResource : Test.MyResource { +public MyChildResource(DistributedConnection connection, uint instanceId, ulong age, string link) : base(connection, instanceId, age, link) {} +public MyChildResource() {} +public AsyncReply ChildMethod(string childName) { +var rt = new AsyncReply(); +_InvokeByArrayArguments(0, new object[] { childName }) +.Then(x => rt.Trigger((int)x)) +.Error(x => rt.TriggerError(x)) +.Chunk(x => rt.TriggerChunk(x)); +return rt; } +public string ChildName { +get => (string)properties[0]; +set => _Set(0, value); +} + +} +} diff --git a/Test.Client/localhost/Test.MyRecord.Generated.cs b/Test.Client/localhost/Test.MyRecord.Generated.cs new file mode 100644 index 0000000..84d2056 --- /dev/null +++ b/Test.Client/localhost/Test.MyRecord.Generated.cs @@ -0,0 +1,16 @@ +using System; +using Esiur.Resource; +using Esiur.Core; +using Esiur.Data; +using Esiur.Net.IIP; +namespace Test { +[Public] public class MyRecord : IRecord { +public string Name { get; set; } + +public int Id { get; set; } + +public double Score { get; set; } + + +} +} diff --git a/Test.Client/localhost/Test.MyResource.Generated.cs b/Test.Client/localhost/Test.MyResource.Generated.cs new file mode 100644 index 0000000..a729448 --- /dev/null +++ b/Test.Client/localhost/Test.MyResource.Generated.cs @@ -0,0 +1,20 @@ +using System; +using Esiur.Resource; +using Esiur.Core; +using Esiur.Data; +using Esiur.Net.IIP; +namespace Test { +public class MyResource : DistributedResource { +public MyResource(DistributedConnection connection, uint instanceId, ulong age, string link) : base(connection, instanceId, age, link) {} +public MyResource() {} +public string Description { +get => (string)properties[0]; +set => _Set(0, value); +} +public int CategoryId { +get => (int)properties[1]; +set => _Set(1, value); +} + +} +} diff --git a/Test.Client/localhost/Test.MyService.Generated.cs b/Test.Client/localhost/Test.MyService.Generated.cs new file mode 100644 index 0000000..793abc6 --- /dev/null +++ b/Test.Client/localhost/Test.MyService.Generated.cs @@ -0,0 +1,257 @@ +using System; +using Esiur.Resource; +using Esiur.Core; +using Esiur.Data; +using Esiur.Net.IIP; +namespace Test { +public class MyService : DistributedResource { +public MyService(DistributedConnection connection, uint instanceId, ulong age, string link) : base(connection, instanceId, age, link) {} +public MyService() {} +public AsyncReply Void() { +var rt = new AsyncReply(); +_InvokeByArrayArguments(0, new object[] { }) +.Then(x => rt.Trigger((object)x)) +.Error(x => rt.TriggerError(x)) +.Chunk(x => rt.TriggerChunk(x)); +return rt; } +public AsyncReply InvokeEvents(string msg) { +var rt = new AsyncReply(); +_InvokeByArrayArguments(1, new object[] { msg }) +.Then(x => rt.Trigger((object)x)) +.Error(x => rt.TriggerError(x)) +.Chunk(x => rt.TriggerChunk(x)); +return rt; } +public AsyncReply Optional(object a1,int a2,string a3) { +var rt = new AsyncReply(); +_InvokeByArrayArguments(2, new object[] { a1, a2, a3 }) +.Then(x => rt.Trigger((double)x)) +.Error(x => rt.TriggerError(x)) +.Chunk(x => rt.TriggerChunk(x)); +return rt; } +public AsyncReply Connection(object a1,int a2) { +var rt = new AsyncReply(); +_InvokeByArrayArguments(3, new object[] { a1, a2 }) +.Then(x => rt.Trigger((object)x)) +.Error(x => rt.TriggerError(x)) +.Chunk(x => rt.TriggerChunk(x)); +return rt; } +public AsyncReply ConnectionOptional(object a1,int a2,string a3) { +var rt = new AsyncReply(); +_InvokeByArrayArguments(4, new object[] { a1, a2, a3 }) +.Then(x => rt.Trigger((object)x)) +.Error(x => rt.TriggerError(x)) +.Chunk(x => rt.TriggerChunk(x)); +return rt; } +public AsyncReply<(int,string)> Tuple2(int a1,string a2) { +var rt = new AsyncReply<(int,string)>(); +_InvokeByArrayArguments(5, new object[] { a1, a2 }) +.Then(x => rt.Trigger(((int,string))x)) +.Error(x => rt.TriggerError(x)) +.Chunk(x => rt.TriggerChunk(x)); +return rt; } +public AsyncReply<(int,string,double)> Tuple3(int a1,string a2,double a3) { +var rt = new AsyncReply<(int,string,double)>(); +_InvokeByArrayArguments(6, new object[] { a1, a2, a3 }) +.Then(x => rt.Trigger(((int,string,double))x)) +.Error(x => rt.TriggerError(x)) +.Chunk(x => rt.TriggerChunk(x)); +return rt; } +public AsyncReply<(int,string,double,bool)> Tuple4(int a1,string a2,double a3,bool a4) { +var rt = new AsyncReply<(int,string,double,bool)>(); +_InvokeByArrayArguments(7, new object[] { a1, a2, a3, a4 }) +.Then(x => rt.Trigger(((int,string,double,bool))x)) +.Error(x => rt.TriggerError(x)) +.Chunk(x => rt.TriggerChunk(x)); +return rt; } +public int PropertyContext { +get => (int)properties[0]; +set => _Set(0, value); +} +public Test.SizeEnum Enum { +get => (Test.SizeEnum)properties[1]; +set => _Set(1, value); +} +public Test.MyRecord Record { +get => (Test.MyRecord)properties[2]; +set => _Set(2, value); +} +public int[] IntList { +get => (int[])properties[3]; +set => _Set(3, value); +} +public IRecord[] RecordsArray { +get => (IRecord[])properties[4]; +set => _Set(4, value); +} +public Test.MyRecord[] RecordsList { +get => (Test.MyRecord[])properties[5]; +set => _Set(5, value); +} +public Test.MyResource Resource { +get => (Test.MyResource)properties[6]; +set => _Set(6, value); +} +public Test.MyChildResource Child { +get => (Test.MyChildResource)properties[7]; +set => _Set(7, value); +} +public IResource[] Resources { +get => (IResource[])properties[8]; +set => _Set(8, value); +} +public Test.MyService Me { +get => (Test.MyService)properties[9]; +set => _Set(9, value); +} +public bool Boolean { +get => (bool)properties[10]; +set => _Set(10, value); +} +public bool[] BooleanArray { +get => (bool[])properties[11]; +set => _Set(11, value); +} +public byte UInt8 { +get => (byte)properties[12]; +set => _Set(12, value); +} +public byte? UInt8Null { +get => (byte?)properties[13]; +set => _Set(13, value); +} +public byte[] UInt8Array { +get => (byte[])properties[14]; +set => _Set(14, value); +} +public byte?[] UInt8ArrayNull { +get => (byte?[])properties[15]; +set => _Set(15, value); +} +public sbyte Int8 { +get => (sbyte)properties[16]; +set => _Set(16, value); +} +public sbyte[] Int8Array { +get => (sbyte[])properties[17]; +set => _Set(17, value); +} +public char Char16 { +get => (char)properties[18]; +set => _Set(18, value); +} +public char[] Char16Array { +get => (char[])properties[19]; +set => _Set(19, value); +} +public short Int16 { +get => (short)properties[20]; +set => _Set(20, value); +} +public short[] Int16Array { +get => (short[])properties[21]; +set => _Set(21, value); +} +public ushort UInt16 { +get => (ushort)properties[22]; +set => _Set(22, value); +} +public ushort[] UInt16Array { +get => (ushort[])properties[23]; +set => _Set(23, value); +} +public int Int32 { +get => (int)properties[24]; +set => _Set(24, value); +} +public int[] Int32Array { +get => (int[])properties[25]; +set => _Set(25, value); +} +public uint UInt32 { +get => (uint)properties[26]; +set => _Set(26, value); +} +public uint[] UInt32Array { +get => (uint[])properties[27]; +set => _Set(27, value); +} +public long Int64 { +get => (long)properties[28]; +set => _Set(28, value); +} +public long[] Int64Array { +get => (long[])properties[29]; +set => _Set(29, value); +} +public ulong UInt64 { +get => (ulong)properties[30]; +set => _Set(30, value); +} +public ulong[] UInt64Array { +get => (ulong[])properties[31]; +set => _Set(31, value); +} +public float Float32 { +get => (float)properties[32]; +set => _Set(32, value); +} +public float[] Float32Array { +get => (float[])properties[33]; +set => _Set(33, value); +} +public double Float64 { +get => (double)properties[34]; +set => _Set(34, value); +} +public double[] Float64Array { +get => (double[])properties[35]; +set => _Set(35, value); +} +public decimal Float128 { +get => (decimal)properties[36]; +set => _Set(36, value); +} +public decimal[] Float128Array { +get => (decimal[])properties[37]; +set => _Set(37, value); +} +public string String { +get => (string)properties[38]; +set => _Set(38, value); +} +public string[] StringArray { +get => (string[])properties[39]; +set => _Set(39, value); +} +public DateTime DateTime { +get => (DateTime)properties[40]; +set => _Set(40, value); +} +public Map StringMap { +get => (Map)properties[41]; +set => _Set(41, value); +} +public Map IntStringMap { +get => (Map)properties[42]; +set => _Set(42, value); +} +public object Object { +get => (object)properties[43]; +set => _Set(43, value); +} +public object[] ObjectArray { +get => (object[])properties[44]; +set => _Set(44, value); +} +public const double PI = 3.14159265358979; +protected override void _EmitEventByIndex(byte index, object args) { +switch (index) { +case 0: StringEvent?.Invoke((string)args); break; +case 1: ArrayEvent?.Invoke((object[])args); break; +}} +public event ResourceEventHandler StringEvent; +public event ResourceEventHandler ArrayEvent; + + +} +} diff --git a/Test.Client/localhost/Test.SizeEnum.Generated.cs b/Test.Client/localhost/Test.SizeEnum.Generated.cs new file mode 100644 index 0000000..463b98e --- /dev/null +++ b/Test.Client/localhost/Test.SizeEnum.Generated.cs @@ -0,0 +1,15 @@ +using System; +using Esiur.Resource; +using Esiur.Core; +using Esiur.Data; +using Esiur.Net.IIP; +namespace Test { +[Public] public enum SizeEnum { +xSmall=-11, +Small=-10, +Medium=0, +Large=1, +XLarge=22 + +} +} diff --git a/Test/MyChildRecord.cs b/Test/MyChildRecord.cs new file mode 100644 index 0000000..484174f --- /dev/null +++ b/Test/MyChildRecord.cs @@ -0,0 +1,15 @@ +using Esiur.Resource; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Test +{ + [Public] + public class MyChildRecord : MyRecord + { + public string ChildName { get; set; } + } +} diff --git a/Test/MyChildResource.cs b/Test/MyChildResource.cs new file mode 100644 index 0000000..2a5c122 --- /dev/null +++ b/Test/MyChildResource.cs @@ -0,0 +1,16 @@ +using Esiur.Resource; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Test +{ + [Resource] + public partial class MyChildResource : MyResource + { + [Public] string childName; + [Public] public int ChildMethod(string childName) => 111; + } +} diff --git a/Test/MyMembership.cs b/Test/MyMembership.cs deleted file mode 100644 index 2c78096..0000000 --- a/Test/MyMembership.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Esiur.Data; -using Esiur.Core; -using Esiur.Resource; -using Esiur.Security.Authority; -using Esiur.Security.Membership; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Test -{ - public class MyMembership : IMembership - { - public Instance Instance { get; set; } - - public event DestroyedEvent OnDestroy; - - - - public void Destroy() - { - } - - public AsyncReply GetPassword(string username, string domain) - { - return new AsyncReply(DC.ToBytes("1234")); - } - - public AsyncReply Login(Session session) - { - return new AsyncReply(true); - } - - public AsyncReply Logout(Session session) - { - return new AsyncReply(true); - } - - public AsyncReply Trigger(ResourceTrigger trigger) - { - return new AsyncReply(true); - } - - - public AsyncReply UserExists(string username, string domain) - { - return new AsyncReply(username == "demo"); - } - } - -} diff --git a/Test/MyObject.cs b/Test/MyObject.cs deleted file mode 100644 index cfcce58..0000000 --- a/Test/MyObject.cs +++ /dev/null @@ -1,156 +0,0 @@ -using Esiur.Data; -using Esiur.Core; -using Esiur.Net.IIP; -using Esiur.Resource; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; - -namespace Test -{ - public class MyObject : EntryPoint - { - - [ResourceEvent] - public event ResourceEventHanlder LevelUp; - [ResourceEvent] - public event ResourceEventHanlder LevelDown; - - public MyObject() - { - Info = new Structure(); - Info["size"] = 200; - Info["age"] = 28; - Info["name"] = "Esiur"; - Name = "Esiur Project"; - Level = 5; - } - - - [ResourceFunction] - public int Add(int? value) - { - Level += (int)value; - LevelUp?.Invoke(null, "going up", value); - return Level; - } - - [ResourceFunction("Divide takes two arguments nominator and denominator")] - public double Divide(float n, float d, DistributedConnection sender) - { - return n / d; - } - - [ResourceFunction] - public int Subtract(int value) - { - Level -= value; - LevelDown?.Invoke(null, "going down", value); - return Level; - } - - [ResourceFunction("use it with next()")] - public IEnumerable Enum(int count) - { - var msg = new string[] { "Have you throught what if a function has multiple returns ?", "So you can return chunks of IO operation that not yet finished.", "Also, what about the progress ?", "This is an example of both.", "Use it anyway you like" }; - - for (var i = 0; i < count; i++) - { - Thread.Sleep(2000); - yield return msg[(int)(i % msg.Length)]; - } - } - - [ResourceFunction("Stream returns progress")] - public AsyncReply Stream(int count) - { - var reply = new AsyncReply(); - var msg = new object[] { "Have you throught what if a function has multiple returns ?", "So you can return chunks of IO operation that not yet finished.", "Also, what about the progress ?", "This is an example of both.", "Use it anyway you like" }; - Timer timer = null; - var msgCounter = 0; - - timer = new Timer((x) => - { - - reply.TriggerProgress(ProgressType.Execution, count, 22); - - if (count % 2 == 0 && msgCounter < msg.Length) - reply.TriggerChunk(msg[msgCounter++]); - - count--; - if (count <= 0) - { - timer.Dispose(); - reply.Trigger("Done"); - } - - }, null, 10, 3000); - - return reply; - } - - public override AsyncReply Query(string path, DistributedConnection sender) - { - return new AsyncReply(new IResource[] { this }); - } - - public override bool Create() - { - return true; - } - - [ResourceProperty] - public Structure Info - { - get; - set; - } - - [ResourceProperty] - public string Name - { - get; - set; - } - - [ResourceProperty] - public MyObject Me - { - get - { - return this; - } - } - - /* - int level; - [ResourceProperty] - public int Level - { - get { return level; } - set - { - level = value; - Instance?.Modified(); - } - } - */ - - [ResourceProperty] - public virtual int Level - { - get; - set; - } - - [ResourceProperty] - public int Level3 - { - get => 0; - set => Instance?.Modified(); - } - } - - -} diff --git a/Test/MyRecord.cs b/Test/MyRecord.cs new file mode 100644 index 0000000..0946d86 --- /dev/null +++ b/Test/MyRecord.cs @@ -0,0 +1,20 @@ +using Esiur.Data; +using Esiur.Resource; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Test +{ + [Public] + public class MyRecord:IRecord + { + public string Name { get; set; } + public int Id { get; set; } + + public double Score { get; set; } + + } +} diff --git a/Test/MyResource.cs b/Test/MyResource.cs new file mode 100644 index 0000000..937e1a1 --- /dev/null +++ b/Test/MyResource.cs @@ -0,0 +1,16 @@ +using Esiur.Resource; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Test +{ + [Resource] + public partial class MyResource + { + [Public] string description; + [Public] int categoryId; + } +} diff --git a/Test/MyService.cs b/Test/MyService.cs new file mode 100644 index 0000000..74929e8 --- /dev/null +++ b/Test/MyService.cs @@ -0,0 +1,171 @@ +using Esiur.Data; +using Esiur.Core; +using Esiur.Net.IIP; +using Esiur.Resource; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace Test; + + +public enum SizeEnum:short +{ + xSmall = -11, + Small, + Medium = 0, + Large, + XLarge = 22 +} + +[Resource] +public partial class MyService +{ + + [Public] public event ResourceEventHandler StringEvent; + [Public] public event ResourceEventHandler ArrayEvent; + + [Public] bool boolean = true; + [Public] bool[] booleanArray = new bool[] { true, false, true, false, true }; + + [Public] byte uInt8Test = 8; + [Public] byte? uInt8Null = null; + [Public] byte[] uInt8Array = new byte[] { 0, 1, 2, 3, 4, 5 }; + [Public] byte?[] uInt8ArrayNull = new byte?[] { 0, null, 2, null, 4, null }; + + [Public] sbyte int8 = -8; + [Public] sbyte[] int8Array = new sbyte[] { -3, -2, -1, 0, 1, 2 }; + + [Public] char char16 = 'ح'; + [Public] char[] char16Array = new char[] { 'م', 'ر', 'ح', 'ب', 'ا' }; + + [Public] short int16 = -16; + [Public] short[] int16Array = new short[] { -3, -2, -1, 0, 1, 2 }; + + [Public] ushort uInt16 = 16; + [Public] ushort[] uInt16Array = new ushort[] { 0, 1, 2, 3, 4, 5 }; + + + [Public] int int32Prop = -32; + [Public] int[] int32Array = new int[] { -3, -2, -1, 0, 1, 2 }; + + [Public] uint uInt32 = 32; + [Public] uint[] uInt32Array = new uint[] { 0, 1, 2, 3, 4, 5 }; + + [Public] long int64 = 323232323232; + [Public] long[] int64Array = new long[] { -3, -2, -1, 0, 1, 2 }; + + [Public] ulong uInt64; + [Public] ulong[] uInt64Array = new ulong[] { 0, 1, 2, 3, 4, 5 }; + + [Public] float float32 = 32.32f; + [Public] float[] float32Array = new float[] { -3.3f, -2.2f, -1.1f, 0, 1.1f, 2.2f }; + + [Public] double float64 = 32.323232; + [Public] double[] float64Array = new double[] { -3.3, -2.2, -1.1, 0, 1.1, 2.2 }; + + [Public] decimal float128 = 3232.323232323232m; + [Public] decimal[] float128Array = new decimal[] { -3.3m, -2.2m, -1.1m, 0, 1.1m, 2.2m }; + + [Public("Text")] string stringTest = "Hello World"; + [Public] string[] stringArray = new string[] { "Hello", "World" }; + + [Public] DateTime time = DateTime.Now; + + + [Public] + Map stringMap = new Map() + { + ["int"] = 33, + ["string"] = "Hello World" + }; + + [Public] + Map intStringMap = new() + { + [4] = "Abcd", + [44] = "EfG" + }; + + + [Public("Object")] object objectTest = "object"; + + [Public] object[] objectArray = new object[] { 1, 1.2f, Math.PI, "Hello World" }; + + [Public] + public DistributedPropertyContext PropertyContext + { + get => new DistributedPropertyContext((sender) => sender.RemoteEndPoint.Port); + set + { + Console.WriteLine($"PropertyContext Set: {value.Value} {value.Connection.RemoteEndPoint.Port}"); + } + } + + [Public] public SizeEnum Enum => SizeEnum.Medium; + + + [Public] public MyRecord Record => new MyRecord() { Id = 33, Name = "Test", Score = 99.33 }; + + [Public] public List IntList => new List() { 1, 2, 3, 4, 5 }; + + [Public] public IRecord[] RecordsArray => new IRecord[] { new MyRecord() { Id = 22, Name = "Test", Score = 22.1 } }; + [Public] public List RecordsList => new() { new MyRecord() { Id = 22, Name = "Test", Score = 22.1 } }; + + + [Public] public MyResource[] myResources; + + [Public] public MyResource Resource { get; set; } + [Public] public MyChildResource ChildResource { get; set; } + + [Public] public MyChildRecord ChildRecord { get; set; } = new MyChildRecord() { ChildName = "Child", Id = 12, Name = "Parent", Score = 12.2 }; + + [Public] public IResource[] Resources { get; set; } + + [Public] + public void Void() => + Console.WriteLine("Void()"); + + [Public] + public void InvokeEvents(string msg) + { + StringEvent?.Invoke(msg); + ArrayEvent?.Invoke(new object[] { DateTime.UtcNow, "Event", msg }); + } + + [Public] + public double Optional(object a1, int a2, string a3 = "Hello", string a4 = "World") + { + Console.WriteLine($"VoidArgs {a1} {a2} {a3}"); + return new Random().NextDouble(); + } + + [Public] + public void Connection(object a1, int a2, DistributedConnection a3) => + Console.WriteLine($"VoidArgs {a1} {a2} {a3}"); + + + [Public] + public void ConnectionOptional(object a1, int a2, string a3 = "sss", DistributedConnection a4 = null) => + Console.WriteLine($"VoidArgs {a1} {a2} {a3}"); + + [Public] + public (int, string) GetTuple2(int a1, string a2) => (a1, a2); + + [Public] + public (int, string, double) GetTuple3(int a1, string a2, double a3) => (a1, a2, a3); + + [Public] + public (int, string, double, bool) GetTuple4(int a1, string a2, double a3, bool a4) => (a1, a2, a3, a4); + + [Public] public MyRecord SendRecord(MyRecord record) + { + Console.WriteLine(record.ToString()); + return record; + } + + [Public] public const double PI = Math.PI; + + [Public] public MyService Me => this; +} diff --git a/Test/Program.cs b/Test/Program.cs index 54c8bbb..33c068e 100644 --- a/Test/Program.cs +++ b/Test/Program.cs @@ -30,178 +30,149 @@ using Esiur.Net.Sockets; using Esiur.Resource; using Esiur.Security.Permissions; using Esiur.Stores; -using Esiur.Stores.MongoDB; -using System; + using System; using System.Threading; using System.Threading.Tasks; using Esiur.Security.Integrity; using System.Linq; +using Esiur.Resource.Template; +using System.Collections; +using System.Runtime.CompilerServices; +using Esiur.Proxy; namespace Test { class Program { - static MyObject localObject; - static IResource remoteObject; - - - + static async Task Main(string[] args) { + + Warehouse.GetTemplateByType(typeof(MyChildRecord)); // Create stores to keep objects. - var system = Warehouse.New("system"); - var remote = Warehouse.New("remote"); - var mongo = Warehouse.New("db"); + var system = await Warehouse.Put("mem", new MemoryStore()); + var server = await Warehouse.Put("mem/server", new DistributedServer()); + var service = await Warehouse.Put("mem/service", new MyService()); + var res1 = await Warehouse.Put("mem/service/r1", new MyResource() { Description = "Testing 1", CategoryId = 10 }); + var res2 = await Warehouse.Put("mem/service/r2", new MyResource() { Description = "Testing 2", CategoryId = 11 }); + var res3 = await Warehouse.Put("mem/service/c1", new MyChildResource() { ChildName = "Child 1", Description = "Child Testing 3", CategoryId = 12 }); - // Create new distributed server object - var iip = Warehouse.New("iip", system); - // Set membership which handles authentication. - iip.Membership = Warehouse.New("ms", system); - // Start the server on port 5000. - iip.Start(new TCPSocket(new System.Net.IPEndPoint(System.Net.IPAddress.Any, 500)), 600000, 60000); - - - // Create http server to handle IIP over Websockets - var http = Warehouse.New("http", system); - http.Start(new TCPSocket(new System.Net.IPEndPoint(System.Net.IPAddress.Any, 501)), 600000, 60000); - - // Create IIP over Websocket HTTP module and give it to HTTP server. - var wsOverHttp = Warehouse.New("IIPoWS", system, http); - - wsOverHttp.DistributedServer = iip; - - - /* - var system = await Warehouse.Get("mem://system").Task; - var remote = await Warehouse.Get("mem://remote").Task; - var mongo = await Warehouse.Get("mongo://db").Task; - var iip = await Warehouse.Get("iip://:5000").Task; - var iws = await Warehouse.Get("iipows://:5001", new Structure() { ["iip"] = iip }).Task; - */ + service.Resource = res1; + service.ChildResource = res3; + service.Resources = new MyResource[] { res1, res2, res1 , res3 }; var ok = await Warehouse.Open(); - - // Open the warehouse - - - // Create new object if the store is empty - if (mongo.Count == 0) - localObject = Warehouse.New("my", mongo, null, - new UserPermissionsManager(new Structure() - { - ["demo@localhost"] = new Structure() - { - ["Subtract"] = new Structure { ["Execute"] = "yes" }, - ["Stream"] = new Structure { ["Execute"] = "yes" }, - ["_attach"] = "yes", - ["_get_attributes"] = "yes", - ["_set_attributes"] = "yes", - } - })); - else - localObject = (MyObject)(await Warehouse.Get("db/my")); - - - iip.EntryPoint = localObject; - - Warehouse.StoreConnected += (store, name) => - { - if (store.Instance.Parents.Contains(iip)) - { - store.Get("local/js").Then((r) => - { - if (r != null) - { - dynamic d = r; - d.send("Welcome"); - } - }); - } - }; - + Console.WriteLine(String.Join(" ", service.Instance.Template.ClassId.ToByteArray())); // Start testing - TestClient(); + TestClient(service); + // TestClient(service); + } - var running = true; - while (running) + enum aa + { + a, + b, + c, + d + } + + public static (int, string) tuple() => (33, "sss"); + + private static async void TestClient(IResource local) + { + dynamic remote = await Warehouse.Get("iip://localhost/mem/service"); + + TestObjectProps(local, remote); + + var opt = await remote.Optional(new { a1 = 22, a2 = 33, a4 = "What?" }); + Console.WriteLine(opt); + + await remote.Void(); + await remote.Connection("ss", 33); + await remote.ConnectionOptional("Test 2", 88); + var rt = await remote.Optional("Optiona", 311); + Console.WriteLine(rt); + + var t2 = await remote.GetTuple2(1, "A"); + Console.WriteLine(t2); + var t3 = await remote.GetTuple3(1, "A", 1.3); + Console.WriteLine(t3); + var t4 = await remote.GetTuple4(1, "A", 1.3, true); + Console.WriteLine(t4); + + remote.StringEvent += new DistributedResourceEvent((sender, args) => + Console.WriteLine($"StringEvent {args}") + ); + + remote.ArrayEvent += new DistributedResourceEvent((sender, args) => + Console.WriteLine($"ArrayEvent {args}") + ); + + await remote.InvokeEvents("Hello"); + + //var childTemplate = remote.Child.Instance.Template; + + + var path = TemplateGenerator.GetTemplate("iip://localhost/mem/service", "Generated"); + + Console.WriteLine(path); + + } + + + + static void TestObjectProps(IResource local, DistributedResource remote) + { + + foreach(var pt in local.Instance.Template.Properties) { - var cmd = Console.ReadLine(); - if (cmd.ToLower() == "exit") - Warehouse.Close().Then((x) => - { - if (!x) - Console.WriteLine("Failed to close the warehouse."); - else - Console.WriteLine("Successfully closed the warehouse."); - running = false; - }); + var lv = pt.PropertyInfo.GetValue(local); + object v; + var rv = remote.TryGetPropertyValue(pt.Index, out v); + if (!rv) + Console.WriteLine($" ** {pt.Name } Failed"); else - { - localObject.Level = 88; - Console.WriteLine(localObject.Name + " " + localObject.Level); - } + Console.WriteLine($"{pt.Name } {GetString(lv)} == {GetString(v)}"); } - } - private static async void TestClient() + static string GetString(object value) { + if (value == null) + return "NULL"; - remoteObject = await Warehouse.Get("iip://localhost:500/db/my", new { username= "demo", password = 1234 }); - - dynamic x = remoteObject; + var t = value.GetType(); + var nt = Nullable.GetUnderlyingType(t); + if (nt != null) + t = nt; + if (t.IsArray) + { + var ar = (Array)value; + if (ar.Length == 0) + return "[]"; + var rt = "["; + for (var i = 0; i < ar.Length - 1; i++) + rt += GetString(ar.GetValue(i)) + ","; + rt += GetString(ar.GetValue(ar.Length - 1)) + "]"; + return rt; + } else if (value is IRecord) + { + return "{" + String.Join(", ", t.GetProperties().Select(x => x.Name + ": " + x.GetValue(value))) + "}"; + } - Console.WriteLine("My Name is: " + x.Name); - x.Name = "Hamoo"; - x.LevelUp += new DistributedResourceEvent((sender, parameters) => - { - Console.WriteLine("LevelUp " + parameters[0] + " " + parameters[1]); - }); - - x.LevelDown += new DistributedResourceEvent((sender, parameters) => - { - Console.WriteLine("LevelUp " + parameters[0] + " " + parameters[1]); - }); - - - (x.Stream(10) as AsyncReply).Then(r => - { - Console.WriteLine("Stream ended: " + r); - }).Chunk(r => - { - Console.WriteLine("Chunk..." + r); - }).Progress((t, v, m) => Console.WriteLine("Processing {0}/{1}", v, m)); - - var rt = await x.Subtract(10); - - - Console.WriteLine(rt); - // Getting object record - (remoteObject.Instance.Store as DistributedConnection).GetRecord(remoteObject, DateTime.Now - TimeSpan.FromDays(1), DateTime.Now).Then(record => - { - Console.WriteLine("Records received: " + record.Count); - }); - - //var timer = new Timer(T_Elapsed, null, 5000, 5000); - - - } - - private static void T_Elapsed(object state) - { - localObject.Level++; - dynamic o = remoteObject; - Console.WriteLine(localObject.Level + " " + o.Level + o.Me.Me.Level); + else + return value.ToString(); } + } } diff --git a/Test/Test.csproj b/Test/Test.csproj index 820e315..00950c4 100644 --- a/Test/Test.csproj +++ b/Test/Test.csproj @@ -2,12 +2,11 @@ Exe - netcoreapp2.0 + net6.0 - - + \ No newline at end of file