diff --git a/Esyur.Stores.EntityCore/EntityStore.cs b/Esyur.Stores.EntityCore/EntityStore.cs index 1f1de17..eb2f7d8 100644 --- a/Esyur.Stores.EntityCore/EntityStore.cs +++ b/Esyur.Stores.EntityCore/EntityStore.cs @@ -34,6 +34,8 @@ using Microsoft.EntityFrameworkCore.Proxies; using Microsoft.EntityFrameworkCore.Infrastructure; using Esyur.Proxy; using System.Linq; +using Microsoft.EntityFrameworkCore.Metadata; +using System.Reflection; namespace Esyur.Stores.EntityCore { @@ -43,6 +45,16 @@ namespace Esyur.Stores.EntityCore public event DestroyedEvent OnDestroy; + struct TypeInfo + { + public string Name; + public IEntityType Type; + public PropertyInfo PrimaryKey; + } + + Dictionary TypesByName = new Dictionary(); + Dictionary TypesByType = new Dictionary(); + /* protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { @@ -56,27 +68,27 @@ namespace Esyur.Stores.EntityCore } */ - /* - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - //modelBuilder.Entity().ToTable("Series"); - //modelBuilder.Entity().ToTable("Episodes").; - //modelBuilder.Ignore - // modelBuilder.Entity(x=>x.Property(p=>p.Instance).HasConversion(v=>v.Managers.) - Console.WriteLine("OnModelCreating"); - //modelBuilder.Entity() + /* + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + //modelBuilder.Entity().ToTable("Series"); + //modelBuilder.Entity().ToTable("Episodes").; + //modelBuilder.Ignore + // modelBuilder.Entity(x=>x.Property(p=>p.Instance).HasConversion(v=>v.Managers.) + Console.WriteLine("OnModelCreating"); + //modelBuilder.Entity() - base.OnModelCreating(modelBuilder); - }*/ + base.OnModelCreating(modelBuilder); + }*/ public async AsyncReply Get(string path) { var p = path.Split('/'); - var type = Options.Cache.Keys.Where(x => x.Name.ToLower() == p[0].ToLower()).FirstOrDefault(); + var ti = TypesByName[p[0]]; var id = Convert.ToInt32(p[1]); - return DbContext.Find(type, id) as IResource; + return DbContext.Find(ti.Type.ClrType, id) as IResource; } public async AsyncReply Put(IResource resource) @@ -87,6 +99,7 @@ namespace Esyur.Stores.EntityCore [Attribute] public EsyurExtensionOptions Options { get; set; } + //DbContext dbContext; [Attribute] public DbContext DbContext { get; set; } @@ -94,7 +107,16 @@ namespace Esyur.Stores.EntityCore { var type = ResourceProxy.GetBaseType(resource.GetType()); - var id = Options.Cache[type].GetValue(resource); + var id = TypesByType[type].PrimaryKey.GetValue(resource); + //DbContext.Model.FindEntityType(type).DisplayName(); + + + // DbContext.Model.FindEntityType(type).DisplayName + //var entityType = DbContext.Model.FindEntityType(type); + //var id = entityType.FindPrimaryKey().Properties + // .FirstOrDefault()?.PropertyInfo + // .GetValue(resource); + // var id = Types if (id != null) return this.Instance.Name + "/" + type.Name + "/" + id.ToString(); @@ -156,6 +178,24 @@ namespace Esyur.Stores.EntityCore public AsyncReply Trigger(ResourceTrigger trigger) { + if (trigger == ResourceTrigger.SystemInitialized && DbContext != null) + { + var types = DbContext.Model.GetEntityTypes(); + foreach (var t in types) + { + var ti = new TypeInfo() + { + Name = t.ClrType.Name, + PrimaryKey = t.FindPrimaryKey().Properties.FirstOrDefault()?.PropertyInfo, + Type = t + }; + + TypesByName.Add(t.ClrType.Name, ti); + TypesByType.Add(t.ClrType, ti); + } + + } + return new AsyncReply(true); } diff --git a/Esyur.Stores.EntityCore/EsyurExtensionOptions.cs b/Esyur.Stores.EntityCore/EsyurExtensionOptions.cs index 7d31f71..cb60eba 100644 --- a/Esyur.Stores.EntityCore/EsyurExtensionOptions.cs +++ b/Esyur.Stores.EntityCore/EsyurExtensionOptions.cs @@ -41,12 +41,12 @@ namespace Esyur.Stores.EntityCore public class EsyurExtensionOptions : IDbContextOptionsExtension { - public Dictionary Cache { get; } = new Dictionary(); - public void AddType(IEntityType type) - { - if (!Cache.ContainsKey(type.ClrType)) - Cache.Add(type.ClrType, type.FindPrimaryKey().Properties[0].PropertyInfo); - } + //public Dictionary Cache { get; } = new Dictionary(); + //public void AddType(IEntityType type) + //{ + // if (!Cache.ContainsKey(type.ClrType)) + // Cache.Add(type.ClrType, type.FindPrimaryKey().Properties[0].PropertyInfo); + //} diff --git a/Esyur.Stores.EntityCore/EsyurProxyRewrite.cs b/Esyur.Stores.EntityCore/EsyurProxyRewrite.cs index cb34f18..dc035e1 100644 --- a/Esyur.Stores.EntityCore/EsyurProxyRewrite.cs +++ b/Esyur.Stores.EntityCore/EsyurProxyRewrite.cs @@ -68,7 +68,7 @@ namespace Esyur.Stores.EntityCore object[] constructorArguments) { //var key = entityType.FindPrimaryKey(); - options.AddType(entityType); + //options.AddType(entityType); var manager = options.Store.Instance.Managers.Count > 0 ? options.Store.Instance.Managers.First() : null; return Warehouse.New(entityType.ClrType, "", options.Store, null, manager); diff --git a/Esyur/Core/AsyncBag.cs b/Esyur/Core/AsyncBag.cs index 8819777..c1eabd3 100644 --- a/Esyur/Core/AsyncBag.cs +++ b/Esyur/Core/AsyncBag.cs @@ -56,6 +56,10 @@ namespace Esyur.Core return (object[])base.Wait(); } + public new object[] Wait(int timeout) + { + return (object[])base.Wait(timeout); + } public void Seal() { diff --git a/Esyur/Core/AsyncException.cs b/Esyur/Core/AsyncException.cs index 7b5a657..b09e052 100644 --- a/Esyur/Core/AsyncException.cs +++ b/Esyur/Core/AsyncException.cs @@ -28,13 +28,18 @@ using System.Text; namespace Esyur.Core { - public class AsyncException: Exception + public class AsyncException : Exception { - - public readonly ErrorType Type; public readonly ExceptionCode Code; + public AsyncException(Exception exception) :base(exception.Message, exception) + { + Type = ErrorType.Exception; + Code = 0; + } + + public override string StackTrace => InnerException != null && Type == ErrorType.Exception ? InnerException.StackTrace : base.StackTrace; public AsyncException(ErrorType type, ushort code, string message) : base(type == ErrorType.Management ? ((ExceptionCode)code).ToString() : message) diff --git a/Esyur/Core/AsyncReply.cs b/Esyur/Core/AsyncReply.cs index c820788..04c7fe0 100644 --- a/Esyur/Core/AsyncReply.cs +++ b/Esyur/Core/AsyncReply.cs @@ -89,6 +89,27 @@ namespace Esyur.Core } + public object Wait(int millisecondsTimeout) + { + if (resultReady) + return result; + + if (Debug) + Console.WriteLine($"AsyncReply: {Id} Wait"); + + if (!mutex.WaitOne(millisecondsTimeout)) + { + var e = new Exception("AsyncReply timeout"); + TriggerError(e); + throw e; + } + + if (Debug) + Console.WriteLine($"AsyncReply: {Id} Wait ended"); + + return result; + } + public object Result { get { return result; } @@ -210,9 +231,9 @@ namespace Esyur.Core if (exception is AsyncException) this.exception = exception as AsyncException; else - this.exception = new AsyncException(ErrorType.Management, 0, exception.Message); - + this.exception = new AsyncException(exception); + // lock (callbacksLock) // { foreach (var cb in errorCallbacks) diff --git a/Esyur/Core/AsyncReplyGeneric.cs b/Esyur/Core/AsyncReplyGeneric.cs index e57e281..aeaceb3 100644 --- a/Esyur/Core/AsyncReplyGeneric.cs +++ b/Esyur/Core/AsyncReplyGeneric.cs @@ -79,6 +79,12 @@ namespace Esyur.Core { return (T)base.Wait(); } + + public new T Wait(int millisecondsTimeout) + { + return (T)base.Wait(millisecondsTimeout); + } + /* protected new List callbacks = new List(); protected new object result; diff --git a/Esyur/Data/AutoList.cs b/Esyur/Data/AutoList.cs index 6fcf4fa..ff45dd8 100644 --- a/Esyur/Data/AutoList.cs +++ b/Esyur/Data/AutoList.cs @@ -49,9 +49,10 @@ namespace Esyur.Data public event Cleared OnCleared; public event Added OnAdd; - ST state; bool removableList; + + public ST State { get; set; } /* IOrderedEnumerable OrderBy(Func keySelector) { @@ -95,7 +96,7 @@ namespace Esyur.Data /// State object to be included when an event is raised. public AutoList(ST state) { - this.state = state; + State = state; #if NETSTANDARD removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())); #else @@ -110,7 +111,7 @@ namespace Esyur.Data /// public AutoList(ST state, T[] values) { - this.state = state; + State = state; #if NETSTANDARD removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())); #else @@ -163,7 +164,7 @@ namespace Esyur.Data lock (syncRoot) list[index] = value; - OnModified?.Invoke(state, index, oldValue, value); + OnModified?.Invoke(State, index, oldValue, value); } } @@ -179,7 +180,7 @@ namespace Esyur.Data lock (syncRoot) list.Add(value); - OnAdd?.Invoke(state, value); + OnAdd?.Invoke(State, value); } /// @@ -209,7 +210,7 @@ namespace Esyur.Data lock (syncRoot) list.Clear(); - OnCleared?.Invoke(state); + OnCleared?.Invoke(State); } /// @@ -228,7 +229,7 @@ namespace Esyur.Data lock (syncRoot) list.Remove(value); - OnRemoved?.Invoke(state, value); + OnRemoved?.Invoke(State, value); } /// diff --git a/Esyur/Data/Structure.cs b/Esyur/Data/Structure.cs index f75ac90..a558eb1 100644 --- a/Esyur/Data/Structure.cs +++ b/Esyur/Data/Structure.cs @@ -91,18 +91,18 @@ namespace Esyur.Data if (obj is Structure) return obj as Structure; - else if (Codec.IsAnonymous(type)) + else //if (Codec.IsAnonymous(type)) { var st = new Structure(); - var pi = type.GetTypeInfo().GetProperties(); + var pi = type.GetTypeInfo().GetProperties().Where(x=>x.CanRead); foreach (var p in pi) st[p.Name] = p.GetValue(obj); return st; } - else - return null; + //else + // return null; } public IEnumerator> GetEnumerator() { diff --git a/Esyur/Net/HTTP/HTTPConnection.cs b/Esyur/Net/HTTP/HTTPConnection.cs index e3c04e9..d5e3b26 100644 --- a/Esyur/Net/HTTP/HTTPConnection.cs +++ b/Esyur/Net/HTTP/HTTPConnection.cs @@ -265,7 +265,7 @@ namespace Esyur.Net.HTTP try { var ims = DateTime.Parse(Request.Headers["if-modified-since"]); - if (Math.Abs((fileEditTime - ims).TotalSeconds) < 0) + if ((fileEditTime - ims).TotalSeconds < 2) { Response.Number = HTTPResponsePacket.ResponseCode.NotModified; //Response.Text = "Not Modified"; @@ -274,7 +274,7 @@ namespace Esyur.Net.HTTP } catch { - + return false; } } diff --git a/Esyur/Net/HTTP/HTTPServer.cs b/Esyur/Net/HTTP/HTTPServer.cs index da31168..a21cc4f 100644 --- a/Esyur/Net/HTTP/HTTPServer.cs +++ b/Esyur/Net/HTTP/HTTPServer.cs @@ -100,18 +100,7 @@ namespace Esyur.Net.HTTP get; set; } - - - public enum ResponseCodes : int - { - HTTP_OK = 200, - HTTP_NOTFOUND = 404, - HTTP_SERVERERROR = 500, - HTTP_MOVED = 301, - HTTP_NOTMODIFIED = 304, - HTTP_REDIRECT = 307 - } - + public HTTPSession CreateSession(string id, int timeout) { @@ -322,9 +311,7 @@ namespace Esyur.Net.HTTP // else listener = new TCPSocket(new IPEndPoint(ipAdd, Port)); - Start(listener, - Timeout, - Clock); + Start(listener); } else if (trigger == ResourceTrigger.Terminate) { diff --git a/Esyur/Net/IIP/DistributedConnection.cs b/Esyur/Net/IIP/DistributedConnection.cs index 5d8dc67..1ef8bc7 100644 --- a/Esyur/Net/IIP/DistributedConnection.cs +++ b/Esyur/Net/IIP/DistributedConnection.cs @@ -72,6 +72,9 @@ namespace Esyur.Net.IIP bool ready, readyToEstablish; + string _hostname; + ushort _port; + DateTime loginDate; /// @@ -194,15 +197,15 @@ namespace Esyur.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); + session.RemoteAuthentication.Source.Attributes[SourceAttributeType.IPv4] = socket.RemoteEndPoint.Address; + session.RemoteAuthentication.Source.Attributes[SourceAttributeType.Port] = socket.RemoteEndPoint.Port; + session.LocalAuthentication.Source.Attributes[SourceAttributeType.IPv4] = socket.LocalEndPoint.Address; + session.LocalAuthentication.Source.Attributes[SourceAttributeType.Port] = socket.LocalEndPoint.Port; if (session.LocalAuthentication.Type == AuthenticationType.Client) { // declare (Credentials -> No Auth, No Enctypt) - + var un = DC.ToBytes(session.LocalAuthentication.Username); var dmn = DC.ToBytes(session.LocalAuthentication.Domain);// domain); @@ -245,7 +248,7 @@ namespace Esyur.Net.IIP /// Password. public DistributedConnection(ISocket socket, string domain, string username, string password) { - this.session = new Session( new ClientAuthentication() + this.session = new Session(new ClientAuthentication() , new HostAuthentication()); //Instance.Name = Global.GenerateCode(12); //this.hostType = AuthenticationType.Client; @@ -309,7 +312,7 @@ namespace Esyur.Net.IIP { //var packet = new IIPPacket(); - + // packets++; @@ -430,7 +433,7 @@ namespace Esyur.Net.IIP case IIPPacketAction.ResourceParents: IIPRequestResourceParents(packet.CallbackId, packet.ResourceId); break; - + case IIPPacket.IIPPacketAction.ResourceHistory: IIPRequestInquireResourceHistory(packet.CallbackId, packet.ResourceId, packet.FromDate, packet.ToDate); break; @@ -503,7 +506,7 @@ namespace Esyur.Net.IIP IIPReply(packet.CallbackId); break; - // Inquire + // Inquire case IIPPacket.IIPPacketAction.TemplateFromClassName: case IIPPacket.IIPPacketAction.TemplateFromClassId: @@ -634,7 +637,7 @@ namespace Esyur.Net.IIP //var hash = hashFunc.ComputeHash(BinaryList.ToBytes(pw, remoteNonce, localNonce)); var hash = hashFunc.ComputeHash((new BinaryList()) .AddUInt8Array(pw) - .AddUInt8Array( remoteNonce) + .AddUInt8Array(remoteNonce) .AddUInt8Array(localNonce) .ToArray()); if (hash.SequenceEqual(remoteHash)) @@ -719,7 +722,7 @@ namespace Esyur.Net.IIP .AddUInt8Array(localPassword) .ToArray()); - + if (remoteHash.SequenceEqual(authPacket.Hash)) { // send establish request @@ -764,7 +767,7 @@ namespace Esyur.Net.IIP return offset; //if (offset < ends) - // processPacket(msg, offset, ends, data, chunkId); + // processPacket(msg, offset, ends, data, chunkId); } protected override void DataReceived(NetworkBuffer data) @@ -773,14 +776,14 @@ namespace Esyur.Net.IIP var msg = data.Read(); uint offset = 0; uint ends = (uint)msg.Length; - + var packs = new List(); var chunkId = (new Random()).Next(1000, 1000000); var list = new List();// double, IIPPacketCommand>(); - + this.Socket.Hold(); try @@ -798,7 +801,7 @@ namespace Esyur.Net.IIP { this.Socket.Unhold(); } - } + } [Attribute] @@ -831,31 +834,115 @@ namespace Esyur.Net.IIP var domain = Domain != null ? Domain : address;// Instance.Attributes.ContainsKey("domain") ? Instance.Attributes["domain"].ToString() : address; - session = new Session(new ClientAuthentication() - , new HostAuthentication()); - session.LocalAuthentication.Domain = domain; - session.LocalAuthentication.Username = username; - localPassword = DC.ToBytes(Password);// Instance.Attributes["password"].ToString()); + return Connect(null, address, port, username, DC.ToBytes(Password), domain); - openReply = new AsyncReply(); - var sock = new TCPSocket(); - - - sock.Connect(address, port).Then((x)=> { - Assign(sock); - //rt.trigger(true); - }).Error((x) => - openReply.TriggerError(x) - ); - - return openReply; } } return new AsyncReply(); } + + protected override void ConnectionClosed() + { + // clean up + ready = false; + readyToEstablish = false; + + foreach (var x in requests.Values) + x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed")); + + foreach (var x in resourceRequests.Values) + x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed")); + + foreach (var x in templateRequests.Values) + x.TriggerError(new AsyncException(ErrorType.Management, 0, "Connection closed")); + + requests.Clear(); + resourceRequests.Clear(); + templateRequests.Clear(); + + foreach (var x in resources.Values) + x.Suspend(); + } + + public AsyncReply Connect(ISocket socket = null, string hostname = null, ushort port = 0, string username = null, byte[] password = null, string domain = null) + { + if (openReply != null) + throw new AsyncException(ErrorType.Exception, 0, "Connection in progress"); + + openReply = new AsyncReply(); + + if (hostname != null) + { + session = new Session(new ClientAuthentication() + , new HostAuthentication()); + + session.LocalAuthentication.Domain = domain; + session.LocalAuthentication.Username = username; + localPassword = password; + } + + if (session == null) + throw new AsyncException(ErrorType.Exception, 0, "Session not initialized"); + + if (socket == null) + socket = new TCPSocket(); + + if (port > 0) + this._port = port; + if (hostname != null) + this._hostname = hostname; + + socket.Connect(this._hostname, this._port).Then(x => + { + Assign(socket); + }).Error((x) => + { + openReply.TriggerError(x); + openReply = null; + }); + + return openReply; + } + + public async AsyncReply Reconnect() + { + try + { + if (await Connect()) + { + try + { + var bag = new AsyncBag(); + + for (var i = 0; i < resources.Keys.Count; i++) + { + var index = resources.Keys.ElementAt(i); + bag.Add(Fetch(index)); + } + + bag.Seal(); + await bag; + } + catch (Exception ex) + { + Global.Log(ex); + //print(ex.toString()); + } + } + } + catch + { + return false; + } + + return true; + } + + // AsyncReply connect({ISocket socket, String hostname, int port, String username, DC password, String domain}) + /// /// Store interface. /// @@ -908,7 +995,7 @@ namespace Esyur.Net.IIP throw new Exception("SS"); //if (Codec.IsLocalResource(resource, this)) - // return new AsyncBag((resource as DistributedResource).children.Where(x => x.GetType() == typeof(T)).Select(x => (T)x)); + // return new AsyncBag((resource as DistributedResource).children.Where(x => x.GetType() == typeof(T)).Select(x => (T)x)); return null; } @@ -917,7 +1004,7 @@ namespace Esyur.Net.IIP { throw new Exception("SS"); //if (Codec.IsLocalResource(resource, this)) - // return (resource as DistributedResource).parents.Where(x => x.GetType() == typeof(T)).Select(x => (T)x); + // return (resource as DistributedResource).parents.Where(x => x.GetType() == typeof(T)).Select(x => (T)x); return null; } diff --git a/Esyur/Net/IIP/DistributedConnectionProtocol.cs b/Esyur/Net/IIP/DistributedConnectionProtocol.cs index b615925..0397215 100644 --- a/Esyur/Net/IIP/DistributedConnectionProtocol.cs +++ b/Esyur/Net/IIP/DistributedConnectionProtocol.cs @@ -134,6 +134,18 @@ namespace Esyur.Net.IIP return reply; } + internal AsyncReply SendDetachRequest(uint instanceId) + { + try + { + return SendRequest(IIPPacket.IIPPacketAction.DetachResource).AddUInt32(instanceId).Done(); + } + catch + { + return null; + } + } + internal AsyncReply SendInvokeByNamedArguments(uint instanceId, byte index, Structure parameters) { var pb = Codec.ComposeStructure(parameters, this, true, true, true); @@ -433,6 +445,7 @@ namespace Esyur.Net.IIP void IIPRequestAttachResource(uint callback, uint resourceId) { + Warehouse.GetById(resourceId).Then((res) => { if (res != null) @@ -449,19 +462,12 @@ namespace Esyur.Net.IIP 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.Children.OnAdd -= Children_OnAdd; + // r.Instance.Children.OnRemoved -= Children_OnRemoved; + //r.Instance.Attributes.OnModified -= Attributes_OnModified; - // subscribe - 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; + // Console.WriteLine("Attach {0} {1}", r.Instance.Link, r.Instance.Id); // add it to attached resources so GC won't remove it from memory attachedResources.Add(r); @@ -490,6 +496,19 @@ namespace Esyur.Net.IIP .AddUInt8Array(Codec.ComposePropertyValueArray(r.Instance.Serialize(), this, true)) .Done(); } + + + + // subscribe + 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; + + } else { @@ -1886,19 +1905,23 @@ namespace Esyur.Net.IIP /// DistributedResource public AsyncReply Fetch(uint id) { - if (resourceRequests.ContainsKey(id) && resources.ContainsKey(id)) + var resource = resources[id]; + var request = resourceRequests[id]; + + if (request != null) { - Console.WriteLine("DEAD LOCK " + id); - - return new AsyncReply(resources[id]); - // dig for dead locks - return resourceRequests[id]; + if (resource != null) + // dig for dead locks // or not + return new AsyncReply(resource); + else + return request; + } + else if (resource != null && !resource.Suspended) + { + return new AsyncReply(resource); } - else if (resourceRequests.ContainsKey(id)) - return resourceRequests[id]; - else if (resources.ContainsKey(id)) - return new AsyncReply(resources[id]); + var reply = new AsyncReply(); resourceRequests.Add(id, reply); @@ -1907,16 +1930,18 @@ namespace Esyur.Net.IIP .Done() .Then((rt) => { - var dr = new DistributedResource(this, id, (ulong)rt[1], (string)rt[2]); + + var dr = resource ?? new DistributedResource(this, id, (ulong)rt[1], (string)rt[2]); GetTemplate((Guid)rt[0]).Then((tmp) => { // ClassId, ResourceAge, ResourceLink, Content - Warehouse.Put(dr, id.ToString(), this, null, tmp); + if (resource == null) + Warehouse.Put(dr, id.ToString(), this, null, tmp); Codec.ParsePropertyValueArray((byte[])rt[3], this).Then((ar) => { - dr._Attached(ar); + dr._Attach(ar); resourceRequests.Remove(id); reply.Trigger(dr); }); diff --git a/Esyur/Net/IIP/DistributedResource.cs b/Esyur/Net/IIP/DistributedResource.cs index a1d4aeb..13b39eb 100644 --- a/Esyur/Net/IIP/DistributedResource.cs +++ b/Esyur/Net/IIP/DistributedResource.cs @@ -58,9 +58,9 @@ namespace Esyur.Net.IIP DistributedConnection connection; - bool isAttached = false; - bool isReady = false; - + bool attached = false; + bool destroyed = false; + bool suspended = false; //Structure properties = new Structure(); @@ -73,23 +73,7 @@ namespace Esyur.Net.IIP DistributedResourceEvent[] events; - //ResourceTemplate template; - - - //DistributedResourceStack stack; - - - bool destroyed; - - /* - Dictionary afterAttachmentTriggers = new Dictionary(); - - internal void AddAfterAttachement(AsyncReply trigger, object value) - { - afterAttachmentTriggers.Add(trigger, value); - } - */ - + /// /// Resource template for the remotely located resource. @@ -130,31 +114,28 @@ namespace Esyur.Net.IIP public void Destroy() { destroyed = true; + attached = false; + connection.SendDetachRequest(instanceId); OnDestroy?.Invoke(this); } - + /// - /// Resource is ready when all its properties are attached. + /// Suspend resource /// - internal bool IsReady + + internal void Suspend() { - get - { - return isReady; - } + suspended = true; + attached = false; } + /// /// Resource is attached when all its properties are received. /// - internal bool IsAttached - { - get - { - return isAttached; - } - } - + internal bool Attached => attached; + + internal bool Suspended => suspended; // public DistributedResourceStack Stack @@ -182,11 +163,6 @@ namespace Esyur.Net.IIP } - internal void _Ready() - { - isReady = true; - } - /// /// Export all properties with ResourceProperty attributed as bytes array. /// @@ -203,12 +179,14 @@ namespace Esyur.Net.IIP return props; } - internal bool _Attached(PropertyValue[] properties) + internal bool _Attach(PropertyValue[] properties) { - if (isAttached) + if (attached) return false; else { + suspended = false; + this.properties = new object[properties.Length]; this.events = new DistributedResourceEvent[Instance.Template.Events.Length]; @@ -226,7 +204,7 @@ namespace Esyur.Net.IIP //afterAttachmentTriggers.Clear(); - isAttached = true; + attached = true; } return true; @@ -244,6 +222,9 @@ namespace Esyur.Net.IIP if (destroyed) throw new Exception("Trying to access destroyed object"); + if (suspended) + throw new Exception("Trying to access suspended object"); + if (index >= Instance.Template.Functions.Length) throw new Exception("Function index is incorrect"); @@ -256,6 +237,9 @@ namespace Esyur.Net.IIP if (destroyed) throw new Exception("Trying to access destroyed object"); + if (suspended) + throw new Exception("Trying to access suspended object"); + if (index >= Instance.Template.Functions.Length) throw new Exception("Function index is incorrect"); @@ -270,7 +254,7 @@ namespace Esyur.Net.IIP var reply = new AsyncReply(); - if (isAttached && ft!=null) + if (attached && ft!=null) { if (args.Length == 1) { @@ -321,9 +305,10 @@ namespace Esyur.Net.IIP if (destroyed) throw new Exception("Trying to access destroyed object"); + result = null; - if (!isAttached) + if (!attached) return false; var pt = Instance.Template.GetPropertyTemplateByName(binder.Name); @@ -388,7 +373,10 @@ namespace Esyur.Net.IIP if (destroyed) throw new Exception("Trying to access destroyed object"); - if (!isAttached) + if (suspended) + throw new Exception("Trying to access suspended object"); + + if (!attached) return false; var pt = Instance.Template.GetPropertyTemplateByName(binder.Name); diff --git a/Esyur/Net/IIP/DistributedServer.cs b/Esyur/Net/IIP/DistributedServer.cs index 1afc275..f1e5243 100644 --- a/Esyur/Net/IIP/DistributedServer.cs +++ b/Esyur/Net/IIP/DistributedServer.cs @@ -67,21 +67,7 @@ namespace Esyur.Net.IIP set; } - [Attribute] - public uint Timeout - { - get; - set; - } - - [Attribute] - public uint Clock - { - get; - set; - } - public Instance Instance { @@ -100,7 +86,7 @@ namespace Esyur.Net.IIP else listener = new TCPSocket(new IPEndPoint(IPAddress.Any, Port)); - Start(listener, Timeout, Clock); + Start(listener); } else if (trigger == ResourceTrigger.Terminate) { diff --git a/Esyur/Net/NetworkConnection.cs b/Esyur/Net/NetworkConnection.cs index f70e516..8901274 100644 --- a/Esyur/Net/NetworkConnection.cs +++ b/Esyur/Net/NetworkConnection.cs @@ -101,9 +101,15 @@ namespace Esyur.Net private void Socket_OnClose() { + ConnectionClosed(); OnClose?.Invoke(this); } + protected virtual void ConnectionClosed() + { + + } + private void Socket_OnReceive(NetworkBuffer buffer) { try @@ -264,6 +270,7 @@ namespace Esyur.Net { try { + lastAction = DateTime.Now; return sock.SendAsync(message, offset, length); } catch @@ -275,8 +282,8 @@ namespace Esyur.Net public virtual void Send(byte[] msg) { try - { - sock.Send(msg); + { + sock.Send(msg); lastAction = DateTime.Now; } catch diff --git a/Esyur/Net/NetworkServer.cs b/Esyur/Net/NetworkServer.cs index 1349856..0c9b6b9 100644 --- a/Esyur/Net/NetworkServer.cs +++ b/Esyur/Net/NetworkServer.cs @@ -39,7 +39,6 @@ namespace Esyur.Net public abstract class NetworkServer : IDestructible where TConnection : NetworkConnection, new() { //private bool isRunning; - uint clock; private ISocket listener; private AutoList> connections; @@ -50,7 +49,6 @@ namespace Esyur.Net protected abstract void ClientDisconnected(TConnection sender); - private uint timeout; private Timer timer; //public KeyList Sessions = new KeyList(); @@ -125,7 +123,7 @@ namespace Esyur.Net { foreach (TConnection c in connections) { - if (DateTime.Now.Subtract(c.LastAction).TotalSeconds >= timeout) + if (DateTime.Now.Subtract(c.LastAction).TotalSeconds >= Timeout) { if (ToBeClosed == null) ToBeClosed = new List(); @@ -147,7 +145,7 @@ namespace Esyur.Net } } - public void Start(ISocket socket, uint timeout, uint clock) + public void Start(ISocket socket)//, uint timeout, uint clock) { if (listener != null) return; @@ -161,16 +159,11 @@ namespace Esyur.Net connections = new AutoList>(this); - if (timeout > 0 & clock > 0) + if (Timeout > 0 & Clock > 0) { - timer = new Timer(MinuteThread, null, TimeSpan.FromMinutes(0), TimeSpan.FromSeconds(clock)); - this.timeout = timeout; + timer = new Timer(MinuteThread, null, TimeSpan.FromMinutes(0), TimeSpan.FromSeconds(Clock)); } - //this.ip = ip; - //this.port = port; - this.clock = clock; - // start a new thread for the server to live on //isRunning = true; @@ -208,12 +201,22 @@ namespace Esyur.Net } */ + [Attribute] + public uint Timeout + { + get; + set; + } + + [Attribute] public uint Clock { - get { return clock; } + get; + set; } + public void Stop() { var port = 0; diff --git a/Esyur/Net/Packets/HTTPRequestPacket.cs b/Esyur/Net/Packets/HTTPRequestPacket.cs index ec40e52..55495ba 100644 --- a/Esyur/Net/Packets/HTTPRequestPacket.cs +++ b/Esyur/Net/Packets/HTTPRequestPacket.cs @@ -134,7 +134,7 @@ namespace Esyur.Net.Packets sMethod[1] = WebUtility.UrlDecode(sMethod[1]); if (sMethod[1].Length >= 7) { - if (sMethod[1].Substring(0, 7) == "http://") + if (sMethod[1].StartsWith("http://")) { sMethod[1] = sMethod[1].Substring(sMethod[1].IndexOf("/", 7)); } diff --git a/Esyur/Net/Packets/IIPPacket.cs b/Esyur/Net/Packets/IIPPacket.cs index 5d08568..175e088 100644 --- a/Esyur/Net/Packets/IIPPacket.cs +++ b/Esyur/Net/Packets/IIPPacket.cs @@ -343,6 +343,9 @@ namespace Esyur.Net.Packets var cl = data.GetUInt32(offset); offset += 4; + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; + Content = data.Clip(offset, cl); offset += cl; diff --git a/Esyur/Net/Sockets/TCPSocket.cs b/Esyur/Net/Sockets/TCPSocket.cs index c1ed314..99e5c52 100644 --- a/Esyur/Net/Sockets/TCPSocket.cs +++ b/Esyur/Net/Sockets/TCPSocket.cs @@ -74,7 +74,7 @@ namespace Esyur.Net.Sockets socketArgs.SetBuffer(receiveBuffer, 0, receiveBuffer.Length); socketArgs.Completed += SocketArgs_Completed; - + if (!sock.ReceiveAsync(socketArgs)) SocketArgs_Completed(null, socketArgs); @@ -160,43 +160,50 @@ namespace Esyur.Net.Sockets { try { - // SocketError err; - - if (state == SocketState.Closed || state == SocketState.Terminated) + if (state != SocketState.Established) return; - if (e.BytesTransferred == 0) + if (e.BytesTransferred <= 0) { Close(); return; } - //if (receiveNetworkBuffer.Protected) - // Console.WriteLine(); - - - //lock (receiveNetworkBuffer.SyncLock) - // Console.WriteLine(e. + " " + e.BytesTransferred); - var recCount = e.BytesTransferred > e.Count ? e.Count : e.BytesTransferred; - receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)recCount); - //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)) + while(!sock.ReceiveAsync(e)) { - //Console.WriteLine("Sync"); - SocketArgs_Completed(sender, e); + if (e.SocketError != SocketError.Success) + { + Close(); + return; + } + + if (State != SocketState.Established) + return; + + if (e.BytesTransferred < 0) + Console.WriteLine("BytesTransferred is less than zero"); + + if (e.BytesTransferred <= 0) + { + Close(); + return; + } + + if (e.BytesTransferred > 100000) + Console.WriteLine("BytesTransferred is large " + e.BytesTransferred); + + recCount = e.BytesTransferred > e.Count ? e.Count : e.BytesTransferred; + + receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)recCount); + + OnReceive?.Invoke(receiveNetworkBuffer); } - } } catch (Exception ex) @@ -510,8 +517,9 @@ namespace Esyur.Net.Sockets { sock.BeginSend(msg, 0, msg.Length, SocketFlags.None, PacketSent, rt);// null); } - catch + catch(Exception ex) { + rt.TriggerError(ex); asyncSending = false; state = SocketState.Terminated; Close(); diff --git a/Esyur/Net/TCP/TCPServer.cs b/Esyur/Net/TCP/TCPServer.cs index 1e4c242..0bcfed8 100644 --- a/Esyur/Net/TCP/TCPServer.cs +++ b/Esyur/Net/TCP/TCPServer.cs @@ -80,7 +80,7 @@ namespace Esyur.Net.TCP else listener = new TCPSocket(new IPEndPoint(IPAddress.Any, Port)); - Start(listener, Timeout, Clock); + Start(listener); } diff --git a/Esyur/Resource/Template/ResourceTemplate.cs b/Esyur/Resource/Template/ResourceTemplate.cs index c9c2698..b47ef2c 100644 --- a/Esyur/Resource/Template/ResourceTemplate.cs +++ b/Esyur/Resource/Template/ResourceTemplate.cs @@ -167,7 +167,76 @@ namespace Esyur.Resource.Template if (classIsPublic) { + foreach (var pi in propsInfo) + { + var privateAttr = pi.GetCustomAttribute(true); + if (privateAttr == null) + { + var annotationAttr = pi.GetCustomAttribute(true); + var storageAttr = pi.GetCustomAttribute(true); + + var pt = new PropertyTemplate(this, i++, pi.Name);//, rp.ReadExpansion, rp.WriteExpansion, rp.Storage); + if (storageAttr != null) + pt.Recordable = storageAttr.Mode == StorageMode.Recordable; + + if (annotationAttr != null) + pt.ReadExpansion = annotationAttr.Annotation; + else + pt.ReadExpansion = pi.PropertyType.Name; + + pt.Info = pi; + //pt.Serilize = publicAttr.Serialize; + properties.Add(pt); + } + else + { + var attributeAttr = pi.GetCustomAttribute(true); + if (attributeAttr != null) + { + var at = new AttributeTemplate(this, 0, pi.Name); + at.Info = pi; + attributes.Add(at); + } + } + } + + i = 0; + + foreach (var ei in eventsInfo) + { + var privateAttr = ei.GetCustomAttribute(true); + if (privateAttr == null) + { + var annotationAttr = ei.GetCustomAttribute(true); + + var et = new EventTemplate(this, i++, ei.Name); + et.Info = ei; + + if (annotationAttr != null) + et.Expansion = annotationAttr.Annotation; + + events.Add(et); + } + } + + i = 0; + foreach (MethodInfo mi in methodsInfo) + { + var privateAttr = mi.GetCustomAttribute(true); + if (privateAttr == null) + { + var annotationAttr = mi.GetCustomAttribute(true); + + var ft = new FunctionTemplate(this, i++, mi.Name, mi.ReturnType == typeof(void)); + + if (annotationAttr != null) + ft.Expansion = annotationAttr.Annotation; + else + ft.Expansion = "(" + String.Join(",", mi.GetParameters().Where(x => x.ParameterType != typeof(DistributedConnection)).Select(x => "[" + x.ParameterType.Name + "] " + x.Name)) + ") -> " + mi.ReturnType.Name; + functions.Add(ft); + } + } } else { diff --git a/Esyur/Resource/Warehouse.cs b/Esyur/Resource/Warehouse.cs index 3ab8d20..527def1 100644 --- a/Esyur/Resource/Warehouse.cs +++ b/Esyur/Resource/Warehouse.cs @@ -571,9 +571,19 @@ namespace Esyur.Resource foreach (var p in ps) { - var pi = type.GetProperty(p.Key, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly); - if (pi != null) - pi.SetValue(res, p.Value); + + var pi = type.GetProperty(p.Key, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + if (pi != null && pi.CanWrite) + { + try + { + pi.SetValue(res, p.Value); + } + catch(Exception ex) + { + Global.Log(ex); + } + } } }