mirror of
				https://github.com/esiur/esiur-dotnet.git
				synced 2025-10-29 23:21:36 +00:00 
			
		
		
		
	Add project files.
This commit is contained in:
		
							
								
								
									
										514
									
								
								Esiur/Net/IIP/DistributedConnection.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										514
									
								
								Esiur/Net/IIP/DistributedConnection.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,514 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.Net; | ||||
| using System.Net.Sockets; | ||||
| using System.Security.Cryptography; | ||||
| using Esiur.Net.Sockets; | ||||
| using Esiur.Data; | ||||
| using Esiur.Misc; | ||||
| using Esiur.Engine; | ||||
| using Esiur.Net.Packets; | ||||
| using Esiur.Resource; | ||||
| using Esiur.Security.Authority; | ||||
| using Esiur.Resource.Template; | ||||
| using System.Linq; | ||||
| using System.Diagnostics; | ||||
|  | ||||
| namespace Esiur.Net.IIP | ||||
| { | ||||
|     public partial class DistributedConnection : NetworkConnection, IStore | ||||
|     { | ||||
|         public delegate void ReadyEvent(DistributedConnection sender); | ||||
|         public delegate void ErrorEvent(DistributedConnection sender, byte errorCode, string errorMessage); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Ready event is raised when the connection is fully established. | ||||
|         /// </summary> | ||||
|         public event ReadyEvent OnReady; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Error event | ||||
|         /// </summary> | ||||
|         public event ErrorEvent OnError; | ||||
|  | ||||
|         IIPPacket packet = new IIPPacket(); | ||||
|         IIPAuthPacket authPacket = new IIPAuthPacket(); | ||||
|  | ||||
|         byte[] sessionId; | ||||
|         AuthenticationType hostType; | ||||
|         string domain; | ||||
|         string localUsername, remoteUsername; | ||||
|         byte[] localPassword; | ||||
|  | ||||
|         byte[] localNonce, remoteNonce; | ||||
|  | ||||
|         bool ready, readyToEstablish; | ||||
|  | ||||
|         DateTime loginDate; | ||||
|         KeyList<string, object> variables = new KeyList<string, object>(); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Local username to authenticate ourselves.   | ||||
|         /// </summary> | ||||
|         public string LocalUsername { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Peer's username. | ||||
|         /// </summary> | ||||
|         public string RemoteUsername { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Working domain. | ||||
|         /// </summary> | ||||
|         public string Domain { get { return domain; } } | ||||
|  | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Distributed server responsible for this connection, usually for incoming connections. | ||||
|         /// </summary> | ||||
|         public DistributedServer Server | ||||
|         { | ||||
|             get; | ||||
|             set; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Send data to the other end as parameters | ||||
|         /// </summary> | ||||
|         /// <param name="values">Values will be converted to bytes then sent.</param> | ||||
|         internal void SendParams(params object[] values) | ||||
|         { | ||||
|             var ar = BinaryList.ToBytes(values); | ||||
|             Send(ar); | ||||
|  | ||||
|             //StackTrace stackTrace = new StackTrace(; | ||||
|  | ||||
|             // Get calling method name | ||||
|  | ||||
|             //Console.WriteLine("TX " + hostType + " " + ar.Length + " " + stackTrace.GetFrame(1).GetMethod().ToString()); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Send raw data through the connection. | ||||
|         /// </summary> | ||||
|         /// <param name="data">Data to send.</param> | ||||
|         public override void Send(byte[] data) | ||||
|         { | ||||
|             //Console.WriteLine("Client: {0}", Data.Length); | ||||
|  | ||||
|             Global.Counters["IIP Sent Packets"]++; | ||||
|             base.Send(data); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// KeyList to store user variables related to this connection. | ||||
|         /// </summary> | ||||
|         public KeyList<string, object> Variables | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 return variables; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// IResource interface. | ||||
|         /// </summary> | ||||
|         public Instance Instance | ||||
|         { | ||||
|             get; | ||||
|             set; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Assign a socket to the connection. | ||||
|         /// </summary> | ||||
|         /// <param name="socket">Any socket that implements ISocket.</param> | ||||
|         public override void Assign(ISocket socket) | ||||
|         { | ||||
|             base.Assign(socket); | ||||
|  | ||||
|  | ||||
|             if (hostType == AuthenticationType.Client) | ||||
|             { | ||||
|                 // declare (Credentials -> No Auth, No Enctypt) | ||||
|                 var un = DC.ToBytes(localUsername); | ||||
|                 var dmn = DC.ToBytes(domain); | ||||
|  | ||||
|                 if (socket.State == SocketState.Established) | ||||
|                 { | ||||
|                     SendParams((byte)0x60, (byte)dmn.Length, dmn, localNonce, (byte)un.Length, un); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     socket.OnConnect += () => | ||||
|                     {   // declare (Credentials -> No Auth, No Enctypt) | ||||
|                          SendParams((byte)0x60, (byte)dmn.Length, dmn, localNonce, (byte)un.Length, un); | ||||
|                     }; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Create a new distributed connection.  | ||||
|         /// </summary> | ||||
|         /// <param name="socket">Socket to transfer data through.</param> | ||||
|         /// <param name="domain">Working domain.</param> | ||||
|         /// <param name="username">Username.</param> | ||||
|         /// <param name="password">Password.</param> | ||||
|         public DistributedConnection(ISocket socket, string domain, string username, string password) | ||||
|         { | ||||
|             //Instance.Name = Global.GenerateCode(12); | ||||
|             this.hostType = AuthenticationType.Client; | ||||
|             this.domain = domain; | ||||
|             this.localUsername = username; | ||||
|             this.localPassword = DC.ToBytes(password); | ||||
|  | ||||
|             init(); | ||||
|  | ||||
|             Assign(socket); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Create a new instance of a distributed connection | ||||
|         /// </summary> | ||||
|         public DistributedConnection() | ||||
|         { | ||||
|             //myId = Global.GenerateCode(12); | ||||
|             // localParams.Host = DistributedParameters.HostType.Host; | ||||
|             init(); | ||||
|         } | ||||
|  | ||||
|  | ||||
|  | ||||
|         public string Link(IResource resource) | ||||
|         { | ||||
|             if (resource is DistributedConnection) | ||||
|             { | ||||
|                 var r = resource as DistributedResource; | ||||
|                 if (r.Instance.Store == this) | ||||
|                     return this.Instance.Name + "/" + r.Id; | ||||
|             } | ||||
|  | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         void init() | ||||
|         { | ||||
|             queue.Then((x) => | ||||
|             { | ||||
|                 if (x.Type == DistributedResourceQueueItem.DistributedResourceQueueItemType.Event) | ||||
|                     x.Resource._EmitEventByIndex(x.Index, (object[])x.Value); | ||||
|                 else | ||||
|                     x.Resource.UpdatePropertyByIndex(x.Index, x.Value); | ||||
|             }); | ||||
|  | ||||
|             var r = new Random(); | ||||
|             localNonce = new byte[32]; | ||||
|             r.NextBytes(localNonce); | ||||
|         } | ||||
|  | ||||
|  | ||||
|  | ||||
|         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; | ||||
|             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(); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Resource interface | ||||
|         /// </summary> | ||||
|         /// <param name="trigger">Resource trigger.</param> | ||||
|         /// <returns></returns> | ||||
|         public AsyncReply<bool> Trigger(ResourceTrigger trigger) | ||||
|         { | ||||
|             return new AsyncReply<bool>(); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Store interface. | ||||
|         /// </summary> | ||||
|         /// <param name="resource">Resource.</param> | ||||
|         /// <returns></returns> | ||||
|         public bool Put(IResource resource) | ||||
|         { | ||||
|             resources.Add(Convert.ToUInt32(resource.Instance.Name), (DistributedResource)resource); | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										802
									
								
								Esiur/Net/IIP/DistributedConnectionProtocol.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										802
									
								
								Esiur/Net/IIP/DistributedConnectionProtocol.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,802 @@ | ||||
| using Esiur.Data; | ||||
| using Esiur.Engine; | ||||
| using Esiur.Net.Packets; | ||||
| using Esiur.Resource; | ||||
| using Esiur.Resource.Template; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| using System.Linq; | ||||
| using System.Reflection; | ||||
| using System.Text; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace Esiur.Net.IIP | ||||
| { | ||||
|     partial class DistributedConnection | ||||
|     { | ||||
|         KeyList<uint, DistributedResource> resources = new KeyList<uint, DistributedResource>(); | ||||
|         KeyList<uint, AsyncReply<DistributedResource>> resourceRequests = new KeyList<uint, AsyncReply<DistributedResource>>(); | ||||
|         KeyList<Guid, AsyncReply<ResourceTemplate>> templateRequests = new KeyList<Guid, AsyncReply<ResourceTemplate>>(); | ||||
|  | ||||
|  | ||||
|         KeyList<string, AsyncReply<IResource>> pathRequests = new KeyList<string, AsyncReply<IResource>>(); | ||||
|  | ||||
|         Dictionary<Guid, ResourceTemplate> templates = new Dictionary<Guid, ResourceTemplate>(); | ||||
|  | ||||
|         KeyList<uint, AsyncReply<object[]>> requests = new KeyList<uint, AsyncReply<object[]>>(); | ||||
|  | ||||
|         uint callbackCounter = 0; | ||||
|  | ||||
|         AsyncQueue<DistributedResourceQueueItem> queue = new AsyncQueue<DistributedResourceQueueItem>(); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Send IIP request. | ||||
|         /// </summary> | ||||
|         /// <param name="action">Packet action.</param> | ||||
|         /// <param name="args">Arguments to send.</param> | ||||
|         /// <returns></returns> | ||||
|         internal AsyncReply<object[]> SendRequest(IIPPacket.IIPPacketAction action, params object[] args) | ||||
|         { | ||||
|             var reply = new AsyncReply<object[]>(); | ||||
|             callbackCounter++; | ||||
|             var bl = new BinaryList((byte)(0x40 | (byte)action), callbackCounter); | ||||
|             bl.AddRange(args); | ||||
|             Send(bl.ToArray()); | ||||
|             requests.Add(callbackCounter, reply); | ||||
|             return reply; | ||||
|         } | ||||
|  | ||||
|         void IIPReply(uint callbackId, params object[] results) | ||||
|         { | ||||
|             var req = requests.Take(callbackId); | ||||
|             req?.Trigger(results); | ||||
|         } | ||||
|  | ||||
|         void IIPEventResourceReassigned(uint resourceId, uint newResourceId) | ||||
|         { | ||||
|  | ||||
|         } | ||||
|  | ||||
|         void IIPEventResourceDestroyed(uint resourceId) | ||||
|         { | ||||
|             if (resources.Contains(resourceId)) | ||||
|             { | ||||
|                 var r = resources[resourceId]; | ||||
|                 resources.Remove(resourceId); | ||||
|                 r.Destroy(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         void IIPEventPropertyUpdated(uint resourceId, byte index, byte[] content) | ||||
|         { | ||||
|             if (resources.Contains(resourceId)) | ||||
|             { | ||||
|                 // push to the queue to gaurantee serialization | ||||
|                 var reply = new AsyncReply<DistributedResourceQueueItem>(); | ||||
|                 queue.Add(reply); | ||||
|  | ||||
|                 var r = resources[resourceId]; | ||||
|                 Codec.Parse(content, 0, this).Then((arguments) => | ||||
|                 { | ||||
|                     var pt = r.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) | ||||
|         { | ||||
|             if (resources.Contains(resourceId)) | ||||
|             { | ||||
|                 // push to the queue to gaurantee serialization | ||||
|                 var reply = new AsyncReply<DistributedResourceQueueItem>(); | ||||
|                 var r = resources[resourceId]; | ||||
|  | ||||
|                 queue.Add(reply); | ||||
|  | ||||
|                 Codec.ParseVarArray(content, this).Then((arguments) => | ||||
|                 { | ||||
|                     var et = r.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 IIPRequestAttachResource(uint callback, uint resourceId) | ||||
|         { | ||||
|             Warehouse.Get(resourceId).Then((res) => | ||||
|             { | ||||
|                 if (res != null) | ||||
|                 { | ||||
|                     var r = res as IResource; | ||||
|                     r.Instance.ResourceEventOccured += Instance_EventOccured; | ||||
|                     r.Instance.ResourceModified += Instance_PropertyModified; | ||||
|                     r.Instance.ResourceDestroyed += Instance_ResourceDestroyed; | ||||
|  | ||||
|                     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)); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     // reply failed | ||||
|                     //SendParams(0x80, r.Instance.Id, r.Instance.Age, r.Instance.Serialize(false, this)); | ||||
|  | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         void IIPRequestReattachResource(uint callback, uint resourceId, uint resourceAge) | ||||
|         { | ||||
|             Warehouse.Get(resourceId).Then((res) => | ||||
|             { | ||||
|                 if (res != null) | ||||
|                 { | ||||
|                     var r = res as IResource; | ||||
|                     r.Instance.ResourceEventOccured += Instance_EventOccured; | ||||
|                     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)); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     // reply failed | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         void IIPRequestDetachResource(uint callback, uint resourceId) | ||||
|         { | ||||
|             Warehouse.Get(resourceId).Then((res) => | ||||
|             { | ||||
|                 if (res != null) | ||||
|                 { | ||||
|                     var r = res as IResource; | ||||
|                     r.Instance.ResourceEventOccured -= Instance_EventOccured; | ||||
|                     r.Instance.ResourceModified -= Instance_PropertyModified; | ||||
|                     r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed; | ||||
|                     // reply ok | ||||
|                     SendParams((byte)0x82, callback); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     // reply failed | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         void IIPRequestCreateResource(uint callback, string className) | ||||
|         { | ||||
|             // not implemented | ||||
|         } | ||||
|  | ||||
|         void IIPRequestDeleteResource(uint callback, uint resourceId) | ||||
|         { | ||||
|             // not implemented | ||||
|  | ||||
|         } | ||||
|  | ||||
|         void IIPRequestTemplateFromClassName(uint callback, string className) | ||||
|         { | ||||
|             Warehouse.GetTemplate(className).Then((t) => | ||||
|             { | ||||
|                 if (t != null) | ||||
|                     SendParams((byte)0x88, callback, t.Content); | ||||
|                 else | ||||
|                 { | ||||
|                     // reply failed | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         void IIPRequestTemplateFromClassId(uint callback, Guid classId) | ||||
|         { | ||||
|             Warehouse.GetTemplate(classId).Then((t) => | ||||
|             { | ||||
|                 if (t != null) | ||||
|                     SendParams((byte)0x89, callback, (uint)t.Content.Length, t.Content); | ||||
|                 else | ||||
|                 { | ||||
|                     // reply failed | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         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); | ||||
|                 else | ||||
|                 { | ||||
|                     // reply failed | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         void IIPRequestResourceIdFromResourceLink(uint callback, string resourceLink) | ||||
|         { | ||||
|             Warehouse.Get(resourceLink).Then((r) => | ||||
|             { | ||||
|                 if (r != null) | ||||
|                     SendParams((byte)0x8C, callback, r.Instance.Template.ClassId, r.Instance.Id, r.Instance.Age); | ||||
|                 else | ||||
|                 { | ||||
|                     // reply failed | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         void IIPRequestInvokeFunction(uint callback, uint resourceId, byte index, byte[] content) | ||||
|         { | ||||
|             Warehouse.Get(resourceId).Then((r) => | ||||
|             { | ||||
|                 if (r != null) | ||||
|                 { | ||||
|                     Codec.ParseVarArray(content, this).Then(async (arguments) => | ||||
|                     { | ||||
|                         var ft = r.Instance.Template.GetFunctionTemplate(index); | ||||
|                         if (ft != null) | ||||
|                         { | ||||
|                             if (r is DistributedResource) | ||||
|                             { | ||||
|                                 var rt = (r as DistributedResource)._Invoke(index, arguments); | ||||
|                                 if (rt != null) | ||||
|                                 { | ||||
|                                     rt.Then(res => | ||||
|                                     { | ||||
|                                         SendParams((byte)0x90, callback, Codec.Compose(res, this)); | ||||
|                                     }); | ||||
|                                 } | ||||
|                                 else | ||||
|                                 { | ||||
|                                     // function not found on a distributed object | ||||
|                                 } | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
| #if NETSTANDARD1_5 | ||||
|                                 var fi = r.GetType().GetTypeInfo().GetMethod(ft.Name); | ||||
| #else | ||||
|                                 var fi = r.GetType().GetMethod(ft.Name); | ||||
| #endif | ||||
|  | ||||
|                                 if (fi != null) | ||||
|                                 { | ||||
|                                     // cast shit | ||||
|                                     ParameterInfo[] pi = fi.GetParameters(); | ||||
|                                     object[] args = null; | ||||
|  | ||||
|                                     if (pi.Length > 0) | ||||
|                                     { | ||||
|                                         int argsCount = pi.Length; | ||||
|                                         args = new object[pi.Length]; | ||||
|  | ||||
|                                         if (pi[pi.Length - 1].ParameterType == typeof(DistributedConnection)) | ||||
|                                         { | ||||
|                                             args[--argsCount] = this; | ||||
|                                         } | ||||
|  | ||||
|                                         if (arguments != null) | ||||
|                                         { | ||||
|                                             for (int i = 0; i < argsCount && i < arguments.Length; i++) | ||||
|                                             { | ||||
|                                                 args[i] = DC.CastConvert(arguments[i], pi[i].ParameterType); | ||||
|                                             } | ||||
|                                         } | ||||
|                                     } | ||||
|  | ||||
|                                     var rt = fi.Invoke(r, args); | ||||
|  | ||||
|                                     if (rt is Task) | ||||
|                                     { | ||||
|                                         var t = (Task)rt; | ||||
|                                         //Console.WriteLine(t.IsCompleted); | ||||
|                                         await t; | ||||
| #if NETSTANDARD1_5 | ||||
|                                         var res = t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t); | ||||
| #else | ||||
|                                         var res = t.GetType().GetProperty("Result").GetValue(t); | ||||
| #endif | ||||
|                                         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)); | ||||
|                                         }); | ||||
|                                     } | ||||
|                                     else | ||||
|                                     { | ||||
|                                         SendParams((byte)0x90, callback, Codec.Compose(rt, this)); | ||||
|                                     } | ||||
|                                 } | ||||
|                                 else | ||||
|                                 { | ||||
|                                     // ft found, fi not found, this should never happen | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             // no function at this index | ||||
|                         } | ||||
|                     }); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     // no resource with this id | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         void IIPRequestGetProperty(uint callback, uint resourceId, byte index) | ||||
|         { | ||||
|             Warehouse.Get(resourceId).Then((r) => | ||||
|             { | ||||
|                 if (r != null) | ||||
|                 { | ||||
|                     var pt = r.Instance.Template.GetFunctionTemplate(index); | ||||
|                     if (pt != null) | ||||
|                     { | ||||
|                         if (r is DistributedResource) | ||||
|                         { | ||||
|                             SendParams((byte)0x91, callback, Codec.Compose((r as DistributedResource)._Get(pt.Index), this)); | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
| #if NETSTANDARD1_5 | ||||
|                             var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name); | ||||
| #else | ||||
|                             var pi = r.GetType().GetProperty(pt.Name); | ||||
| #endif | ||||
|  | ||||
|                             if (pi != null) | ||||
|                             { | ||||
|                                 SendParams((byte)0x91, callback, Codec.Compose(pi.GetValue(r), this)); | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
|                                 // pt found, pi not found, this should never happen | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         // pt not found | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     // resource not found | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         void IIPRequestGetPropertyIfModifiedSince(uint callback, uint resourceId, byte index, uint age) | ||||
|         { | ||||
|             Warehouse.Get(resourceId).Then((r) => | ||||
|             { | ||||
|                 if (r != null) | ||||
|                 { | ||||
|                     var pt = r.Instance.Template.GetFunctionTemplate(index); | ||||
|                     if (pt != null) | ||||
|                     { | ||||
|                         if (r.Instance.GetAge(index) > age) | ||||
|                         { | ||||
| #if NETSTANDARD1_5 | ||||
|                             var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name); | ||||
| #else | ||||
|                             var pi = r.GetType().GetProperty(pt.Name); | ||||
| #endif | ||||
|                             if (pi != null) | ||||
|                             { | ||||
|                                 SendParams((byte)0x92, callback, Codec.Compose(pi.GetValue(r), this)); | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
|                                 // pt found, pi not found, this should never happen | ||||
|                             } | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             SendParams((byte)0x92, callback, (byte)DataType.NotModified); | ||||
|                         } | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         // pt not found | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     // resource not found | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         void IIPRequestSetProperty(uint callback, uint resourceId, byte index, byte[] content) | ||||
|         { | ||||
|             Warehouse.Get(resourceId).Then((r) => | ||||
|             { | ||||
|                 if (r != null) | ||||
|                 { | ||||
|  | ||||
|  | ||||
|                     var pt = r.Instance.Template.GetPropertyTemplate(index); | ||||
|                     if (pt != null) | ||||
|                     { | ||||
|                         Codec.Parse(content, 0, this).Then((value) => | ||||
|                         { | ||||
|                             if (r is DistributedResource) | ||||
|                             { | ||||
|                                 // propagation | ||||
|                                 (r as DistributedResource)._Set(index, value).Then((x) => | ||||
|                                 { | ||||
|                                     SendParams((byte)0x93, callback); | ||||
|                                 }); | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
| #if NETSTANDARD1_5 | ||||
|                                 var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name); | ||||
| #else | ||||
|                                 var pi = r.GetType().GetProperty(pt.Name); | ||||
| #endif | ||||
|                                 if (pi != null) | ||||
|                                 { | ||||
|                                     // cast new value type to property type | ||||
|  | ||||
|                                     var v = DC.CastConvert(value, pi.PropertyType); | ||||
|                                     pi.SetValue(r, v); | ||||
|  | ||||
|                                     SendParams((byte)0x93, callback); | ||||
|                                 } | ||||
|                                 else | ||||
|                                 { | ||||
|                                     // pt found, pi not found, this should never happen | ||||
|                                 } | ||||
|                             } | ||||
|  | ||||
|                         }); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         // property not found | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     // resource not found | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|         void IIPReplyAttachResource(uint callback, uint resourceAge, object[] properties) | ||||
|         { | ||||
|             if (requests.ContainsKey(callback)) | ||||
|             { | ||||
|                 var req = requests[callback]; | ||||
|                 var r = resources[(uint)req.Arguments[0]]; | ||||
|  | ||||
|                 if (r == null) | ||||
|                 { | ||||
|                     r.Instance.Deserialize(properties); | ||||
|                     r.Instance.Age = resourceAge; | ||||
|                     r.Attached(); | ||||
|  | ||||
|                     // process stack | ||||
|                     foreach (var rr in resources.Values) | ||||
|                         rr.Stack.ProcessStack(); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     // resource not found | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         void IIPReplyReattachResource(uint callback, uint resourceAge, object[] properties) | ||||
|         { | ||||
|             var req = requests.Take(callback); | ||||
|  | ||||
|             if (req != null) | ||||
|             { | ||||
|                 var r = resources[(uint)req.Arguments[0]]; | ||||
|  | ||||
|                 if (r == null) | ||||
|                 { | ||||
|                     r.Instance.Deserialize(properties); | ||||
|                     r.Instance.Age = resourceAge; | ||||
|                     r.Attached(); | ||||
|  | ||||
|                     // process stack | ||||
|                     foreach (var rr in resources.Values) | ||||
|                         rr.Stack.ProcessStack(); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     // resource not found | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         | ||||
|         void IIPReplyDetachResource(uint callback) | ||||
|         { | ||||
|             var req = requests.Take(callback); | ||||
|             // nothing to do | ||||
|         } | ||||
|  | ||||
|         void IIPReplyCreateResource(uint callback, Guid classId, uint resourceId) | ||||
|         { | ||||
|             var req = requests.Take(callback); | ||||
|             // nothing to do | ||||
|  | ||||
|         } | ||||
|         void IIPReplyDeleteResource(uint callback) | ||||
|         { | ||||
|             var req = requests.Take(callback); | ||||
|             // nothing to do | ||||
|  | ||||
|         } | ||||
|  | ||||
|         void IIPReplyTemplateFromClassName(uint callback, ResourceTemplate template) | ||||
|         { | ||||
|             // cache | ||||
|             if (!templates.ContainsKey(template.ClassId)) | ||||
|                 templates.Add(template.ClassId, template); | ||||
|  | ||||
|             var req = requests.Take(callback); | ||||
|             req?.Trigger(template); | ||||
|         } | ||||
|  | ||||
|         void IIPReplyTemplateFromClassId(uint callback, ResourceTemplate template) | ||||
|         { | ||||
|             // cache | ||||
|             if (!templates.ContainsKey(template.ClassId)) | ||||
|                 templates.Add(template.ClassId, template); | ||||
|  | ||||
|             var req = requests.Take(callback); | ||||
|             req?.Trigger(template); | ||||
|  | ||||
|         } | ||||
|  | ||||
|         void IIPReplyTemplateFromResourceLink(uint callback, ResourceTemplate template) | ||||
|         { | ||||
|             // cache | ||||
|             if (!templates.ContainsKey(template.ClassId)) | ||||
|                 templates.Add(template.ClassId, template); | ||||
|  | ||||
|             var req = requests.Take(callback); | ||||
|             req?.Trigger(template); | ||||
|         } | ||||
|  | ||||
|         void IIPReplyTemplateFromResourceId(uint callback, ResourceTemplate template) | ||||
|         { | ||||
|             // cache | ||||
|             if (!templates.ContainsKey(template.ClassId)) | ||||
|                 templates.Add(template.ClassId, template); | ||||
|  | ||||
|             var req = requests.Take(callback); | ||||
|             req?.Trigger(template); | ||||
|         } | ||||
|  | ||||
|         void IIPReplyResourceIdFromResourceLink(uint callback, Guid classId, uint resourceId, uint resourceAge) | ||||
|         { | ||||
|             var req = requests.Take(callback); | ||||
|             req?.Trigger(template); | ||||
|         } | ||||
|  | ||||
|         void IIPReplyInvokeFunction(uint callback, object returnValue) | ||||
|         { | ||||
|  | ||||
|         } | ||||
|  | ||||
|         void IIPReplyGetProperty(uint callback, object value) | ||||
|         { | ||||
|  | ||||
|         } | ||||
|         void IIPReplyGetPropertyIfModifiedSince(uint callback, object value) | ||||
|         { | ||||
|  | ||||
|         } | ||||
|         void IIPReplySetProperty(uint callback) | ||||
|         { | ||||
|  | ||||
|         } | ||||
|         */ | ||||
|  | ||||
|             /// <summary> | ||||
|             /// Get the ResourceTemplate for a given class Id.  | ||||
|             /// </summary> | ||||
|             /// <param name="classId">Class GUID.</param> | ||||
|             /// <returns>ResourceTemplate.</returns> | ||||
|         public AsyncReply<ResourceTemplate> GetTemplate(Guid classId) | ||||
|         { | ||||
|             if (templates.ContainsKey(classId)) | ||||
|                 return new AsyncReply<ResourceTemplate>(templates[classId]); | ||||
|             else if (templateRequests.ContainsKey(classId)) | ||||
|                 return templateRequests[classId]; | ||||
|  | ||||
|             var reply = new AsyncReply<ResourceTemplate>(); | ||||
|             templateRequests.Add(classId, reply); | ||||
|  | ||||
|             SendRequest(IIPPacket.IIPPacketAction.TemplateFromClassId, classId).Then((rt) => | ||||
|             { | ||||
|                 templateRequests.Remove(classId); | ||||
|                 templates.Add(((ResourceTemplate)rt[0]).ClassId, (ResourceTemplate)rt[0]); | ||||
|                 reply.Trigger(rt[0]); | ||||
|             }); | ||||
|  | ||||
|             return reply; | ||||
|         } | ||||
|  | ||||
|         // IStore interface  | ||||
|         /// <summary> | ||||
|         /// Get a resource by its path. | ||||
|         /// </summary> | ||||
|         /// <param name="path">Path to the resource.</param> | ||||
|         /// <returns>Resource</returns> | ||||
|         public AsyncReply<IResource> Get(string path) | ||||
|         { | ||||
|             if (pathRequests.ContainsKey(path)) | ||||
|                 return pathRequests[path]; | ||||
|  | ||||
|             var reply = new AsyncReply<IResource>(); | ||||
|             pathRequests.Add(path, reply); | ||||
|  | ||||
|             var bl = new BinaryList(path); | ||||
|             bl.Insert(0, (ushort)bl.Length); | ||||
|  | ||||
|             SendRequest(IIPPacket.IIPPacketAction.ResourceIdFromResourceLink, bl.ToArray()).Then((rt) => | ||||
|             { | ||||
|                 pathRequests.Remove(path); | ||||
| //(Guid)rt[0], | ||||
|                 Fetch( (uint)rt[1]).Then((r) => | ||||
|                 { | ||||
|                     reply.Trigger(r); | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|  | ||||
|             return reply; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Retrive a resource by its instance Id. | ||||
|         /// </summary> | ||||
|         /// <param name="iid">Instance Id</param> | ||||
|         /// <returns>Resource</returns> | ||||
|         public AsyncReply<IResource> Retrieve(uint iid) | ||||
|         { | ||||
|             foreach (var r in resources.Values) | ||||
|                 if (r.Instance.Id == iid) | ||||
|                     return new AsyncReply<IResource>(r); | ||||
|             return new AsyncReply<IResource>(null); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Fetch a resource from the other end | ||||
|         /// </summary> | ||||
|         /// <param name="classId">Class GUID</param> | ||||
|         /// <param name="id">Resource Id</param>Guid classId | ||||
|         /// <returns>DistributedResource</returns> | ||||
|         public AsyncReply<DistributedResource> Fetch( uint id) | ||||
|         { | ||||
|             if (resourceRequests.ContainsKey(id) && resources.ContainsKey(id)) | ||||
|             { | ||||
|                 // dig for dead locks | ||||
|                 return resourceRequests[id]; | ||||
|             } | ||||
|             else if (resourceRequests.ContainsKey(id)) | ||||
|                 return resourceRequests[id]; | ||||
|             else if (resources.ContainsKey(id)) | ||||
|                 return new AsyncReply<DistributedResource>(resources[id]); | ||||
|  | ||||
|             var reply = new AsyncReply<DistributedResource>(); | ||||
|  | ||||
|                 SendRequest(IIPPacket.IIPPacketAction.AttachResource, id).Then((rt) => | ||||
|                 { | ||||
|                     GetTemplate((Guid)rt[0]).Then((tmp) => | ||||
|                     { | ||||
|  | ||||
|                     // ClassId, ResourceAge, ResourceLink, Content | ||||
|  | ||||
|                     //var dr = Warehouse.New<DistributedResource>(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) => | ||||
|                     { | ||||
|                         dr._Attached(ar); | ||||
|                         resourceRequests.Remove(id); | ||||
|                         reply.Trigger(dr); | ||||
|                     }); | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|             return reply; | ||||
|         } | ||||
|  | ||||
|         private void Instance_ResourceDestroyed(IResource resource) | ||||
|         { | ||||
|             // compose the packet | ||||
|             SendParams((byte)0x1, resource.Instance.Id); | ||||
|         } | ||||
|  | ||||
|         private void Instance_PropertyModified(IResource resource, string name, object newValue, object oldValue) | ||||
|         { | ||||
|             var pt = resource.Instance.Template.GetPropertyTemplate(name); | ||||
|  | ||||
|             if (pt == null) | ||||
|                 return; | ||||
|  | ||||
|             // compose the packet | ||||
|             if (newValue is Func<DistributedConnection, object>) | ||||
|                 SendParams((byte)0x10, resource.Instance.Id, pt.Index, Codec.Compose((newValue as Func<DistributedConnection, object>)(this), this)); | ||||
|             else | ||||
|                 SendParams((byte)0x10, resource.Instance.Id, pt.Index, Codec.Compose(newValue, this)); | ||||
|  | ||||
|         } | ||||
|  | ||||
|         private void Instance_EventOccured(IResource resource, string name, string[] receivers, object[] args) | ||||
|         { | ||||
|             var et = resource.Instance.Template.GetEventTemplate(name); | ||||
|  | ||||
|             if (et == null) | ||||
|                 return; | ||||
|  | ||||
|             if (receivers != null) | ||||
|                 if (!receivers.Contains(RemoteUsername)) | ||||
|                     return; | ||||
|  | ||||
|             var clientArgs = new object[args.Length]; | ||||
|             for (var i = 0; i < args.Length; i++) | ||||
|                 if (args[i] is Func<DistributedConnection, object>) | ||||
|                     clientArgs[i] = (args[i] as Func<DistributedConnection, object>)(this); | ||||
|                 else | ||||
|                     clientArgs[i] = args[i]; | ||||
|  | ||||
|  | ||||
|             // compose the packet | ||||
|             SendParams((byte)0x11, resource.Instance.Id, (byte)et.Index, Codec.ComposeVarArray(args, this, true)); | ||||
|  | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										374
									
								
								Esiur/Net/IIP/DistributedResource.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										374
									
								
								Esiur/Net/IIP/DistributedResource.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,374 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.Reflection; | ||||
| using System.IO; | ||||
| using System.Collections; | ||||
| using System.ComponentModel; | ||||
| using Esiur.Misc; | ||||
| using Esiur.Data; | ||||
| using System.Dynamic; | ||||
| using System.Security.Cryptography; | ||||
| using Esiur.Engine; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Reflection.Emit; | ||||
| using System.Linq; | ||||
| using System.Linq.Expressions; | ||||
| using System.Threading.Tasks; | ||||
| using Esiur.Resource; | ||||
| using Esiur.Resource.Template; | ||||
|  | ||||
| namespace Esiur.Net.IIP | ||||
| { | ||||
|      | ||||
|     //[System.Runtime.InteropServices.ComVisible(true)] | ||||
|     public class DistributedResource : DynamicObject, IResource | ||||
|     { | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Raised when the distributed resource is destroyed. | ||||
|         /// </summary> | ||||
|         public event DestroyedEvent OnDestroy; | ||||
|  | ||||
|         uint instanceId; | ||||
|         DistributedConnection connection; | ||||
|  | ||||
|  | ||||
|         bool isAttached = false; | ||||
|         bool isReady = false; | ||||
|  | ||||
|  | ||||
|         //Structure properties = new Structure(); | ||||
|  | ||||
|         string link; | ||||
|         uint age; | ||||
|         uint[] ages; | ||||
|         object[] properties; | ||||
|         DistributedResourceEvent[] events; | ||||
|  | ||||
|         ResourceTemplate template; | ||||
|  | ||||
|   | ||||
|         //DistributedResourceStack stack; | ||||
|  | ||||
|   | ||||
|         bool destroyed; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Resource template for the remotely located resource. | ||||
|         /// </summary> | ||||
|         public ResourceTemplate Template | ||||
|         { | ||||
|             get { return template; } | ||||
|         } | ||||
|  | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Connection responsible for the distributed resource. | ||||
|         /// </summary> | ||||
|         public DistributedConnection Connection | ||||
|         { | ||||
|             get { return connection; } | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Resource link | ||||
|         /// </summary> | ||||
|         public string Link | ||||
|         { | ||||
|             get { return link; } | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Instance Id given by the other end. | ||||
|         /// </summary> | ||||
|         public uint Id | ||||
|         { | ||||
|             get {  return instanceId; } | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// IDestructible interface. | ||||
|         /// </summary> | ||||
|         public void Destroy() | ||||
|         { | ||||
|             destroyed = true; | ||||
|             OnDestroy?.Invoke(this); | ||||
|         } | ||||
|           | ||||
|         /// <summary> | ||||
|         /// Resource is ready when all its properties are attached. | ||||
|         /// </summary> | ||||
|         internal bool IsReady | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 return isReady; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Resource is attached when all its properties are received. | ||||
|         /// </summary> | ||||
|         internal bool IsAttached | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 return isAttached; | ||||
|             } | ||||
|         } | ||||
|   | ||||
|      | ||||
|  | ||||
|        // public DistributedResourceStack Stack | ||||
|         //{ | ||||
|        //     get { return stack; } | ||||
|         //} | ||||
|  | ||||
|             /// <summary> | ||||
|             /// Create a new distributed resource. | ||||
|             /// </summary> | ||||
|             /// <param name="connection">Connection responsible for the distributed resource.</param> | ||||
|             /// <param name="template">Resource template.</param> | ||||
|             /// <param name="instanceId">Instance Id given by the other end.</param> | ||||
|             /// <param name="age">Resource age.</param> | ||||
|         public DistributedResource(DistributedConnection connection, ResourceTemplate template, uint instanceId, uint age, string link) | ||||
|         { | ||||
|             this.link = link; | ||||
|             this.connection = connection; | ||||
|             this.instanceId = instanceId; | ||||
|             this.template = template; | ||||
|             this.age = age; | ||||
|         } | ||||
|  | ||||
|         internal void _Ready() | ||||
|         { | ||||
|             isReady = true; | ||||
|         } | ||||
|          | ||||
|         internal bool _Attached(object[] properties) | ||||
|         { | ||||
|              | ||||
|             if (isAttached) | ||||
|                 return false; | ||||
|             else | ||||
|             { | ||||
|                 this.properties = properties; | ||||
|                 ages = new uint[properties.Length]; | ||||
|                 this.events = new DistributedResourceEvent[template.Events.Length]; | ||||
|                 isAttached = true; | ||||
|             } | ||||
|            return true; | ||||
|         } | ||||
|  | ||||
|         internal void _EmitEventByIndex(byte index, object[] args) | ||||
|         { | ||||
|             var et = template.GetEventTemplate(index); | ||||
|             events[index]?.Invoke(this, args); | ||||
|             Instance.EmitResourceEvent(et.Name, null, args); | ||||
|         } | ||||
|  | ||||
|         public AsyncReply _Invoke(byte index, object[] args) | ||||
|         { | ||||
|             if (destroyed) | ||||
|                 throw new Exception("Trying to access destroyed object"); | ||||
|  | ||||
|             if (index >= template.Functions.Length) | ||||
|                 throw new Exception("Function index is incorrect"); | ||||
|  | ||||
|             var reply = new AsyncReply(); | ||||
|  | ||||
|             var parameters = Codec.ComposeVarArray(args, connection, true); | ||||
|             connection.SendRequest(Packets.IIPPacket.IIPPacketAction.InvokeFunction, instanceId, index, parameters).Then((res) => | ||||
|             { | ||||
|                 Codec.Parse((byte[])res[0], 0, connection).Then((rt) => | ||||
|                 { | ||||
|                     reply.Trigger(rt); | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|   | ||||
|             return reply; | ||||
|  | ||||
|         } | ||||
|  | ||||
|   | ||||
|         public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) | ||||
|         { | ||||
|             var ft = template.GetFunctionTemplate(binder.Name); | ||||
|  | ||||
|             var reply = new AsyncReply(); | ||||
|  | ||||
|             if (isAttached && ft!=null) | ||||
|             { | ||||
|                 result = _Invoke(ft.Index, args); | ||||
|                 return true; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 result = null; | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Get a property value. | ||||
|         /// </summary> | ||||
|         /// <param name="index">Zero-based property index.</param> | ||||
|         /// <returns>Value</returns> | ||||
|         internal object _Get(byte index) | ||||
|         { | ||||
|             if (index >= properties.Length) | ||||
|                 return null; | ||||
|             return properties[index]; | ||||
|         } | ||||
|  | ||||
|         public override bool TryGetMember(GetMemberBinder binder, out object result) | ||||
|         { | ||||
|             if (destroyed) | ||||
|                 throw new Exception("Trying to access destroyed object"); | ||||
|  | ||||
|             result = null; | ||||
|  | ||||
|             if (!isAttached) | ||||
|                 return false; | ||||
|  | ||||
|             var pt = template.GetPropertyTemplate(binder.Name); | ||||
|  | ||||
|             if (pt != null) | ||||
|             { | ||||
|                 result = properties[pt.Index]; | ||||
|                 return true; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 var et = template.GetEventTemplate(binder.Name); | ||||
|                 if (et == null) | ||||
|                     return false; | ||||
|  | ||||
|                 result = events[et.Index]; | ||||
|  | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|  | ||||
|         internal void UpdatePropertyByIndex(byte index, object value) | ||||
|         { | ||||
|             var pt = template.GetPropertyTemplate(index); | ||||
|             properties[index] = value; | ||||
|             Instance.Modified(pt.Name, value); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Set property value. | ||||
|         /// </summary> | ||||
|         /// <param name="index">Zero-based property index.</param> | ||||
|         /// <param name="value">Value</param> | ||||
|         /// <returns>Indicator when the property is set.</returns> | ||||
|         internal AsyncReply _Set(byte index, object value) | ||||
|         { | ||||
|             if (index >= properties.Length) | ||||
|                 return null; | ||||
|  | ||||
|             var reply = new AsyncReply(); | ||||
|  | ||||
|             var parameters = Codec.Compose(value, connection); | ||||
|             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); | ||||
|                 reply.Trigger(null); | ||||
|                 // nothing to do here | ||||
|             }); | ||||
|  | ||||
|             return reply; | ||||
|         } | ||||
|  | ||||
|         public override bool TrySetMember(SetMemberBinder binder, object value) | ||||
|         { | ||||
|             if (destroyed) | ||||
|                 throw new Exception("Trying to access destroyed object"); | ||||
|  | ||||
|             if (!isAttached) | ||||
|                 return false; | ||||
|  | ||||
|             var pt = template.GetPropertyTemplate(binder.Name); | ||||
|  | ||||
|   | ||||
|             if (pt != null) | ||||
|             { | ||||
|                 _Set(pt.Index, value); | ||||
|                 return true; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 var et = template.GetEventTemplate(binder.Name); | ||||
|                 if (et == null) | ||||
|                     return false; | ||||
|  | ||||
|                 events[et.Index] = (DistributedResourceEvent)value; | ||||
|  | ||||
|                 return true; | ||||
|             } | ||||
|  | ||||
|          } | ||||
|  | ||||
|         /* | ||||
|               public async void InvokeMethod(byte index, object[] arguments, DistributedConnection sender) | ||||
|               { | ||||
|                   // get function parameters | ||||
|                   Type t = this.GetType(); | ||||
|  | ||||
|                   MethodInfo mi = t.GetMethod(GetFunctionName(index), BindingFlags.DeclaredOnly | | ||||
|                                                           BindingFlags.Public | | ||||
|                                                           BindingFlags.Instance | BindingFlags.InvokeMethod); | ||||
|                   if (mi != null) | ||||
|                   { | ||||
|                       try | ||||
|                       { | ||||
|                           var res = await invokeMethod(mi, arguments, sender); | ||||
|                           object rt = Codec.Compose(res); | ||||
|                           sender.SendParams((byte)0x80, instanceId, index, rt); | ||||
|                       } | ||||
|                       catch(Exception ex) | ||||
|                       { | ||||
|                           var msg = ex.InnerException != null ? ex.InnerException.Message : ex.Message; | ||||
|                           sender.SendParams((byte)0x8E, instanceId, index, Codec.Compose(msg)); | ||||
|                       } | ||||
|                   } | ||||
|               } | ||||
|               */ | ||||
|  | ||||
|  | ||||
|     | ||||
|             /// <summary> | ||||
|             /// Resource interface. | ||||
|             /// </summary> | ||||
|         public Instance Instance | ||||
|         { | ||||
|             get; | ||||
|             set; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Create a new instance of distributed resource. | ||||
|         /// </summary> | ||||
|         public DistributedResource() | ||||
|         { | ||||
|             //stack = new DistributedResourceStack(this); | ||||
|  | ||||
|         } | ||||
|           | ||||
|         /// <summary> | ||||
|         /// Resource interface. | ||||
|         /// </summary> | ||||
|         /// <param name="trigger"></param> | ||||
|         /// <returns></returns> | ||||
|         public AsyncReply<bool> Trigger(ResourceTrigger trigger) | ||||
|         { | ||||
|             // do nothing. | ||||
|             return new AsyncReply<bool>(true); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										10
									
								
								Esiur/Net/IIP/DistributedResourceEvent.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Esiur/Net/IIP/DistributedResourceEvent.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace Esiur.Net.IIP | ||||
| { | ||||
|     public delegate void DistributedResourceEvent(DistributedResource sender, params object[] arguments); | ||||
| } | ||||
							
								
								
									
										49
									
								
								Esiur/Net/IIP/DistributedResourceQueueItem.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								Esiur/Net/IIP/DistributedResourceQueueItem.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace Esiur.Net.IIP | ||||
| { | ||||
|     public class DistributedResourceQueueItem | ||||
|     { | ||||
|         public enum DistributedResourceQueueItemType | ||||
|         { | ||||
|             Propery, | ||||
|             Event | ||||
|         } | ||||
|  | ||||
|         DistributedResourceQueueItemType type; | ||||
|         byte index; | ||||
|         object value; | ||||
|         DistributedResource resource; | ||||
|  | ||||
|         public DistributedResourceQueueItem(DistributedResource resource, DistributedResourceQueueItemType type, object value, byte index) | ||||
|         { | ||||
|             this.resource = resource; | ||||
|             this.index = index; | ||||
|             this.type = type; | ||||
|             this.value = value; | ||||
|         } | ||||
|  | ||||
|         public DistributedResource Resource | ||||
|         { | ||||
|             get { return resource; } | ||||
|         } | ||||
|         public DistributedResourceQueueItemType Type | ||||
|         { | ||||
|             get { return type; } | ||||
|         } | ||||
|  | ||||
|         public byte Index | ||||
|         { | ||||
|             get { return index; } | ||||
|         } | ||||
|  | ||||
|         public object Value | ||||
|         { | ||||
|             get { return value; } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										117
									
								
								Esiur/Net/IIP/DistributedServer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								Esiur/Net/IIP/DistributedServer.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
| using Esiur.Net.Sockets; | ||||
| using Esiur.Misc; | ||||
| using System.Threading; | ||||
| using Esiur.Data; | ||||
| using Esiur.Engine; | ||||
| using System.Net; | ||||
| using Esiur.Resource; | ||||
| using Esiur.Security.Membership; | ||||
|  | ||||
| namespace Esiur.Net.IIP | ||||
| { | ||||
|     public class DistributedServer : NetworkServer<DistributedConnection>, IResource | ||||
|     { | ||||
|  | ||||
|         [Storable] | ||||
|         [ResourceProperty] | ||||
|         public string ip | ||||
|         { | ||||
|             get; | ||||
|             set; | ||||
|         } | ||||
|  | ||||
|         [Storable] | ||||
|         [ResourceProperty] | ||||
|         public IMembership Membership | ||||
|         { | ||||
|             get; | ||||
|             set; | ||||
|         } | ||||
|         [Storable] | ||||
|         [ResourceProperty] | ||||
|         public ushort port | ||||
|         { | ||||
|             get; | ||||
|             set; | ||||
|         } | ||||
|  | ||||
|         [Storable] | ||||
|         [ResourceProperty] | ||||
|         public uint timeout | ||||
|         { | ||||
|             get; | ||||
|             set; | ||||
|         } | ||||
|          | ||||
|         [Storable] | ||||
|         [ResourceProperty] | ||||
|         public uint clock | ||||
|         { | ||||
|             get; | ||||
|             set; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         public Instance Instance | ||||
|         { | ||||
|             get; | ||||
|             set; | ||||
|         } | ||||
|  | ||||
|         public AsyncReply<bool> Trigger(ResourceTrigger trigger) | ||||
|         { | ||||
|             if (trigger == ResourceTrigger.Initialize) | ||||
|             { | ||||
|                 TCPSocket listener; | ||||
|  | ||||
|                 if (ip != null) | ||||
|                     listener = new TCPSocket(new IPEndPoint(IPAddress.Parse(ip), port)); | ||||
|                 else | ||||
|                     listener = new TCPSocket(new IPEndPoint(IPAddress.Any, port)); | ||||
|  | ||||
|                 Start(listener, timeout, clock); | ||||
|             } | ||||
|             else if (trigger == ResourceTrigger.Terminate) | ||||
|             { | ||||
|                 Stop(); | ||||
|             } | ||||
|             else if (trigger == ResourceTrigger.SystemReload) | ||||
|             { | ||||
|                 Trigger(ResourceTrigger.Terminate); | ||||
|                 Trigger(ResourceTrigger.Initialize); | ||||
|             } | ||||
|  | ||||
|             return new AsyncReply<bool>(true); | ||||
|         } | ||||
|  | ||||
|  | ||||
|  | ||||
|         protected override void DataReceived(DistributedConnection sender, NetworkBuffer data) | ||||
|         { | ||||
|             //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; | ||||
|          } | ||||
|  | ||||
|         protected override void ClientDisconnected(DistributedConnection sender) | ||||
|         { | ||||
|           Console.WriteLine("DistributedConnection Client Disconnected"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										14
									
								
								Esiur/Net/IIP/DistributedSession.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								Esiur/Net/IIP/DistributedSession.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using Esiur.Net.Sockets; | ||||
| using Esiur.Security.Authority; | ||||
|  | ||||
| namespace Esiur.Net.IIP | ||||
| { | ||||
|     public class DistributedSession : NetworkSession | ||||
|     { | ||||
|         Source Source { get; } | ||||
|         Authentication Authentication; | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user