From 08e95bd4dcc6c8dd5a15aa28f5d91c9c4532ddb7 Mon Sep 17 00:00:00 2001 From: Ahmed Zamil Date: Fri, 24 May 2019 05:38:53 +0300 Subject: [PATCH] Updated to support IIP v3.3 --- Esiur.Stores.MongoDB/MongoDBStore.cs | 317 ++++- Esiur/Data/AutoList.cs | 53 +- Esiur/Data/BinaryList.cs | 26 +- Esiur/Data/Codec.cs | 340 ++++- Esiur/Data/DataConverter.cs | 211 ++- Esiur/Data/DataType.cs | 26 +- Esiur/Data/KeyList.cs | 57 +- Esiur/Data/NotModified.cs | 26 +- Esiur/Data/PropertyValue.cs | 35 + Esiur/Data/StringKeyList.cs | 38 +- Esiur/Data/Structure.cs | 42 +- Esiur/Engine/AsyncBag.cs | 58 +- Esiur/Engine/AsyncException.cs | 85 ++ Esiur/Engine/AsyncQueue.cs | 30 +- Esiur/Engine/AsyncReply.cs | 160 ++- Esiur/Engine/AsyncReplyGeneric.cs | 47 +- Esiur/Engine/IDestructible.cs | 25 +- Esiur/Engine/LogType.cs | 27 +- Esiur/Esiur.csproj | 2 +- Esiur/Misc/Global.cs | 33 +- Esiur/Net/DataLink/PacketFilter.cs | 26 +- Esiur/Net/DataLink/PacketServer.cs | 26 +- Esiur/Net/DataLink/PacketSource.cs | 26 +- Esiur/Net/HTTP/HTTPConnection.cs | 26 +- Esiur/Net/HTTP/HTTPFilter.cs | 26 +- Esiur/Net/HTTP/HTTPServer.cs | 28 +- Esiur/Net/HTTP/HTTPSession.cs | 28 +- Esiur/Net/HTTP/IIPoWS.cs | 45 +- Esiur/Net/IIP/DistributedConnection.cs | 803 +++++++---- .../Net/IIP/DistributedConnectionProtocol.cs | 1229 +++++++++++++++-- Esiur/Net/IIP/DistributedPropertyContext.cs | 24 + Esiur/Net/IIP/DistributedResource.cs | 144 +- Esiur/Net/IIP/DistributedResourceEvent.cs | 26 +- Esiur/Net/IIP/DistributedResourceQueueItem.cs | 26 +- Esiur/Net/IIP/DistributedServer.cs | 82 +- Esiur/Net/IIP/DistributedSession.cs | 26 +- Esiur/Net/NetworkBuffer.cs | 121 +- Esiur/Net/NetworkConnection.cs | 59 +- Esiur/Net/NetworkServer.cs | 76 +- Esiur/Net/NetworkSession.cs | 28 +- Esiur/Net/Packets/HTTPRequestPacket.cs | 29 +- Esiur/Net/Packets/HTTPResponsePacket.cs | 25 +- Esiur/Net/Packets/IIPAuthPacket.cs | 26 +- Esiur/Net/Packets/IIPPacket.cs | 417 +++++- Esiur/Net/Packets/WebsocketPacket.cs | 49 +- Esiur/Net/Sockets/ISocket.cs | 26 +- Esiur/Net/Sockets/SSLSocket.cs | 26 +- Esiur/Net/Sockets/SocketState.cs | 26 +- Esiur/Net/Sockets/TCPSocket.cs | 123 +- Esiur/Net/Sockets/WSSocket.cs | 50 +- Esiur/Net/TCP/TCPConnection.cs | 26 +- Esiur/Net/TCP/TCPFilter.cs | 26 +- Esiur/Net/TCP/TCPServer.cs | 26 +- Esiur/Net/TCP/TCPSession.cs | 26 +- Esiur/Net/UDP/UDPFilter.cs | 26 +- Esiur/Net/UDP/UDPServer.cs | 24 + .../PublishProfiles/FolderProfile.pubxml | 13 + Esiur/Resource/IResource.cs | 26 +- Esiur/Resource/IStore.cs | 38 +- Esiur/Resource/Instance.cs | 502 ++++++- Esiur/Resource/Resource.cs | 47 + Esiur/Resource/ResourceEvent.cs | 25 +- Esiur/Resource/ResourceEventHandler.cs | 36 +- Esiur/Resource/ResourceFunction.cs | 26 +- Esiur/Resource/ResourceProperty.cs | 38 +- Esiur/Resource/ResourceTrigger.cs | 26 +- Esiur/Resource/Storable.cs | 26 +- Esiur/Resource/StorageMode.cs | 13 + Esiur/Resource/Template/EventTemplate.cs | 7 +- Esiur/Resource/Template/FunctionTemplate.cs | 7 +- Esiur/Resource/Template/MemberTemplate.cs | 23 +- Esiur/Resource/Template/PropertyTemplate.cs | 37 +- Esiur/Resource/Template/ResourceTemplate.cs | 74 +- Esiur/Resource/Warehouse.cs | 174 ++- .../Security/Authority/AlienAuthentication.cs | 30 +- Esiur/Security/Authority/Authentication.cs | 51 +- .../Security/Authority/AuthenticationState.cs | 26 +- .../Security/Authority/AuthenticationType.cs | 26 +- Esiur/Security/Authority/CACertificate.cs | 26 +- Esiur/Security/Authority/Certificate.cs | 26 +- Esiur/Security/Authority/CertificateType.cs | 26 +- .../Authority/ClientAuthentication.cs | 61 +- .../Authority/CoHostAuthentication.cs | 30 +- Esiur/Security/Authority/DomainCertificate.cs | 26 +- .../Security/Authority/HostAuthentication.cs | 34 +- Esiur/Security/Authority/Session.cs | 52 +- Esiur/Security/Authority/Source.cs | 45 +- .../Security/Authority/SourceAttributeType.cs | 31 +- Esiur/Security/Authority/UserCertificate.cs | 26 +- .../AsymetricEncryptionAlgorithmType.cs | 26 +- .../SymetricEncryptionAlgorithmType.cs | 25 +- Esiur/Security/Integrity/HashFunctionType.cs | 26 +- Esiur/Security/Membership/IDomain.cs | 26 +- Esiur/Security/Membership/IMembership.cs | 30 +- Esiur/Security/Membership/IUser.cs | 26 +- Esiur/Security/Permissions/ActionType.cs | 39 +- .../Permissions/IPermissionManager.cs | 18 - .../Permissions/IPermissionsManager.cs | 56 + .../Permissions/ParentalPermissionsManager.cs | 60 + Esiur/Security/Permissions/Ruling.cs | 13 + .../Permissions/UserPermissionsManager.cs | 127 ++ Esiur/Stores/MemoryStore.cs | 23 + Test/MyMembership.cs | 6 +- Test/MyObject.cs | 47 +- Test/Program.cs | 154 ++- Test/Test.csproj | 2 +- 106 files changed, 6643 insertions(+), 1179 deletions(-) create mode 100644 Esiur/Data/PropertyValue.cs create mode 100644 Esiur/Engine/AsyncException.cs create mode 100644 Esiur/Net/IIP/DistributedPropertyContext.cs create mode 100644 Esiur/Properties/PublishProfiles/FolderProfile.pubxml create mode 100644 Esiur/Resource/Resource.cs create mode 100644 Esiur/Resource/StorageMode.cs delete mode 100644 Esiur/Security/Permissions/IPermissionManager.cs create mode 100644 Esiur/Security/Permissions/IPermissionsManager.cs create mode 100644 Esiur/Security/Permissions/ParentalPermissionsManager.cs create mode 100644 Esiur/Security/Permissions/Ruling.cs create mode 100644 Esiur/Security/Permissions/UserPermissionsManager.cs diff --git a/Esiur.Stores.MongoDB/MongoDBStore.cs b/Esiur.Stores.MongoDB/MongoDBStore.cs index 3519a9e..fd02924 100644 --- a/Esiur.Stores.MongoDB/MongoDBStore.cs +++ b/Esiur.Stores.MongoDB/MongoDBStore.cs @@ -7,6 +7,10 @@ using MongoDB.Bson; using Esiur.Data; using System.Collections.Generic; using System.Reflection; +using System.Threading.Tasks; +using Esiur.Resource.Template; +using System.Linq; +using Esiur.Security.Permissions; namespace Esiur.Stores.MongoDB { @@ -17,6 +21,7 @@ namespace Esiur.Stores.MongoDB public event DestroyedEvent OnDestroy; MongoClient client; IMongoDatabase database; + IMongoCollection resourcesCollection; Dictionary resources = new Dictionary(); @@ -25,28 +30,70 @@ namespace Esiur.Stores.MongoDB { get { return resources.Count; } } + public void Destroy() { } + + public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime date) + { + var objectId = resource.Instance.Attributes["objectId"].ToString(); + //var bsonObjectId = new BsonObjectId(new ObjectId(objectId)); + + var record = this.database.GetCollection("record_" + objectId); + + record.InsertOne(new BsonDocument() + { + {"property", propertyName}, {"age", BsonValue.Create(age) }, {"date", date}, {"value", Compose(value) } + }); + + var col = this.database.GetCollection("resources"); + + + + var filter = Builders.Filter.Eq("_id", new BsonObjectId(new ObjectId(objectId))); + var update = Builders.Update + .Set("values." + propertyName, new BsonDocument { { "age", BsonValue.Create(age) }, + { "modification", date }, + { "value", Compose(value) } }); + + col.UpdateOne(filter, update); + + return true; + } + public MongoDBStore() { client = new MongoClient(); this.database = client.GetDatabase("esiur"); + this.resourcesCollection = this.database.GetCollection("resources"); + } public MongoDBStore(string connectionString, string database) { client = new MongoClient(connectionString); this.database = client.GetDatabase(database); + this.resourcesCollection = this.database.GetCollection("resources"); } + public bool Remove(IResource resource) + { + var objectId = resource.Instance.Attributes["objectId"].ToString(); + var filter = Builders.Filter.Eq("_id", new BsonObjectId(new ObjectId(objectId))); + + this.database.DropCollection("record_" + objectId); + resourcesCollection.DeleteOne(filter); + + return true; + } AsyncReply Fetch(string id) { var filter = Builders.Filter.Eq("_id", new BsonObjectId(new ObjectId(id))); - var list = this.database.GetCollection("resources").Find(filter).ToList(); + var list = resourcesCollection.Find(filter).ToList(); if (list.Count == 0) return new AsyncReply(null); var document = list[0]; @@ -60,6 +107,11 @@ namespace Esiur.Stores.MongoDB var parents = document["parents"].AsBsonArray; var children = document["children"].AsBsonArray; + //var managers = document["managers"].AsBsonArray; + + var attributes = Parse(document["attributes"]).Then(x=> { + resource.Instance.SetAttributes(x as Structure); + }); var bag = new AsyncBag(); @@ -69,7 +121,8 @@ namespace Esiur.Stores.MongoDB bag.Add(ap); ap.Then((x) => { - resource.Instance.Parents.Add(x); + if (!resource.Instance.Parents.Contains(x)) + resource.Instance.Parents.Add(x); }); } @@ -80,28 +133,41 @@ namespace Esiur.Stores.MongoDB bag.Add(ac); ac.Then((x) => { - resource.Instance.Children.Add(x); + if (!resource.Instance.Children.Contains(x)) + resource.Instance.Children.Add(x); }); } + /* + // load managers + foreach(var m in managers) + { + IPermissionsManager pm = (IPermissionsManager)Activator.CreateInstance(Type.GetType(m["classname"].AsString)); + var sr = Parse(m["settings"]); + bag.Add(sr); + sr.Then((x) => + { + pm.Initialize((Structure)x, resource); + resource.Instance.Managers.Add(pm); + }); + } + */ + // Load values var values = document["values"].AsBsonDocument; foreach (var v in values) { -#if NETSTANDARD1_5 - var pi = resource.GetType().GetTypeInfo().GetProperty(v.Name); -#else - var pi = resource.GetType().GetProperty(pt.Name); -#endif + - var av = Parse(v.Value); + var valueInfo = v.Value as BsonDocument; + + var av = Parse(valueInfo["value"]); bag.Add(av); av.Then((x) => { - if (pi.CanWrite) - pi.SetValue(resource, DC.CastConvert(x, pi.PropertyType)); + resource.Instance.LoadProperty(v.Name, (ulong)valueInfo["age"].AsInt64, valueInfo["modification"].ToUniversalTime(), x); }); } @@ -163,8 +229,13 @@ namespace Esiur.Stores.MongoDB return bag; } + else if (value.BsonType == BsonType.DateTime) + { + return new AsyncReply(value.ToUniversalTime()); + } else { + return new AsyncReply(value.RawValue); } } @@ -194,6 +265,8 @@ namespace Esiur.Stores.MongoDB public bool Put(IResource resource) { + var attrs = resource.Instance.GetAttributes(); + foreach (var kv in resources) if (kv.Value == resource) { @@ -203,6 +276,7 @@ namespace Esiur.Stores.MongoDB var parents = new BsonArray(); var children = new BsonArray(); + var template = resource.Instance.Template; foreach (IResource c in resource.Instance.Children) @@ -210,22 +284,13 @@ namespace Esiur.Stores.MongoDB foreach (IResource p in resource.Instance.Parents) parents.Add(p.Instance.Link); + - var document = new BsonDocument - { - { "parents", parents }, - { "children", children }, - { "classname", resource.GetType().AssemblyQualifiedName }, - { "name", resource.Instance.Name } - }; + var attrsDoc = ComposeStructure(attrs); + - var col = this.database.GetCollection("resources"); - - col.InsertOne(document); - - resource.Instance.Attributes["objectId"] = document["_id"].ToString(); - + var values = new BsonDocument(); foreach (var pt in template.Properties) @@ -236,19 +301,34 @@ namespace Esiur.Stores.MongoDB var pi = resource.GetType().GetProperty(pt.Name); #endif var rt = pi.GetValue(resource, null); - - values.Add(pt.Name, Compose(rt)); + + values.Add(pt.Name, + new BsonDocument { { "age", BsonValue.Create(resource.Instance.GetAge(pt.Index)) }, + { "modification", resource.Instance.GetModificationDate(pt.Index) }, + { "value", Compose(rt) } }); } - var filter = Builders.Filter.Eq("_id", document["_id"]); - var update = Builders.Update - .Set("values", values); +// var filter = Builders.Filter.Eq("_id", document["_id"]); +// var update = Builders.Update +// .Set("values", values); +// col.UpdateOne(filter, update); - col.UpdateOne(filter, update); - //document.Add("values", values); + var document = new BsonDocument + { + { "parents", parents }, + { "children", children }, + { "attributes", attrsDoc }, + { "classname", resource.GetType().FullName + "," + resource.GetType().GetTypeInfo().Assembly.GetName().Name }, + { "name", resource.Instance.Name }, + { "values", values } + }; + + + resourcesCollection.InsertOne(document); + + resource.Instance.Attributes["objectId"] = document["_id"].ToString(); - //col.ReplaceOne(document, document); return true; } @@ -356,17 +436,19 @@ namespace Esiur.Stores.MongoDB { var filter = new BsonDocument(); - var list = this.database.GetCollection("resources").Find(filter).ToList(); + var list = resourcesCollection.Find(filter).ToList(); + Console.WriteLine(list.Count); // if (list.Count == 0) // return new AsyncBag(new IResource[0]); var bag = new AsyncBag(); - foreach (var r in list) + for(var i = 0; i < list.Count; i++) { - bag.Add(Get("id/" + r["_id"].AsObjectId.ToString())); + Console.WriteLine("Loading {0}/{1}", i, list.Count); + bag.Add(Get("id/" + list[i]["_id"].AsObjectId.ToString())); } bag.Seal(); @@ -392,6 +474,8 @@ namespace Esiur.Stores.MongoDB public void SaveResource(IResource resource) { + var attrs = resource.Instance.GetAttributes(); + var parents = new BsonArray(); var children = new BsonArray(); var template = resource.Instance.Template; @@ -401,6 +485,7 @@ namespace Esiur.Stores.MongoDB foreach (IResource p in resource.Instance.Parents) parents.Add(p.Instance.Link); + var values = new BsonDocument(); @@ -413,27 +498,181 @@ namespace Esiur.Stores.MongoDB #endif var rt = pi.GetValue(resource, null); - values.Add(pt.Name, Compose(rt)); + values.Add(pt.Name, + new BsonDocument { { "age", BsonValue.Create(resource.Instance.GetAge(pt.Index)) }, + { "modification", resource.Instance.GetModificationDate(pt.Index) }, + { "value", Compose(rt) } }); + } + var attrsDoc = ComposeStructure(attrs); + var document = new BsonDocument { { "parents", parents }, { "children", children }, - { "classname", resource.GetType().AssemblyQualifiedName }, + {"attributes", attrsDoc }, + { "classname", resource.GetType().FullName + "," + resource.GetType().GetTypeInfo().Assembly.GetName().Name }, { "name", resource.Instance.Name }, { "_id", new BsonObjectId(new ObjectId(resource.Instance.Attributes["objectId"].ToString())) }, {"values", values } }; - var col = this.database.GetCollection("resources"); var filter = Builders.Filter.Eq("_id", document["_id"]); + + /* var update = Builders.Update .Set("values", values); - col.UpdateOne(filter, update); + var update = Builders.Update.Set("values", values).Set("parents", parents; + col.UpdateOne(filter, update); + + */ + + resourcesCollection.ReplaceOne(filter, document); + } + + public AsyncReply GetPropertyRecordByAge(IResource resource, string propertyName, ulong fromAge, ulong toAge) + { + var objectId = resource.Instance.Attributes["objectId"].ToString(); + + var record = this.database.GetCollection("record_" + objectId); + var builder = Builders.Filter; + + var filter = builder.Gte("age", fromAge) & builder.Lte("age", toAge) & builder.Eq("property", propertyName); + + var reply = new AsyncReply(); + + record.FindAsync(filter).ContinueWith((x) => + { + var values = ((Task>)x).Result.ToList(); + + var bag = new AsyncBag(); + + foreach(var v in values) + bag.Add(Parse(v["value"])); + + bag.Seal(); + + bag.Then((results) => + { + var list = new List(); + for(var i = 0; i < results.Length; i++) + list.Add(new PropertyValue(results[i], (ulong)values[i]["age"].AsInt64, values[i]["date"].ToUniversalTime())); + + reply.Trigger(list.ToArray()); + }); + + }); + + return reply; + } + + public AsyncReply GetPropertyRecordByDate(IResource resource, string propertyName, DateTime fromDate, DateTime toDate) + { + var objectId = resource.Instance.Attributes["objectId"].ToString(); + + var record = this.database.GetCollection("record_" + objectId); + var builder = Builders.Filter; + + var filter = builder.Gte("date", fromDate) & builder.Lte("date", toDate) & builder.Eq("property", propertyName); + + var reply = new AsyncReply(); + + record.FindAsync(filter).ContinueWith((x) => + { + var values = ((Task>)x).Result.ToList(); + + var bag = new AsyncBag(); + + foreach (var v in values) + bag.Add(Parse(v["value"])); + + bag.Seal(); + + bag.Then((results) => + { + var list = new List(); + for (var i = 0; i < results.Length; i++) + list.Add(new PropertyValue(results[i], (ulong)values[i]["age"].AsInt64, values[i]["date"].ToUniversalTime())); + + reply.Trigger(list.ToArray()); + }); + + }); + + return reply; + } + + AsyncReply> GetRecordByAge(IResource resource, ulong fromAge, ulong toAge) + { + var properties = resource.Instance.Template.Properties.Where(x => x.Storage == StorageMode.Recordable).ToList(); + + var reply = new AsyncReply>(); + + AsyncBag bag = new AsyncBag(); + + foreach (var p in properties) + bag.Add(GetPropertyRecordByAge(resource, p.Name, fromAge, toAge)); + + bag.Seal(); + + bag.Then(x => + { + var list = new KeyList(); + + for (var i = 0; i < x.Length; i++) + list.Add(properties[i], x[i]); + + reply.Trigger(list); + }); + + return reply; + } + + public AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate) + { + var properties = resource.Instance.Template.Properties.Where(x => x.Storage == StorageMode.Recordable).ToList(); + + var reply = new AsyncReply>(); + + AsyncBag bag = new AsyncBag(); + + foreach (var p in properties) + bag.Add(GetPropertyRecordByDate(resource, p.Name, fromDate, toDate)); + + bag.Seal(); + + bag.Then(x => + { + var list = new KeyList(); + + for (var i = 0; i < x.Length; i++) + list.Add(properties[i], x[i]); + + reply.Trigger(list); + }); + + return reply; + } + + public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + { + + + var objectId = resource.Instance.Attributes["objectId"].ToString(); + + var filter = Builders.Filter.Eq("_id", new BsonObjectId(new ObjectId(objectId))); + var update = Builders.Update + .Set("values." + propertyName, new BsonDocument { { "age", BsonValue.Create(age) }, + { "modification", dateTime }, + { "value", Compose(value) } }); + + resourcesCollection.UpdateOne(filter, update); + + return true; } } diff --git a/Esiur/Data/AutoList.cs b/Esiur/Data/AutoList.cs index e6426c7..e479adc 100644 --- a/Esiur/Data/AutoList.cs +++ b/Esiur/Data/AutoList.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; @@ -8,7 +32,7 @@ using System.Reflection; namespace Esiur.Data { - public class AutoList : IEnumerable + public class AutoList : IEnumerable { private readonly object syncRoot = new object(); @@ -45,6 +69,10 @@ namespace Esiur.Data list.Sort(comparer); } + public void Sort(Comparison comparison) + { + list.Sort(comparison); + } public IEnumerable Where(Func predicate) { @@ -80,9 +108,9 @@ namespace Esiur.Data /// /// Populate the list with items /// - public AutoList(T[] values) + public AutoList(ST state, T[] values) { - + this.state = state; #if NETSTANDARD1_5 removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())); #else @@ -167,12 +195,7 @@ namespace Esiur.Data { Remove((T)sender); } - - public IEnumerator GetEnumerator() - { - return list.GetEnumerator(); - } - + /// /// Clear the list /// @@ -249,5 +272,15 @@ namespace Esiur.Data return true; return false; } + + public IEnumerator GetEnumerator() + { + return ((IEnumerable)list).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)list).GetEnumerator(); + } } } diff --git a/Esiur/Data/BinaryList.cs b/Esiur/Data/BinaryList.cs index 8e669fa..86e2f51 100644 --- a/Esiur/Data/BinaryList.cs +++ b/Esiur/Data/BinaryList.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Data/Codec.cs b/Esiur/Data/Codec.cs index c0836ca..d8ff15b 100644 --- a/Esiur/Data/Codec.cs +++ b/Esiur/Data/Codec.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Text; using Esiur.Misc; @@ -9,6 +33,7 @@ using Esiur.Net.IIP; using Esiur.Resource; using System.Linq; using System.Reflection; +using Esiur.Resource.Template; namespace Esiur.Data { @@ -98,13 +123,13 @@ namespace Esiur.Data public static byte[] ComposeStructureArray(Structure[] structures, DistributedConnection connection, bool prependLength = false) { if (structures == null || structures?.Length == 0) - return new byte[0]; - + return prependLength ? new byte[] { 0, 0, 0, 0 } : new byte[0]; + var rt = new BinaryList(); var comparsion = StructureComparisonResult.Structure; rt.Append((byte)comparsion); - rt.Append(ComposeStructure(structures[0], connection)); + rt.Append(ComposeStructure(structures[0], connection, true, true, true)); for (var i = 1; i < structures.Length; i++) { @@ -112,11 +137,11 @@ namespace Esiur.Data rt.Append((byte)comparsion); if (comparsion == StructureComparisonResult.Structure) - rt.Append(ComposeStructure(structures[i], connection)); + rt.Append(ComposeStructure(structures[i], connection, true, true, true)); else if (comparsion == StructureComparisonResult.StructureSameKeys) - rt.Append(ComposeStructure(structures[i], connection, false)); + rt.Append(ComposeStructure(structures[i], connection, false, true, true)); else if (comparsion == StructureComparisonResult.StructureSameTypes) - rt.Append(ComposeStructure(structures[i], connection, false, false)); + rt.Append(ComposeStructure(structures[i], connection, false, false, true)); } if (prependLength) @@ -147,18 +172,19 @@ namespace Esiur.Data var result = (StructureComparisonResult)data[offset++]; AsyncReply previous = null; - string[] previousKeys = null; - DataType[] previousTypes = 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); - cs += 4; - previous = ParseStructure(data, offset, cs, connection, out previousKeys, out previousTypes); + offset += 4; + previous = ParseStructure(data, offset, cs, connection, out metadata); offset += cs; } @@ -174,22 +200,22 @@ namespace Esiur.Data else if (result == StructureComparisonResult.Structure) { uint cs = data.GetUInt32(offset); - cs += 4; - previous = ParseStructure(data, offset, cs, connection, out previousKeys, out previousTypes); + 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); - cs += 4; - previous = ParseStructure(data, offset, cs, connection, out previousKeys, out previousTypes, previousKeys); + offset += 4; + previous = ParseStructure(data, offset, cs, connection, out metadata, metadata.Keys); offset += cs; } else if (result == StructureComparisonResult.StructureSameTypes) { uint cs = data.GetUInt32(offset); - cs += 4; - previous = ParseStructure(data, offset, cs, connection, out previousKeys, out previousTypes, previousKeys, previousTypes); + offset += 4; + previous = ParseStructure(data, offset, cs, connection, out metadata, metadata.Keys, metadata.Types); offset += cs; } @@ -243,9 +269,8 @@ namespace Esiur.Data /// Value public static AsyncReply ParseStructure(byte[] data, uint offset, uint contentLength, DistributedConnection connection) { - string[] pk; - DataType[] pt; - return ParseStructure(data, offset, contentLength, connection, out pk, out pt); + Structure.StructureMetadata metadata; + return ParseStructure(data, offset, contentLength, connection, out metadata); } /// @@ -260,7 +285,7 @@ namespace Esiur.Data /// 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 string[] parsedKeys, out DataType[] parsedTypes, string[] keys = null, DataType[] types = null) + 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(); @@ -293,8 +318,8 @@ namespace Esiur.Data uint rt; bag.Add(Codec.Parse(data, offset, out rt, connection)); - length -= rt + 1; - offset += rt + 1; + length -= rt; + offset += rt; } } else @@ -324,8 +349,8 @@ namespace Esiur.Data reply.Trigger(s); }); - parsedKeys = keylist.ToArray(); - parsedTypes = typelist.ToArray(); + metadata = new Structure.StructureMetadata() { Keys = keylist.ToArray(), Types = typelist.ToArray() }; + return reply; } @@ -544,7 +569,6 @@ namespace Esiur.Data { Null, Distributed, - DistributedSameClass, Local, Same } @@ -585,21 +609,12 @@ namespace Esiur.Data { if (next == null) return ResourceComparisonResult.Null; - - if (next == initial) + else if (next == initial) return ResourceComparisonResult.Same; - - if (IsLocalResource(next, connection)) + else if (IsLocalResource(next, connection)) return ResourceComparisonResult.Local; - - if (initial == null) + else return ResourceComparisonResult.Distributed; - - if (initial.Instance.Template.ClassId == next.Instance.Template.ClassId) - return ResourceComparisonResult.DistributedSameClass; - - return ResourceComparisonResult.Distributed; - } /// @@ -629,7 +644,7 @@ namespace Esiur.Data public static byte[] ComposeResourceArray(IResource[] resources, DistributedConnection connection, bool prependLength = false) { if (resources == null || resources?.Length == 0) - return new byte[0]; + return prependLength ? new byte[] { 0, 0, 0, 0 } : new byte[0]; var rt = new BinaryList(); var comparsion = Compare(null, resources[0], connection); @@ -639,26 +654,16 @@ namespace Esiur.Data if (comparsion == ResourceComparisonResult.Local) rt.Append((resources[0] as DistributedResource).Id); else if (comparsion == ResourceComparisonResult.Distributed) - { - rt.Append(resources[0].Instance.Template.ClassId); rt.Append(resources[0].Instance.Id); - } - + for (var i = 1; i < resources.Length; i++) { comparsion = Compare(resources[i - 1], resources[i], connection); rt.Append((byte)comparsion); if (comparsion == ResourceComparisonResult.Local) - rt.Append((resources[0] as DistributedResource).Id); + rt.Append((resources[i] as DistributedResource).Id); else if (comparsion == ResourceComparisonResult.Distributed) - { - rt.Append(resources[0].Instance.Template.ClassId); - rt.Append(resources[0].Instance.Id); - } - else if (comparsion == ResourceComparisonResult.DistributedSameClass) - { - rt.Append(resources[0].Instance.Id); - } + rt.Append(resources[i].Instance.Id); } if (prependLength) @@ -690,7 +695,6 @@ namespace Esiur.Data var result = (ResourceComparisonResult)data[offset++]; AsyncReply previous = null; - Guid previousGuid = Guid.Empty; if (result == ResourceComparisonResult.Null) previous = new AsyncReply(null); @@ -701,9 +705,7 @@ namespace Esiur.Data } else if (result == ResourceComparisonResult.Distributed) { - previousGuid = data.GetGuid(offset); - offset += 16; - //previous = connection.Fetch(previousGuid, data.GetUInt32(offset)); + previous = connection.Fetch(data.GetUInt32(offset)); offset += 4; } @@ -714,32 +716,30 @@ namespace Esiur.Data { result = (ResourceComparisonResult)data[offset++]; + AsyncReply current = null; + if (result == ResourceComparisonResult.Null) - previous = new AsyncReply(null); - //else if (result == ResourceComparisonResult.Same) - // reply.Add(previous); + { + current = new AsyncReply(null); + } + else if (result == ResourceComparisonResult.Same) + { + current = previous; + } else if (result == ResourceComparisonResult.Local) { - // overwrite previous - previous = Warehouse.Get(data.GetUInt32(offset)); + current = Warehouse.Get(data.GetUInt32(offset)); offset += 4; } else if (result == ResourceComparisonResult.Distributed) { - // overwrite previous - previousGuid = data.GetGuid(offset); - offset += 16; - //previous = connection.Fetch(previousGuid, data.GetUInt32(offset)); - offset += 4; - } - else if (result == ResourceComparisonResult.DistributedSameClass) - { - // overwrite previous - //previous = connection.Fetch(previousGuid, data.GetUInt32(offset)); + current = connection.Fetch(data.GetUInt32(offset)); offset += 4; } - reply.Add(previous); + reply.Add(current); + + previous = current; } reply.Seal(); @@ -763,7 +763,12 @@ namespace Esiur.Data 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); @@ -801,6 +806,180 @@ namespace Esiur.Data 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) + { + // 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.GetPropertyTemplate(index); + list.Add(pt, null); + var cs = DC.GetUInt32(data, 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.Append((byte)history.Keys.ElementAt(i).Index, + ComposePropertyValueArray(history.Values.ElementAt(i), connection, true)); + + if (prependLength) + rt.Insert(0, (uint)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 /// @@ -810,6 +989,11 @@ namespace Esiur.Data /// Array of bytes in the network byte order. public static byte[] Compose(object value, DistributedConnection connection, bool prependType = true) { + + if (value is Func) + value = (value as Func)(connection); + else if (value is DistributedPropertyContext) + value = (value as DistributedPropertyContext).Method(connection); var type = GetDataType(value, connection); var rt = new BinaryList(); @@ -873,11 +1057,15 @@ namespace Esiur.Data /// Sub-class type. /// Super-interface type. /// True, if implements . - private static bool ImplementsInterface(Type type, Type iface) + public static bool ImplementsInterface(Type type, Type iface) { + while (type != null) { + if (type == iface) + return true; + #if NETSTANDARD1_5 if (type.GetTypeInfo().GetInterfaces().Contains(iface)) return true; @@ -977,7 +1165,7 @@ namespace Esiur.Data } } else - return DataType.Void; + type = DataType.Void; if (isArray) diff --git a/Esiur/Data/DataConverter.cs b/Esiur/Data/DataConverter.cs index 714f742..8b477a4 100644 --- a/Esiur/Data/DataConverter.cs +++ b/Esiur/Data/DataConverter.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; @@ -225,14 +249,14 @@ namespace Esiur.Data UInt64 rt = 0; byte* p = (byte*)&rt; - *(p + 7) = data[0]; - *(p + 6) = data[1]; - *(p + 5) = data[2]; - *(p + 4) = data[3]; - *(p + 3) = data[4]; - *(p + 2) = data[5]; - *(p + 1) = data[6]; - *(p) = data[7]; + *(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; @@ -252,14 +276,14 @@ namespace Esiur.Data Int64 rt = 0; byte* p = (byte*)&rt; - *(p + 7) = data[0]; - *(p + 6) = data[1]; - *(p + 5) = data[2]; - *(p + 4) = data[3]; - *(p + 3) = data[4]; - *(p + 2) = data[5]; - *(p + 1) = data[6]; - *(p) = data[7]; + *(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; @@ -311,14 +335,14 @@ namespace Esiur.Data double rt = 0; byte* p = (byte*)&rt; - *(p + 7) = data[0]; - *(p + 6) = data[1]; - *(p + 5) = data[2]; - *(p + 4) = data[3]; - *(p + 3) = data[4]; - *(p + 2) = data[5]; - *(p + 1) = data[6]; - *(p) = data[7]; + *(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; } @@ -792,33 +816,48 @@ namespace Esiur.Data return rt.ToArray(); } - public static byte[] ToBytes(int value) + public static unsafe byte[] ToBytes(int value) { - byte[] ret = BitConverter.GetBytes(value); + var rt = new byte[4]; + byte* p = (byte*)&value; - Array.Reverse(ret); + rt[0] = *(p + 3); + rt[1] = *(p + 2); + rt[2] = *(p + 1); + rt[3] = *(p + 0); - return ret; + return rt; } - public static byte[] ToBytes(short value) + public static unsafe byte[] ToBytes(short value) { - byte[] ret = BitConverter.GetBytes(value); + var rt = new byte[2]; + byte* p = (byte*)&value; - Array.Reverse(ret); + rt[0] = *(p + 1); + rt[1] = *(p + 0); - return ret; + return rt; } - public static byte[] ToBytes(float value) + public static unsafe byte[] ToBytes(float value) + { - byte[] ret = BitConverter.GetBytes(value); + var rt = new byte[4]; - Array.Reverse(ret); + //float rt = 0; + byte* p = (byte*)&value; + rt[0] = *(p + 3); + rt[1] = *(p + 2); + rt[2] = *(p + 1); + rt[3] = *(p); - return ret; + return rt; } + + + /* public static byte[] ToBytes(Structure[] values) { @@ -888,58 +927,108 @@ namespace Esiur.Data return Encoding.UTF8.GetBytes(value); } - public static byte[] ToBytes(double value) + public unsafe static byte[] ToBytes(double value) { - byte[] ret = BitConverter.GetBytes(value); + var rt = new byte[8]; - Array.Reverse(ret); + byte* p = (byte*)&value; - return ret; + 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 byte[] ToBytes(long value) + public static unsafe byte[] ToBytes(long value) { - byte[] ret = BitConverter.GetBytes(value); + var rt = new byte[8]; - Array.Reverse(ret); + 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); + + return rt; - return ret; } - public static byte[] ToBytes(DateTime value) + public static unsafe byte[] ToBytes(DateTime value) { - byte[] ret = BitConverter.GetBytes(value.ToUniversalTime().Ticks); - Array.Reverse(ret); - return ret; + + 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); + + return rt; + } - public static byte[] ToBytes(ulong value) + public static unsafe byte[] ToBytes(ulong value) { - byte[] ret = BitConverter.GetBytes(value); + var rt = new byte[8]; - Array.Reverse(ret); + byte* p = (byte*)&value; - return ret; + 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 byte[] ToBytes(uint value) + public static unsafe byte[] ToBytes(uint value) { - byte[] ret = BitConverter.GetBytes(value); + var rt = new byte[4]; - Array.Reverse(ret); + byte* p = (byte*)&value; - return ret; + rt[0] = *(p + 3); + rt[1] = *(p + 2); + rt[2] = *(p + 1); + rt[3] = *(p + 0); + + return rt; } - public static byte[] ToBytes(ushort value) + public static unsafe byte[] ToBytes(ushort value) { - byte[] ret = BitConverter.GetBytes(value); + var rt = new byte[2]; - Array.Reverse(ret); + byte* p = (byte*)&value; - return ret; + rt[0] = *(p + 1); + rt[1] = *(p); + + return rt; } public static byte[] ToBytes(decimal value) diff --git a/Esiur/Data/DataType.cs b/Esiur/Data/DataType.cs index f61cb33..998c42c 100644 --- a/Esiur/Data/DataType.cs +++ b/Esiur/Data/DataType.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Data/KeyList.cs b/Esiur/Data/KeyList.cs index 5e2af0a..b91696b 100644 --- a/Esiur/Data/KeyList.cs +++ b/Esiur/Data/KeyList.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.IO; using System.Collections; using System.Security.Cryptography; @@ -17,10 +41,10 @@ namespace Esiur.Data private readonly object syncRoot = new object(); private Dictionary dic; - public delegate void Modified(KT key, T oldValue, T newValue); - public delegate void Added(T value); - public delegate void Removed(KT key, T value); - public delegate void Cleared(); + public delegate void Modified(KT key, T oldValue, T newValue, KeyList sender); + public delegate void Added(T value, KeyList sender); + public delegate void Removed(KT key, T value, KeyList sender); + public delegate void Cleared(KeyList sender); public event Modified OnModified; public event Removed OnRemoved; @@ -77,14 +101,14 @@ namespace Esiur.Data ((IDestructible)oldValue).OnDestroy -= ItemDestroyed; dic[key] = value; if (OnModified != null) - OnModified(key, oldValue, value); + OnModified(key, oldValue, value, this); } else { dic.Add(key, value); if (OnAdd != null) - OnAdd(value); + OnAdd(value, this); } } } @@ -136,7 +160,7 @@ namespace Esiur.Data dic.Clear(); if (OnCleared != null) - OnCleared(); + OnCleared(this); } public Dictionary.KeyCollection Keys @@ -167,7 +191,13 @@ namespace Esiur.Data dic.Remove(key); if (OnRemoved != null) - OnRemoved(key, value); + OnRemoved(key, value, this); + } + + public object Owner + { + get; + set; } public int Count @@ -187,13 +217,16 @@ namespace Esiur.Data return dic.ContainsValue(Value); } - public KeyList() + + public KeyList(object owner = null) { #if NETSTANDARD1_5 removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())); - #else +#else removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T))); - #endif +#endif + + this.Owner = owner; if (typeof(KT) == typeof(string)) dic = (Dictionary)(object)new Dictionary(StringComparer.OrdinalIgnoreCase); diff --git a/Esiur/Data/NotModified.cs b/Esiur/Data/NotModified.cs index 17710b2..0ae002c 100644 --- a/Esiur/Data/NotModified.cs +++ b/Esiur/Data/NotModified.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Data/PropertyValue.cs b/Esiur/Data/PropertyValue.cs new file mode 100644 index 0000000..8a52c57 --- /dev/null +++ b/Esiur/Data/PropertyValue.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Data +{ + public class PropertyValue + { + /// + /// Get or set the value. + /// + public object Value { get; set; } + /// + /// Get or set date of modification or occurrence. + /// + public DateTime Date { get; set; } + /// + /// Get or set property age. + /// + public ulong Age { get; set; } + + /// + /// Create an instance of PropertyValue. + /// + /// Value. + /// Age. + /// Date. + public PropertyValue(object value, ulong age, DateTime date) + { + Value = value; + Age = age; + Date = date; + } + } +} diff --git a/Esiur/Data/StringKeyList.cs b/Esiur/Data/StringKeyList.cs index 7104239..fd48a99 100644 --- a/Esiur/Data/StringKeyList.cs +++ b/Esiur/Data/StringKeyList.cs @@ -1,10 +1,35 @@ -using System; +/* + +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.IO; using System.Collections; using System.Collections.Generic; using System.Security.Cryptography; using System.Text; using System.Reflection; +using System.Linq; namespace Esiur.Data { @@ -64,15 +89,16 @@ namespace Esiur.Data { var key = Key.ToLower(); - if (OnModified != null) - OnModified(Key, value); + var toRemove = m_Variables.Where(x => x.Key.ToLower() == key); + foreach (var item in toRemove) + m_Variables.Remove(item); - foreach (var kv in m_Variables) - if (kv.Key.ToLower() == key) - m_Variables.Remove(kv); m_Variables.Add(new KeyValuePair(Key, value)); + + OnModified?.Invoke(Key, value); + } } diff --git a/Esiur/Data/Structure.cs b/Esiur/Data/Structure.cs index 946496a..dee4f71 100644 --- a/Esiur/Data/Structure.cs +++ b/Esiur/Data/Structure.cs @@ -1,4 +1,28 @@ -using System; +/* + +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; @@ -13,6 +37,12 @@ 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(); @@ -56,11 +86,11 @@ namespace Esiur.Data get { return syncRoot; } } - public string[] GetKeys() - { - return dic.Keys.ToArray(); - } - + public string[] GetKeys() => dic.Keys.ToArray();//GetKeys() + //{ + // return dic.Keys.ToArray(); + //} + public object this[string index] { get diff --git a/Esiur/Engine/AsyncBag.cs b/Esiur/Engine/AsyncBag.cs index 6b10b1f..8ac4f95 100644 --- a/Esiur/Engine/AsyncBag.cs +++ b/Esiur/Engine/AsyncBag.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; @@ -8,36 +32,54 @@ namespace Esiur.Engine { public class AsyncBag:AsyncReply { - Dictionary results = new Dictionary(); + //Dictionary results = new Dictionary(); + + List replies = new List(); + List results = new List(); + int count = 0; bool sealedBag = false; - public void Then(Action callback) + public AsyncBag Then(Action callback) { base.Then(new Action(o => callback((T[])o))); + return this; } public void Seal() { + if (sealedBag) + return; + sealedBag = true; if (results.Count == 0) Trigger(new T[0]); - for(var i = 0; i < results.Count; i++) + for (var i = 0; i < results.Count; i++) //foreach(var reply in results.Keys) - results.Keys.ElementAt(i).Then((r) => { - results[results.Keys.ElementAt(i)] = (T)r; + { + var k = replies[i];// results.Keys.ElementAt(i); + var index = i; + + k.Then((r) => + { + results[index] = (T)r; count++; if (count == results.Count) - Trigger(results.Values.ToArray()); + Trigger(results.ToArray()); }); + } } public void Add(AsyncReply reply) { if (!sealedBag) - results.Add(reply, default(T)); + { + results.Add(default(T)); + replies.Add(reply); + } + //results.Add(reply, default(T)); } public AsyncBag() diff --git a/Esiur/Engine/AsyncException.cs b/Esiur/Engine/AsyncException.cs new file mode 100644 index 0000000..ecc75a3 --- /dev/null +++ b/Esiur/Engine/AsyncException.cs @@ -0,0 +1,85 @@ +/* + +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.Generic; +using System.Text; + +namespace Esiur.Engine +{ + public enum ExceptionCode : ushort + { + HostNotReachable, + AccessDenied, + ResourceNotFound, + AttachDenied, + InvalidMethod, + InvokeDenied, + CreateDenied, + AddParentDenied, + AddChildDenied, + ViewAttributeDenied, + UpdateAttributeDenied, + StoreNotFound, + ParentNotFound, + ChildNotFound, + ResourceIsNotStore, + DeleteDenied, + DeleteFailed, + UpdateAttributeFailed, + GetAttributesFailed, + ClearAttributesFailed, + TemplateNotFound, + RenameDenied, + ClassNotFound, + MethodNotFound, + PropertyNotFound, + SetPropertyDenied, + ReadOnlyProperty + } + + public class AsyncException: Exception + { + + + AsyncReply.ErrorType type; + ExceptionCode code; + + public AsyncReply.ErrorType Type => type; + public ExceptionCode Code => code; + + public AsyncException(AsyncReply.ErrorType type, ushort code, string message) + : base(type == AsyncReply.ErrorType.Management ? ((ExceptionCode)code).ToString() : message) + { + this.type = type; + this.code = (ExceptionCode)code; + + } + + public override string ToString() + { + return code.ToString() + ": " + Message; + } + } +} diff --git a/Esiur/Engine/AsyncQueue.cs b/Esiur/Engine/AsyncQueue.cs index af26c5d..3900f50 100644 --- a/Esiur/Engine/AsyncQueue.cs +++ b/Esiur/Engine/AsyncQueue.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; @@ -12,9 +36,11 @@ namespace Esiur.Engine //Action callback; object queueLock = new object(); - public void Then(Action callback) + public AsyncQueue Then(Action callback) { base.Then(new Action(o => callback((T)o))); + + return this; } public void Add(AsyncReply reply) diff --git a/Esiur/Engine/AsyncReply.cs b/Esiur/Engine/AsyncReply.cs index 2baf7c6..6d4b822 100644 --- a/Esiur/Engine/AsyncReply.cs +++ b/Esiur/Engine/AsyncReply.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; @@ -8,12 +32,34 @@ namespace Esiur.Engine { public class AsyncReply { + public enum ErrorType + { + Management, + Exception + } + + public enum ProgressType + { + Execution, + Network, + } + protected List> callbacks = new List>(); protected object result; + + protected List> errorCallbacks = new List>(); + + protected List> progressCallbacks = new List>(); + + protected List> chunkCallbacks = new List>(); + object callbacksLock = new object(); - //bool fired = false; protected bool resultReady = false; + AsyncException exception; + + TaskCompletionSource tcs = new TaskCompletionSource(); + public bool Ready { @@ -25,40 +71,111 @@ namespace Esiur.Engine get { return result; } } - public void Then(Action callback) + public AsyncReply Then(Action callback) { callbacks.Add(callback); if (resultReady) callback(result); - // Trigger(this.result); + + return this; + } + + public AsyncReply Error(Action callback) + { + errorCallbacks.Add(callback); + + if (exception != null) + { + callback(exception); + tcs.SetException(exception); + } + + return this; + } + + public AsyncReply Progress(Action callback) + { + progressCallbacks.Add(callback); + return this; + } + + public AsyncReply Chunk(Action callback) + { + chunkCallbacks.Add(callback); + return this; } public void Trigger(object result) { - //if (!fired) - //{ - this.result = result; - resultReady = true; lock (callbacksLock) { + if (resultReady) + return; + + this.result = result; + resultReady = true; + foreach (var cb in callbacks) cb(result); - //callbacks.Clear(); + + tcs.TrySetResult(result); + + } + + } + + public void TriggerError(AsyncException exception) + { + if (resultReady) + return; + + this.exception = exception; + + + lock (callbacksLock) + { + foreach (var cb in errorCallbacks) + cb(exception); + } + + tcs.TrySetException(exception); + } + + public void TriggerProgress(ProgressType type, int value, int max) + { + if (resultReady) + return; + + lock (callbacksLock) + { + foreach (var cb in progressCallbacks) + cb(type, value, max); + + } + } + + public void TriggerChunk(object value) + { + if (resultReady) + return; + + lock (callbacksLock) + { + foreach (var cb in chunkCallbacks) + cb(value); + + } + } + + + public Task Task + { + get + { + return tcs.Task; } - /* - if (callback == null) - { - fireAtChance = true; - } - else - { - callback(result); - fired = true; - } - */ - //} } public AsyncReply() @@ -69,6 +186,7 @@ namespace Esiur.Engine public AsyncReply(object result) { resultReady = true; + tcs.SetResult(result); this.result = result; } } diff --git a/Esiur/Engine/AsyncReplyGeneric.cs b/Esiur/Engine/AsyncReplyGeneric.cs index 2649339..9546703 100644 --- a/Esiur/Engine/AsyncReplyGeneric.cs +++ b/Esiur/Engine/AsyncReplyGeneric.cs @@ -1,17 +1,44 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Esiur.Resource; +using System.Reflection; namespace Esiur.Engine { public class AsyncReply: AsyncReply { - public void Then(Action callback) + + public AsyncReply Then(Action callback) { base.Then(new Action(o => callback((T)o))); + return this; } public void Trigger(T result) @@ -24,6 +51,22 @@ namespace Esiur.Engine } + public new Task Task + { + get + { + return base.Task.ContinueWith((t) => + { + +#if NETSTANDARD1_5 + return (T)t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t); +#else + return (T)t.GetType().GetProperty("Result").GetValue(t); +#endif + }); + } + } + public AsyncReply(T result) : base(result) { diff --git a/Esiur/Engine/IDestructible.cs b/Esiur/Engine/IDestructible.cs index 28397e0..01c531d 100644 --- a/Esiur/Engine/IDestructible.cs +++ b/Esiur/Engine/IDestructible.cs @@ -1,4 +1,27 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Engine/LogType.cs b/Esiur/Engine/LogType.cs index 063b68b..7c60bd3 100644 --- a/Esiur/Engine/LogType.cs +++ b/Esiur/Engine/LogType.cs @@ -1,4 +1,29 @@ -using System; + +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Esiur.csproj b/Esiur/Esiur.csproj index f125026..0750132 100644 --- a/Esiur/Esiur.csproj +++ b/Esiur/Esiur.csproj @@ -6,7 +6,7 @@ Ahmed Kh. Zamil https://github.com/esiur/esiur-dotnet/blob/master/LICENSE http://www.esiur.com - True + False 1.0.0 https://github.com/esiur/esiur-dotnet Ahmed Kh. Zamil diff --git a/Esiur/Misc/Global.cs b/Esiur/Misc/Global.cs index bb39d17..da593e8 100644 --- a/Esiur/Misc/Global.cs +++ b/Esiur/Misc/Global.cs @@ -1,3 +1,27 @@ +/* + +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.IO; using System.Collections; @@ -31,7 +55,7 @@ namespace Esiur.Misc public delegate void LogEvent(string service, LogType type, string message); - public static LogEvent SystemLog; + public static event LogEvent SystemLog; static Random random = new Random(); @@ -88,8 +112,7 @@ namespace Esiur.Misc //if (type != LogType.Debug) Console.WriteLine(service + " " + message); - if (SystemLog != null) - SystemLog(service, type, message); + SystemLog?.Invoke(service, type, message); } /* @@ -398,8 +421,8 @@ namespace Esiur.Misc Enumerable.Repeat(chars, length) .Select(s => s[random.Next(s.Length)]) .ToArray()); - if (result.Length < length) - Console.WriteLine(); + //if (result.Length < length) + // Console.WriteLine(); return result; /* int len = 0; diff --git a/Esiur/Net/DataLink/PacketFilter.cs b/Esiur/Net/DataLink/PacketFilter.cs index 4c96c26..753930d 100644 --- a/Esiur/Net/DataLink/PacketFilter.cs +++ b/Esiur/Net/DataLink/PacketFilter.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Net/DataLink/PacketServer.cs b/Esiur/Net/DataLink/PacketServer.cs index cfe7047..072bff5 100644 --- a/Esiur/Net/DataLink/PacketServer.cs +++ b/Esiur/Net/DataLink/PacketServer.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Net/DataLink/PacketSource.cs b/Esiur/Net/DataLink/PacketSource.cs index 490e7a0..30c3bd3 100644 --- a/Esiur/Net/DataLink/PacketSource.cs +++ b/Esiur/Net/DataLink/PacketSource.cs @@ -1,4 +1,28 @@ -using Esiur.Net.Packets; +/* + +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 Esiur.Net.Packets; using System; using System.Collections.Generic; using System.Linq; diff --git a/Esiur/Net/HTTP/HTTPConnection.cs b/Esiur/Net/HTTP/HTTPConnection.cs index c654078..77375f8 100644 --- a/Esiur/Net/HTTP/HTTPConnection.cs +++ b/Esiur/Net/HTTP/HTTPConnection.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Diagnostics; using System.IO; using System.Net.Sockets; diff --git a/Esiur/Net/HTTP/HTTPFilter.cs b/Esiur/Net/HTTP/HTTPFilter.cs index deb1196..64d6fa9 100644 --- a/Esiur/Net/HTTP/HTTPFilter.cs +++ b/Esiur/Net/HTTP/HTTPFilter.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Diagnostics; using System.IO; using System.Net.Sockets; diff --git a/Esiur/Net/HTTP/HTTPServer.cs b/Esiur/Net/HTTP/HTTPServer.cs index 1ed322b..6e1819d 100644 --- a/Esiur/Net/HTTP/HTTPServer.cs +++ b/Esiur/Net/HTTP/HTTPServer.cs @@ -1,3 +1,27 @@ +/* + +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.Diagnostics; using System.IO; @@ -157,7 +181,7 @@ namespace Esiur.Net.HTTP protected override void ClientDisconnected(HTTPConnection sender) { - Console.WriteLine("OUT: " + this.Connections.Count); + //Console.WriteLine("OUT: " + this.Connections.Count); foreach (IResource resource in Instance.Children) { @@ -369,7 +393,7 @@ namespace Esiur.Net.HTTP //sender.SessionEnded += SessionExpired; sender.SetParent(this); - Console.WriteLine("IN: " + this.Connections.Count); + //Console.WriteLine("IN: " + this.Connections.Count); foreach (IResource resource in Instance.Children) { diff --git a/Esiur/Net/HTTP/HTTPSession.cs b/Esiur/Net/HTTP/HTTPSession.cs index 075bb01..3b56eb8 100644 --- a/Esiur/Net/HTTP/HTTPSession.cs +++ b/Esiur/Net/HTTP/HTTPSession.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Diagnostics; using System.IO; using System.Net.Sockets; @@ -61,7 +85,7 @@ namespace Esiur.Net.HTTP OnEnd?.Invoke(this); } - void VariablesModified(string key, object oldValue, object newValue) + void VariablesModified(string key, object oldValue, object newValue, KeyList sender) { OnModify?.Invoke(this, key, oldValue, newValue); } diff --git a/Esiur/Net/HTTP/IIPoWS.cs b/Esiur/Net/HTTP/IIPoWS.cs index 1433060..f7ee919 100644 --- a/Esiur/Net/HTTP/IIPoWS.cs +++ b/Esiur/Net/HTTP/IIPoWS.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; @@ -27,11 +51,21 @@ namespace Esiur.Net.HTTP var httpServer = sender.Parent; var iipServer = r as DistributedServer; var tcpSocket = sender.Unassign(); + if (tcpSocket == null) + return; + var wsSocket = new WSSocket(tcpSocket); - httpServer.Connections.Remove(sender); + httpServer.RemoveConnection(sender); + + //httpServer.Connections.Remove(sender); var iipConnection = new DistributedConnection(); - iipConnection.Server = iipServer; + // iipConnection.OnReady += IipConnection_OnReady; +// iipConnection.Server = iipServer; + // iipConnection.Assign(wsSocket); + + iipServer.AddConnection(iipConnection); iipConnection.Assign(wsSocket); + wsSocket.Begin(); } }); @@ -41,6 +75,11 @@ namespace Esiur.Net.HTTP return false; } + private void IipConnection_OnReady(DistributedConnection sender) + { + Warehouse.Put(sender, sender.RemoteUsername, null, sender.Server); + } + public override AsyncReply Trigger(ResourceTrigger trigger) { return new AsyncReply(true); diff --git a/Esiur/Net/IIP/DistributedConnection.cs b/Esiur/Net/IIP/DistributedConnection.cs index 713b911..625c72e 100644 --- a/Esiur/Net/IIP/DistributedConnection.cs +++ b/Esiur/Net/IIP/DistributedConnection.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Text; using System.Net; @@ -14,6 +38,7 @@ using Esiur.Security.Authority; using Esiur.Resource.Template; using System.Linq; using System.Diagnostics; +using static Esiur.Net.Packets.IIPPacket; namespace Esiur.Net.IIP { @@ -35,35 +60,36 @@ namespace Esiur.Net.IIP IIPPacket packet = new IIPPacket(); IIPAuthPacket authPacket = new IIPAuthPacket(); - byte[] sessionId; - AuthenticationType hostType; - string domain; - string localUsername, remoteUsername; - byte[] localPassword; + Session session; + byte[] localPassword; byte[] localNonce, remoteNonce; bool ready, readyToEstablish; DateTime loginDate; - KeyList variables = new KeyList(); /// /// Local username to authenticate ourselves. /// - public string LocalUsername { get; set; } + public string LocalUsername => session.LocalAuthentication.Username;// { get; set; } /// /// Peer's username. /// - public string RemoteUsername { get; set; } + public string RemoteUsername => session.RemoteAuthentication.Username;// { get; set; } /// /// Working domain. /// - public string Domain { get { return domain; } } + //public string Domain { get { return domain; } } + /// + /// The session related to this connection. + /// + public Session Session => session; + /// /// Distributed server responsible for this connection, usually for incoming connections. /// @@ -73,14 +99,50 @@ namespace Esiur.Net.IIP set; } + public bool Remove(IResource resource) + { + // nothing to do + return true; + } + /// /// Send data to the other end as parameters /// /// Values will be converted to bytes then sent. internal void SendParams(params object[] values) { - var ar = BinaryList.ToBytes(values); - Send(ar); + var data = BinaryList.ToBytes(values); + + if (ready) + { + var cmd = (IIPPacketCommand)(data[0] >> 6); + + if (cmd == IIPPacketCommand.Event) + { + var evt = (IIPPacketEvent)(data[0] & 0x3f); + //Console.Write("Sent: " + cmd.ToString() + " " + evt.ToString()); + } + else if (cmd == IIPPacketCommand.Report) + { + var r = (IIPPacketReport)(data[0] & 0x3f); + //Console.Write("Sent: " + cmd.ToString() + " " + r.ToString()); + + } + else + { + var act = (IIPPacketAction)(data[0] & 0x3f); + //Console.Write("Sent: " + cmd.ToString() + " " + act.ToString()); + + } + + //foreach (var param in values) + // Console.Write(", " + param); + + //Console.WriteLine(); + } + + + Send(data); //StackTrace stackTrace = new StackTrace(; @@ -104,13 +166,7 @@ namespace Esiur.Net.IIP /// /// KeyList to store user variables related to this connection. /// - public KeyList Variables - { - get - { - return variables; - } - } + public KeyList Variables { get; } = new KeyList(); /// /// IResource interface. @@ -129,12 +185,17 @@ namespace Esiur.Net.IIP { base.Assign(socket); + session.RemoteAuthentication.Source.Attributes.Add(SourceAttributeType.IPv4, socket.RemoteEndPoint.Address); + session.RemoteAuthentication.Source.Attributes.Add(SourceAttributeType.Port, socket.RemoteEndPoint.Port); + session.LocalAuthentication.Source.Attributes.Add(SourceAttributeType.IPv4, socket.LocalEndPoint.Address); + session.LocalAuthentication.Source.Attributes.Add(SourceAttributeType.Port, socket.LocalEndPoint.Port); - if (hostType == AuthenticationType.Client) + if (session.LocalAuthentication.Type == AuthenticationType.Client) { // declare (Credentials -> No Auth, No Enctypt) - var un = DC.ToBytes(localUsername); - var dmn = DC.ToBytes(domain); + + var un = DC.ToBytes(session.LocalAuthentication.Username); + var dmn = DC.ToBytes(session.LocalAuthentication.Domain);// domain); if (socket.State == SocketState.Established) { @@ -160,10 +221,14 @@ namespace Esiur.Net.IIP /// Password. public DistributedConnection(ISocket socket, string domain, string username, string password) { + this.session = new Session( new ClientAuthentication() + , new HostAuthentication()); //Instance.Name = Global.GenerateCode(12); - this.hostType = AuthenticationType.Client; - this.domain = domain; - this.localUsername = username; + //this.hostType = AuthenticationType.Client; + //this.domain = domain; + //this.localUsername = username; + session.LocalAuthentication.Domain = domain; + session.LocalAuthentication.Username = username; this.localPassword = DC.ToBytes(password); init(); @@ -178,6 +243,7 @@ namespace Esiur.Net.IIP { //myId = Global.GenerateCode(12); // localParams.Host = DistributedParameters.HostType.Host; + session = new Session(new HostAuthentication(), new ClientAuthentication()); init(); } @@ -185,7 +251,7 @@ namespace Esiur.Net.IIP public string Link(IResource resource) { - if (resource is DistributedConnection) + if (resource is DistributedResource) { var r = resource as DistributedResource; if (r.Instance.Store == this) @@ -203,7 +269,7 @@ namespace Esiur.Net.IIP if (x.Type == DistributedResourceQueueItem.DistributedResourceQueueItemType.Event) x.Resource._EmitEventByIndex(x.Index, (object[])x.Value); else - x.Resource.UpdatePropertyByIndex(x.Index, x.Value); + x.Resource._UpdatePropertyByIndex(x.Index, x.Value); }); var r = new Random(); @@ -213,279 +279,420 @@ namespace Esiur.Net.IIP + private uint processPacket(byte[] msg, uint offset, uint ends, NetworkBuffer data, int chunkId) + { + var packet = new IIPPacket(); + + + + // packets++; + + if (ready) + { + var rt = packet.Parse(msg, offset, ends); + //Console.WriteLine("Rec: " + chunkId + " " + packet.ToString()); + + /* + if (packet.Command == IIPPacketCommand.Event) + Console.WriteLine("Rec: " + packet.Command.ToString() + " " + packet.Event.ToString()); + else if (packet.Command == IIPPacketCommand.Report) + Console.WriteLine("Rec: " + packet.Command.ToString() + " " + packet.Report.ToString()); + else + Console.WriteLine("Rec: " + packet.Command.ToString() + " " + packet.Action.ToString() + " " + packet.ResourceId + " " + offset + "/" + ends); + */ + + + //packs.Add(packet.Command.ToString() + " " + packet.Action.ToString() + " " + packet.Event.ToString()); + + //if (packs.Count > 1) + // Console.WriteLine("P2"); + + if (rt <= 0) + { + var size = ends - offset; + data.HoldFor(msg, offset, size, size + (uint)(-rt)); + return ends; + } + else + { + offset += (uint)rt; + + if (packet.Command == IIPPacket.IIPPacketCommand.Event) + { + switch (packet.Event) + { + case IIPPacket.IIPPacketEvent.ResourceReassigned: + IIPEventResourceReassigned(packet.ResourceId, packet.NewResourceId); + break; + case IIPPacket.IIPPacketEvent.ResourceDestroyed: + IIPEventResourceDestroyed(packet.ResourceId); + break; + case IIPPacket.IIPPacketEvent.PropertyUpdated: + IIPEventPropertyUpdated(packet.ResourceId, packet.MethodIndex, packet.Content); + break; + case IIPPacket.IIPPacketEvent.EventOccurred: + IIPEventEventOccurred(packet.ResourceId, packet.MethodIndex, packet.Content); + break; + + case IIPPacketEvent.ChildAdded: + IIPEventChildAdded(packet.ResourceId, packet.ChildId); + break; + case IIPPacketEvent.ChildRemoved: + IIPEventChildRemoved(packet.ResourceId, packet.ChildId); + break; + case IIPPacketEvent.Renamed: + IIPEventRenamed(packet.ResourceId, packet.Content); + break; + case IIPPacketEvent.AttributesUpdated: + IIPEventAttributesUpdated(packet.ResourceId, packet.Content); + break; + } + } + else if (packet.Command == IIPPacket.IIPPacketCommand.Request) + { + switch (packet.Action) + { + // Manage + case IIPPacket.IIPPacketAction.AttachResource: + IIPRequestAttachResource(packet.CallbackId, packet.ResourceId); + break; + case IIPPacket.IIPPacketAction.ReattachResource: + IIPRequestReattachResource(packet.CallbackId, packet.ResourceId, packet.ResourceAge); + break; + case IIPPacket.IIPPacketAction.DetachResource: + IIPRequestDetachResource(packet.CallbackId, packet.ResourceId); + break; + case IIPPacket.IIPPacketAction.CreateResource: + IIPRequestCreateResource(packet.CallbackId, packet.StoreId, packet.ResourceId, packet.Content); + break; + case IIPPacket.IIPPacketAction.DeleteResource: + IIPRequestDeleteResource(packet.CallbackId, packet.ResourceId); + break; + case IIPPacketAction.AddChild: + IIPRequestAddChild(packet.CallbackId, packet.ResourceId, packet.ChildId); + break; + case IIPPacketAction.RemoveChild: + IIPRequestRemoveChild(packet.CallbackId, packet.ResourceId, packet.ChildId); + break; + case IIPPacketAction.RenameResource: + IIPRequestRenameResource(packet.CallbackId, packet.ResourceId, packet.Content); + break; + + // Inquire + case IIPPacket.IIPPacketAction.TemplateFromClassName: + IIPRequestTemplateFromClassName(packet.CallbackId, packet.ClassName); + break; + case IIPPacket.IIPPacketAction.TemplateFromClassId: + IIPRequestTemplateFromClassId(packet.CallbackId, packet.ClassId); + break; + case IIPPacket.IIPPacketAction.TemplateFromResourceId: + IIPRequestTemplateFromResourceId(packet.CallbackId, packet.ResourceId); + break; + case IIPPacketAction.QueryLink: + IIPRequestQueryResources(packet.CallbackId, packet.ResourceLink); + break; + + case IIPPacketAction.ResourceChildren: + IIPRequestResourceChildren(packet.CallbackId, packet.ResourceId); + break; + case IIPPacketAction.ResourceParents: + IIPRequestResourceParents(packet.CallbackId, packet.ResourceId); + break; + + case IIPPacket.IIPPacketAction.ResourceHistory: + IIPRequestInquireResourceHistory(packet.CallbackId, packet.ResourceId, packet.FromDate, packet.ToDate); + break; + + // Invoke + case IIPPacket.IIPPacketAction.InvokeFunction: + IIPRequestInvokeFunction(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content); + break; + case IIPPacket.IIPPacketAction.GetProperty: + IIPRequestGetProperty(packet.CallbackId, packet.ResourceId, packet.MethodIndex); + break; + case IIPPacket.IIPPacketAction.GetPropertyIfModified: + IIPRequestGetPropertyIfModifiedSince(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.ResourceAge); + break; + case IIPPacket.IIPPacketAction.SetProperty: + IIPRequestSetProperty(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content); + break; + + // Attribute + case IIPPacketAction.GetAllAttributes: + IIPRequestGetAttributes(packet.CallbackId, packet.ResourceId, packet.Content, true); + break; + case IIPPacketAction.UpdateAllAttributes: + IIPRequestUpdateAttributes(packet.CallbackId, packet.ResourceId, packet.Content, true); + break; + case IIPPacketAction.ClearAllAttributes: + IIPRequestClearAttributes(packet.CallbackId, packet.ResourceId, packet.Content, true); + break; + case IIPPacketAction.GetAttributes: + IIPRequestGetAttributes(packet.CallbackId, packet.ResourceId, packet.Content, false); + break; + case IIPPacketAction.UpdateAttributes: + IIPRequestUpdateAttributes(packet.CallbackId, packet.ResourceId, packet.Content, false); + break; + case IIPPacketAction.ClearAttributes: + IIPRequestClearAttributes(packet.CallbackId, packet.ResourceId, packet.Content, false); + break; + } + } + else if (packet.Command == IIPPacket.IIPPacketCommand.Reply) + { + switch (packet.Action) + { + // Manage + case IIPPacket.IIPPacketAction.AttachResource: + IIPReply(packet.CallbackId, packet.ClassId, packet.ResourceAge, packet.ResourceLink, packet.Content); + break; + + case IIPPacket.IIPPacketAction.ReattachResource: + IIPReply(packet.CallbackId, packet.ResourceAge, packet.Content); + + break; + case IIPPacket.IIPPacketAction.DetachResource: + IIPReply(packet.CallbackId); + break; + + case IIPPacket.IIPPacketAction.CreateResource: + IIPReply(packet.CallbackId, packet.ResourceId); + break; + + case IIPPacket.IIPPacketAction.DeleteResource: + case IIPPacketAction.AddChild: + case IIPPacketAction.RemoveChild: + case IIPPacketAction.RenameResource: + IIPReply(packet.CallbackId); + break; + + // Inquire + + case IIPPacket.IIPPacketAction.TemplateFromClassName: + case IIPPacket.IIPPacketAction.TemplateFromClassId: + case IIPPacket.IIPPacketAction.TemplateFromResourceId: + IIPReply(packet.CallbackId, ResourceTemplate.Parse(packet.Content)); + break; + + case IIPPacketAction.QueryLink: + case IIPPacketAction.ResourceChildren: + case IIPPacketAction.ResourceParents: + case IIPPacketAction.ResourceHistory: + IIPReply(packet.CallbackId, packet.Content); + break; + + // Invoke + case IIPPacket.IIPPacketAction.InvokeFunction: + IIPReplyInvoke(packet.CallbackId, packet.Content); + + break; + case IIPPacket.IIPPacketAction.GetProperty: + IIPReply(packet.CallbackId, packet.Content); + break; + + case IIPPacket.IIPPacketAction.GetPropertyIfModified: + IIPReply(packet.CallbackId, packet.Content); + break; + case IIPPacket.IIPPacketAction.SetProperty: + IIPReply(packet.CallbackId); + break; + + // Attribute + case IIPPacketAction.GetAllAttributes: + case IIPPacketAction.GetAttributes: + IIPReply(packet.CallbackId, packet.Content); + break; + + case IIPPacketAction.UpdateAllAttributes: + case IIPPacketAction.UpdateAttributes: + case IIPPacketAction.ClearAllAttributes: + case IIPPacketAction.ClearAttributes: + IIPReply(packet.CallbackId); + break; + + } + + } + else if (packet.Command == IIPPacketCommand.Report) + { + switch (packet.Report) + { + case IIPPacketReport.ManagementError: + IIPReportError(packet.CallbackId, AsyncReply.ErrorType.Management, packet.ErrorCode, null); + break; + case IIPPacketReport.ExecutionError: + IIPReportError(packet.CallbackId, AsyncReply.ErrorType.Exception, packet.ErrorCode, packet.ErrorMessage); + break; + case IIPPacketReport.ProgressReport: + IIPReportProgress(packet.CallbackId, AsyncReply.ProgressType.Execution, packet.ProgressValue, packet.ProgressMax); + break; + case IIPPacketReport.ChunkStream: + IIPReportChunk(packet.CallbackId, packet.Content); + + break; + } + } + } + } + + else + { + var rt = authPacket.Parse(msg, offset, ends); + + //Console.WriteLine(session.LocalAuthentication.Type.ToString() + " " + offset + " " + ends + " " + rt + " " + authPacket.ToString()); + + if (rt <= 0) + { + data.HoldFor(msg, ends + (uint)(-rt)); + return ends; + } + else + { + offset += (uint)rt; + + if (session.LocalAuthentication.Type == AuthenticationType.Host) + { + if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Declare) + { + if (authPacket.RemoteMethod == IIPAuthPacket.IIPAuthPacketMethod.Credentials && authPacket.LocalMethod == IIPAuthPacket.IIPAuthPacketMethod.None) + { + Server.Membership.UserExists(authPacket.RemoteUsername, authPacket.Domain).Then(x => + { + if (x) + { + session.RemoteAuthentication.Username = authPacket.RemoteUsername; + remoteNonce = authPacket.RemoteNonce; + session.RemoteAuthentication.Domain = authPacket.Domain; + SendParams((byte)0xa0, localNonce); + } + else + { + //Console.WriteLine("User not found"); + SendParams((byte)0xc0, (byte)1, (ushort)14, DC.ToBytes("User not found")); + } + }); + + } + } + else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Action) + { + if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.AuthenticateHash) + { + var remoteHash = authPacket.Hash; + + Server.Membership.GetPassword(session.RemoteAuthentication.Username, + session.RemoteAuthentication.Domain).Then((pw) => + { + if (pw != null) + { + var hashFunc = SHA256.Create(); + var hash = hashFunc.ComputeHash(BinaryList.ToBytes(pw, remoteNonce, localNonce)); + if (hash.SequenceEqual(remoteHash)) + { + // send our hash + var localHash = hashFunc.ComputeHash(BinaryList.ToBytes(localNonce, remoteNonce, pw)); + + SendParams((byte)0, localHash); + + readyToEstablish = true; + } + else + { + Global.Log("auth", LogType.Warning, "U:" + RemoteUsername + " IP:" + Socket.RemoteEndPoint.Address.ToString() + " S:DENIED"); + //Console.WriteLine("Incorrect password"); + SendParams((byte)0xc0, (byte)1, (ushort)5, DC.ToBytes("Error")); + } + } + }); + } + else if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.NewConnection) + { + if (readyToEstablish) + { + var r = new Random(); + session.Id = new byte[32]; + r.NextBytes(session.Id); + SendParams((byte)0x28, session.Id); + ready = true; + OnReady?.Invoke(this); + Server.Membership.Login(session); + + Global.Log("auth", LogType.Warning, "U:" + RemoteUsername + " IP:" + Socket.RemoteEndPoint.Address.ToString() + " S:AUTH"); + + } + } + } + } + else if (session.LocalAuthentication.Type == AuthenticationType.Client) + { + if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Acknowledge) + { + remoteNonce = authPacket.RemoteNonce; + + // send our hash + var hashFunc = SHA256.Create(); + var localHash = hashFunc.ComputeHash(BinaryList.ToBytes(localPassword, localNonce, remoteNonce)); + + SendParams((byte)0, localHash); + } + else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Action) + { + if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.AuthenticateHash) + { + // check if the server knows my password + var hashFunc = SHA256.Create(); + var remoteHash = hashFunc.ComputeHash(BinaryList.ToBytes(remoteNonce, localNonce, localPassword)); + + if (remoteHash.SequenceEqual(authPacket.Hash)) + { + // send establish request + SendParams((byte)0x20, (ushort)0); + } + else + { + SendParams((byte)0xc0, 1, (ushort)5, DC.ToBytes("Error")); + } + } + else if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.ConnectionEstablished) + { + session.Id = authPacket.SessionId; + + ready = true; + OnReady?.Invoke(this); + + } + } + else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Error) + { + OnError?.Invoke(this, authPacket.ErrorCode, authPacket.ErrorMessage); + Close(); + } + } + } + } + + return offset; + + //if (offset < ends) + // processPacket(msg, offset, ends, data, chunkId); + } + protected override void DataReceived(NetworkBuffer data) { // Console.WriteLine("DR " + hostType + " " + data.Available + " " + RemoteEndPoint.ToString()); var msg = data.Read(); uint offset = 0; uint ends = (uint)msg.Length; + + var packs = new List(); + + var chunkId = (new Random()).Next(1000, 1000000); + + + while (offset < ends) { - - if (ready) - { - var rt = packet.Parse(msg, offset, ends); - if (rt <= 0) - { - data.HoldFor(msg, offset, ends - offset, (uint)(-rt)); - return; - } - else - { - offset += (uint)rt; - - if (packet.Command == IIPPacket.IIPPacketCommand.Event) - { - switch (packet.Event) - { - case IIPPacket.IIPPacketEvent.ResourceReassigned: - IIPEventResourceReassigned(packet.ResourceId, packet.NewResourceId); - break; - case IIPPacket.IIPPacketEvent.ResourceDestroyed: - IIPEventResourceDestroyed(packet.ResourceId); - break; - case IIPPacket.IIPPacketEvent.PropertyUpdated: - IIPEventPropertyUpdated(packet.ResourceId, packet.MethodIndex, packet.Content); - break; - case IIPPacket.IIPPacketEvent.EventOccured: - IIPEventEventOccured(packet.ResourceId, packet.MethodIndex, packet.Content); - break; - } - } - else if (packet.Command == IIPPacket.IIPPacketCommand.Request) - { - switch (packet.Action) - { - case IIPPacket.IIPPacketAction.AttachResource: - IIPRequestAttachResource(packet.CallbackId, packet.ResourceId); - break; - case IIPPacket.IIPPacketAction.ReattachResource: - IIPRequestReattachResource(packet.CallbackId, packet.ResourceId, packet.ResourceAge); - break; - case IIPPacket.IIPPacketAction.DetachResource: - IIPRequestDetachResource(packet.CallbackId, packet.ResourceId); - break; - case IIPPacket.IIPPacketAction.CreateResource: - IIPRequestCreateResource(packet.CallbackId, packet.ClassName); - break; - case IIPPacket.IIPPacketAction.DeleteResource: - IIPRequestDeleteResource(packet.CallbackId, packet.ResourceId); - break; - case IIPPacket.IIPPacketAction.TemplateFromClassName: - IIPRequestTemplateFromClassName(packet.CallbackId, packet.ClassName); - break; - case IIPPacket.IIPPacketAction.TemplateFromClassId: - IIPRequestTemplateFromClassId(packet.CallbackId, packet.ClassId); - break; - case IIPPacket.IIPPacketAction.TemplateFromResourceLink: - IIPRequestTemplateFromResourceLink(packet.CallbackId, packet.ResourceLink); - break; - case IIPPacket.IIPPacketAction.TemplateFromResourceId: - IIPRequestTemplateFromResourceId(packet.CallbackId, packet.ResourceId); - break; - case IIPPacket.IIPPacketAction.ResourceIdFromResourceLink: - IIPRequestResourceIdFromResourceLink(packet.CallbackId, packet.ResourceLink); - break; - case IIPPacket.IIPPacketAction.InvokeFunction: - IIPRequestInvokeFunction(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content); - break; - case IIPPacket.IIPPacketAction.GetProperty: - IIPRequestGetProperty(packet.CallbackId, packet.ResourceId, packet.MethodIndex); - break; - case IIPPacket.IIPPacketAction.GetPropertyIfModified: - IIPRequestGetPropertyIfModifiedSince(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.ResourceAge); - break; - case IIPPacket.IIPPacketAction.SetProperty: - IIPRequestSetProperty(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content); - break; - } - } - else if (packet.Command == IIPPacket.IIPPacketCommand.Reply) - { - switch (packet.Action) - { - case IIPPacket.IIPPacketAction.AttachResource: - IIPReply(packet.CallbackId, packet.ClassId, packet.ResourceAge, packet.ResourceLink, packet.Content); - - //IIPReplyAttachResource(packet.CallbackId, packet.ResourceAge, Codec.ParseValues(packet.Content)); - break; - case IIPPacket.IIPPacketAction.ReattachResource: - //IIPReplyReattachResource(packet.CallbackId, packet.ResourceAge, Codec.ParseValues(packet.Content)); - IIPReply(packet.CallbackId, packet.ResourceAge, packet.Content); - - break; - case IIPPacket.IIPPacketAction.DetachResource: - //IIPReplyDetachResource(packet.CallbackId); - IIPReply(packet.CallbackId); - break; - case IIPPacket.IIPPacketAction.CreateResource: - //IIPReplyCreateResource(packet.CallbackId, packet.ClassId, packet.ResourceId); - IIPReply(packet.CallbackId, packet.ClassId, packet.ResourceId); - break; - case IIPPacket.IIPPacketAction.DeleteResource: - //IIPReplyDeleteResource(packet.CallbackId); - IIPReply(packet.CallbackId); - break; - case IIPPacket.IIPPacketAction.TemplateFromClassName: - //IIPReplyTemplateFromClassName(packet.CallbackId, ResourceTemplate.Parse(packet.Content)); - IIPReply(packet.CallbackId, ResourceTemplate.Parse(packet.Content)); - break; - case IIPPacket.IIPPacketAction.TemplateFromClassId: - //IIPReplyTemplateFromClassId(packet.CallbackId, ResourceTemplate.Parse(packet.Content)); - IIPReply(packet.CallbackId, ResourceTemplate.Parse(packet.Content)); - break; - case IIPPacket.IIPPacketAction.TemplateFromResourceLink: - //IIPReplyTemplateFromResourceLink(packet.CallbackId, ResourceTemplate.Parse(packet.Content)); - IIPReply(packet.CallbackId, ResourceTemplate.Parse(packet.Content)); - break; - case IIPPacket.IIPPacketAction.TemplateFromResourceId: - //IIPReplyTemplateFromResourceId(packet.CallbackId, ResourceTemplate.Parse(packet.Content)); - IIPReply(packet.CallbackId, ResourceTemplate.Parse(packet.Content)); - break; - case IIPPacket.IIPPacketAction.ResourceIdFromResourceLink: - //IIPReplyResourceIdFromResourceLink(packet.CallbackId, packet.ClassId, packet.ResourceId, packet.ResourceAge); - IIPReply(packet.CallbackId, packet.ClassId, packet.ResourceId, packet.ResourceAge); - break; - case IIPPacket.IIPPacketAction.InvokeFunction: - //IIPReplyInvokeFunction(packet.CallbackId, Codec.Parse(packet.Content, 0)); - IIPReply(packet.CallbackId, packet.Content); - break; - case IIPPacket.IIPPacketAction.GetProperty: - //IIPReplyGetProperty(packet.CallbackId, Codec.Parse(packet.Content, 0)); - IIPReply(packet.CallbackId, packet.Content); - break; - case IIPPacket.IIPPacketAction.GetPropertyIfModified: - //IIPReplyGetPropertyIfModifiedSince(packet.CallbackId, Codec.Parse(packet.Content, 0)); - IIPReply(packet.CallbackId, packet.Content); - break; - case IIPPacket.IIPPacketAction.SetProperty: - //IIPReplySetProperty(packet.CallbackId); - IIPReply(packet.CallbackId); - break; - } - - } - - } - } - - else - { - var rt = authPacket.Parse(msg, offset, ends); - - Console.WriteLine(hostType.ToString() + " " + offset + " " + ends + " " + rt + " " + authPacket.ToString()); - - if (rt <= 0) - { - data.HoldFor(msg, ends + (uint)(-rt)); - return; - } - else - { - offset += (uint)rt; - - if (hostType == AuthenticationType.Host) - { - if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Declare) - { - if (authPacket.RemoteMethod == IIPAuthPacket.IIPAuthPacketMethod.Credentials && authPacket.LocalMethod == IIPAuthPacket.IIPAuthPacketMethod.None) - { - remoteUsername = authPacket.RemoteUsername; - remoteNonce = authPacket.RemoteNonce; - domain = authPacket.Domain; - SendParams((byte)0xa0, localNonce); - } - } - else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Action) - { - if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.AuthenticateHash) - { - var remoteHash = authPacket.Hash; - - Server.Membership.GetPassword(remoteUsername, domain).Then((pw) => - { - - - if (pw != null) - { - var hashFunc = SHA256.Create(); - var hash = hashFunc.ComputeHash(BinaryList.ToBytes(pw, remoteNonce, localNonce)); - if (hash.SequenceEqual(remoteHash)) - { - // send our hash - var localHash = hashFunc.ComputeHash(BinaryList.ToBytes(localNonce, remoteNonce, pw)); - - SendParams((byte)0, localHash); - - readyToEstablish = true; - } - else - { - Console.WriteLine("Incorrect password"); - SendParams((byte)0xc0, (byte)1, (ushort)5, DC.ToBytes("Error")); - } - } - }); - } - else if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.NewConnection) - { - if (readyToEstablish) - { - var r = new Random(); - sessionId = new byte[32]; - r.NextBytes(sessionId); - SendParams((byte)0x28, sessionId); - ready = true; - OnReady?.Invoke(this); - } - } - } - } - else if (hostType == AuthenticationType.Client) - { - if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Acknowledge) - { - remoteNonce = authPacket.RemoteNonce; - - // send our hash - var hashFunc = SHA256.Create(); - var localHash = hashFunc.ComputeHash(BinaryList.ToBytes(localPassword, localNonce, remoteNonce)); - - SendParams((byte)0, localHash); - } - else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Action) - { - if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.AuthenticateHash) - { - // check if the server knows my password - var hashFunc = SHA256.Create(); - var remoteHash = hashFunc.ComputeHash(BinaryList.ToBytes(remoteNonce, localNonce, localPassword)); - - if (remoteHash.SequenceEqual(authPacket.Hash)) - { - // send establish request - SendParams((byte)0x20, (ushort)0); - } - else - { - SendParams((byte)0xc0, 1, (ushort)5, DC.ToBytes("Error")); - } - } - else if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.ConnectionEstablished) - { - sessionId = authPacket.SessionId; - ready = true; - OnReady?.Invoke(this); - } - } - else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Error) - { - OnError?.Invoke(this, authPacket.ErrorCode, authPacket.ErrorMessage); - Close(); - } - } - } - } + offset = processPacket(msg, offset, ends, data, chunkId); } } @@ -510,5 +717,17 @@ namespace Esiur.Net.IIP resources.Add(Convert.ToUInt32(resource.Instance.Name), (DistributedResource)resource); return true; } + + 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) + { + // nothing to do + return true; + } } } diff --git a/Esiur/Net/IIP/DistributedConnectionProtocol.cs b/Esiur/Net/IIP/DistributedConnectionProtocol.cs index 0c3c044..75076fc 100644 --- a/Esiur/Net/IIP/DistributedConnectionProtocol.cs +++ b/Esiur/Net/IIP/DistributedConnectionProtocol.cs @@ -1,8 +1,34 @@ -using Esiur.Data; +/* + +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 Esiur.Data; using Esiur.Engine; using Esiur.Net.Packets; using Esiur.Resource; using Esiur.Resource.Template; +using Esiur.Security.Authority; +using Esiur.Security.Permissions; using System; using System.Collections.Generic; @@ -24,7 +50,7 @@ namespace Esiur.Net.IIP Dictionary templates = new Dictionary(); - KeyList> requests = new KeyList>(); + KeyList requests = new KeyList(); uint callbackCounter = 0; @@ -47,12 +73,107 @@ namespace Esiur.Net.IIP return reply; } + uint maxcallerid = 0; + + internal void SendReply(IIPPacket.IIPPacketAction action, uint callbackId, params object[] args) + { + if (callbackId > maxcallerid) + { + maxcallerid = callbackId; + } + else + { + Console.Beep(); + + } + + var bl = new BinaryList((byte)(0x80 | (byte)action), callbackId); + bl.AddRange(args); + Send(bl.ToArray()); + //Console.WriteLine("SendReply " + action.ToString() + " " + callbackId); + } + + internal void SendEvent(IIPPacket.IIPPacketEvent evt, params object[] args) + { + var bl = new BinaryList((byte)(evt)); + bl.AddRange(args); + Send(bl.ToArray()); + } + + internal AsyncReply SendInvoke(uint instanceId, byte index, object[] parameters) + { + var pb = Codec.ComposeVarArray(parameters, this, true); + + var reply = new AsyncReply(); + callbackCounter++; + var bl = new BinaryList((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.InvokeFunction), + callbackCounter, instanceId, index, pb); + Send(bl.ToArray()); + requests.Add(callbackCounter, reply); + + return reply; + } + + void SendError(AsyncReply.ErrorType type, uint callbackId, ushort errorCode, string errorMessage = "") + { + var msg = DC.ToBytes(errorMessage); + if (type == AsyncReply.ErrorType.Management) + SendParams((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ManagementError), callbackId, errorCode); + else if (type == AsyncReply.ErrorType.Exception) + SendParams((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ExecutionError), callbackId, errorCode, (ushort)msg.Length, msg); + } + + void SendProgress(uint callbackId, int value, int max) + { + SendParams((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ProgressReport), callbackId, value, max); + } + + void SendChunk(uint callbackId, object chunk) + { + var c = Codec.Compose(chunk, this, true); + SendParams((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ChunkStream), callbackId, c); + } + void IIPReply(uint callbackId, params object[] results) { var req = requests.Take(callbackId); req?.Trigger(results); } + void IIPReplyInvoke(uint callbackId, byte[] result) + { + var req = requests.Take(callbackId); + + Codec.Parse(result, 0, this).Then((rt) => + { + req?.Trigger(rt); + }); + } + + void IIPReportError(uint callbackId, AsyncReply.ErrorType errorType, ushort errorCode, string errorMessage) + { + var req = requests.Take(callbackId); + req?.TriggerError(new AsyncException(errorType, errorCode, errorMessage)); + } + + void IIPReportProgress(uint callbackId, AsyncReply.ProgressType type, int value, int max) + { + var req = requests[callbackId]; + req?.TriggerProgress(type, value, max); + } + + void IIPReportChunk(uint callbackId, byte[] data) + { + if (requests.ContainsKey(callbackId)) + { + var req = requests[callbackId]; + Codec.Parse(data, 0, this).Then((x) => + { + req.TriggerChunk(x); + }); + } + } + void IIPEventResourceReassigned(uint resourceId, uint newResourceId) { @@ -70,6 +191,30 @@ namespace Esiur.Net.IIP void IIPEventPropertyUpdated(uint resourceId, byte index, byte[] content) { + + Fetch(resourceId).Then(r => + { + var item = new AsyncReply(); + queue.Add(item); + + Codec.Parse(content, 0, this).Then((arguments) => + { + var pt = r.Instance.Template.GetPropertyTemplate(index); + if (pt != null) + { + item.Trigger(new DistributedResourceQueueItem((DistributedResource)r, + DistributedResourceQueueItem.DistributedResourceQueueItemType.Propery, + arguments, index)); + } + else + { // ft found, fi not found, this should never happen + queue.Remove(item); + } + }); + + }); + + /* if (resources.Contains(resourceId)) { // push to the queue to gaurantee serialization @@ -79,22 +224,59 @@ namespace Esiur.Net.IIP var r = resources[resourceId]; Codec.Parse(content, 0, this).Then((arguments) => { - var pt = r.Template.GetPropertyTemplate(index); - if (pt != null) + if (!r.IsAttached) { - reply.Trigger(new DistributedResourceQueueItem((DistributedResource)r, DistributedResourceQueueItem.DistributedResourceQueueItemType.Propery, arguments, index)); + // property updated before the template is received + r.AddAfterAttachement(reply, + new DistributedResourceQueueItem((DistributedResource)r, + DistributedResourceQueueItem.DistributedResourceQueueItemType.Propery, + arguments, index)); } else - { // ft found, fi not found, this should never happen + { + var pt = r.Instance.Template.GetPropertyTemplate(index); + if (pt != null) + { + reply.Trigger(new DistributedResourceQueueItem((DistributedResource)r, + DistributedResourceQueueItem.DistributedResourceQueueItemType.Propery, + arguments, index)); + } + else + { // ft found, fi not found, this should never happen queue.Remove(reply); + } } }); } + */ } - void IIPEventEventOccured(uint resourceId, byte index, byte[] content) + void IIPEventEventOccurred(uint resourceId, byte index, byte[] content) { + Fetch(resourceId).Then(r => + { + // push to the queue to gaurantee serialization + var item = new AsyncReply(); + queue.Add(item); + + Codec.ParseVarArray(content, this).Then((arguments) => + { + var et = r.Instance.Template.GetEventTemplate(index); + if (et != null) + { + item.Trigger(new DistributedResourceQueueItem((DistributedResource)r, + DistributedResourceQueueItem.DistributedResourceQueueItemType.Event, arguments, index)); + } + else + { // ft found, fi not found, this should never happen + queue.Remove(item); + } + + }); + }); + + /* if (resources.Contains(resourceId)) { // push to the queue to gaurantee serialization @@ -105,17 +287,73 @@ namespace Esiur.Net.IIP Codec.ParseVarArray(content, this).Then((arguments) => { - var et = r.Template.GetEventTemplate(index); - if (et != null) + if (!r.IsAttached) { - reply.Trigger(new DistributedResourceQueueItem((DistributedResource)r, DistributedResourceQueueItem.DistributedResourceQueueItemType.Event, arguments, index)); + // event occurred before the template is received + r.AddAfterAttachement(reply, + new DistributedResourceQueueItem((DistributedResource)r, + DistributedResourceQueueItem.DistributedResourceQueueItemType.Event, arguments, index)); } else - { // ft found, fi not found, this should never happen - queue.Remove(reply); + { + var et = r.Instance.Template.GetEventTemplate(index); + if (et != null) + { + reply.Trigger(new DistributedResourceQueueItem((DistributedResource)r, + DistributedResourceQueueItem.DistributedResourceQueueItemType.Event, arguments, index)); + } + else + { // ft found, fi not found, this should never happen + queue.Remove(reply); + } } }); } + */ + } + + void IIPEventChildAdded(uint resourceId, uint childId) + { + Fetch(resourceId).Then(parent => + { + Fetch(childId).Then(child => + { + parent.Instance.Children.Add(child); + }); + }); + } + + void IIPEventChildRemoved(uint resourceId, uint childId) + { + Fetch(resourceId).Then(parent => + { + Fetch(childId).Then(child => + { + parent.Instance.Children.Remove(child); + }); + }); + } + + void IIPEventRenamed(uint resourceId, byte[] name) + { + Fetch(resourceId).Then(resource => + { + resource.Instance.Attributes["name"] = name.GetString(0, (uint)name.Length); + }); + } + + + void IIPEventAttributesUpdated(uint resourceId, byte[] attributes) + { + Fetch(resourceId).Then(resource => + { + var attrs = attributes.GetStringArray(0, (uint)attributes.Length); + + GetAttributes(resource, attrs).Then(s => + { + resource.Instance.SetAttributes(s); + }); + }); } void IIPRequestAttachResource(uint callback, uint resourceId) @@ -124,41 +362,89 @@ namespace Esiur.Net.IIP { if (res != null) { + if (res.Instance.Applicable(session, ActionType.Attach, null) == Ruling.Denied) + { + SendError(AsyncReply.ErrorType.Management, callback, 6); + return; + } + var r = res as IResource; - r.Instance.ResourceEventOccured += Instance_EventOccured; + r.Instance.ResourceEventOccurred += Instance_EventOccurred; r.Instance.ResourceModified += Instance_PropertyModified; r.Instance.ResourceDestroyed += Instance_ResourceDestroyed; + r.Instance.Children.OnAdd += Children_OnAdd; + r.Instance.Children.OnRemoved += Children_OnRemoved; + r.Instance.Attributes.OnModified += Attributes_OnModified; + var link = DC.ToBytes(r.Instance.Link); - // reply ok - SendParams((byte)0x80, callback, r.Instance.Template.ClassId, r.Instance.Age, (ushort)link.Length, link, Codec.ComposeVarArray(r.Instance.Serialize(), this, true)); + if (r is DistributedResource) + { + // reply ok + SendReply(IIPPacket.IIPPacketAction.AttachResource, + callback, r.Instance.Template.ClassId, + r.Instance.Age, (ushort)link.Length, link, + Codec.ComposePropertyValueArray((r as DistributedResource)._Serialize(), this, true)); + } + else + { + // reply ok + SendReply(IIPPacket.IIPPacketAction.AttachResource, + callback, r.Instance.Template.ClassId, + r.Instance.Age, (ushort)link.Length, link, + Codec.ComposePropertyValueArray(r.Instance.Serialize(), this, true)); + } } else { // reply failed //SendParams(0x80, r.Instance.Id, r.Instance.Age, r.Instance.Serialize(false, this)); - + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); } }); } - void IIPRequestReattachResource(uint callback, uint resourceId, uint resourceAge) + private void Attributes_OnModified(string key, object oldValue, object newValue, KeyList sender) + { + if (key == "name") + { + var instance = (sender.Owner as Instance); + var name = DC.ToBytes(newValue.ToString()); + SendEvent(IIPPacket.IIPPacketEvent.ChildRemoved, instance.Id, (ushort)name.Length, name); + } + } + + private void Children_OnRemoved(Instance sender, IResource value) + { + SendEvent(IIPPacket.IIPPacketEvent.ChildRemoved, sender.Id, value.Instance.Id); + } + + private void Children_OnAdd(Instance sender, IResource value) + { + //if (sender.Applicable(sender.Resource, this.session, ActionType.)) + SendEvent(IIPPacket.IIPPacketEvent.ChildAdded, sender.Id, value.Instance.Id); + } + + void IIPRequestReattachResource(uint callback, uint resourceId, ulong resourceAge) { Warehouse.Get(resourceId).Then((res) => { if (res != null) { var r = res as IResource; - r.Instance.ResourceEventOccured += Instance_EventOccured; + r.Instance.ResourceEventOccurred += Instance_EventOccurred; r.Instance.ResourceModified += Instance_PropertyModified; r.Instance.ResourceDestroyed += Instance_ResourceDestroyed; // reply ok - SendParams((byte)0x81, callback, r.Instance.Age, Codec.ComposeVarArray(r.Instance.Serialize(), this, true)); + SendReply(IIPPacket.IIPPacketAction.ReattachResource, + callback, r.Instance.Age, + Codec.ComposePropertyValueArray(r.Instance.Serialize(), this, true)); } else { // reply failed + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); } }); } @@ -170,27 +456,391 @@ namespace Esiur.Net.IIP if (res != null) { var r = res as IResource; - r.Instance.ResourceEventOccured -= Instance_EventOccured; + r.Instance.ResourceEventOccurred -= Instance_EventOccurred; r.Instance.ResourceModified -= Instance_PropertyModified; r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed; // reply ok - SendParams((byte)0x82, callback); + SendReply(IIPPacket.IIPPacketAction.DetachResource, callback); } else { // reply failed + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); } }); } - void IIPRequestCreateResource(uint callback, string className) + void IIPRequestCreateResource(uint callback, uint storeId, uint parentId, byte[] content) { - // not implemented + + Warehouse.Get(storeId).Then(store => + { + if (store == null) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.StoreNotFound); + return; + } + + if (!(store is IStore)) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceIsNotStore); + return; + } + + // check security + if (store.Instance.Applicable(session, ActionType.CreateResource, null) != Ruling.Allowed) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.CreateDenied); + return; + } + + Warehouse.Get(parentId).Then(parent => + { + + // check security + + if (parent != null) + if (parent.Instance.Applicable(session, ActionType.AddChild, null) != Ruling.Allowed) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.AddChildDenied); + return; + } + + uint offset = 0; + + var className = content.GetString(offset + 1, content[0]); + offset += 1 + (uint)content[0]; + + var nameLength = content.GetUInt16(offset); + offset += 2; + var name = content.GetString(offset, nameLength); + + var cl = content.GetUInt32(offset); + offset += 4; + + var type = Type.GetType(className); + + if (type == null) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ClassNotFound); + return; + } + + Codec.ParseVarArray(content, offset, cl, this).Then(parameters => + { + offset += cl; + cl = content.GetUInt32(offset); + Codec.ParseStructure(content, offset, cl, this).Then(attributes => + { + offset += cl; + cl = (uint)content.Length - offset; + + Codec.ParseStructure(content, offset, cl, this).Then(values => + { + +#if NETSTANDARD1_5 + var constructors = Type.GetType(className).GetTypeInfo().GetConstructors(); +#else + var constructors = Type.GetType(className).GetConstructors(); +#endif + + var matching = constructors.Where(x => + { + var ps = x.GetParameters(); + if (ps.Length > 0 && ps.Length == parameters.Length + 1) + if (ps.Last().ParameterType == typeof(DistributedConnection)) + return true; + + return ps.Length == parameters.Length; + } + ).ToArray(); + + var pi = matching[0].GetParameters(); + + // cast arguments + 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 (parameters != null) + { + for (int i = 0; i < argsCount && i < parameters.Length; i++) + { + args[i] = DC.CastConvert(parameters[i], pi[i].ParameterType); + } + } + } + + // create the resource + var resource = Activator.CreateInstance(type, args) as IResource; + + Warehouse.Put(resource, name, store as IStore, parent); + + SendReply(IIPPacket.IIPPacketAction.CreateResource, callback, resource.Instance.Id); + + }); + }); + }); + }); + }); } void IIPRequestDeleteResource(uint callback, uint resourceId) { - // not implemented + Warehouse.Get(resourceId).Then(r => + { + if (r == null) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + if (r.Instance.Store.Instance.Applicable(session, ActionType.Delete, null) != Ruling.Allowed) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.DeleteDenied); + return; + } + + if (Warehouse.Remove(r)) + SendReply(IIPPacket.IIPPacketAction.DeleteResource, callback); + //SendParams((byte)0x84, callback); + else + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.DeleteFailed); + }); + } + + void IIPRequestGetAttributes(uint callback, uint resourceId, byte[] attributes, bool all = false) + { + Warehouse.Get(resourceId).Then(r => + { + if (r == null) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + // if (!r.Instance.Store.Instance.Applicable(r, session, ActionType.InquireAttributes, null)) + if (r.Instance.Applicable(session, ActionType.InquireAttributes, null) != Ruling.Allowed) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ViewAttributeDenied); + return; + } + + string[] attrs = null; + + if (!all) + attrs = attributes.GetStringArray(0, (uint)attributes.Length); + + var st = r.Instance.GetAttributes(attrs); + + if (st != null) + SendReply(all ? IIPPacket.IIPPacketAction.GetAllAttributes : IIPPacket.IIPPacketAction.GetAttributes, callback, + Codec.ComposeStructure(st, this, true, true, true)); + else + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.GetAttributesFailed); + + }); + } + + void IIPRequestAddChild(uint callback, uint parentId, uint childId) + { + Warehouse.Get(parentId).Then(parent => + { + if (parent == null) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + Warehouse.Get(childId).Then(child => + { + if (child == null) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + if (parent.Instance.Applicable(this.session, ActionType.AddChild, null) != Ruling.Allowed) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.AddChildDenied); + return; + } + + if (child.Instance.Applicable(this.session, ActionType.AddParent, null) != Ruling.Allowed) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.AddParentDenied); + return; + } + + parent.Instance.Children.Add(child); + + SendReply(IIPPacket.IIPPacketAction.AddChild, callback); + //child.Instance.Parents + }); + + }); + } + + void IIPRequestRemoveChild(uint callback, uint parentId, uint childId) + { + Warehouse.Get(parentId).Then(parent => + { + if (parent == null) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + Warehouse.Get(childId).Then(child => + { + if (child == null) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + if (parent.Instance.Applicable(this.session, ActionType.RemoveChild, null) != Ruling.Allowed) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.AddChildDenied); + return; + } + + if (child.Instance.Applicable(this.session, ActionType.RemoveParent, null) != Ruling.Allowed) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.AddParentDenied); + return; + } + + parent.Instance.Children.Remove(child); + + SendReply(IIPPacket.IIPPacketAction.RemoveChild, callback); + //child.Instance.Parents + }); + + }); + } + + void IIPRequestRenameResource(uint callback, uint resourceId, byte[] name) + { + Warehouse.Get(resourceId).Then(resource => + { + if (resource == null) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + if (resource.Instance.Applicable(this.session, ActionType.Rename, null) != Ruling.Allowed) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.RenameDenied); + return; + } + + + resource.Instance.Name = name.GetString(0, (uint)name.Length); + SendReply(IIPPacket.IIPPacketAction.RenameResource, callback); + }); + } + + void IIPRequestResourceChildren(uint callback, uint resourceId) + { + Warehouse.Get(resourceId).Then(resource => + { + if (resource == null) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + SendReply(IIPPacket.IIPPacketAction.ResourceChildren, callback, + + Codec.ComposeResourceArray(resource.Instance.Children.ToArray(), this, true) + ); + + }); + } + + void IIPRequestResourceParents(uint callback, uint resourceId) + { + Warehouse.Get(resourceId).Then(resource => + { + if (resource == null) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + SendReply(IIPPacket.IIPPacketAction.ResourceParents, callback, + + Codec.ComposeResourceArray(resource.Instance.Parents.ToArray(), this, true) + ); + + }); + } + + void IIPRequestClearAttributes(uint callback, uint resourceId, byte[] attributes, bool all = false) + { + Warehouse.Get(resourceId).Then(r => + { + if (r == null) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + if (r.Instance.Store.Instance.Applicable(session, ActionType.UpdateAttributes, null) != Ruling.Allowed) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeDenied); + return; + } + + string[] attrs = null; + + if (!all) + attrs = attributes.GetStringArray(0, (uint)attributes.Length); + + if (r.Instance.RemoveAttributes(attrs)) + SendReply(all ? IIPPacket.IIPPacketAction.ClearAllAttributes : IIPPacket.IIPPacketAction.ClearAttributes, callback); + else + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeFailed); + + }); + } + + void IIPRequestUpdateAttributes(uint callback, uint resourceId, byte[] attributes, bool clearAttributes = false) + { + Warehouse.Get(resourceId).Then(r => + { + if (r == null) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); + return; + } + + if (r.Instance.Store.Instance.Applicable(session, ActionType.UpdateAttributes, null) != Ruling.Allowed) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeDenied); + return; + } + + Codec.ParseStructure(attributes, 0, (uint)attributes.Length, this).Then(attrs => + { + if (r.Instance.SetAttributes(attrs, clearAttributes)) + SendReply(clearAttributes ? IIPPacket.IIPPacketAction.ClearAllAttributes : IIPPacket.IIPPacketAction.ClearAttributes, + callback); + else + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeFailed); + }); + + }); } @@ -199,10 +849,11 @@ namespace Esiur.Net.IIP Warehouse.GetTemplate(className).Then((t) => { if (t != null) - SendParams((byte)0x88, callback, t.Content); + SendReply(IIPPacket.IIPPacketAction.TemplateFromClassName, callback, (uint)t.Content.Length, t.Content); else { // reply failed + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound); } }); } @@ -212,60 +863,69 @@ namespace Esiur.Net.IIP Warehouse.GetTemplate(classId).Then((t) => { if (t != null) - SendParams((byte)0x89, callback, (uint)t.Content.Length, t.Content); + SendReply(IIPPacket.IIPPacketAction.TemplateFromClassId, callback, (uint)t.Content.Length, t.Content); else { // reply failed + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound); } }); } - void IIPRequestTemplateFromResourceLink(uint callback, string resourceLink) - { - Warehouse.GetTemplate(resourceLink).Then((t) => - { - if (t != null) - SendParams((byte)0x8A, callback, t.Content); - else - { - // reply failed - } - }); - } + void IIPRequestTemplateFromResourceId(uint callback, uint resourceId) { Warehouse.Get(resourceId).Then((r) => { if (r != null) - SendParams((byte)0x8B, callback, r.Instance.Template.Content); + SendReply(IIPPacket.IIPPacketAction.TemplateFromResourceId, callback, + (uint)r.Instance.Template.Content.Length, r.Instance.Template.Content); else { // reply failed + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound); } }); } - void IIPRequestResourceIdFromResourceLink(uint callback, string resourceLink) + + + + void IIPRequestQueryResources(uint callback, string resourceLink) { - Warehouse.Get(resourceLink).Then((r) => + Warehouse.Query(resourceLink).Then((r) => { - if (r != null) - SendParams((byte)0x8C, callback, r.Instance.Template.ClassId, r.Instance.Id, r.Instance.Age); + //if (r != null) + //{ + var list = r.Where(x => x.Instance.Applicable(session, ActionType.Attach, null) != Ruling.Denied).ToArray(); + + if (list.Length == 0) + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); else - { - // reply failed - } + SendReply(IIPPacket.IIPPacketAction.QueryLink, callback, Codec.ComposeResourceArray(list, this, true)); + //} + //else + //{ + // reply failed + //} }); } + void IIPRequestResourceAttribute(uint callback, uint resourceId) + { + + } + void IIPRequestInvokeFunction(uint callback, uint resourceId, byte index, byte[] content) { + //Console.WriteLine("IIPRequestInvokeFunction " + callback + " " + resourceId + " " + index); + Warehouse.Get(resourceId).Then((r) => { if (r != null) { - Codec.ParseVarArray(content, this).Then(async (arguments) => + Codec.ParseVarArray(content, this).Then((arguments) => { var ft = r.Instance.Template.GetFunctionTemplate(index); if (ft != null) @@ -277,11 +937,12 @@ namespace Esiur.Net.IIP { rt.Then(res => { - SendParams((byte)0x90, callback, Codec.Compose(res, this)); + SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback, Codec.Compose(res, this)); }); } else { + // function not found on a distributed object } } @@ -295,7 +956,14 @@ namespace Esiur.Net.IIP if (fi != null) { - // cast shit + if (r.Instance.Applicable(session, ActionType.Execute, ft) == Ruling.Denied) + { + SendError(AsyncReply.ErrorType.Management, callback, + (ushort)ExceptionCode.InvokeDenied); + return; + } + + // cast arguments ParameterInfo[] pi = fi.GetParameters(); object[] args = null; @@ -318,30 +986,62 @@ namespace Esiur.Net.IIP } } - var rt = fi.Invoke(r, args); + object rt; - if (rt is Task) + try { - var t = (Task)rt; - //Console.WriteLine(t.IsCompleted); - await t; + rt = fi.Invoke(r, args); + } + catch(Exception ex) + { + SendError(AsyncReply.ErrorType.Exception, callback, 0, ex.ToString()); + return; + } + + if (rt is System.Collections.IEnumerable && !(rt is Array)) + { + var enu = rt as System.Collections.IEnumerable; + + foreach (var v in enu) + SendChunk(callback, v); + + SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback, (byte)DataType.Void); + + } + else if (rt is Task) + { + (rt as Task).ContinueWith(t => + { #if NETSTANDARD1_5 - 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); + var res = t.GetType().GetProperty("Result").GetValue(t); #endif - SendParams((byte)0x90, callback, Codec.Compose(res, this)); + SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback, Codec.Compose(res, this)); + }); + + //await t; + //SendParams((byte)0x90, callback, Codec.Compose(res, this)); } else if (rt is AsyncReply) //(rt.GetType().IsGenericType && (rt.GetType().GetGenericTypeDefinition() == typeof(AsyncReply<>))) { (rt as AsyncReply).Then(res => { - SendParams((byte)0x90, callback, Codec.Compose(res, this)); + SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback, Codec.Compose(res, this)); + }).Error(ex => + { + SendError(AsyncReply.ErrorType.Exception, callback, (ushort)ex.Code, ex.Message); + }).Progress((pt, pv, pm) => + { + SendProgress(callback, pv, pm); + }).Chunk(v => + { + SendChunk(callback, v); }); } else { - SendParams((byte)0x90, callback, Codec.Compose(rt, this)); + SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback, Codec.Compose(rt, this)); } } else @@ -374,7 +1074,8 @@ namespace Esiur.Net.IIP { if (r is DistributedResource) { - SendParams((byte)0x91, callback, Codec.Compose((r as DistributedResource)._Get(pt.Index), this)); + SendReply(IIPPacket.IIPPacketAction.GetProperty, callback, + Codec.Compose((r as DistributedResource)._Get(pt.Index), this)); } else { @@ -386,7 +1087,8 @@ namespace Esiur.Net.IIP if (pi != null) { - SendParams((byte)0x91, callback, Codec.Compose(pi.GetValue(r), this)); + SendReply(IIPPacket.IIPPacketAction.GetProperty, + callback, Codec.Compose(pi.GetValue(r), this)); } else { @@ -406,7 +1108,41 @@ namespace Esiur.Net.IIP }); } - void IIPRequestGetPropertyIfModifiedSince(uint callback, uint resourceId, byte index, uint age) + void IIPRequestInquireResourceHistory(uint callback, uint resourceId, DateTime fromDate, DateTime toDate) + { + Warehouse.Get(resourceId).Then((r) => + { + if (r != null) + { + r.Instance.Store.GetRecord(r, fromDate, toDate).Then((results) => + { + var history = Codec.ComposeHistory(results, this, true); + + /* + ulong fromAge = 0; + ulong toAge = 0; + + if (results.Count > 0) + { + var firstProp = results.Values.First(); + //var lastProp = results.Values.Last(); + + if (firstProp.Length > 0) + { + fromAge = firstProp[0].Age; + toAge = firstProp.Last().Age; + } + + }*/ + + SendReply(IIPPacket.IIPPacketAction.ResourceHistory, callback, history); + + }); + } + }); + } + + void IIPRequestGetPropertyIfModifiedSince(uint callback, uint resourceId, byte index, ulong age) { Warehouse.Get(resourceId).Then((r) => { @@ -424,7 +1160,8 @@ namespace Esiur.Net.IIP #endif if (pi != null) { - SendParams((byte)0x92, callback, Codec.Compose(pi.GetValue(r), this)); + SendReply(IIPPacket.IIPPacketAction.GetPropertyIfModified, callback, + Codec.Compose(pi.GetValue(r), this)); } else { @@ -433,7 +1170,8 @@ namespace Esiur.Net.IIP } else { - SendParams((byte)0x92, callback, (byte)DataType.NotModified); + SendReply(IIPPacket.IIPPacketAction.GetPropertyIfModified, callback, + (byte)DataType.NotModified); } } else @@ -466,7 +1204,10 @@ namespace Esiur.Net.IIP // propagation (r as DistributedResource)._Set(index, value).Then((x) => { - SendParams((byte)0x93, callback); + SendReply(IIPPacket.IIPPacketAction.SetProperty, callback); + }).Error(x => + { + SendError(x.Type, callback, (ushort)x.Code, x.Message); }); } else @@ -478,16 +1219,46 @@ namespace Esiur.Net.IIP #endif if (pi != null) { - // cast new value type to property type - var v = DC.CastConvert(value, pi.PropertyType); - pi.SetValue(r, v); + if (r.Instance.Applicable(session, ActionType.SetProperty, pt, this) == Ruling.Denied) + { + SendError(AsyncReply.ErrorType.Exception, callback, (ushort)ExceptionCode.SetPropertyDenied); + return; + } - SendParams((byte)0x93, callback); + if (!pi.CanWrite) + { + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ReadOnlyProperty); + return; + } + + + if (pi.PropertyType == typeof(DistributedPropertyContext)) + { + value = new DistributedPropertyContext(this, value); + } + else + { + // cast new value type to property type + value = DC.CastConvert(value, pi.PropertyType); + } + + + try + { + pi.SetValue(r, value); + SendReply(IIPPacket.IIPPacketAction.SetProperty, callback); + } + catch(Exception ex) + { + SendError(AsyncReply.ErrorType.Exception, callback, 0, ex.Message); + } + } else { // pt found, pi not found, this should never happen + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.PropertyNotFound); } } @@ -496,11 +1267,13 @@ namespace Esiur.Net.IIP else { // property not found + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.PropertyNotFound); } } else { // resource not found + SendError(AsyncReply.ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); } }); } @@ -641,11 +1414,11 @@ namespace Esiur.Net.IIP } */ - /// - /// Get the ResourceTemplate for a given class Id. - /// - /// Class GUID. - /// ResourceTemplate. + /// + /// Get the ResourceTemplate for a given class Id. + /// + /// Class GUID. + /// ResourceTemplate. public AsyncReply GetTemplate(Guid classId) { if (templates.ContainsKey(classId)) @@ -660,7 +1433,11 @@ namespace Esiur.Net.IIP { templateRequests.Remove(classId); templates.Add(((ResourceTemplate)rt[0]).ClassId, (ResourceTemplate)rt[0]); + Warehouse.PutTemplate(rt[0] as ResourceTemplate); reply.Trigger(rt[0]); + }).Error((ex) => + { + reply.TriggerError(ex); }); return reply; @@ -674,6 +1451,21 @@ namespace Esiur.Net.IIP /// Resource public AsyncReply Get(string path) { + + var rt = new AsyncReply(); + + Query(path).Then(ar => + { + if (ar?.Length > 0) + rt.Trigger(ar[0]); + else + rt.Trigger(null); + }).Error(ex => rt.TriggerError(ex)); + + return rt; + + /* + if (pathRequests.ContainsKey(path)) return pathRequests[path]; @@ -682,19 +1474,23 @@ namespace Esiur.Net.IIP var bl = new BinaryList(path); bl.Insert(0, (ushort)bl.Length); - - SendRequest(IIPPacket.IIPPacketAction.ResourceIdFromResourceLink, bl.ToArray()).Then((rt) => + + SendRequest(IIPPacket.IIPPacketAction.QueryLink, bl.ToArray()).Then((rt) => { pathRequests.Remove(path); -//(Guid)rt[0], - Fetch( (uint)rt[1]).Then((r) => - { - reply.Trigger(r); - }); - }); + //(Guid)rt[0], + Fetch((uint)rt[1]).Then((r) => + { + reply.Trigger(r); + }); + }).Error((ex) => + { + reply.TriggerError(ex); + }); ; return reply; + */ } /// @@ -716,10 +1512,13 @@ namespace Esiur.Net.IIP /// Class GUID /// Resource IdGuid classId /// DistributedResource - public AsyncReply Fetch( uint id) + public AsyncReply Fetch(uint id) { if (resourceRequests.ContainsKey(id) && resources.ContainsKey(id)) { + Console.WriteLine("DEAD LOCK " + id); + + return new AsyncReply(resources[id]); // dig for dead locks return resourceRequests[id]; } @@ -729,26 +1528,231 @@ namespace Esiur.Net.IIP return new AsyncReply(resources[id]); var reply = new AsyncReply(); + resourceRequests.Add(id, reply); - SendRequest(IIPPacket.IIPPacketAction.AttachResource, id).Then((rt) => + SendRequest(IIPPacket.IIPPacketAction.AttachResource, id).Then((rt) => + { + var dr = new DistributedResource(this, id, (ulong)rt[1], (string)rt[2]); + + GetTemplate((Guid)rt[0]).Then((tmp) => { - GetTemplate((Guid)rt[0]).Then((tmp) => - { - // ClassId, ResourceAge, ResourceLink, Content + Warehouse.Put(dr, id.ToString(), this, null, tmp); - //var dr = Warehouse.New(id.ToString(), this); - //var dr = nInitialize(this, tmp, id, (uint)rt[0]); - var dr = new DistributedResource(this, tmp, id, (uint)rt[1], (string)rt[2]); - Warehouse.Put(dr, id.ToString(), this); - - Codec.ParseVarArray((byte[])rt[3], this).Then((ar) => + Codec.ParsePropertyValueArray((byte[])rt[3], this).Then((ar) => { dr._Attached(ar); resourceRequests.Remove(id); reply.Trigger(dr); }); + }).Error((ex) => + { + reply.TriggerError(ex); }); + }).Error((ex) => + { + reply.TriggerError(ex); + }); + + return reply; + } + + + public AsyncReply GetChildren(IResource resource) + { + var rt = new AsyncReply(); + + SendRequest(IIPPacket.IIPPacketAction.ResourceChildren, resource.Instance.Id).Then(ar => + { + var d = (byte[])ar; + Codec.ParseResourceArray(d, 0, (uint)d.Length, this).Then(resources => + { + rt.Trigger(resources); + }).Error(ex => rt.TriggerError(ex)); + }); + + return rt; + } + + public AsyncReply GetParents(IResource resource) + { + var rt = new AsyncReply(); + + SendRequest(IIPPacket.IIPPacketAction.ResourceParents, resource.Instance.Id).Then(ar => + { + var d = (byte[])ar; + Codec.ParseResourceArray(d, 0, (uint)d.Length, this).Then(resources => + { + rt.Trigger(resources); + }).Error(ex => rt.TriggerError(ex)); + }); + + return rt; + } + + public AsyncReply RemoveAttributes(IResource resource, string[] attributes = null) + { + var rt = new AsyncReply(); + + if (attributes == null) + SendRequest(IIPPacket.IIPPacketAction.ClearAllAttributes, resource.Instance.Id).Then(ar => + { + rt.Trigger(true); + }).Error(ex => rt.TriggerError(ex)); + else + { + var attrs = DC.ToBytes(attributes); + SendRequest(IIPPacket.IIPPacketAction.ClearAttributes, resource.Instance.Id, (uint)attrs.Length, attrs).Then(ar => + { + rt.Trigger(true); + }).Error(ex => rt.TriggerChunk(ex)); + } + + return rt; + } + + public AsyncReply SetAttributes(IResource resource, Structure attributes, bool clearAttributes = false) + { + var rt = new AsyncReply(); + + SendRequest(clearAttributes ? IIPPacket.IIPPacketAction.UpdateAllAttributes : IIPPacket.IIPPacketAction.UpdateAttributes + , resource.Instance.Id, + Codec.ComposeStructure(attributes, this, true, true, true)).Then(ar => + { + rt.Trigger(true); + }).Error(ex => rt.TriggerError(ex)); + + return rt; + } + + public AsyncReply GetAttributes(IResource resource, string[] attributes = null) + { + var rt = new AsyncReply(); + + if (attributes == null) + { + SendRequest(IIPPacket.IIPPacketAction.GetAllAttributes, resource.Instance.Id).Then(ar => + { + var d = ar[0] as byte[]; + Codec.ParseStructure(d, 0, (uint)d.Length, this).Then(st => + { + + resource.Instance.SetAttributes(st); + + rt.Trigger(st); + }).Error(ex => rt.TriggerError(ex)); + }); + } + else + { + var attrs = DC.ToBytes(attributes); + SendRequest(IIPPacket.IIPPacketAction.GetAttributes, resource.Instance.Id, (uint)attrs.Length, attrs).Then(ar => + { + var d = ar[0] as byte[]; + Codec.ParseStructure(d, 0, (uint)d.Length, this).Then(st => + { + + resource.Instance.SetAttributes(st); + + rt.Trigger(st); + }).Error(ex => rt.TriggerError(ex)); + }); + } + + return rt; + } + + /// + /// Get resource history. + /// + /// IResource. + /// From date. + /// To date. + /// + public AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate) + { + if (resource is DistributedResource) + { + var dr = resource as DistributedResource; + + if (dr.Connection != this) + return new AsyncReply>(null); + + var reply = new AsyncReply>(); + + SendRequest(IIPPacket.IIPPacketAction.ResourceHistory, dr.Id, fromDate, toDate).Then(rt => + { + var content = (byte[])rt[0]; + + Codec.ParseHistory(content, 0, (uint)content.Length, resource, this).Then((history) => + { + reply.Trigger(history); + }); + }).Error((ex) => + { + reply.TriggerError(ex); + }); ; + + return reply; + } + else + return new AsyncReply>(null); + } + + /// + /// Query resources at specific link. + /// + /// Link path. + /// + public AsyncReply Query(string path) + { + var str = DC.ToBytes(path); + var reply = new AsyncReply(); + + SendRequest(IIPPacket.IIPPacketAction.QueryLink, (ushort)str.Length, str).Then(args => + { + var content = args[0] as byte[]; + + Codec.ParseResourceArray(content, 0, (uint)content.Length, this).Then(resources => + { + reply.Trigger(resources); + }); + }); + + return reply; + } + + + /// + /// Create a new resource. + /// + /// The store in which the resource is saved. + /// Class full name. + /// Constructor parameters. + /// 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) + { + var reply = new AsyncReply(); + var pkt = new BinaryList(store.Instance.Id, + parent.Instance.Id, + className.Length, Encoding.ASCII.GetBytes(className), + Codec.ComposeVarArray(parameters, this, true), + Codec.ComposeStructure(attributes, this, true, true, true), + Codec.ComposeStructure(values, this)); + + pkt.Insert(8, pkt.Length); + + SendRequest(IIPPacket.IIPPacketAction.CreateResource, pkt.ToArray()).Then(args => + { + var rid = (uint)args[0]; + + Fetch(rid).Then((r) => + { + reply.Trigger(r); + }); + }); return reply; @@ -757,46 +1761,49 @@ namespace Esiur.Net.IIP private void Instance_ResourceDestroyed(IResource resource) { // compose the packet - SendParams((byte)0x1, resource.Instance.Id); + SendEvent(IIPPacket.IIPPacketEvent.ResourceDestroyed, resource.Instance.Id); } - private void Instance_PropertyModified(IResource resource, string name, object newValue, object oldValue) + private void Instance_PropertyModified(IResource resource, string name, object newValue) { var pt = resource.Instance.Template.GetPropertyTemplate(name); if (pt == null) return; - // compose the packet - if (newValue is Func) - SendParams((byte)0x10, resource.Instance.Id, pt.Index, Codec.Compose((newValue as Func)(this), this)); - else - SendParams((byte)0x10, resource.Instance.Id, pt.Index, Codec.Compose(newValue, this)); + SendEvent(IIPPacket.IIPPacketEvent.PropertyUpdated, resource.Instance.Id, pt.Index, Codec.Compose(newValue, this)); } - private void Instance_EventOccured(IResource resource, string name, string[] receivers, object[] args) + // private void Instance_EventOccurred(IResource resource, string name, string[] users, DistributedConnection[] connections, object[] args) + + private void Instance_EventOccurred(IResource resource, object issuer, Session[] receivers, string name, object[] args) { var et = resource.Instance.Template.GetEventTemplate(name); if (et == null) return; - if (receivers != null) - if (!receivers.Contains(RemoteUsername)) + /* + if (users != null) + if (!users.Contains(RemoteUsername)) return; - var clientArgs = new object[args.Length]; - for (var i = 0; i < args.Length; i++) - if (args[i] is Func) - clientArgs[i] = (args[i] as Func)(this); - else - clientArgs[i] = args[i]; + if (connections != null) + if (!connections.Contains(this)) + return; + */ + if (receivers != null) + if (!receivers.Contains(this.session)) + return; + + if (resource.Instance.Applicable(this.session, ActionType.ReceiveEvent, et, issuer) == Ruling.Denied) + return; // compose the packet - SendParams((byte)0x11, resource.Instance.Id, (byte)et.Index, Codec.ComposeVarArray(args, this, true)); - + SendEvent(IIPPacket.IIPPacketEvent.EventOccurred, + resource.Instance.Id, (byte)et.Index, Codec.ComposeVarArray(args, this, true)); } } } diff --git a/Esiur/Net/IIP/DistributedPropertyContext.cs b/Esiur/Net/IIP/DistributedPropertyContext.cs new file mode 100644 index 0000000..8c4f06d --- /dev/null +++ b/Esiur/Net/IIP/DistributedPropertyContext.cs @@ -0,0 +1,24 @@ +using System; +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) + { + this.Value = value; + this.Connection = connection; + } + + public DistributedPropertyContext(Func method) + { + this.Method = method; + } + } +} diff --git a/Esiur/Net/IIP/DistributedResource.cs b/Esiur/Net/IIP/DistributedResource.cs index 6f94617..5266577 100644 --- a/Esiur/Net/IIP/DistributedResource.cs +++ b/Esiur/Net/IIP/DistributedResource.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Text; using System.Reflection; @@ -41,12 +65,12 @@ namespace Esiur.Net.IIP //Structure properties = new Structure(); string link; - uint age; - uint[] ages; + //ulong age; + //ulong[] ages; object[] properties; DistributedResourceEvent[] events; - ResourceTemplate template; + //ResourceTemplate template; //DistributedResourceStack stack; @@ -54,13 +78,23 @@ namespace Esiur.Net.IIP bool destroyed; + /* + Dictionary afterAttachmentTriggers = new Dictionary(); + + internal void AddAfterAttachement(AsyncReply trigger, object value) + { + afterAttachmentTriggers.Add(trigger, value); + } + */ + + /// /// Resource template for the remotely located resource. /// - public ResourceTemplate Template - { - get { return template; } - } + //public ResourceTemplate Template + //{ + // get { return template; } + //} /// @@ -132,40 +166,72 @@ namespace Esiur.Net.IIP /// Resource template. /// Instance Id given by the other end. /// Resource age. - public DistributedResource(DistributedConnection connection, ResourceTemplate template, uint instanceId, uint age, string link) + public DistributedResource(DistributedConnection connection, uint instanceId, ulong age, string link) { this.link = link; this.connection = connection; this.instanceId = instanceId; - this.template = template; - this.age = age; + //this.Instance.Template = template; + //this.Instance.Age = age; + //this.template = template; + //this.age = age; } internal void _Ready() { isReady = true; } - - internal bool _Attached(object[] properties) + + /// + /// Export all properties with ResourceProperty attributed as bytes array. + /// + /// + internal PropertyValue[] _Serialize() + { + + var props = new PropertyValue[properties.Length]; + + + for (byte i = 0; i < properties.Length; i++) + props[i] = new PropertyValue(properties[i], Instance.GetAge(i), Instance.GetModificationDate(i)); + + return props; + } + + internal bool _Attached(PropertyValue[] properties) { - if (isAttached) return false; else { - this.properties = properties; - ages = new uint[properties.Length]; - this.events = new DistributedResourceEvent[template.Events.Length]; + this.properties = new object[properties.Length]; + + this.events = new DistributedResourceEvent[Instance.Template.Events.Length]; + + for (byte i = 0; i < properties.Length; i++) + { + Instance.SetAge(i, properties[i].Age); + Instance.SetModificationDate(i, properties[i].Date); + this.properties[i] = properties[i].Value; + } + + // trigger holded events/property updates. + //foreach (var r in afterAttachmentTriggers) + // r.Key.Trigger(r.Value); + + //afterAttachmentTriggers.Clear(); + isAttached = true; + } return true; } internal void _EmitEventByIndex(byte index, object[] args) { - var et = template.GetEventTemplate(index); + var et = Instance.Template.GetEventTemplate(index); events[index]?.Invoke(this, args); - Instance.EmitResourceEvent(et.Name, null, args); + Instance.EmitResourceEvent(null, null, et.Name, args); } public AsyncReply _Invoke(byte index, object[] args) @@ -173,29 +239,37 @@ namespace Esiur.Net.IIP if (destroyed) throw new Exception("Trying to access destroyed object"); - if (index >= template.Functions.Length) + if (index >= Instance.Template.Functions.Length) throw new Exception("Function index is incorrect"); - var reply = new AsyncReply(); + // var reply = new AsyncReply(); - var parameters = Codec.ComposeVarArray(args, connection, true); - connection.SendRequest(Packets.IIPPacket.IIPPacketAction.InvokeFunction, instanceId, index, parameters).Then((res) => + return connection.SendInvoke(instanceId, index, args); + + //var parameters = Codec.ComposeVarArray(args, connection, true); + //return connection.SendRequest(Packets.IIPPacket.IIPPacketAction.InvokeFunction, instanceId, index, parameters); + + /*.Then((res) => { Codec.Parse((byte[])res[0], 0, connection).Then((rt) => { reply.Trigger(rt); }); - }); + }).Error((ex) => { + reply.TriggerError(ex); + }).Progress((t, pv, pm)=> { + reply.TriggerProgress(t, pv, pm); + }).Chunk(v => reply.TriggerChunk(v)); return reply; - + */ } public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { - var ft = template.GetFunctionTemplate(binder.Name); + var ft = Instance.Template.GetFunctionTemplate(binder.Name); var reply = new AsyncReply(); @@ -233,7 +307,7 @@ namespace Esiur.Net.IIP if (!isAttached) return false; - var pt = template.GetPropertyTemplate(binder.Name); + var pt = Instance.Template.GetPropertyTemplate(binder.Name); if (pt != null) { @@ -242,7 +316,7 @@ namespace Esiur.Net.IIP } else { - var et = template.GetEventTemplate(binder.Name); + var et = Instance.Template.GetEventTemplate(binder.Name); if (et == null) return false; @@ -253,11 +327,11 @@ namespace Esiur.Net.IIP } - internal void UpdatePropertyByIndex(byte index, object value) + internal void _UpdatePropertyByIndex(byte index, object value) { - var pt = template.GetPropertyTemplate(index); + var pt = Instance.Template.GetPropertyTemplate(index); properties[index] = value; - Instance.Modified(pt.Name, value); + Instance.EmitModification(pt, value); } /// @@ -277,9 +351,8 @@ namespace Esiur.Net.IIP connection.SendRequest(Packets.IIPPacket.IIPPacketAction.SetProperty, instanceId, index, parameters).Then((res) => { // not really needed, server will always send property modified, this only happens if the programmer forgot to emit in property setter - //Update(index, value); + properties[index] = value; reply.Trigger(null); - // nothing to do here }); return reply; @@ -293,8 +366,7 @@ namespace Esiur.Net.IIP if (!isAttached) return false; - var pt = template.GetPropertyTemplate(binder.Name); - + var pt = Instance.Template.GetPropertyTemplate(binder.Name); if (pt != null) { @@ -303,7 +375,7 @@ namespace Esiur.Net.IIP } else { - var et = template.GetEventTemplate(binder.Name); + var et = Instance.Template.GetEventTemplate(binder.Name); if (et == null) return false; diff --git a/Esiur/Net/IIP/DistributedResourceEvent.cs b/Esiur/Net/IIP/DistributedResourceEvent.cs index 2040408..8241d15 100644 --- a/Esiur/Net/IIP/DistributedResourceEvent.cs +++ b/Esiur/Net/IIP/DistributedResourceEvent.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Net/IIP/DistributedResourceQueueItem.cs b/Esiur/Net/IIP/DistributedResourceQueueItem.cs index 3c951d4..6f4ef36 100644 --- a/Esiur/Net/IIP/DistributedResourceQueueItem.cs +++ b/Esiur/Net/IIP/DistributedResourceQueueItem.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Net/IIP/DistributedServer.cs b/Esiur/Net/IIP/DistributedServer.cs index f8bb883..c234c52 100644 --- a/Esiur/Net/IIP/DistributedServer.cs +++ b/Esiur/Net/IIP/DistributedServer.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; @@ -16,39 +40,40 @@ namespace Esiur.Net.IIP public class DistributedServer : NetworkServer, IResource { - [Storable] - [ResourceProperty] + //[Storable] + //[ResourceProperty] public string ip { get; set; } - [Storable] - [ResourceProperty] + //[Storable] + //[ResourceProperty] public IMembership Membership { get; set; } - [Storable] - [ResourceProperty] + + //[Storable] + //[ResourceProperty] public ushort port { get; set; } - [Storable] - [ResourceProperty] + //[Storable] + //[ResourceProperty] public uint timeout { get; set; } - [Storable] - [ResourceProperty] + //[Storable] + //[ResourceProperty] public uint clock { get; @@ -94,24 +119,45 @@ namespace Esiur.Net.IIP { //throw new NotImplementedException(); - } + } private void SessionModified(DistributedConnection Session, string Key, object NewValue) { } - - protected override void ClientConnected(DistributedConnection sender) { - Console.WriteLine("DistributedConnection Client Connected"); - sender.Server = this; - } + //Console.WriteLine("DistributedConnection Client Connected"); + + } + + private void Sender_OnReady(DistributedConnection sender) + { + Warehouse.Put(sender, sender.LocalUsername, null, this); + } + + public override void RemoveConnection(DistributedConnection connection) + { + connection.OnReady -= Sender_OnReady; + //connection.Server = null; + base.RemoveConnection(connection); + } + + public override void AddConnection(DistributedConnection connection) + { + connection.OnReady += Sender_OnReady; + connection.Server = this; + base.AddConnection(connection); + } protected override void ClientDisconnected(DistributedConnection sender) { - Console.WriteLine("DistributedConnection Client Disconnected"); + sender.Destroy(); + + Warehouse.Remove(sender); + + //Console.WriteLine("DistributedConnection Client Disconnected"); } } } diff --git a/Esiur/Net/IIP/DistributedSession.cs b/Esiur/Net/IIP/DistributedSession.cs index a08bfdc..cd11926 100644 --- a/Esiur/Net/IIP/DistributedSession.cs +++ b/Esiur/Net/IIP/DistributedSession.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Text; using Esiur.Net.Sockets; diff --git a/Esiur/Net/NetworkBuffer.cs b/Esiur/Net/NetworkBuffer.cs index bec11c6..ccfd471 100644 --- a/Esiur/Net/NetworkBuffer.cs +++ b/Esiur/Net/NetworkBuffer.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; @@ -14,6 +38,13 @@ namespace Esiur.Net uint neededDataLength = 0; //bool trim; + object syncLock = new object(); + + //public object SyncLock + //{ + // get { return syncLock; } + //} + public NetworkBuffer() { data = new byte[0]; @@ -62,16 +93,19 @@ namespace Esiur.Net public void HoldFor(byte[] src, uint offset, uint size, uint needed) { - if (size >= needed) - throw new Exception("Size >= Needed !"); + lock (syncLock) + { + if (size >= needed) + throw new Exception("Size >= Needed !"); - //trim = true; - data = DC.Combine(src, offset, size, data, 0, (uint)data.Length); - neededDataLength = needed; + //trim = true; + data = DC.Combine(src, offset, size, data, 0, (uint)data.Length); + neededDataLength = needed; - // Console.WriteLine("Hold StackTrace: '{0}'", Environment.StackTrace); + // Console.WriteLine("Hold StackTrace: '{0}'", Environment.StackTrace); - Console.WriteLine("Holded {0} {1} {2} {3} - {4}", offset, size, needed, data.Length, GetHashCode()); + //Console.WriteLine("Holded {0} {1} {2} {3} - {4}", offset, size, needed, data.Length, GetHashCode()); + } } public void HoldFor(byte[] src, uint needed) @@ -104,7 +138,11 @@ namespace Esiur.Net public void Write(byte[] src, uint offset, uint length) { - DC.Append(ref data, src, offset, length); + //if (data.Length > 0) + // Console.WriteLine(); + + lock(syncLock) + DC.Append(ref data, src, offset, length); } public bool CanRead @@ -122,46 +160,49 @@ namespace Esiur.Net public byte[] Read() { - if (data.Length == 0) - return null; - - byte[] rt = null; - - if (neededDataLength == 0) + lock (syncLock) { - rt = data; - data = new byte[0]; - } - else - { - //Console.WriteLine("P STATE:" + data.Length + " " + neededDataLength); + if (data.Length == 0) + return null; - if (data.Length >= neededDataLength) + byte[] rt = null; + + if (neededDataLength == 0) { - //Console.WriteLine("data.Length >= neededDataLength " + data.Length + " >= " + neededDataLength + " " + trim); - - //if (trim) - //{ - // rt = DC.Clip(data, 0, neededDataLength); - // data = DC.Clip(data, neededDataLength, (uint)data.Length - neededDataLength); - //} - //else - //{ - // return all data rt = data; data = new byte[0]; - //} - - neededDataLength = 0; - return rt; } else { - return null; - } - } + //Console.WriteLine("P STATE:" + data.Length + " " + neededDataLength); - return rt; + if (data.Length >= neededDataLength) + { + //Console.WriteLine("data.Length >= neededDataLength " + data.Length + " >= " + neededDataLength + " " + trim); + + //if (trim) + //{ + // rt = DC.Clip(data, 0, neededDataLength); + // data = DC.Clip(data, neededDataLength, (uint)data.Length - neededDataLength); + //} + //else + //{ + // return all data + rt = data; + data = new byte[0]; + //} + + neededDataLength = 0; + return rt; + } + else + { + return null; + } + } + + return rt; + } } } } diff --git a/Esiur/Net/NetworkConnection.cs b/Esiur/Net/NetworkConnection.cs index 5a6c666..1802cef 100644 --- a/Esiur/Net/NetworkConnection.cs +++ b/Esiur/Net/NetworkConnection.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.IO; using System.Net.Sockets; using System.Text; @@ -29,9 +53,11 @@ namespace Esiur.Net public event DataReceivedEvent OnDataReceived; public event ConnectionClosedEvent OnClose; public event DestroyedEvent OnDestroy; + object receivingLock = new object(); + + bool processing = false; + - - public void Destroy() { // if (connected) @@ -62,8 +88,8 @@ namespace Esiur.Net socket.OnReceive += Socket_OnReceive; socket.OnClose += Socket_OnClose; socket.OnConnect += Socket_OnConnect; - if (socket.State == SocketState.Established) - socket.Begin(); + //if (socket.State == SocketState.Established) + // socket.Begin(); } private void Socket_OnConnect() @@ -90,8 +116,23 @@ namespace Esiur.Net lastAction = DateTime.Now; - while (buffer.Available > 0 && !buffer.Protected) - DataReceived(buffer); + if (!processing) + { + processing = true; + + try + { + //lock(buffer.SyncLock) + while (buffer.Available > 0 && !buffer.Protected) + DataReceived(buffer); + } + catch + { + + } + + processing = false; + } } catch (Exception ex) @@ -234,9 +275,9 @@ namespace Esiur.Net sock.Send(msg); } } - catch + catch (Exception ex) { - + Console.WriteLine(ex.ToString()); } } diff --git a/Esiur/Net/NetworkServer.cs b/Esiur/Net/NetworkServer.cs index 9e7a693..ac62098 100644 --- a/Esiur/Net/NetworkServer.cs +++ b/Esiur/Net/NetworkServer.cs @@ -1,3 +1,27 @@ +/* + +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.Threading; using System.Collections.Generic; @@ -10,7 +34,6 @@ using System.Threading.Tasks; namespace Esiur.Net { - //public abstract class NetworkServer : IResource where TSession : NetworkSession, new() where TConnection : NetworkConnection, new() public abstract class NetworkServer: IDestructible where TConnection : NetworkConnection, new() { @@ -25,8 +48,6 @@ namespace Esiur.Net protected abstract void ClientConnected(TConnection sender); protected abstract void ClientDisconnected(TConnection sender); - // private int port; - // private IPAddress ip = null; private uint timeout; private Timer timer; @@ -201,7 +222,7 @@ namespace Esiur.Net // Thread.Sleep(100); //} - Console.WriteLine("Listener stopped"); + //Console.WriteLine("Listener stopped"); var cons = connections.ToArray(); @@ -211,14 +232,13 @@ namespace Esiur.Net con.Close(); //} - Console.WriteLine("Sockets Closed"); + //Console.WriteLine("Sockets Closed"); - while (connections.Count > 0) - { - Console.WriteLine("Waiting... " + connections.Count); - - //Thread.Sleep(1000); - } + //while (connections.Count > 0) + //{ + // Console.WriteLine("Waiting... " + connections.Count); + // Thread.Sleep(1000); + //} } finally @@ -228,6 +248,21 @@ namespace Esiur.Net } + public virtual void RemoveConnection(TConnection connection) + { + connection.OnDataReceived -= OnDataReceived; + connection.OnConnect -= OnClientConnect; + connection.OnClose -= OnClientClose; + connections.Remove(connection); + } + + public virtual void AddConnection(TConnection connection) + { + connection.OnDataReceived += OnDataReceived; + connection.OnConnect += OnClientConnect; + connection.OnClose += OnClientClose; + connections.Add(connection); + } private void NewConnection(ISocket sock) { @@ -246,20 +281,17 @@ namespace Esiur.Net if (sock == null) { - Console.Write("sock == null"); + //Console.Write("sock == null"); return; } - //sock.ReceiveBufferSize = 102400; - //sock.SendBufferSize = 102400; + //sock.ReceiveBufferSize = 102400; + //sock.SendBufferSize = 102400; + TConnection c = new TConnection(); - c.OnDataReceived += OnDataReceived; - c.OnConnect += OnClientConnect; - c.OnClose += OnClientClose; + AddConnection(c); - - connections.Add(c); c.Assign(sock); ClientConnected(c); @@ -267,13 +299,14 @@ namespace Esiur.Net // Accept more listener.Accept().Then(NewConnection); + sock.Begin(); } catch (Exception ex) { - Console.WriteLine("TSERVER " + ex.ToString()); - Global.Log("TServer", LogType.Error, ex.ToString()); + //Console.WriteLine("TSERVER " + ex.ToString()); + Global.Log("NetworkServer", LogType.Error, ex.ToString()); } //isRunning = false; @@ -317,6 +350,7 @@ namespace Esiur.Net try { sender.Destroy(); + RemoveConnection((TConnection)sender); ClientDisconnected((TConnection)sender); } catch (Exception ex) diff --git a/Esiur/Net/NetworkSession.cs b/Esiur/Net/NetworkSession.cs index 1ad583f..2626734 100644 --- a/Esiur/Net/NetworkSession.cs +++ b/Esiur/Net/NetworkSession.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Diagnostics; using System.IO; using System.Net.Sockets; @@ -61,7 +85,7 @@ namespace Esiur.Net OnEnd?.Invoke(this); } - void VariablesModified(string key, object oldValue, object newValue) + void VariablesModified(string key, object oldValue, object newValue, KeyList sender) { OnModify?.Invoke(this, key, oldValue, newValue); } diff --git a/Esiur/Net/Packets/HTTPRequestPacket.cs b/Esiur/Net/Packets/HTTPRequestPacket.cs index 7317354..3d62894 100644 --- a/Esiur/Net/Packets/HTTPRequestPacket.cs +++ b/Esiur/Net/Packets/HTTPRequestPacket.cs @@ -1,4 +1,29 @@ -using System; + +/* + +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.Generic; using System.Linq; using System.Text; @@ -218,7 +243,7 @@ namespace Esiur.Net.Packets return postSize - (data.Length - headerSize); - if (Headers["content-type"] == "application/x-www-form-urlencoded" + if (Headers["content-type"].StartsWith("application/x-www-form-urlencoded") || Headers["content-type"] == "" || Headers["content-type"] == null) { diff --git a/Esiur/Net/Packets/HTTPResponsePacket.cs b/Esiur/Net/Packets/HTTPResponsePacket.cs index d15a350..3aeaec3 100644 --- a/Esiur/Net/Packets/HTTPResponsePacket.cs +++ b/Esiur/Net/Packets/HTTPResponsePacket.cs @@ -1,4 +1,27 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Net/Packets/IIPAuthPacket.cs b/Esiur/Net/Packets/IIPAuthPacket.cs index 171e85a..be26858 100644 --- a/Esiur/Net/Packets/IIPAuthPacket.cs +++ b/Esiur/Net/Packets/IIPAuthPacket.cs @@ -1,4 +1,28 @@ - using Esiur.Data; +/* + +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 Esiur.Data; using System; using System.Collections.Generic; using System.Linq; diff --git a/Esiur/Net/Packets/IIPPacket.cs b/Esiur/Net/Packets/IIPPacket.cs index d3a33f9..03d2fd8 100644 --- a/Esiur/Net/Packets/IIPPacket.cs +++ b/Esiur/Net/Packets/IIPPacket.cs @@ -1,4 +1,28 @@ - using Esiur.Data; +/* + +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 Esiur.Data; using Esiur.Engine; using Esiur.Misc; using Esiur.Net.Packets; @@ -12,12 +36,39 @@ namespace Esiur.Net.Packets { class IIPPacket : Packet { + + public override string ToString() + { + var rt = Command.ToString(); + + if (Command == IIPPacketCommand.Event) + { + rt += " " + Event.ToString(); + //if (Event == IIPPacketEvent.AttributesUpdated) + // rt += + } + else if (Command == IIPPacketCommand.Request) + { + rt += " " + Action.ToString(); + if (Action == IIPPacketAction.AttachResource) + { + rt += " CID: " + CallbackId + " RID: " + ResourceId; + } + } + else if (Command == IIPPacketCommand.Reply) + rt += " " + Action.ToString(); + else if (Command == IIPPacketCommand.Report) + rt += " " + Report.ToString(); + + return rt; + } + public enum IIPPacketCommand : byte { Event = 0, Request, Reply, - Error, + Report, } public enum IIPPacketEvent: byte @@ -25,10 +76,15 @@ namespace Esiur.Net.Packets // Event Manage ResourceReassigned = 0, ResourceDestroyed, - + ChildAdded, + ChildRemoved, + Renamed, // Event Invoke PropertyUpdated = 0x10, - EventOccured, + EventOccurred, + + // Attribute + AttributesUpdated = 0x18 } public enum IIPPacketAction : byte @@ -39,22 +95,49 @@ namespace Esiur.Net.Packets DetachResource, CreateResource, DeleteResource, + AddChild, + RemoveChild, + RenameResource, // Request Inquire TemplateFromClassName = 0x8, TemplateFromClassId, - TemplateFromResourceLink, TemplateFromResourceId, - ResourceIdFromResourceLink, + QueryLink, + ResourceHistory, + ResourceChildren, + ResourceParents, // Request Invoke InvokeFunction = 0x10, GetProperty, GetPropertyIfModified, SetProperty, + + // Request Attribute + GetAllAttributes = 0x18, + UpdateAllAttributes, + ClearAllAttributes, + GetAttributes, + UpdateAttributes, + ClearAttributes + } + + public enum IIPPacketReport: byte + { + ManagementError, + ExecutionError, + ProgressReport = 0x8, + ChunkStream = 0x9 + } + + + public IIPPacketReport Report + { + get; + set; } - public IIPPacketCommand Command { get; @@ -72,13 +155,33 @@ namespace Esiur.Net.Packets set; } - + public IIPPacketCommand PreviousCommand + { + get; + set; + } + public IIPPacketAction PreviousAction + { + get; + set; + } + + public IIPPacketEvent PreviousEvent + { + get; + set; + } + + public uint ResourceId { get; set; } public uint NewResourceId { get; set; } + //public uint ParentId { get; set; } + public uint ChildId { get; set; } + public uint StoreId { get; set; } - public uint ResourceAge { get; set; } + public ulong ResourceAge { get; set; } public byte[] Content { get; set; } - public byte ErrorCode { get; set; } + public ushort ErrorCode { get; set; } public string ErrorMessage { get; set; } public string ClassName { get; set; } public string ResourceLink { get; set; } @@ -86,8 +189,15 @@ namespace Esiur.Net.Packets public byte MethodIndex { get; set; } public string MethodName { get; set; } public uint CallbackId { get; set; } + public int ProgressValue { get; set; } + public int ProgressMax { get; set; } + public DateTime FromDate { get; set; } + public DateTime ToDate { get; set; } + public ulong FromAge { get; set; } + public ulong ToAge { get; set; } private uint dataLengthNeeded; + private uint originalOffset; public override bool Compose() { @@ -98,7 +208,9 @@ namespace Esiur.Net.Packets { if (offset + needed > ends) { - dataLengthNeeded = needed - (ends - offset); + //dataLengthNeeded = needed - (ends - offset); + dataLengthNeeded = needed - (ends - originalOffset); + return true; } else @@ -107,13 +219,15 @@ namespace Esiur.Net.Packets public override long Parse(byte[] data, uint offset, uint ends) { - var oOffset = offset; + originalOffset = offset; if (NotEnough(offset, ends, 1)) return -dataLengthNeeded; - Command = (IIPPacketCommand)(data[offset] >> 6); + PreviousCommand = Command; + Command = (IIPPacketCommand)(data[offset] >> 6); + if (Command == IIPPacketCommand.Event) { Event = (IIPPacketEvent)(data[offset++] & 0x3f); @@ -124,8 +238,19 @@ namespace Esiur.Net.Packets ResourceId = data.GetUInt32(offset); offset += 4; } + else if (Command == IIPPacketCommand.Report) + { + Report = (IIPPacketReport)(data[offset++] & 0x3f); + + if (NotEnough(offset, ends, 4)) + return -dataLengthNeeded; + + CallbackId = data.GetUInt32(offset); + offset += 4; + } else { + PreviousAction = Action; Action = (IIPPacketAction)(data[offset++] & 0x3f); if (NotEnough(offset, ends, 4)) @@ -150,6 +275,30 @@ namespace Esiur.Net.Packets { // nothing to parse } + else if (Event == IIPPacketEvent.ChildAdded + || Event == IIPPacketEvent.ChildRemoved) + { + if (NotEnough(offset, ends, 4)) + return -dataLengthNeeded; + + ChildId = data.GetUInt32(offset); + offset += 4; + } + else if(Event == IIPPacketEvent.Renamed) + { + if (NotEnough(offset, ends, 2)) + return -dataLengthNeeded; + + var cl = data.GetUInt16(offset); + offset += 2; + + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; + + Content = data.Clip(offset, cl); + + offset += cl; + } else if (Event == IIPPacketEvent.PropertyUpdated) { if (NotEnough(offset, ends, 2)) @@ -183,7 +332,7 @@ namespace Esiur.Net.Packets offset += (uint)size; } } - else if (Event == IIPPacketEvent.EventOccured) + else if (Event == IIPPacketEvent.EventOccurred) { if (NotEnough(offset, ends, 5)) return -dataLengthNeeded; @@ -197,6 +346,22 @@ namespace Esiur.Net.Packets offset += cl; } + // Attribute + else if (Event == IIPPacketEvent.AttributesUpdated) + { + if (NotEnough(offset, ends, 4)) + return -dataLengthNeeded; + + var cl = data.GetUInt32(offset); + offset += 4; + + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; + + Content = data.Clip(offset, cl); + + offset += cl; + } } else if (Command == IIPPacketCommand.Request) { @@ -210,14 +375,14 @@ namespace Esiur.Net.Packets } else if (Action == IIPPacketAction.ReattachResource) { - if (NotEnough(offset, ends, 8)) + if (NotEnough(offset, ends, 12)) return -dataLengthNeeded; ResourceId = data.GetUInt32(offset); offset += 4; - ResourceAge = data.GetUInt32(offset); - offset += 4; + ResourceAge = data.GetUInt64(offset); + offset += 8; } else if (Action == IIPPacketAction.DetachResource) @@ -231,16 +396,21 @@ namespace Esiur.Net.Packets } else if (Action == IIPPacketAction.CreateResource) { - if (NotEnough(offset, ends, 1)) + if (NotEnough(offset, ends, 12)) return -dataLengthNeeded; - var cl = data[offset++]; + StoreId = data.GetUInt32(offset); + offset += 4; + ResourceId = data.GetUInt32(offset); + offset += 4; + + var cl = data.GetUInt32(offset); + offset += 4; if (NotEnough(offset, ends, cl)) return -dataLengthNeeded; - ClassName = data.GetString(offset, cl); - offset += cl; + this.Content = data.Clip(offset, cl); } else if (Action == IIPPacketAction.DeleteResource) { @@ -251,6 +421,33 @@ namespace Esiur.Net.Packets offset += 4; } + else if (Action == IIPPacketAction.AddChild + || Action == IIPPacketAction.RemoveChild) + { + if (NotEnough(offset, ends, 8)) + return -dataLengthNeeded; + + ResourceId = data.GetUInt32(offset); + offset += 4; + ChildId = data.GetUInt32(offset); + offset += 4; + } + else if (Action == IIPPacketAction.RenameResource) + { + if (NotEnough(offset, ends, 6)) + return -dataLengthNeeded; + + ResourceId = data.GetUInt32(offset); + offset += 4; + var cl = data.GetUInt16(offset); + offset += 2; + + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; + + Content = data.Clip(offset, cl); + offset += cl; + } else if (Action == IIPPacketAction.TemplateFromClassName) { if (NotEnough(offset, ends, 1)) @@ -274,20 +471,6 @@ namespace Esiur.Net.Packets offset += 16; } - else if (Action == IIPPacketAction.TemplateFromResourceLink) - { - if (NotEnough(offset, ends, 2)) - return -dataLengthNeeded; - - var cl = data.GetUInt16(offset); - offset += 2; - - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; - - ResourceLink = data.GetString(offset, cl); - offset += cl; - } else if (Action == IIPPacketAction.TemplateFromResourceId) { if (NotEnough(offset, ends, 4)) @@ -296,7 +479,7 @@ namespace Esiur.Net.Packets ResourceId = data.GetUInt32(offset); offset += 4; } - else if (Action == IIPPacketAction.ResourceIdFromResourceLink) + else if (Action == IIPPacketAction.QueryLink) { if (NotEnough(offset, ends, 2)) return -dataLengthNeeded; @@ -310,6 +493,30 @@ namespace Esiur.Net.Packets ResourceLink = data.GetString(offset, cl); offset += cl; } + else if (Action == IIPPacketAction.ResourceChildren + || Action == IIPPacketAction.ResourceParents) + { + if (NotEnough(offset, ends, 4)) + return -dataLengthNeeded; + + ResourceId = data.GetUInt32(offset); + offset += 4; + } + else if (Action == IIPPacketAction.ResourceHistory) + { + if (NotEnough(offset, ends, 20)) + return -dataLengthNeeded; + + ResourceId = data.GetUInt32(offset); + offset += 4; + + FromDate = data.GetDateTime(offset); + offset += 8; + + ToDate = data.GetDateTime(offset); + offset += 8; + + } else if (Action == IIPPacketAction.InvokeFunction) { if (NotEnough(offset, ends, 9)) @@ -351,8 +558,8 @@ namespace Esiur.Net.Packets MethodIndex = data[offset++]; - ResourceAge = data.GetUInt32(offset); - offset += 4; + ResourceAge = data.GetUInt64(offset); + offset += 8; } else if (Action == IIPPacketAction.SetProperty) @@ -392,6 +599,26 @@ namespace Esiur.Net.Packets offset += (uint)size; } } + // Attributes + else if (Action == IIPPacketAction.UpdateAllAttributes + || Action == IIPPacketAction.GetAttributes + || Action == IIPPacketAction.UpdateAttributes + || Action == IIPPacketAction.ClearAttributes) + { + if (NotEnough(offset, ends, 8)) + return -dataLengthNeeded; + + ResourceId = data.GetUInt32(offset); + offset += 4; + var cl = data.GetUInt32(offset); + offset += 4; + + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; + + Content = data.Clip(offset, cl); + offset += cl; + } } else if (Command == IIPPacketCommand.Reply) { @@ -405,8 +632,8 @@ namespace Esiur.Net.Packets ClassId = data.GetGuid(offset); offset += 16; - ResourceAge = data.GetUInt32(offset); - offset += 4; + ResourceAge = data.GetUInt64(offset); + offset += 8; uint cl = data.GetUInt16(offset); offset += 2; @@ -438,8 +665,8 @@ namespace Esiur.Net.Packets if (NotEnough(offset, ends, 20)) return -dataLengthNeeded; - ClassId = data.GetGuid(offset); - offset += 16; + //ClassId = data.GetGuid(offset); + //offset += 16; ResourceId = data.GetUInt32(offset); offset += 4; @@ -449,10 +676,17 @@ namespace Esiur.Net.Packets { // nothing to do } + // Inquire else if (Action == IIPPacketAction.TemplateFromClassName || Action == IIPPacketAction.TemplateFromClassId - || Action == IIPPacketAction.TemplateFromResourceLink - || Action == IIPPacketAction.TemplateFromResourceId) + || Action == IIPPacketAction.TemplateFromResourceId + || Action == IIPPacketAction.QueryLink + || Action == IIPPacketAction.ResourceChildren + || Action == IIPPacketAction.ResourceParents + || Action == IIPPacketAction.ResourceHistory + // Attribute + || Action == IIPPacketAction.GetAllAttributes + || Action == IIPPacketAction.GetAttributes) { if (NotEnough(offset, ends, 4)) return -dataLengthNeeded; @@ -466,20 +700,6 @@ namespace Esiur.Net.Packets Content = data.Clip(offset, cl); offset += cl; } - else if (Action == IIPPacketAction.ResourceIdFromResourceLink) - { - if (NotEnough(offset, ends, 24)) - return -dataLengthNeeded; - - ClassId = data.GetGuid(offset); - offset += 16; - - ResourceId = data.GetUInt32(offset); - offset += 4; - - ResourceAge = data.GetUInt32(offset); - offset += 4; - } else if (Action == IIPPacketAction.InvokeFunction || Action == IIPPacketAction.GetProperty || Action == IIPPacketAction.GetPropertyIfModified) @@ -518,33 +738,80 @@ namespace Esiur.Net.Packets // nothing to do } } - else if (Command == IIPPacketCommand.Error) + else if (Command == IIPPacketCommand.Report) { - // Error - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; + if (Report == IIPPacketReport.ManagementError) + { + if (NotEnough(offset, ends, 2)) + return -dataLengthNeeded; - CallbackId = data.GetUInt32(offset); + ErrorCode = data.GetUInt16(offset); + offset += 2; + } + else if (Report == IIPPacketReport.ExecutionError) + { + if (NotEnough(offset, ends, 2)) + return -dataLengthNeeded; - if (NotEnough(offset, ends, 1)) - return -dataLengthNeeded; + ErrorCode = data.GetUInt16(offset); + offset += 2; - ErrorCode = data[offset++]; + if (NotEnough(offset, ends, 2)) + return -dataLengthNeeded; - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; + var cl = data.GetUInt16(offset); + offset += 2; - var cl = data.GetUInt32(offset); - offset += 4; + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; + ErrorMessage = data.GetString(offset, cl); + offset += cl; + } + else if (Report == IIPPacketReport.ProgressReport) + { + if (NotEnough(offset, ends, 8)) + return -dataLengthNeeded; - ErrorMessage = data.GetString(offset, cl); - offset += cl; + ProgressValue = data.GetInt32(offset); + offset += 4; + ProgressMax = data.GetInt32(offset); + offset += 4; + } + else if (Report == IIPPacketReport.ChunkStream) + { + 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 cl = data.GetUInt32(offset); + offset += 4; + + 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; + } + } } - return offset - oOffset; + return offset - originalOffset; } } } diff --git a/Esiur/Net/Packets/WebsocketPacket.cs b/Esiur/Net/Packets/WebsocketPacket.cs index 5eb28d8..14f4009 100644 --- a/Esiur/Net/Packets/WebsocketPacket.cs +++ b/Esiur/Net/Packets/WebsocketPacket.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; @@ -138,9 +162,10 @@ namespace Esiur.Net.Packets offset += 8; } + /* if (Mask) { - MaskKey = new byte[4]; + MaskKey = new byte[4]; MaskKey[0] = data[offset++]; MaskKey[1] = data[offset++]; MaskKey[2] = data[offset++]; @@ -149,6 +174,7 @@ namespace Esiur.Net.Packets //MaskKey = DC.GetUInt32(data, offset); //offset += 4; } + */ needed += PayloadLength; if (length < needed) @@ -156,23 +182,26 @@ namespace Esiur.Net.Packets //Console.WriteLine("stage 4"); return length - needed; } - - // if ((int)PayloadLength > (ends - offset)) - // { - // return -((int)PayloadLength - (ends - offset)); - // } else { - Message = DC.Clip(data, offset, (uint)PayloadLength); if (Mask) { + MaskKey = new byte[4]; + MaskKey[0] = data[offset++]; + MaskKey[1] = data[offset++]; + MaskKey[2] = data[offset++]; + MaskKey[3] = data[offset++]; + + Message = DC.Clip(data, offset, (uint)PayloadLength); + //var aMask = BitConverter.GetBytes(MaskKey); for (int i = 0; i < Message.Length; i++) - { Message[i] = (byte)(Message[i] ^ MaskKey[i % 4]); - } } + else + Message = DC.Clip(data, offset, (uint)PayloadLength); + return (offset - oOffset) + (int)PayloadLength; } diff --git a/Esiur/Net/Sockets/ISocket.cs b/Esiur/Net/Sockets/ISocket.cs index 8fb843a..26e9274 100644 --- a/Esiur/Net/Sockets/ISocket.cs +++ b/Esiur/Net/Sockets/ISocket.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.IO; using System.Net.Sockets; using System.Text; diff --git a/Esiur/Net/Sockets/SSLSocket.cs b/Esiur/Net/Sockets/SSLSocket.cs index ef1e897..58eb7e1 100644 --- a/Esiur/Net/Sockets/SSLSocket.cs +++ b/Esiur/Net/Sockets/SSLSocket.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Net/Sockets/SocketState.cs b/Esiur/Net/Sockets/SocketState.cs index 85e6a9f..e99df3d 100644 --- a/Esiur/Net/Sockets/SocketState.cs +++ b/Esiur/Net/Sockets/SocketState.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Net/Sockets/TCPSocket.cs b/Esiur/Net/Sockets/TCPSocket.cs index c37b196..62b6345 100644 --- a/Esiur/Net/Sockets/TCPSocket.cs +++ b/Esiur/Net/Sockets/TCPSocket.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; @@ -27,7 +51,7 @@ namespace Esiur.Net.Sockets Queue sendBufferQueue = new Queue(); bool asyncSending; - + bool began = false; SocketState state = SocketState.Initial; @@ -36,6 +60,7 @@ namespace Esiur.Net.Sockets public event ISocketCloseEvent OnClose; public event DestroyedEvent OnDestroy; + SocketAsyncEventArgs socketArgs = new SocketAsyncEventArgs(); private void Connected(Task t) { @@ -46,7 +71,18 @@ namespace Esiur.Net.Sockets public bool Begin() { - sock.ReceiveAsync(receiveBufferSegment, SocketFlags.None).ContinueWith(DataReceived); + if (began) + return false; + + began = true; + + socketArgs.SetBuffer(receiveBuffer, 0, receiveBuffer.Length); + socketArgs.Completed += SocketArgs_Completed; + + if (!sock.ReceiveAsync(socketArgs)) + SocketArgs_Completed(null, socketArgs); + + //sock.ReceiveAsync(receiveBufferSegment, SocketFlags.None).ContinueWith(DataReceived); return true; } @@ -80,11 +116,21 @@ namespace Esiur.Net.Sockets return; } + //if (receiveNetworkBuffer.Protected) + // Console.WriteLine(); + //lock (receiveNetworkBuffer.SyncLock) receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)task.Result); + + //Console.WriteLine("TC IN: " + (uint)task.Result + " " + DC.ToHex(receiveBuffer, 0, (uint)task.Result)); + OnReceive?.Invoke(receiveNetworkBuffer); if (state == SocketState.Established) + { sock.ReceiveAsync(receiveBufferSegment, SocketFlags.None).ContinueWith(DataReceived); + + } + } catch (Exception ex) { @@ -98,6 +144,56 @@ namespace Esiur.Net.Sockets } } + private void SocketArgs_Completed(object sender, SocketAsyncEventArgs e) + { + try + { + // SocketError err; + + if (state == SocketState.Closed || state == SocketState.Terminated) + return; + + if (e.BytesTransferred == 0) + { + Close(); + return; + } + + //if (receiveNetworkBuffer.Protected) + // Console.WriteLine(); + + + //lock (receiveNetworkBuffer.SyncLock) + receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)e.BytesTransferred); + + //Console.WriteLine("TC IN: " + (uint)e.BytesTransferred + " " + DC.ToHex(receiveBuffer, 0, (uint)e.BytesTransferred)); + + + + + OnReceive?.Invoke(receiveNetworkBuffer); + + if (state == SocketState.Established) + { + if (!sock.ReceiveAsync(socketArgs)) + { + //Console.WriteLine("Sync"); + SocketArgs_Completed(sender, e); + } + } + + } + catch (Exception ex) + { + if (state != SocketState.Closed && !sock.Connected) + { + state = SocketState.Terminated; + Close(); + } + + Global.Log("TCPSocket", LogType.Error, ex.ToString()); + } + } public IPEndPoint LocalEndPoint { @@ -234,18 +330,19 @@ namespace Esiur.Net.Sockets public void Send(byte[] message, int offset, int size) { - lock (sendLock) - { - if (asyncSending) + if (sock.Connected) + lock (sendLock) { - sendBufferQueue.Enqueue(message.Clip((uint)offset, (uint)size)); + if (asyncSending) + { + sendBufferQueue.Enqueue(message.Clip((uint)offset, (uint)size)); + } + else + { + asyncSending = true; + sock.SendAsync(new ArraySegment(message, offset, size), SocketFlags.None).ContinueWith(DataSent); + } } - else - { - asyncSending = true; - sock.SendAsync(new ArraySegment(message, offset, size), SocketFlags.None).ContinueWith(DataSent); - } - } } diff --git a/Esiur/Net/Sockets/WSSocket.cs b/Esiur/Net/Sockets/WSSocket.cs index 6de470b..b913aa5 100644 --- a/Esiur/Net/Sockets/WSSocket.cs +++ b/Esiur/Net/Sockets/WSSocket.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; @@ -9,6 +33,7 @@ using Esiur.Misc; using System.IO; using Esiur.Engine; using Esiur.Resource; +using Esiur.Data; namespace Esiur.Net.Sockets { @@ -28,6 +53,8 @@ namespace Esiur.Net.Sockets long totalSent, totalReceived; + bool processing = false; + public IPEndPoint LocalEndPoint { get { return (IPEndPoint)sock.LocalEndPoint; } @@ -70,9 +97,17 @@ namespace Esiur.Net.Sockets if (buffer.Protected) return; + if (processing) + return; + + var msg = buffer.Read(); + if (msg == null) + return; + var wsPacketLength = pkt_receive.Parse(msg, 0, (uint)msg.Length); + //Console.WriteLine("WSP: " + wsPacketLength); if (wsPacketLength < 0) { @@ -114,12 +149,16 @@ namespace Esiur.Net.Sockets receiveNetworkBuffer.Write(pkt_receive.Message); offset += (uint)wsPacketLength; + + //Console.WriteLine("WS IN: " + pkt_receive.Opcode.ToString() + " " + pkt_receive.Message.Length + " | " + offset + " " + string.Join(" ", pkt_receive.Message));// DC.ToHex(pkt_receive.Message)); + } else Console.WriteLine("Unknown WS opcode:" + pkt_receive.Opcode); if (offset == msg.Length) { + // Console.WriteLine("WS IN: " + receiveNetworkBuffer.Available); OnReceive?.Invoke(receiveNetworkBuffer); return; } @@ -132,11 +171,18 @@ namespace Esiur.Net.Sockets //receiveNetworkBuffer.HoldFor(msg, offset, (uint)(msg.Length - offset), (uint)msg.Length + (uint)-wsPacketLength); // save the incomplete packet to the heldBuffer queue - receiveNetworkBuffer.HoldFor(msg, offset, (uint)(msg.Length - offset), (uint)(msg.Length - offset) + (uint)-wsPacketLength); + buffer.HoldFor(msg, offset, (uint)(msg.Length - offset), (uint)(msg.Length - offset) + (uint)-wsPacketLength); } + //Console.WriteLine("WS IN: " + receiveNetworkBuffer.Available); + OnReceive?.Invoke(receiveNetworkBuffer); + + processing = false; + + if (buffer.Available > 0 && !buffer.Protected) + Sock_OnReceive(buffer); } private void Sock_OnConnect() diff --git a/Esiur/Net/TCP/TCPConnection.cs b/Esiur/Net/TCP/TCPConnection.cs index f2d93c1..61d575b 100644 --- a/Esiur/Net/TCP/TCPConnection.cs +++ b/Esiur/Net/TCP/TCPConnection.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Net/TCP/TCPFilter.cs b/Esiur/Net/TCP/TCPFilter.cs index 82a3c80..df86ebb 100644 --- a/Esiur/Net/TCP/TCPFilter.cs +++ b/Esiur/Net/TCP/TCPFilter.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Net/TCP/TCPServer.cs b/Esiur/Net/TCP/TCPServer.cs index af23844..16cd88b 100644 --- a/Esiur/Net/TCP/TCPServer.cs +++ b/Esiur/Net/TCP/TCPServer.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Net/TCP/TCPSession.cs b/Esiur/Net/TCP/TCPSession.cs index 7bca931..f2cfb52 100644 --- a/Esiur/Net/TCP/TCPSession.cs +++ b/Esiur/Net/TCP/TCPSession.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Net/UDP/UDPFilter.cs b/Esiur/Net/UDP/UDPFilter.cs index 06f6a67..01633f9 100644 --- a/Esiur/Net/UDP/UDPFilter.cs +++ b/Esiur/Net/UDP/UDPFilter.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Net/UDP/UDPServer.cs b/Esiur/Net/UDP/UDPServer.cs index ea461b9..0de3199 100644 --- a/Esiur/Net/UDP/UDPServer.cs +++ b/Esiur/Net/UDP/UDPServer.cs @@ -1,3 +1,27 @@ +/* + +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.Net; using System.Net.Sockets; diff --git a/Esiur/Properties/PublishProfiles/FolderProfile.pubxml b/Esiur/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000..2716dc5 --- /dev/null +++ b/Esiur/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,13 @@ + + + + + FileSystem + Release + netstandard1.5 + M:\opt\esiur + Any CPU + + \ No newline at end of file diff --git a/Esiur/Resource/IResource.cs b/Esiur/Resource/IResource.cs index 3ee0efa..95a6230 100644 --- a/Esiur/Resource/IResource.cs +++ b/Esiur/Resource/IResource.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Resource/IStore.cs b/Esiur/Resource/IStore.cs index 894b1cb..96df8af 100644 --- a/Esiur/Resource/IStore.cs +++ b/Esiur/Resource/IStore.cs @@ -1,4 +1,30 @@ -using Esiur.Engine; +/* + +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 Esiur.Data; +using Esiur.Engine; +using Esiur.Resource.Template; using System; using System.Collections.Generic; using System.Linq; @@ -13,5 +39,15 @@ namespace Esiur.Resource AsyncReply Retrieve(uint iid); bool 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 Remove(IResource resource); + //AsyncReply GetPropertyRecord(IResource resource, string propertyName, ulong fromAge, ulong toAge); + //AsyncReply GetPropertyRecordByDate(IResource resource, string propertyName, DateTime fromDate, DateTime toDate); + + //AsyncReply> GetRecord(IResource resource, ulong fromAge, ulong toAge); + // AsyncReply> GetRecordByDate(IResource resource, DateTime fromDate, DateTime toDate); + + AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate); } } diff --git a/Esiur/Resource/Instance.cs b/Esiur/Resource/Instance.cs index b6bfaa7..c8ef27d 100644 --- a/Esiur/Resource/Instance.cs +++ b/Esiur/Resource/Instance.cs @@ -10,6 +10,7 @@ using Esiur.Net.IIP; using Esiur.Misc; using Esiur.Security.Permissions; using Esiur.Resource.Template; +using Esiur.Security.Authority; namespace Esiur.Resource { @@ -21,27 +22,33 @@ namespace Esiur.Resource IResource resource; IStore store; AutoList parents;// = new AutoList(); - bool inherit; + //bool inherit; ResourceTemplate template; - AutoList managers;// = new AutoList(); + AutoList managers;// = new AutoList(); + + + public delegate void ResourceModifiedEvent(IResource resource, string propertyName, object newValue); + //public delegate void ResourceEventOccurredEvent(IResource resource, string eventName, string[] users, DistributedConnection[] connections, object[] args); + + public delegate void ResourceEventOccurredEvent(IResource resource, object issuer, Session[] receivers, string eventName, object[] args); - public delegate void ResourceModifiedEvent(IResource resource, string propertyName, object newValue, object oldValue); - public delegate void ResourceEventOccurredEvent(IResource resource, string eventName, string[] receivers, object[] args); public delegate void ResourceDestroyedEvent(IResource resource); public event ResourceModifiedEvent ResourceModified; - public event ResourceEventOccurredEvent ResourceEventOccured; + public event ResourceEventOccurredEvent ResourceEventOccurred; public event ResourceDestroyedEvent ResourceDestroyed; - KeyList attributes = new KeyList(); + KeyList attributes; - List ages = new List(); - private uint age; + List ages = new List(); + List modificationDates = new List(); + private ulong instanceAge; + private DateTime instanceModificationDate; uint id; - + /// /// Instance attributes are custom properties associated with the instance, a place to store information by IStore. /// @@ -53,12 +60,151 @@ namespace Esiur.Resource } } + public override string ToString() + { + return name + " (" + Link + ")"; + } + + public bool RemoveAttributes(string[] attributes = null) + { + if (attributes == null) + this.attributes.Clear(); + else + { + foreach (var attr in attributes) + this.attributes.Remove(attr); + } + + return true; + } + + public Structure GetAttributes(string[] attributes = null) + { + var st = new Structure(); + + if (attributes == null) + { + var clone = this.attributes.Keys.ToList(); + clone.Add("managers"); + attributes = clone.ToArray();// this.attributes.Keys.ToList().Add("managers"); + } + + foreach(var attr in attributes) + { + if (attr == "name") + st["name"] = this.name; + else if (attr == "managers") + { + var mngrs = new List(); + + foreach (var manager in this.managers) + mngrs.Add(new Structure() + { + ["type"] = manager.GetType().FullName + "," + manager.GetType().GetTypeInfo().Assembly.GetName().Name, + ["settings"] = manager.Settings + }); + + st["managers"] = mngrs.ToArray(); + } + else if (attr == "parents") + { + st["parents"] = parents.ToArray(); + } + else if (attr == "children") + { + st["children"] = children.ToArray(); + } + else if (attr == "childrenCount") + { + st["childrenCount"] = children.Count; + } + else if (attr == "type") + { + st["type"] = resource.GetType().FullName; + } + else + st[attr] = this.attributes[attr]; + } + + return st; + } + + public bool SetAttributes(Structure attributes, bool clearAttributes = false) + { + try + { + + if (clearAttributes) + this.attributes.Clear(); + + foreach (var attr in attributes) + if (attr.Key == "name") + this.name = attr.Value as string; + else if (attr.Key == "managers") + { + this.managers.Clear(); + + var mngrs = attr.Value as object[]; + + foreach (var mngr in mngrs) + { + var m = mngr as Structure; + var type = Type.GetType(m["type"] as string); + if (Codec.ImplementsInterface(type, typeof(IPermissionsManager))) + { + var settings = m["settings"] as Structure; + var manager = Activator.CreateInstance(type) as IPermissionsManager; + manager.Initialize(settings, this.resource); + this.managers.Add(manager); + } + else + return false; + } + } + else + { + this.attributes[attr.Key] = attr.Value; + } + + } + catch + { + return false; + } + + return true; + } + + /* + public Structure GetAttributes() + { + var st = new Structure(); + foreach (var a in attributes.Keys) + st[a] = attributes[a]; + + st["name"] = name; + + var mngrs = new List(); + + foreach (var manager in managers) + { + var mngr = new Structure(); + mngr["settings"] = manager.Settings; + mngr["type"] = manager.GetType().FullName; + mngrs.Add(mngr); + } + + st["managers"] = mngrs; + + return st; + }*/ + /// /// Get the age of a given property index. /// /// Zero-based property index. /// Age. - public uint GetAge(byte index) + public ulong GetAge(byte index) { if (index < ages.Count) return ages[index]; @@ -67,12 +213,107 @@ namespace Esiur.Resource } /// - /// Age of the instance, increments by 1 in every modification. + /// Set the age of a property. /// - public uint Age + /// Zero-based property index. + /// Age. + public void SetAge(byte index, ulong value) { - get { return age; } - internal set { age = value; } + if (index < ages.Count) + { + ages[index] = value; + if (value > instanceAge) + instanceAge = value; + } + } + + /// + /// Set the modification date of a property. + /// + /// Zero-based property index. + /// Modification date. + public void SetModificationDate(byte index, DateTime value) + { + if (index < modificationDates.Count) + { + modificationDates[index] = value; + if (value > instanceModificationDate) + instanceModificationDate = value; + } + } + + /// + /// Get modification date of a specific property. + /// + /// Zero-based property index + /// Modification date. + public DateTime GetModificationDate(byte index) + { + if (index < modificationDates.Count) + return modificationDates[index]; + else + return DateTime.MinValue; + } + + + /// + /// Load property value (used by stores) + /// + /// Property name + /// Property age + /// Property value + /// + public bool LoadProperty(string name, ulong age, DateTime modificationDate, object value) + { + var pt = template.GetPropertyTemplate(name); + + if (pt == null) + return false; + +#if NETSTANDARD1_5 + var pi = resource.GetType().GetTypeInfo().GetProperty(name); +#else + var pi = resource.GetType().GetProperty(pt.Name); +#endif + if (pi.PropertyType == typeof(DistributedPropertyContext)) + return false; + + + try + { + if (pi.CanWrite) + pi.SetValue(resource, DC.CastConvert(value, pi.PropertyType)); + } + catch(Exception ex) + { + //Console.WriteLine(resource.ToString() + " " + name); + Global.Log(ex); + } + + SetAge(pt.Index, age); + SetModificationDate(pt.Index, modificationDate); + + return true; + } + + /// + /// Age of the instance, incremented by 1 in every modification. + /// + public ulong Age + { + get { return instanceAge; } + internal set { instanceAge = value; } + } + + /// + /// Last modification date. + /// + public DateTime ModificationDate + { + get + { + return instanceModificationDate; + } } /// @@ -88,18 +329,18 @@ namespace Esiur.Resource /// /// /// - public bool Deserialize(object[] properties) - { - foreach (var pt in template.Properties) + public bool Deserialize(PropertyValue[] properties) + { + for (byte i = 0; i < properties.Length; i++) { -#if NETSTANDARD1_5 - var pi = resource.GetType().GetTypeInfo().GetProperty(pt.Name); -#else - var pi = resource.GetType().GetProperty(pt.Name); -#endif - if (!(properties[pt.Index] is NotModified)) - pi.SetValue(resource, properties[pt.Index]); + var pt = this.template.GetPropertyTemplate(i); + if (pt != null) + { + var pv = properties[i]; + LoadProperty(pt.Name, pv.Age, pv.Date, pv.Value); + } } + return true; } @@ -107,9 +348,9 @@ namespace Esiur.Resource /// Export all properties with ResourceProperty attributed as bytes array. /// /// - public object[] Serialize() + public PropertyValue[] Serialize() { - List props = new List(); + List props = new List(); foreach (var pt in template.Properties) { @@ -119,7 +360,7 @@ namespace Esiur.Resource var pi = resource.GetType().GetProperty(pt.Name); #endif var rt = pi.GetValue(resource, null); - props.Add(rt); + props.Add(new PropertyValue(rt, ages[pt.Index], modificationDates[pt.Index])); } return props.ToArray(); @@ -191,10 +432,10 @@ namespace Esiur.Resource } */ - /// - /// If True, the instance can be stored to disk. - /// - /// + /// + /// If True, the instance can be stored to disk. + /// + /// public bool IsStorable() { #if NETSTANDARD1_5 @@ -207,27 +448,47 @@ namespace Esiur.Resource } + internal void EmitModification(PropertyTemplate pt, object value) + { + instanceAge++; + var now = DateTime.UtcNow; + + ages[pt.Index] = instanceAge; + modificationDates[pt.Index] = now; + + if (pt.Storage == StorageMode.NonVolatile) + { + store.Modify(resource, pt.Name, value, ages[pt.Index], now); + } + else if (pt.Storage == StorageMode.Recordable) + { + store.Record(resource, pt.Name, value, ages[pt.Index], now); + } + + ResourceModified?.Invoke(resource, pt.Name, value); + } + /// /// Notify listeners that a property was modified. /// /// /// /// - public void Modified([CallerMemberName] string propertyName = "", object newValue = null, object oldValue = null) + public void Modified([CallerMemberName] string propertyName = "")//, object newValue = null)//, object oldValue = null) { - if (newValue == null) + object value; + if (GetPropertyValue(propertyName, out value)) { - object val; - if (GetPropertyValue(propertyName, out val)) - ResourceModified?.Invoke(resource, propertyName, val, oldValue); + var pt = template.GetPropertyTemplate(propertyName); + EmitModification(pt, value); } - else - ResourceModified?.Invoke(resource, propertyName, newValue, oldValue); } - internal void EmitResourceEvent(string name, string[] receivers, object[] args) + // internal void EmitResourceEvent(string name, string[] users, DistributedConnection[] connections, object[] args) + + internal void EmitResourceEvent(object issuer, Session[] receivers, string name, object[] args) { - ResourceEventOccured?.Invoke(resource, name, receivers, args); + ResourceEventOccurred?.Invoke(resource, issuer, receivers, name, args); } /// @@ -259,7 +520,7 @@ namespace Esiur.Resource { value = pi.GetValue(resource, null); //if (value is Func) - // value = (value as Func)(sender); + // value = (value as Func)(sender); return true; } } @@ -269,10 +530,11 @@ namespace Esiur.Resource } + /* public bool Inherit { get { return inherit; } - } + }*/ /// /// List of parents. @@ -289,7 +551,7 @@ namespace Esiur.Resource { get { return store; } } - + /// /// List of children. /// @@ -335,6 +597,7 @@ namespace Esiur.Resource public string Name { get { return name; } + set { name = value; } } @@ -352,38 +615,86 @@ namespace Esiur.Resource public ResourceTemplate Template { get { return template; } + + /* + internal set + { + template = Warehouse.GetTemplate(resource.GetType()); + + // set ages + for (byte i = 0; i < template.Properties.Length; i++) + { + ages.Add(0); + modificationDates.Add(DateTime.MinValue); + } + } + */ } - /// - /// Create new instance. - /// - /// Instance Id. - /// Name of the instance. - /// Resource to manage. - /// Store responsible for the resource. - public Instance(uint id, string name, IResource resource, IStore store) + /// + /// Check for permission. + /// + /// Caller sessions. + /// Action type + /// Function, property or event to check for permission. + /// Permission inquirer. + /// Ruling. + public Ruling Applicable(Session session, ActionType action, MemberTemplate member, object inquirer = null) + { + foreach (IPermissionsManager manager in managers) + { + var r = manager.Applicable(this.resource, session, action, member, inquirer); + if (r != Ruling.DontCare) + return r; + } + + return Ruling.DontCare; + + } + + /// + /// Execution managers. + /// + public AutoList Managers => managers; + + /// + /// Create new instance. + /// + /// Instance Id. + /// Name of the instance. + /// Resource to manage. + /// Store responsible for the resource. + public Instance(uint id, string name, IResource resource, IStore store, ResourceTemplate customTemplate = null, ulong age = 0) { this.store = store; this.resource = resource; this.id = id; this.name = name; + this.instanceAge = age; + this.attributes = new KeyList(this); children = new AutoList(this); parents = new AutoList(this); - managers = new AutoList(this); + managers = new AutoList(this); children.OnAdd += Children_OnAdd; children.OnRemoved += Children_OnRemoved; + parents.OnAdd += Parents_OnAdd; + parents.OnRemoved += Parents_OnRemoved; resource.OnDestroy += Resource_OnDestroy; - template = Warehouse.GetTemplate(resource.GetType()); - - - // set ages + if (customTemplate != null) + this.template = customTemplate; + else + this.template = Warehouse.GetTemplate(resource.GetType()); + + // set ages for (byte i = 0; i < template.Properties.Length; i++) + { ages.Add(0); - - + modificationDates.Add(DateTime.MinValue); + } + // connect events Type t = resource.GetType(); @@ -396,16 +707,62 @@ namespace Esiur.Resource foreach (var evt in events) { - if (evt.EventHandlerType != typeof(ResourceEventHanlder)) - continue; + //if (evt.EventHandlerType != typeof(ResourceEventHanlder)) + // continue; - var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); - if (ca.Length == 0) - continue; + if (evt.EventHandlerType == typeof(ResourceEventHanlder)) + { + var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); + if (ca.Length == 0) + continue; + + ResourceEventHanlder proxyDelegate = (args) => EmitResourceEvent(null, null, evt.Name, args); + evt.AddEventHandler(resource, proxyDelegate); + + } + else if (evt.EventHandlerType == typeof(CustomResourceEventHanlder)) + { + var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); + if (ca.Length == 0) + continue; + + CustomResourceEventHanlder proxyDelegate = (issuer, receivers, args) => EmitResourceEvent(issuer, receivers, evt.Name, args); + evt.AddEventHandler(resource, proxyDelegate); + } + + + /* + else if (evt.EventHandlerType == typeof(CustomUsersEventHanlder)) + { + var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); + if (ca.Length == 0) + continue; + + CustomUsersEventHanlder proxyDelegate = (users, args) => EmitResourceEvent(evt.Name, users, null, args); + evt.AddEventHandler(resource, proxyDelegate); + } + else if (evt.EventHandlerType == typeof(CustomConnectionsEventHanlder)) + { + var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); + if (ca.Length == 0) + continue; + + CustomConnectionsEventHanlder proxyDelegate = (connections, args) => EmitResourceEvent(evt.Name, null, connections, args); + evt.AddEventHandler(resource, proxyDelegate); + } + else if (evt.EventHandlerType == typeof(CustomReceiversEventHanlder)) + { + var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); + if (ca.Length == 0) + continue; + + CustomReceiversEventHanlder proxyDelegate = (users, connections, args) => EmitResourceEvent(evt.Name, users, connections, args); + evt.AddEventHandler(resource, proxyDelegate); + + } + */ - ResourceEventHanlder proxyDelegate = (receivers, args) => EmitResourceEvent(evt.Name, receivers, args); - evt.AddEventHandler(resource, proxyDelegate); } } @@ -416,9 +773,22 @@ namespace Esiur.Resource private void Children_OnAdd(Instance parent, IResource value) { - value.Instance.parents.Add(resource); + if (!value.Instance.parents.Contains(resource)) + value.Instance.parents.Add(resource); } + private void Parents_OnRemoved(Instance parent, IResource value) + { + value.Instance.children.Remove(resource); + } + + private void Parents_OnAdd(Instance parent, IResource value) + { + if (!value.Instance.children.Contains(resource)) + value.Instance.children.Add(resource); + } + + private void Resource_OnDestroy(object sender) { ResourceDestroyed?.Invoke((IResource)sender); diff --git a/Esiur/Resource/Resource.cs b/Esiur/Resource/Resource.cs new file mode 100644 index 0000000..336ceda --- /dev/null +++ b/Esiur/Resource/Resource.cs @@ -0,0 +1,47 @@ +/* + +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.Generic; +using System.Text; +using Esiur.Engine; + +namespace Esiur.Resource +{ + public class Resource : IResource + { + public Instance Instance { get; set; } + + public event DestroyedEvent OnDestroy; + + public virtual void Destroy() + { + + } + + public virtual AsyncReply Trigger(ResourceTrigger trigger) + { + return new AsyncReply(true); + } + } +} diff --git a/Esiur/Resource/ResourceEvent.cs b/Esiur/Resource/ResourceEvent.cs index b50d4e3..f308d48 100644 --- a/Esiur/Resource/ResourceEvent.cs +++ b/Esiur/Resource/ResourceEvent.cs @@ -1,4 +1,27 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Resource/ResourceEventHandler.cs b/Esiur/Resource/ResourceEventHandler.cs index 3eec4a1..18954e1 100644 --- a/Esiur/Resource/ResourceEventHandler.cs +++ b/Esiur/Resource/ResourceEventHandler.cs @@ -1,5 +1,30 @@ -using Esiur.Data; +/* + +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 Esiur.Data; using Esiur.Engine; +using Esiur.Net.IIP; +using Esiur.Security.Authority; using System; using System.Collections.Generic; using System.Linq; @@ -8,6 +33,13 @@ using System.Threading.Tasks; namespace Esiur.Resource { - public delegate void ResourceEventHanlder(string[] receivers, params object[] args); + public delegate void ResourceEventHanlder(params object[] args); + // public delegate void CustomUsersEventHanlder(string[] usernames, params object[] args); + //public delegate void CustomReceiversEventHanlder(DistributedConnection[] connections, params object[] args); + //public delegate void CustomInquirerEventHanlder(object inquirer, params object[] args); + + public delegate void CustomResourceEventHanlder(object issuer, Session[] receivers, params object[] args); + + // public delegate void CustomReceiversEventHanlder(string[] usernames, DistributedConnection[] connections, params object[] args); } diff --git a/Esiur/Resource/ResourceFunction.cs b/Esiur/Resource/ResourceFunction.cs index af524bf..c562e27 100644 --- a/Esiur/Resource/ResourceFunction.cs +++ b/Esiur/Resource/ResourceFunction.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Resource/ResourceProperty.cs b/Esiur/Resource/ResourceProperty.cs index 686436d..aef6567 100644 --- a/Esiur/Resource/ResourceProperty.cs +++ b/Esiur/Resource/ResourceProperty.cs @@ -1,4 +1,29 @@ -using System; +/* + +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 Esiur.Resource.Template; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -12,7 +37,15 @@ namespace Esiur.Resource { string readExpansion; string writeExpansion; + // bool recordable; + //bool storable; + //public bool Recordable => recordable; + + //public bool Storable => storable; + StorageMode storage; + + public StorageMode Storage => storage; public string ReadExpansion { @@ -30,10 +63,11 @@ namespace Esiur.Resource } } - public ResourceProperty(string readExpansion = null, string writeExpansion = null) + public ResourceProperty(StorageMode storage = StorageMode.Volatile, string readExpansion = null, string writeExpansion = null) { this.readExpansion = readExpansion; this.writeExpansion = writeExpansion; + this.storage = storage; } } } diff --git a/Esiur/Resource/ResourceTrigger.cs b/Esiur/Resource/ResourceTrigger.cs index b90e6aa..837d75e 100644 --- a/Esiur/Resource/ResourceTrigger.cs +++ b/Esiur/Resource/ResourceTrigger.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Resource/Storable.cs b/Esiur/Resource/Storable.cs index de8f15a..76184cc 100644 --- a/Esiur/Resource/Storable.cs +++ b/Esiur/Resource/Storable.cs @@ -1,4 +1,28 @@ -using Esiur.Data; +/* + +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 Esiur.Data; using Esiur.Engine; using System; using System.Collections.Generic; diff --git a/Esiur/Resource/StorageMode.cs b/Esiur/Resource/StorageMode.cs new file mode 100644 index 0000000..5513838 --- /dev/null +++ b/Esiur/Resource/StorageMode.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Resource +{ + public enum StorageMode : byte + { + Volatile = 0, + NonVolatile, + Recordable + } +} diff --git a/Esiur/Resource/Template/EventTemplate.cs b/Esiur/Resource/Template/EventTemplate.cs index 48afc6e..e132e97 100644 --- a/Esiur/Resource/Template/EventTemplate.cs +++ b/Esiur/Resource/Template/EventTemplate.cs @@ -28,6 +28,11 @@ namespace Esiur.Resource.Template return BinaryList.ToBytes((byte)0x40, (byte)name.Length, name); } - public EventTemplate() { Type = MemberType.Event; } + + public EventTemplate(ResourceTemplate template, byte index, string name, string expansion) + :base(template, MemberType.Property, index, name) + { + this.Expansion = expansion; + } } } diff --git a/Esiur/Resource/Template/FunctionTemplate.cs b/Esiur/Resource/Template/FunctionTemplate.cs index 8fa2389..512c35e 100644 --- a/Esiur/Resource/Template/FunctionTemplate.cs +++ b/Esiur/Resource/Template/FunctionTemplate.cs @@ -37,6 +37,11 @@ namespace Esiur.Resource.Template } - public FunctionTemplate() { Type = MemberType.Function; } + public FunctionTemplate(ResourceTemplate template, byte index, string name,bool isVoid, string expansion) + :base(template, MemberType.Property, index, name) + { + this.IsVoid = isVoid; + this.Expansion = expansion; + } } } diff --git a/Esiur/Resource/Template/MemberTemplate.cs b/Esiur/Resource/Template/MemberTemplate.cs index a24b5d8..b57bdde 100644 --- a/Esiur/Resource/Template/MemberTemplate.cs +++ b/Esiur/Resource/Template/MemberTemplate.cs @@ -16,9 +16,26 @@ namespace Esiur.Resource.Template Event = 2, } - public byte Index { get; set; } - public string Name { get; set; } - public MemberType Type { get; set; } + public byte Index => index; + public string Name => name; + public MemberType Type => type; + + ResourceTemplate template; + string name; + MemberType type; + byte index; + + public ResourceTemplate Template => template; + + public MemberTemplate(ResourceTemplate 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 virtual byte[] Compose() { diff --git a/Esiur/Resource/Template/PropertyTemplate.cs b/Esiur/Resource/Template/PropertyTemplate.cs index 96cf427..3bc8df3 100644 --- a/Esiur/Resource/Template/PropertyTemplate.cs +++ b/Esiur/Resource/Template/PropertyTemplate.cs @@ -16,13 +16,27 @@ namespace Esiur.Resource.Template ReadWrite } + //bool ReadOnly; //IIPTypes::DataType ReturnType; public PropertyPermission Permission { get; set; } - + + /* + public bool Recordable + { + get; + set; + }*/ + + public StorageMode Storage + { + get; + set; + } + public string ReadExpansion { get; @@ -35,37 +49,46 @@ namespace Esiur.Resource.Template set; } + /* public bool Storable { get; set; - } + }*/ public override byte[] Compose() { var name = base.Compose(); + var pv = ((byte)(Permission) << 1) | (Storage == StorageMode.Recordable ? 1 : 0); if (WriteExpansion != null && ReadExpansion != null) { var rexp = DC.ToBytes(ReadExpansion); var wexp = DC.ToBytes(WriteExpansion); - return BinaryList.ToBytes((byte)(0x38 | (byte)Permission), wexp.Length, wexp, rexp.Length, rexp, (byte)name.Length, name); + return BinaryList.ToBytes((byte)(0x38 | pv), wexp.Length, wexp, rexp.Length, rexp, (byte)name.Length, name); } else if (WriteExpansion != null) { var wexp = DC.ToBytes(WriteExpansion); - return BinaryList.ToBytes((byte)(0x30 | (byte)Permission), wexp.Length, wexp, (byte)name.Length, name); + return BinaryList.ToBytes((byte)(0x30 | pv), wexp.Length, wexp, (byte)name.Length, name); } else if (ReadExpansion != null) { var rexp = DC.ToBytes(ReadExpansion); - return BinaryList.ToBytes((byte)(0x28 | (byte)Permission), rexp.Length, rexp, (byte)name.Length, name); + return BinaryList.ToBytes((byte)(0x28 | pv), rexp.Length, rexp, (byte)name.Length, name); } else - return BinaryList.ToBytes((byte)(0x20 | (byte)Permission), (byte)name.Length, name); + return BinaryList.ToBytes((byte)(0x20 | pv), (byte)name.Length, name); } - public PropertyTemplate() { Type = MemberType.Property; } + public PropertyTemplate(ResourceTemplate template, byte index, string name, string read, string write, StorageMode storage) + :base(template, MemberType.Property, index, name) + { + //this.Recordable = recordable; + this.Storage = storage; + this.ReadExpansion = read; + this.WriteExpansion = write; + } } } diff --git a/Esiur/Resource/Template/ResourceTemplate.cs b/Esiur/Resource/Template/ResourceTemplate.cs index 9fa713c..ce52094 100644 --- a/Esiur/Resource/Template/ResourceTemplate.cs +++ b/Esiur/Resource/Template/ResourceTemplate.cs @@ -155,12 +155,8 @@ namespace Esiur.Resource.Template var ps = (ResourceProperty[])pi.GetCustomAttributes(typeof(ResourceProperty), true); if (ps.Length > 0) { - var pt = new PropertyTemplate(); - pt.Name = pi.Name; - pt.Index = i++; - pt.ReadExpansion = ps[0].ReadExpansion; - pt.WriteExpansion = ps[0].WriteExpansion; - properties.Add(pt); + var pt = new PropertyTemplate(this, i++, pi.Name, ps[0].ReadExpansion, ps[0].WriteExpansion, ps[0].Storage); + properties.Add(pt); } } @@ -171,10 +167,7 @@ namespace Esiur.Resource.Template var es = (ResourceEvent[])ei.GetCustomAttributes(typeof(ResourceEvent), true); if (es.Length > 0) { - var et = new EventTemplate(); - et.Name = ei.Name; - et.Index = i++; - et.Expansion = es[0].Expansion; + var et = new EventTemplate(this, i++, ei.Name, es[0].Expansion); events.Add(et); } } @@ -185,11 +178,7 @@ namespace Esiur.Resource.Template var fs = (ResourceFunction[])mi.GetCustomAttributes(typeof(ResourceFunction), true); if (fs.Length > 0) { - var ft = new FunctionTemplate(); - ft.Name = mi.Name; - ft.Index = i++; - ft.IsVoid = mi.ReturnType == typeof(void); - ft.Expansion = fs[0].Expansion; + var ft = new FunctionTemplate(this, i++, mi.Name, mi.ReturnType == typeof(void), fs[0].Expansion); functions.Add(ft); } } @@ -258,69 +247,76 @@ namespace Esiur.Resource.Template if (type == 0) // function { - var ft = new FunctionTemplate(); - ft.Index = functionIndex++; - var expansion = ((data[offset] & 0x10) == 0x10); - ft.IsVoid = ((data[offset++] & 0x08) == 0x08); - ft.Name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]); + string expansion = null; + var hasExpansion = ((data[offset] & 0x10) == 0x10); + var isVoid = ((data[offset++] & 0x08) == 0x08); + var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]); offset += (uint)data[offset] + 1; - - if (expansion) // expansion ? + + if (hasExpansion) // expansion ? { var cs = data.GetUInt32(offset); offset += 4; - ft.Expansion = data.GetString(offset, cs); + expansion = data.GetString(offset, cs); offset += cs; } + var ft = new FunctionTemplate(od, functionIndex++, name, isVoid, expansion); + od.functions.Add(ft); } else if (type == 1) // property { - var pt = new PropertyTemplate(); - pt.Index = propertyIndex++; - var readExpansion = ((data[offset] & 0x8) == 0x8); - var writeExpansion = ((data[offset] & 0x10) == 0x10); - pt.Permission = (PropertyTemplate.PropertyPermission)((data[offset++] >> 1) & 0x3); - pt.Name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]); + string readExpansion = null, writeExpansion = null; + + var hasReadExpansion = ((data[offset] & 0x8) == 0x8); + var hasWriteExpansion = ((data[offset] & 0x10) == 0x10); + var recordable = ((data[offset] & 1) == 1); + var permission = (PropertyTemplate.PropertyPermission)((data[offset++] >> 1) & 0x3); + var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]); + offset += (uint)data[offset] + 1; - if (readExpansion) // expansion ? + if (hasReadExpansion) // expansion ? { var cs = data.GetUInt32(offset); offset += 4; - pt.ReadExpansion = data.GetString(offset, cs); + readExpansion = data.GetString(offset, cs); offset += cs; } - if (writeExpansion) // expansion ? + if (hasWriteExpansion) // expansion ? { var cs = data.GetUInt32(offset); offset += 4; - pt.WriteExpansion = data.GetString(offset, cs); + writeExpansion = data.GetString(offset, cs); offset += cs; } + var pt = new PropertyTemplate(od, propertyIndex++, name, readExpansion, writeExpansion, recordable ? StorageMode.Recordable : StorageMode.Volatile); + od.properties.Add(pt); } else if (type == 2) // Event { - var et = new EventTemplate(); - et.Index = eventIndex++; - var expansion = ((data[offset++] & 0x10) == 0x10); - et.Name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, (int)data[offset]); + string expansion = null; + var hasExpansion = ((data[offset++] & 0x10) == 0x10); + + var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, (int)data[offset]); offset += (uint)data[offset] + 1; - if (expansion) // expansion ? + if (hasExpansion) // expansion ? { var cs = data.GetUInt32(offset); offset += 4; - et.Expansion = data.GetString(offset, cs); + expansion = data.GetString(offset, cs); offset += cs; } + var et = new EventTemplate(od, eventIndex++, name, expansion); + od.events.Add(et); } diff --git a/Esiur/Resource/Warehouse.cs b/Esiur/Resource/Warehouse.cs index a408ba0..e049f10 100644 --- a/Esiur/Resource/Warehouse.cs +++ b/Esiur/Resource/Warehouse.cs @@ -1,6 +1,31 @@ -using Esiur.Data; +/* + +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 Esiur.Data; using Esiur.Engine; using Esiur.Resource.Template; +using Esiur.Security.Permissions; using System; using System.Collections.Generic; using System.Linq; @@ -14,12 +39,20 @@ namespace Esiur.Resource { //static byte prefixCounter; - static List stores = new List(); + static AutoList stores = new AutoList(null); static Dictionary resources = new Dictionary(); static uint resourceCounter = 0; static KeyList templates = new KeyList(); + static bool storeIsOpen = false; + + public delegate void StoreConnectedEvent(IStore store, string name); + public delegate void StoreDisconnectedEvent(IStore store); + + public static event StoreConnectedEvent StoreConnected; + public static event StoreDisconnectedEvent StoreDisconnected; + /// /// Get a store by its name. @@ -30,7 +63,7 @@ namespace Esiur.Resource { foreach (var s in stores) if (s.Instance.Name == name) - return s; + return s as IStore; return null; } @@ -44,7 +77,7 @@ namespace Esiur.Resource if (resources.ContainsKey(id)) return new AsyncReply(resources[id]); else - return null; + return new AsyncReply(null); } /// @@ -59,22 +92,38 @@ namespace Esiur.Resource foreach (var store in stores) bag.Add(store.Trigger(ResourceTrigger.Initialize)); - foreach (var store in stores) - bag.Add(store.Trigger(ResourceTrigger.SystemInitialized)); bag.Seal(); var rt = new AsyncReply(); bag.Then((x) => { - foreach(var b in x) + foreach (var b in x) if (!b) { rt.Trigger(false); return; } - rt.Trigger(true); + var rBag = new AsyncBag(); + foreach (var rk in resources) + rBag.Add(rk.Value.Trigger(ResourceTrigger.SystemInitialized)); + + rBag.Seal(); + + rBag.Then(y => + { + foreach (var b in y) + if (!b) + { + rt.Trigger(false); + return; + } + + rt.Trigger(true); + storeIsOpen = true; + }); + }); return rt; @@ -122,6 +171,63 @@ namespace Esiur.Resource return rt; } + + private static IResource[] QureyIn(string[] path, int index, AutoList resources) + { + var rt = new List(); + + if (index == path.Length - 1) + { + if (path[index] == "") + foreach (IResource child in resources) + rt.Add(child); + else + foreach (IResource child in resources) + if (child.Instance.Name == path[index]) + rt.Add(child); + } + else + foreach (IResource child in resources) + if (child.Instance.Name == path[index]) + rt.AddRange(QureyIn(path, index+1, child.Instance.Children)); + + return rt.ToArray(); + } + + public static AsyncReply Query(string path) + { + + + if (path == null || path == "") + { + var roots = stores.Where(s => s.Instance.Parents.Count == 0).ToArray(); + return new AsyncReply(roots); + } + else + { + var rt = new AsyncReply(); + Get(path).Then(x => + { + var p = path.Split('/'); + + if (x == null) + { + rt.Trigger(QureyIn(p, 0, stores)); + } + else + { + var ar = QureyIn(p, 0, stores).Where(r => r != x).ToList(); + ar.Insert(0, x); + rt.Trigger(ar.ToArray()); + } + }); + + return rt; + + } + + } + /// /// Get a resource by its path. /// Resource path is sperated by '/' character, e.g. "system/http". @@ -169,9 +275,12 @@ namespace Esiur.Resource /// Resource name. /// IStore that manages the resource. Can be null if the resource is a store. /// Parent resource. if not presented the store becomes the parent for the resource. - public static void Put(IResource resource, string name, IStore store = null, IResource parent = null) + public static void Put(IResource resource, string name, IStore store = null, IResource parent = null, ResourceTemplate customTemplate = null, ulong age = 0, IPermissionsManager manager = null) { - resource.Instance = new Instance(resourceCounter++, name, resource, store); + resource.Instance = new Instance(resourceCounter++, name, resource, store, customTemplate, age); + + if (manager != null) + resource.Instance.Managers.Add(manager); if (store == parent) parent = null; @@ -184,19 +293,27 @@ namespace Esiur.Resource else parent.Instance.Children.Add(resource); + if (resource is IStore) + { stores.Add(resource as IStore); + StoreConnected?.Invoke(resource as IStore, name); + } else store.Put(resource); resources.Add(resource.Instance.Id, resource); + + if (!storeIsOpen) + resource.Trigger(ResourceTrigger.Initialize); + } - public static T New(string name, IStore store = null, IResource parent = null) + public static T New(string name, IStore store = null, IResource parent = null, IPermissionsManager manager = null) { var res = Activator.CreateInstance(typeof(T)) as IResource; - Put(res, name, store, parent); + Put(res, name, store, parent, null, 0, manager); return (T)res; } @@ -206,7 +323,7 @@ namespace Esiur.Resource /// Resource template. public static void PutTemplate(ResourceTemplate template) { - if (templates.ContainsKey(template.ClassId)) + if (!templates.ContainsKey(template.ClassId)) templates.Add(template.ClassId, template); } @@ -254,5 +371,36 @@ namespace Esiur.Resource return null; } + + public static bool Remove(IResource resource) + { + + if (resource.Instance == null) + return false; + + if (resources.ContainsKey(resource.Instance.Id)) + resources.Remove(resource.Instance.Id); + else + return false; + + if (resource is IStore) + { + stores.Remove(resource as IStore); + + // remove all objects associated with the store + var toBeRemoved = resources.Values.Where(x => x.Instance.Store == resource); + foreach (var o in toBeRemoved) + Remove(o); + + StoreDisconnected?.Invoke(resource as IStore); + } + + if (resource.Instance.Store != null) + resource.Instance.Store.Remove(resource); + + resource.Destroy(); + + return true; + } } } diff --git a/Esiur/Security/Authority/AlienAuthentication.cs b/Esiur/Security/Authority/AlienAuthentication.cs index 739ee97..137c911 100644 --- a/Esiur/Security/Authority/AlienAuthentication.cs +++ b/Esiur/Security/Authority/AlienAuthentication.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; @@ -8,8 +32,8 @@ namespace Esiur.Security.Authority { public class AlienAuthentication : Authentication { - public AlienAuthentication(Certificate certificate, AuthenticationState state) : - base(certificate, state, AuthenticationType.Alien) + public AlienAuthentication() : + base(AuthenticationType.Alien) { } diff --git a/Esiur/Security/Authority/Authentication.cs b/Esiur/Security/Authority/Authentication.cs index b95b00b..b353e83 100644 --- a/Esiur/Security/Authority/Authentication.cs +++ b/Esiur/Security/Authority/Authentication.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; @@ -8,28 +32,31 @@ namespace Esiur.Security.Authority { public class Authentication { - Certificate certificate; - AuthenticationState state; - AuthenticationType type; + AuthenticationType type; + - public Certificate Certificate - { - get { return certificate; } - } + public string Username { get; set; } + public Certificate Certificate { get; set; } + public string Domain { get; set; } + + public string FullName => Username + "@" + Domain; + + public Source Source { get; } = new Source(); public AuthenticationState State { - get { return state; } + get; + set; } public AuthenticationType Type { - get { return type; } + get => type; } - public Authentication(Certificate certificate, AuthenticationState state, AuthenticationType type) + public Authentication(AuthenticationType type) { - + this.type = type; } } } diff --git a/Esiur/Security/Authority/AuthenticationState.cs b/Esiur/Security/Authority/AuthenticationState.cs index 58b84d6..90515d8 100644 --- a/Esiur/Security/Authority/AuthenticationState.cs +++ b/Esiur/Security/Authority/AuthenticationState.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Security/Authority/AuthenticationType.cs b/Esiur/Security/Authority/AuthenticationType.cs index 5dd10d9..3b4bcf5 100644 --- a/Esiur/Security/Authority/AuthenticationType.cs +++ b/Esiur/Security/Authority/AuthenticationType.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Security/Authority/CACertificate.cs b/Esiur/Security/Authority/CACertificate.cs index 2115e0a..28dcfb3 100644 --- a/Esiur/Security/Authority/CACertificate.cs +++ b/Esiur/Security/Authority/CACertificate.cs @@ -1,4 +1,28 @@ -using Esiur.Data; +/* + +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 Esiur.Data; using Esiur.Engine; using Esiur.Misc; using Esiur.Security.Cryptography; diff --git a/Esiur/Security/Authority/Certificate.cs b/Esiur/Security/Authority/Certificate.cs index 0d5e8a2..cc91da8 100644 --- a/Esiur/Security/Authority/Certificate.cs +++ b/Esiur/Security/Authority/Certificate.cs @@ -1,4 +1,28 @@ -using Esiur.Data; +/* + +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 Esiur.Data; using Esiur.Engine; using Esiur.Misc; using Esiur.Security.Cryptography; diff --git a/Esiur/Security/Authority/CertificateType.cs b/Esiur/Security/Authority/CertificateType.cs index 99cb85a..5bbc8ff 100644 --- a/Esiur/Security/Authority/CertificateType.cs +++ b/Esiur/Security/Authority/CertificateType.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Security/Authority/ClientAuthentication.cs b/Esiur/Security/Authority/ClientAuthentication.cs index b4a57c6..8863613 100644 --- a/Esiur/Security/Authority/ClientAuthentication.cs +++ b/Esiur/Security/Authority/ClientAuthentication.cs @@ -1,4 +1,27 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; @@ -8,10 +31,42 @@ namespace Esiur.Security.Authority { public class ClientAuthentication : Authentication { - public ClientAuthentication(byte[] credentials, UserCertificate certificate, AuthenticationState state) - : base(certificate, state, AuthenticationType.Client) + /* + string username; + byte[] password; + string domain; + byte[] token; + UserCertificate certificate; + + public string Username => username; + public byte[] Password => password; + //public string Domain => domain; + public byte[] Token => token; + + public byte[] Nounce { get; set; } + */ + + public ClientAuthentication() + :base(AuthenticationType.Client) { } + + + /* + public ClientAuthentication(byte[] token) + : base(AuthenticationType.Client) + { + this.token = token; + } + + public ClientAuthentication(string username, byte[] password) + : base(AuthenticationType.Client) + { + this.username = username; + this.password = password; + //this.domain = domain; + } + */ } } diff --git a/Esiur/Security/Authority/CoHostAuthentication.cs b/Esiur/Security/Authority/CoHostAuthentication.cs index a429e64..33f5557 100644 --- a/Esiur/Security/Authority/CoHostAuthentication.cs +++ b/Esiur/Security/Authority/CoHostAuthentication.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; @@ -8,8 +32,8 @@ namespace Esiur.Security.Authority { public class CoHostAuthentication : Authentication { - public CoHostAuthentication(DomainCertificate certificate, AuthenticationState state) - : base(certificate, state, AuthenticationType.CoHost) + public CoHostAuthentication() + : base(AuthenticationType.CoHost) { } diff --git a/Esiur/Security/Authority/DomainCertificate.cs b/Esiur/Security/Authority/DomainCertificate.cs index caadbbc..5f294fa 100644 --- a/Esiur/Security/Authority/DomainCertificate.cs +++ b/Esiur/Security/Authority/DomainCertificate.cs @@ -1,4 +1,28 @@ -using Esiur.Data; +/* + +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 Esiur.Data; using Esiur.Misc; using Esiur.Security.Cryptography; using Esiur.Security.Integrity; diff --git a/Esiur/Security/Authority/HostAuthentication.cs b/Esiur/Security/Authority/HostAuthentication.cs index eab8530..9ed62c5 100644 --- a/Esiur/Security/Authority/HostAuthentication.cs +++ b/Esiur/Security/Authority/HostAuthentication.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; @@ -8,10 +32,12 @@ namespace Esiur.Security.Authority { public class HostAuthentication : Authentication { - public HostAuthentication(DomainCertificate certificate, AuthenticationState state) - : base(certificate, state, AuthenticationType.Host) + + public HostAuthentication() + :base(AuthenticationType.Host) { } - } + + } } diff --git a/Esiur/Security/Authority/Session.cs b/Esiur/Security/Authority/Session.cs index 5f88ee1..29e8608 100644 --- a/Esiur/Security/Authority/Session.cs +++ b/Esiur/Security/Authority/Session.cs @@ -1,4 +1,27 @@ -using Esiur.Data; +/* + +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 Esiur.Data; using Esiur.Engine; using Esiur.Net; using Esiur.Resource; @@ -12,12 +35,27 @@ namespace Esiur.Security.Authority { public class Session { - Authentication Authentication { get; } - Source Source { get; } - string Id { get; } - DateTime Creation { get; } - DateTime Modification { get; } - //KeyList Variables { get; } + public Authentication LocalAuthentication => localAuth; + public Authentication RemoteAuthentication => remoteAuth; + + // public Source Source { get; } + public byte[] Id { get; set; } + public DateTime Creation { get; } + public DateTime Modification { get; } + public KeyList Variables {get;} = new KeyList(); + + //KeyList Variables { get; } //IStore Store { get; } + + //string id; + Authentication localAuth, remoteAuth; + //string domain; + + public Session(Authentication localAuthentication, Authentication remoteAuthentication) + { + + this.localAuth = localAuthentication; + this.remoteAuth = remoteAuthentication; + } } } diff --git a/Esiur/Security/Authority/Source.cs b/Esiur/Security/Authority/Source.cs index f89e3e4..e740f90 100644 --- a/Esiur/Security/Authority/Source.cs +++ b/Esiur/Security/Authority/Source.cs @@ -1,4 +1,28 @@ -using Esiur.Data; +/* + +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 Esiur.Data; using System; using System.Collections.Generic; using System.Linq; @@ -10,21 +34,26 @@ namespace Esiur.Security.Authority public class Source { - string id; - KeyList attributes; + //string id; + KeyList attributes; - string Id { get { return id; } } + public string Id { get; set; } - KeyList Attributes + public KeyList Attributes { - get { return attributes; } + get => attributes; } - public Source(string id, KeyList attributes) + public Source(string id, KeyList attributes) { - this.id = id; + Id = id; this.attributes = attributes; } + public Source() + { + attributes = new KeyList(); + } + } } diff --git a/Esiur/Security/Authority/SourceAttributeType.cs b/Esiur/Security/Authority/SourceAttributeType.cs index 45c66b4..f773d8b 100644 --- a/Esiur/Security/Authority/SourceAttributeType.cs +++ b/Esiur/Security/Authority/SourceAttributeType.cs @@ -1,4 +1,28 @@ -using Esiur.Data; +/* + +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 Esiur.Data; using System; using System.Collections.Generic; using System.Linq; @@ -11,7 +35,10 @@ namespace Esiur.Security.Authority { Mobility, // Stationary/Mobile CPU, // Arc, Speed, Cores - IP, // IPv4, IPv6 Address + IPv4, // IPv4, IPv6 Address + IPv6, // IPv4, IPv6 Address + Port, // TCP or UDP port + Proxy, // Proxy Route, // Trace Root Location, // Lon, Lat, Alt, Accuracy OS, // OS name, version, distro, kernel diff --git a/Esiur/Security/Authority/UserCertificate.cs b/Esiur/Security/Authority/UserCertificate.cs index 874b947..d538bcb 100644 --- a/Esiur/Security/Authority/UserCertificate.cs +++ b/Esiur/Security/Authority/UserCertificate.cs @@ -1,4 +1,28 @@ -using Esiur.Data; +/* + +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 Esiur.Data; using Esiur.Security.Cryptography; using Esiur.Security.Integrity; using System; diff --git a/Esiur/Security/Cryptography/AsymetricEncryptionAlgorithmType.cs b/Esiur/Security/Cryptography/AsymetricEncryptionAlgorithmType.cs index f3e745e..a2ee1f0 100644 --- a/Esiur/Security/Cryptography/AsymetricEncryptionAlgorithmType.cs +++ b/Esiur/Security/Cryptography/AsymetricEncryptionAlgorithmType.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Security/Cryptography/SymetricEncryptionAlgorithmType.cs b/Esiur/Security/Cryptography/SymetricEncryptionAlgorithmType.cs index ef2d946..e2a4348 100644 --- a/Esiur/Security/Cryptography/SymetricEncryptionAlgorithmType.cs +++ b/Esiur/Security/Cryptography/SymetricEncryptionAlgorithmType.cs @@ -1,4 +1,27 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Security/Integrity/HashFunctionType.cs b/Esiur/Security/Integrity/HashFunctionType.cs index 9ccd7dc..b1e1ac9 100644 --- a/Esiur/Security/Integrity/HashFunctionType.cs +++ b/Esiur/Security/Integrity/HashFunctionType.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; diff --git a/Esiur/Security/Membership/IDomain.cs b/Esiur/Security/Membership/IDomain.cs index 51bcc98..c58d11b 100644 --- a/Esiur/Security/Membership/IDomain.cs +++ b/Esiur/Security/Membership/IDomain.cs @@ -1,4 +1,28 @@ -using Esiur.Resource; +/* + +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 Esiur.Resource; using Esiur.Security.Authority; using System; using System.Collections.Generic; diff --git a/Esiur/Security/Membership/IMembership.cs b/Esiur/Security/Membership/IMembership.cs index e97859b..cf2988c 100644 --- a/Esiur/Security/Membership/IMembership.cs +++ b/Esiur/Security/Membership/IMembership.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; @@ -22,8 +46,10 @@ namespace Esiur.Security.Membership //DomainCertificate[] GetDomainCertificates(string domain); - bool UserExists(string username); + AsyncReply UserExists(string username, string domain); AsyncReply GetPassword(string username, string domain); + AsyncReply Login(Session session); + AsyncReply Logout(Session session); //ClientAuthentication Authenticate(string username, byte[] credentials, int flag); //HostAuthentication Authenticate(DomainCertificate domainCertificate); diff --git a/Esiur/Security/Membership/IUser.cs b/Esiur/Security/Membership/IUser.cs index a806ef2..11f7cd2 100644 --- a/Esiur/Security/Membership/IUser.cs +++ b/Esiur/Security/Membership/IUser.cs @@ -1,4 +1,28 @@ -using Esiur.Engine; +/* + +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 Esiur.Engine; using System; using System.Collections.Generic; using System.Linq; diff --git a/Esiur/Security/Permissions/ActionType.cs b/Esiur/Security/Permissions/ActionType.cs index 5985bd8..9ec856c 100644 --- a/Esiur/Security/Permissions/ActionType.cs +++ b/Esiur/Security/Permissions/ActionType.cs @@ -1,4 +1,28 @@ -using System; +/* + +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.Generic; using System.Linq; using System.Text; @@ -11,7 +35,16 @@ namespace Esiur.Security.Permissions Attach, Delete, Execute, - Get, - Set, + GetProperty, + SetProperty, + CreateResource, + UpdateAttributes, + InquireAttributes, + AddParent, + RemoveParent, + AddChild, + RemoveChild, + Rename, + ReceiveEvent } } diff --git a/Esiur/Security/Permissions/IPermissionManager.cs b/Esiur/Security/Permissions/IPermissionManager.cs deleted file mode 100644 index 58a372f..0000000 --- a/Esiur/Security/Permissions/IPermissionManager.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Esiur.Engine; -using Esiur.Net; -using Esiur.Resource; -using Esiur.Resource.Template; -using Esiur.Security.Authority; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Esiur.Security.Permissions -{ - public interface IPermissionManager - { - bool Applicable(IResource resource, Session session, ActionType action, MemberTemplate member); - } -} diff --git a/Esiur/Security/Permissions/IPermissionsManager.cs b/Esiur/Security/Permissions/IPermissionsManager.cs new file mode 100644 index 0000000..9e94fea --- /dev/null +++ b/Esiur/Security/Permissions/IPermissionsManager.cs @@ -0,0 +1,56 @@ +/* + +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 Esiur.Data; +using Esiur.Engine; +using Esiur.Net; +using Esiur.Resource; +using Esiur.Resource.Template; +using Esiur.Security.Authority; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Esiur.Security.Permissions +{ + public interface IPermissionsManager + { + /// + /// Check for permission. + /// + /// IResource. + /// Caller sessions. + /// Action type + /// Function, property or event to check for permission. + /// Permission inquirer object. + /// Allowed or denined. + Ruling Applicable(IResource resource, Session session, ActionType action, MemberTemplate member, object inquirer = null); + + bool Initialize(Structure settings, IResource resource); + + Structure Settings { get; } + } +} diff --git a/Esiur/Security/Permissions/ParentalPermissionsManager.cs b/Esiur/Security/Permissions/ParentalPermissionsManager.cs new file mode 100644 index 0000000..dff3bde --- /dev/null +++ b/Esiur/Security/Permissions/ParentalPermissionsManager.cs @@ -0,0 +1,60 @@ +/* + +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.Generic; +using System.Text; +using Esiur.Data; +using Esiur.Engine; +using Esiur.Resource; +using Esiur.Resource.Template; +using Esiur.Security.Authority; + +namespace Esiur.Security.Permissions +{ + public class ParentalPermissionsManager : IPermissionsManager + { + Structure settings; + + public Structure Settings => settings; + + public Ruling Applicable(IResource resource, Session session, ActionType action, MemberTemplate member, object inquirer = null) + { + + foreach (IResource parent in resource.Instance.Parents) + { + var ruling = parent.Instance.Applicable(session, action, member, inquirer); + if (ruling != Ruling.DontCare) + return ruling; + } + + return Ruling.DontCare; + } + + public bool Initialize(Structure settings, IResource resource) + { + throw new NotImplementedException(); + } + } +} diff --git a/Esiur/Security/Permissions/Ruling.cs b/Esiur/Security/Permissions/Ruling.cs new file mode 100644 index 0000000..d87cf75 --- /dev/null +++ b/Esiur/Security/Permissions/Ruling.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Security.Permissions +{ + public enum Ruling + { + Denied, + Allowed, + DontCare + } +} diff --git a/Esiur/Security/Permissions/UserPermissionsManager.cs b/Esiur/Security/Permissions/UserPermissionsManager.cs new file mode 100644 index 0000000..1a593dd --- /dev/null +++ b/Esiur/Security/Permissions/UserPermissionsManager.cs @@ -0,0 +1,127 @@ +/* + +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.Generic; +using System.Text; +using Esiur.Data; +using Esiur.Engine; +using Esiur.Resource; +using Esiur.Resource.Template; +using Esiur.Security.Authority; + +namespace Esiur.Security.Permissions +{ + public class UserPermissionsManager : IPermissionsManager + { + IResource resource; + Structure settings; + + public Structure Settings => settings; + + public Ruling Applicable(IResource resource, Session session, ActionType action, MemberTemplate member, object inquirer) + { + Structure userPermissions = null; + + if (settings.ContainsKey(session.RemoteAuthentication.FullName)) + userPermissions = settings[session.RemoteAuthentication.FullName] as Structure; + else if (settings.ContainsKey("public")) + userPermissions = settings["public"] as Structure; + else + return Ruling.Denied; + + if (action == ActionType.Attach)// || action == ActionType.Delete) + { + if ((string)userPermissions["_attach"] != "yes") + return Ruling.Denied; + } + else if (action == ActionType.Delete) + { + if ((string)userPermissions["_delete"] != "yes") + return Ruling.Denied; + } + else if (action== ActionType.InquireAttributes) + { + if ((string)userPermissions["_get_attributes"] == "yes") + return Ruling.Denied; + } + else if (action == ActionType.UpdateAttributes) + { + if ((string)userPermissions["_set_attributes"] != "yes") + return Ruling.Denied; + } + else if (action == ActionType.AddChild) + { + if ((string)userPermissions["_add_child"] != "yes") + return Ruling.Denied; + } + else if (action == ActionType.RemoveChild) + { + if ((string)userPermissions["_remove_child"] != "yes") + return Ruling.Denied; + } + else if (action == ActionType.AddParent) + { + if ((string)userPermissions["_add_parent"] != "yes") + return Ruling.Denied; + } + else if (action == ActionType.RemoveParent) + { + if ((string)userPermissions["_remove_parent"] != "yes") + return Ruling.Denied; + } + else if (action == ActionType.Rename) + { + if ((string)userPermissions["_rename"] != "yes") + return Ruling.Denied; + } + + if (userPermissions.ContainsKey(member.Name)) + { + Structure methodPermissions = userPermissions[member.Name] as Structure; + if ((string)methodPermissions[action.ToString()] != "yes") + return Ruling.Denied; + } + + return Ruling.DontCare; + } + + public UserPermissionsManager() + { + + } + + public UserPermissionsManager(Structure settings) + { + this.settings = settings; + } + + public bool Initialize(Structure settings, IResource resource) + { + this.resource = resource; + this.settings = settings; + return true; + } + } +} diff --git a/Esiur/Stores/MemoryStore.cs b/Esiur/Stores/MemoryStore.cs index dfc290b..499a5ba 100644 --- a/Esiur/Stores/MemoryStore.cs +++ b/Esiur/Stores/MemoryStore.cs @@ -5,6 +5,8 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Esiur.Engine; +using Esiur.Data; +using Esiur.Resource.Template; namespace Esiur.Stores { @@ -52,5 +54,26 @@ namespace Esiur.Stores { return new AsyncReply(true); } + + public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + { + throw new NotImplementedException(); + } + + public AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate) + { + throw new NotImplementedException(); + } + + public bool Remove(IResource resource) + { + resources.Remove(resource.Instance.Id); + return true; + } + + public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + { + return true; + } } } diff --git a/Test/MyMembership.cs b/Test/MyMembership.cs index cace289..249041e 100644 --- a/Test/MyMembership.cs +++ b/Test/MyMembership.cs @@ -22,7 +22,7 @@ namespace Test public AsyncReply GetPassword(string username, string domain) { - return new AsyncReply(DC.ToBytes("password")); + return new AsyncReply(DC.ToBytes("1234")); } public AsyncReply Trigger(ResourceTrigger trigger) @@ -30,9 +30,9 @@ namespace Test return new AsyncReply(true); } - public bool UserExists(string username) + public AsyncReply UserExists(string username) { - throw new NotImplementedException(); + return new AsyncReply(username == "demo"); } } diff --git a/Test/MyObject.cs b/Test/MyObject.cs index b328b22..1bef6b8 100644 --- a/Test/MyObject.cs +++ b/Test/MyObject.cs @@ -4,6 +4,7 @@ using Esiur.Resource; using System; using System.Collections.Generic; using System.Text; +using System.Threading; namespace Test { @@ -16,7 +17,7 @@ namespace Test public event ResourceEventHanlder LevelUp; [ResourceEvent] public event ResourceEventHanlder LevelDown; - + public void Destroy() { @@ -26,8 +27,8 @@ namespace Test Info = new Structure(); Info["size"] = 200; Info["age"] = 28; - Info["name"] = "Zamil"; - Name = "Ahmed"; + Info["name"] = "Esiur"; + Name = "Esiur Project"; Level = 5; } @@ -52,6 +53,46 @@ namespace Test return Level; } + [ResourceFunction] + 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] + 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(AsyncReply.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; + } + [ResourceProperty] public Structure Info { diff --git a/Test/Program.cs b/Test/Program.cs index 758b4f5..e6cb797 100644 --- a/Test/Program.cs +++ b/Test/Program.cs @@ -22,15 +22,18 @@ SOFTWARE. */ +using Esiur.Data; using Esiur.Engine; using Esiur.Net.HTTP; using Esiur.Net.IIP; using Esiur.Net.Sockets; using Esiur.Resource; +using Esiur.Security.Permissions; using Esiur.Stores; using Esiur.Stores.MongoDB; using System; using System.Threading; +using System.Threading.Tasks; namespace Test { @@ -39,34 +42,80 @@ namespace Test static MyObject myObject; static DistributedResource remoteObject; - static void Main(string[] args) - { + + static void Main(string[] args) + { + MainAsync().Wait(); + //Thread.Sleep(-1); + } + + static async Task MainAsync() + { + //AsyncContext.Run(() => ()); + + // Create stores to keep objects. var system = Warehouse.New("system"); var remote = Warehouse.New("remote"); var mongo = Warehouse.New("db"); - Warehouse.Open().Then((ok)=> { + // Open the warehouse + var ok = await Warehouse.Open().Task; + + + // Create new object if the store is empty if (mongo.Count == 0) - myObject = Warehouse.New("my", mongo); + myObject = 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 Warehouse.Get("db/my").Then((o) => { myObject = (MyObject)o; }); + // Create new distributed server object var iip = Warehouse.New("iip", system); - iip.Membership = new MyMembership(); + // 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, 5000)), 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, 5001)), 600000, 60000); + // Create IIP over Websocket HTTP module and give it to HTTP server. var wsOverHttp = Warehouse.New("IIPoWS", system, http); - TestClient(); - }); + + 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"); + } + }); + } + }; + + // Start testing + // TestClient(); + @@ -92,46 +141,64 @@ namespace Test private static void TestClient() { - var client = new DistributedConnection(new TCPSocket("localhost", 5000), "any", "ahmed", "password"); + //return; + // Create a new client + var client = new DistributedConnection(new TCPSocket("localhost", 5000), "localhost", "demo", "1234"); + // Put the client in our memory store var remote = Warehouse.GetStore("remote"); - - - Warehouse.Put(client, client.RemoteEndPoint.ToString(), remote); + Warehouse.Put(client, "Endpoint", remote); - - client.OnReady += (c) => + + client.OnReady += async (c) => { - client.Get("db/my").Then((dynamic x) => + // Get remote object from the server. + remoteObject = await client.Get("db/my").Task as DistributedResource; + + dynamic x = remoteObject; + + Console.WriteLine("My Name is: " + x.Name); + x.Name = "Hamoo"; + x.LevelUp += new DistributedResourceEvent((sender, parameters) => { - remoteObject = x; - - 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.Add(10) as AsyncReply).Then((r) => - { - Console.WriteLine("RT: " + r + " " + x.Level); - }); - - (x.Subtract(10) as AsyncReply).Then((r) => - { - Console.WriteLine("RT: " + r + " " + x.Level); - }); - - - var t = new Timer(T_Elapsed, null, 5000, 5000); - + 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).Task; + + //var rt2 = await x.Add(10).Task; + + Console.WriteLine(rt); + /* + (x.Subtract(10) as AsyncReply).Then((r) => + { + Console.WriteLine("Subtracted: " + r + " " + x.Level); + }).Error((ex) => + { + Console.WriteLine("Exception " + ex.Code + " " + ex.Message); + }); + + // Getting object record + client.GetRecord(remoteObject, DateTime.Now - TimeSpan.FromDays(1), DateTime.Now).Then(record => + { + Console.WriteLine("Records received: " + record.Count); + }); + + var t = new Timer(T_Elapsed, null, 5000, 5000); + */ }; } @@ -139,10 +206,7 @@ namespace Test { myObject.Level++; dynamic o = remoteObject; - - Console.WriteLine(myObject.Level + " " + o.Level + o.Me.Me.Level); - Console.WriteLine(o.Info.ToString()); } } diff --git a/Test/Test.csproj b/Test/Test.csproj index b3da5bf..820e315 100644 --- a/Test/Test.csproj +++ b/Test/Test.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp1.1 + netcoreapp2.0