diff options
author | Halil İbrahim Kalkan <hi_kalkan@yahoo.com> | 2013-04-08 21:44:58 +0300 |
---|---|---|
committer | Halil İbrahim Kalkan <hi_kalkan@yahoo.com> | 2013-04-08 21:44:58 +0300 |
commit | 79953cb56cda204f190ffcd9995b27ebea25e62d (patch) | |
tree | de939755c2e32eaa5fa3e41e21114e1c727ed0a4 | |
parent | 934c543eb6b0bd7173038e45a7dac0241d091da4 (diff) | |
download | scs-79953cb56cda204f190ffcd9995b27ebea25e62d.zip scs-79953cb56cda204f190ffcd9995b27ebea25e62d.tar.gz scs-79953cb56cda204f190ffcd9995b27ebea25e62d.tar.bz2 |
Adding to github
Adding to github
219 files changed, 16746 insertions, 0 deletions
diff --git a/binaries/Scs.XML b/binaries/Scs.XML new file mode 100644 index 0000000..4ad5e46 --- /dev/null +++ b/binaries/Scs.XML @@ -0,0 +1,2697 @@ +<?xml version="1.0"?> +<doc> + <assembly> + <name>Scs</name> + </assembly> + <members> + <member name="T:Hik.Communication.Scs.Server.IScsServer"> + <summary> + Represents a SCS server that is used to accept and manage client connections. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Server.IScsServer.Start"> + <summary> + Starts the server. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Server.IScsServer.Stop"> + <summary> + Stops the server. + </summary> + </member> + <member name="E:Hik.Communication.Scs.Server.IScsServer.ClientConnected"> + <summary> + This event is raised when a new client connected to the server. + </summary> + </member> + <member name="E:Hik.Communication.Scs.Server.IScsServer.ClientDisconnected"> + <summary> + This event is raised when a client disconnected from the server. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Server.IScsServer.WireProtocolFactory"> + <summary> + Gets/sets wire protocol factory to create IWireProtocol objects. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Server.IScsServer.Clients"> + <summary> + A collection of clients that are connected to the server. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Client.IScsClient"> + <summary> + Represents a client to connect to server. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.Messengers.IMessenger"> + <summary> + Represents an object that can send and receive messages. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.IMessenger.SendMessage(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Sends a message to the remote application. + </summary> + <param name="message">Message to be sent</param> + </member> + <member name="E:Hik.Communication.Scs.Communication.Messengers.IMessenger.MessageReceived"> + <summary> + This event is raised when a new message is received. + </summary> + </member> + <member name="E:Hik.Communication.Scs.Communication.Messengers.IMessenger.MessageSent"> + <summary> + This event is raised when a new message is sent without any error. + It does not guaranties that message is properly handled and processed by remote application. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Messengers.IMessenger.WireProtocol"> + <summary> + Gets/sets wire protocol that is used while reading and writing messages. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Messengers.IMessenger.LastReceivedMessageTime"> + <summary> + Gets the time of the last succesfully received message. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Messengers.IMessenger.LastSentMessageTime"> + <summary> + Gets the time of the last succesfully sent message. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Client.IConnectableClient"> + <summary> + Represents a client for SCS servers. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Client.IConnectableClient.Connect"> + <summary> + Connects to server. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Client.IConnectableClient.Disconnect"> + <summary> + Disconnects from server. + Does nothing if already disconnected. + </summary> + </member> + <member name="E:Hik.Communication.Scs.Client.IConnectableClient.Connected"> + <summary> + This event is raised when client connected to server. + </summary> + </member> + <member name="E:Hik.Communication.Scs.Client.IConnectableClient.Disconnected"> + <summary> + This event is raised when client disconnected from server. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Client.IConnectableClient.ConnectTimeout"> + <summary> + Timeout for connecting to a server (as milliseconds). + Default value: 15 seconds (15000 ms). + </summary> + </member> + <member name="P:Hik.Communication.Scs.Client.IConnectableClient.CommunicationState"> + <summary> + Gets the current communication state. + </summary> + </member> + <member name="T:Hik.Communication.ScsServices.Communication.AutoConnectRemoteInvokeProxy`2"> + <summary> + This class extends RemoteInvokeProxy to provide auto connect/disconnect mechanism + if client is not connected to the server when a service method is called. + </summary> + <typeparam name="TProxy">Type of the proxy class/interface</typeparam> + <typeparam name="TMessenger">Type of the messenger object that is used to send/receive messages</typeparam> + </member> + <member name="T:Hik.Communication.ScsServices.Communication.RemoteInvokeProxy`2"> + <summary> + This class is used to generate a dynamic proxy to invoke remote methods. + It translates method invocations to messaging. + </summary> + <typeparam name="TProxy">Type of the proxy class/interface</typeparam> + <typeparam name="TMessenger">Type of the messenger object that is used to send/receive messages</typeparam> + </member> + <member name="F:Hik.Communication.ScsServices.Communication.RemoteInvokeProxy`2._clientMessenger"> + <summary> + Messenger object that is used to send/receive messages. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Communication.RemoteInvokeProxy`2.#ctor(Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger{`1})"> + <summary> + Creates a new RemoteInvokeProxy object. + </summary> + <param name="clientMessenger">Messenger object that is used to send/receive messages</param> + </member> + <member name="M:Hik.Communication.ScsServices.Communication.RemoteInvokeProxy`2.Invoke(System.Runtime.Remoting.Messaging.IMessage)"> + <summary> + Overrides message calls and translates them to messages to remote application. + </summary> + <param name="msg">Method invoke message (from RealProxy base class)</param> + <returns>Method invoke return message (to RealProxy base class)</returns> + </member> + <member name="F:Hik.Communication.ScsServices.Communication.AutoConnectRemoteInvokeProxy`2._client"> + <summary> + Reference to the client object that is used to connect/disconnect. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Communication.AutoConnectRemoteInvokeProxy`2.#ctor(Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger{`1},Hik.Communication.Scs.Client.IConnectableClient)"> + <summary> + Creates a new AutoConnectRemoteInvokeProxy object. + </summary> + <param name="clientMessenger">Messenger object that is used to send/receive messages</param> + <param name="client">Reference to the client object that is used to connect/disconnect</param> + </member> + <member name="M:Hik.Communication.ScsServices.Communication.AutoConnectRemoteInvokeProxy`2.Invoke(System.Runtime.Remoting.Messaging.IMessage)"> + <summary> + Overrides message calls and translates them to messages to remote application. + </summary> + <param name="msg">Method invoke message (from RealProxy base class)</param> + <returns>Method invoke return message (to RealProxy base class)</returns> + </member> + <member name="T:Hik.Communication.Scs.Communication.Channels.Tcp.TcpCommunicationChannel"> + <summary> + This class is used to communicate with a remote application over TCP/IP protocol. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.Channels.CommunicationChannelBase"> + <summary> + This class provides base functionality for all communication channel classes. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.Channels.ICommunicationChannel"> + <summary> + Represents a communication channel. + A communication channel is used to communicate (send/receive messages) with a remote application. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.ICommunicationChannel.Start"> + <summary> + Starts the communication with remote application. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.ICommunicationChannel.Disconnect"> + <summary> + Closes messenger. + </summary> + </member> + <member name="E:Hik.Communication.Scs.Communication.Channels.ICommunicationChannel.Disconnected"> + <summary> + This event is raised when client disconnected from server. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Channels.ICommunicationChannel.RemoteEndPoint"> + <summary> + Gets endpoint of remote application. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Channels.ICommunicationChannel.CommunicationState"> + <summary> + Gets the current communication state. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.CommunicationChannelBase.#ctor"> + <summary> + Constructor. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.CommunicationChannelBase.Disconnect"> + <summary> + Disconnects from remote application and closes this channel. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.CommunicationChannelBase.Start"> + <summary> + Starts the communication with remote application. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.CommunicationChannelBase.SendMessage(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Sends a message to the remote application. + </summary> + <param name="message">Message to be sent</param> + <exception cref="T:System.ArgumentNullException">Throws ArgumentNullException if message is null</exception> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.CommunicationChannelBase.StartInternal"> + <summary> + Starts the communication with remote application really. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.CommunicationChannelBase.SendMessageInternal(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Sends a message to the remote application. + This method is overrided by derived classes to really send to message. + </summary> + <param name="message">Message to be sent</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.CommunicationChannelBase.OnDisconnected"> + <summary> + Raises Disconnected event. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.CommunicationChannelBase.OnMessageReceived(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Raises MessageReceived event. + </summary> + <param name="message">Received message</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.CommunicationChannelBase.OnMessageSent(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Raises MessageSent event. + </summary> + <param name="message">Received message</param> + </member> + <member name="E:Hik.Communication.Scs.Communication.Channels.CommunicationChannelBase.MessageReceived"> + <summary> + This event is raised when a new message is received. + </summary> + </member> + <member name="E:Hik.Communication.Scs.Communication.Channels.CommunicationChannelBase.MessageSent"> + <summary> + This event is raised when a new message is sent without any error. + It does not guaranties that message is properly handled and processed by remote application. + </summary> + </member> + <member name="E:Hik.Communication.Scs.Communication.Channels.CommunicationChannelBase.Disconnected"> + <summary> + This event is raised when communication channel closed. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Channels.CommunicationChannelBase.RemoteEndPoint"> + <summary> + Gets endpoint of remote application. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Channels.CommunicationChannelBase.CommunicationState"> + <summary> + Gets the current communication state. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Channels.CommunicationChannelBase.LastReceivedMessageTime"> + <summary> + Gets the time of the last succesfully received message. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Channels.CommunicationChannelBase.LastSentMessageTime"> + <summary> + Gets the time of the last succesfully sent message. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Channels.CommunicationChannelBase.WireProtocol"> + <summary> + Gets/sets wire protocol that the channel uses. + This property must set before first communication. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Channels.Tcp.TcpCommunicationChannel.ReceiveBufferSize"> + <summary> + Size of the buffer that is used to receive bytes from TCP socket. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Channels.Tcp.TcpCommunicationChannel._buffer"> + <summary> + This buffer is used to receive bytes + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Channels.Tcp.TcpCommunicationChannel._clientSocket"> + <summary> + Socket object to send/reveice messages. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Channels.Tcp.TcpCommunicationChannel._running"> + <summary> + A flag to control thread's running + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Channels.Tcp.TcpCommunicationChannel._syncLock"> + <summary> + This object is just used for thread synchronizing (locking). + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.Tcp.TcpCommunicationChannel.#ctor(System.Net.Sockets.Socket)"> + <summary> + Creates a new TcpCommunicationChannel object. + </summary> + <param name="clientSocket">A connected Socket object that is + used to communicate over network</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.Tcp.TcpCommunicationChannel.Disconnect"> + <summary> + Disconnects from remote application and closes channel. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.Tcp.TcpCommunicationChannel.StartInternal"> + <summary> + Starts the thread to receive messages from socket. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.Tcp.TcpCommunicationChannel.SendMessageInternal(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Sends a message to the remote application. + </summary> + <param name="message">Message to be sent</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.Tcp.TcpCommunicationChannel.ReceiveCallback(System.IAsyncResult)"> + <summary> + This method is used as callback method in _clientSocket's BeginReceive method. + It reveives bytes from socker. + </summary> + <param name="ar">Asyncronous call result</param> + </member> + <member name="P:Hik.Communication.Scs.Communication.Channels.Tcp.TcpCommunicationChannel.RemoteEndPoint"> + <summary> + Gets the endpoint of remote application. + </summary> + </member> + <member name="T:Hik.Communication.ScsServices.Service.ScsService"> + <summary> + Base class for all services that is serviced by IScsServiceApplication. + A class must be derived from ScsService to serve as a SCS service. + </summary> + </member> + <member name="F:Hik.Communication.ScsServices.Service.ScsService._currentClient"> + <summary> + The current client for a thread that called service method. + </summary> + </member> + <member name="P:Hik.Communication.ScsServices.Service.ScsService.CurrentClient"> + <summary> + Gets the current client which called this service method. + </summary> + <remarks> + This property is thread-safe, if returns correct client when + called in a service method if the method is called by SCS system, + else throws exception. + </remarks> + </member> + <member name="T:Hik.Communication.Scs.Communication.Channels.CommunicationChannelEventArgs"> + <summary> + Stores communication channel information to be used by an event. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.CommunicationChannelEventArgs.#ctor(Hik.Communication.Scs.Communication.Channels.ICommunicationChannel)"> + <summary> + Creates a new CommunicationChannelEventArgs object. + </summary> + <param name="channel">Communication channel that is associated with this event</param> + </member> + <member name="P:Hik.Communication.Scs.Communication.Channels.CommunicationChannelEventArgs.Channel"> + <summary> + Communication channel that is associated with this event. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Client.ScsClientFactory"> + <summary> + This class is used to create SCS Clients to connect to a SCS server. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Client.ScsClientFactory.CreateClient(Hik.Communication.Scs.Communication.EndPoints.ScsEndPoint)"> + <summary> + Creates a new client to connect to a server using an end point. + </summary> + <param name="endpoint">End point of the server to connect it</param> + <returns>Created TCP client</returns> + </member> + <member name="M:Hik.Communication.Scs.Client.ScsClientFactory.CreateClient(System.String)"> + <summary> + Creates a new client to connect to a server using an end point. + </summary> + <param name="endpointAddress">End point address of the server to connect it</param> + <returns>Created TCP client</returns> + </member> + <member name="T:Hik.Communication.ScsServices.Communication.Messages.ScsRemoteInvokeMessage"> + <summary> + This message is sent to invoke a method of a remote application. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.Messages.ScsMessage"> + <summary> + Represents a message that is sent and received by server and client. + This is the base class for all messages. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.Messages.IScsMessage"> + <summary> + Represents a message that is sent and received by server and client. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Messages.IScsMessage.MessageId"> + <summary> + Unique identified for this message. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Messages.IScsMessage.RepliedMessageId"> + <summary> + Unique identified for this message. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messages.ScsMessage.#ctor"> + <summary> + Creates a new ScsMessage. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messages.ScsMessage.#ctor(System.String)"> + <summary> + Creates a new reply ScsMessage. + </summary> + <param name="repliedMessageId"> + Replied message id if this is a reply for + a message. + </param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messages.ScsMessage.ToString"> + <summary> + Creates a string to represents this object. + </summary> + <returns>A string to represents this object</returns> + </member> + <member name="P:Hik.Communication.Scs.Communication.Messages.ScsMessage.MessageId"> + <summary> + Unique identified for this message. + Default value: New GUID. + Do not change if you do not want to do low level changes + such as custom wire protocols. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Messages.ScsMessage.RepliedMessageId"> + <summary> + This property is used to indicate that this is + a Reply message to a message. + It may be null if this is not a reply message. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Communication.Messages.ScsRemoteInvokeMessage.ToString"> + <summary> + Represents this object as string. + </summary> + <returns>String representation of this object</returns> + </member> + <member name="P:Hik.Communication.ScsServices.Communication.Messages.ScsRemoteInvokeMessage.ServiceClassName"> + <summary> + Name of the remove service class. + </summary> + </member> + <member name="P:Hik.Communication.ScsServices.Communication.Messages.ScsRemoteInvokeMessage.MethodName"> + <summary> + Method of remote application to invoke. + </summary> + </member> + <member name="P:Hik.Communication.ScsServices.Communication.Messages.ScsRemoteInvokeMessage.Parameters"> + <summary> + Parameters of method. + </summary> + </member> + <member name="T:Hik.Communication.ScsServices.Client.IScsServiceClient`1"> + <summary> + Represents a service client that consumes a SCS service. + </summary> + <typeparam name="T">Type of service interface</typeparam> + </member> + <member name="P:Hik.Communication.ScsServices.Client.IScsServiceClient`1.ServiceProxy"> + <summary> + Reference to the service proxy to invoke remote service methods. + </summary> + </member> + <member name="P:Hik.Communication.ScsServices.Client.IScsServiceClient`1.Timeout"> + <summary> + Timeout value when invoking a service method. + If timeout occurs before end of remote method call, an exception is thrown. + Use -1 for no timeout (wait indefinite). + Default value: 60000 (1 minute). + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.Protocols.BinarySerialization.BinarySerializationProtocol"> + <summary> + Default communication protocol between server and clients to send and receive a message. + It uses .NET binary serialization to write and read messages. + + A Message format: + [Message Length (4 bytes)][Serialized Message Content] + + If a message is serialized to byte array as N bytes, this protocol + adds 4 bytes size information to head of the message bytes, so total length is (4 + N) bytes. + + This class can be derived to change serializer (default: BinaryFormatter). To do this, + SerializeMessage and DeserializeMessage methods must be overrided. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.Protocols.IScsWireProtocol"> + <summary> + Represents a byte-level communication protocol between applications. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Protocols.IScsWireProtocol.GetBytes(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Serializes a message to a byte array to send to remote application. + This method is synchronized. So, only one thread can call it concurrently. + </summary> + <param name="message">Message to be serialized</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Protocols.IScsWireProtocol.CreateMessages(System.Byte[])"> + <summary> + Builds messages from a byte array that is received from remote application. + The Byte array may contain just a part of a message, the protocol must + cumulate bytes to build messages. + This method is synchronized. So, only one thread can call it concurrently. + </summary> + <param name="receivedBytes">Received bytes from remote application</param> + <returns> + List of messages. + Protocol can generate more than one message from a byte array. + Also, if received bytes are not sufficient to build a message, the protocol + may return an empty list (and save bytes to combine with next method call). + </returns> + </member> + <member name="M:Hik.Communication.Scs.Communication.Protocols.IScsWireProtocol.Reset"> + <summary> + This method is called when connection with remote application is reset (connection is renewing or first connecting). + So, wire protocol must reset itself. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Protocols.BinarySerialization.BinarySerializationProtocol.MaxMessageLength"> + <summary> + Maximum length of a message. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Protocols.BinarySerialization.BinarySerializationProtocol._receiveMemoryStream"> + <summary> + This MemoryStream object is used to collect receiving bytes to build messages. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Protocols.BinarySerialization.BinarySerializationProtocol.#ctor"> + <summary> + Creates a new instance of BinarySerializationProtocol. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Protocols.BinarySerialization.BinarySerializationProtocol.GetBytes(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Serializes a message to a byte array to send to remote application. + This method is synchronized. So, only one thread can call it concurrently. + </summary> + <param name="message">Message to be serialized</param> + <exception cref="T:Hik.Communication.Scs.Communication.CommunicationException">Throws CommunicationException if message is bigger than maximum allowed message length.</exception> + </member> + <member name="M:Hik.Communication.Scs.Communication.Protocols.BinarySerialization.BinarySerializationProtocol.CreateMessages(System.Byte[])"> + <summary> + Builds messages from a byte array that is received from remote application. + The Byte array may contain just a part of a message, the protocol must + cumulate bytes to build messages. + This method is synchronized. So, only one thread can call it concurrently. + </summary> + <param name="receivedBytes">Received bytes from remote application</param> + <returns> + List of messages. + Protocol can generate more than one message from a byte array. + Also, if received bytes are not sufficient to build a message, the protocol + may return an empty list (and save bytes to combine with next method call). + </returns> + </member> + <member name="M:Hik.Communication.Scs.Communication.Protocols.BinarySerialization.BinarySerializationProtocol.Reset"> + <summary> + This method is called when connection with remote application is reset (connection is renewing or first connecting). + So, wire protocol must reset itself. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Protocols.BinarySerialization.BinarySerializationProtocol.SerializeMessage(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + This method is used to serialize a IScsMessage to a byte array. + This method can be overrided by derived classes to change serialization strategy. + It is a couple with DeserializeMessage method and must be overrided together. + </summary> + <param name="message">Message to be serialized</param> + <returns> + Serialized message bytes. + Does not include length of the message. + </returns> + </member> + <member name="M:Hik.Communication.Scs.Communication.Protocols.BinarySerialization.BinarySerializationProtocol.DeserializeMessage(System.Byte[])"> + <summary> + This method is used to deserialize a IScsMessage from it's bytes. + This method can be overrided by derived classes to change deserialization strategy. + It is a couple with SerializeMessage method and must be overrided together. + </summary> + <param name="bytes"> + Bytes of message to be deserialized (does not include message length. It consist + of a single whole message) + </param> + <returns>Deserialized message</returns> + </member> + <member name="M:Hik.Communication.Scs.Communication.Protocols.BinarySerialization.BinarySerializationProtocol.ReadSingleMessage(System.Collections.Generic.ICollection{Hik.Communication.Scs.Communication.Messages.IScsMessage})"> + <summary> + This method tries to read a single message and add to the messages collection. + </summary> + <param name="messages">Messages collection to collect messages</param> + <returns> + Returns a boolean value indicates that if there is a need to re-call this method. + </returns> + <exception cref="T:Hik.Communication.Scs.Communication.CommunicationException">Throws CommunicationException if message is bigger than maximum allowed message length.</exception> + </member> + <member name="M:Hik.Communication.Scs.Communication.Protocols.BinarySerialization.BinarySerializationProtocol.WriteInt32(System.Byte[],System.Int32,System.Int32)"> + <summary> + Writes a int value to a byte array from a starting index. + </summary> + <param name="buffer">Byte array to write int value</param> + <param name="startIndex">Start index of byte array to write</param> + <param name="number">An integer value to write</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Protocols.BinarySerialization.BinarySerializationProtocol.ReadInt32(System.IO.Stream)"> + <summary> + Deserializes and returns a serialized integer. + </summary> + <returns>Deserialized integer</returns> + </member> + <member name="M:Hik.Communication.Scs.Communication.Protocols.BinarySerialization.BinarySerializationProtocol.ReadByteArray(System.IO.Stream,System.Int32)"> + <summary> + Reads a byte array with specified length. + </summary> + <param name="stream">Stream to read from</param> + <param name="length">Length of the byte array to read</param> + <returns>Read byte array</returns> + <exception cref="T:System.IO.EndOfStreamException">Throws EndOfStreamException if can not read from stream.</exception> + </member> + <member name="T:Hik.Communication.Scs.Communication.Protocols.BinarySerialization.BinarySerializationProtocol.DeserializationAppDomainBinder"> + <summary> + This class is used in deserializing to allow deserializing objects that are defined + in assemlies that are load in runtime (like PlugIns). + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.Channels.IConnectionListener"> + <summary> + Represents a communication listener. + A connection listener is used to accept incoming client connection requests. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.IConnectionListener.Start"> + <summary> + Starts listening incoming connections. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.IConnectionListener.Stop"> + <summary> + Stops listening incoming connections. + </summary> + </member> + <member name="E:Hik.Communication.Scs.Communication.Channels.IConnectionListener.CommunicationChannelConnected"> + <summary> + This event is raised when a new communication channel connected. + </summary> + </member> + <member name="T:Hik.Communication.ScsServices.Client.ScsServiceClient`1"> + <summary> + Represents a service client that consumes a SCS service. + </summary> + <typeparam name="T">Type of service interface</typeparam> + </member> + <member name="F:Hik.Communication.ScsServices.Client.ScsServiceClient`1._client"> + <summary> + Underlying IScsClient object to communicate with server. + </summary> + </member> + <member name="F:Hik.Communication.ScsServices.Client.ScsServiceClient`1._requestReplyMessenger"> + <summary> + Messenger object to send/receive messages over _client. + </summary> + </member> + <member name="F:Hik.Communication.ScsServices.Client.ScsServiceClient`1._realServiceProxy"> + <summary> + This object is used to create a transparent proxy to invoke remote methods on server. + </summary> + </member> + <member name="F:Hik.Communication.ScsServices.Client.ScsServiceClient`1._clientObject"> + <summary> + The client object that is used to call method invokes in client side. + May be null if client has no methods to be invoked by server. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Client.ScsServiceClient`1.#ctor(Hik.Communication.Scs.Client.IScsClient,System.Object)"> + <summary> + Creates a new ScsServiceClient object. + </summary> + <param name="client">Underlying IScsClient object to communicate with server</param> + <param name="clientObject">The client object that is used to call method invokes in client side. + May be null if client has no methods to be invoked by server.</param> + </member> + <member name="M:Hik.Communication.ScsServices.Client.ScsServiceClient`1.Connect"> + <summary> + Connects to server. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Client.ScsServiceClient`1.Disconnect"> + <summary> + Disconnects from server. + Does nothing if already disconnected. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Client.ScsServiceClient`1.Dispose"> + <summary> + Calls Disconnect method. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Client.ScsServiceClient`1.RequestReplyMessenger_MessageReceived(System.Object,Hik.Communication.Scs.Communication.Messages.MessageEventArgs)"> + <summary> + Handles MessageReceived event of messenger. + It gets messages from server and invokes appropriate method. + </summary> + <param name="sender">Source of event</param> + <param name="e">Event arguments</param> + </member> + <member name="M:Hik.Communication.ScsServices.Client.ScsServiceClient`1.SendInvokeResponse(Hik.Communication.Scs.Communication.Messages.IScsMessage,System.Object,Hik.Communication.ScsServices.Communication.Messages.ScsRemoteException)"> + <summary> + Sends response to the remote application that invoked a service method. + </summary> + <param name="requestMessage">Request message</param> + <param name="returnValue">Return value to send</param> + <param name="exception">Exception to send</param> + </member> + <member name="M:Hik.Communication.ScsServices.Client.ScsServiceClient`1.Client_Connected(System.Object,System.EventArgs)"> + <summary> + Handles Connected event of _client object. + </summary> + <param name="sender">Source of object</param> + <param name="e">Event arguments</param> + </member> + <member name="M:Hik.Communication.ScsServices.Client.ScsServiceClient`1.Client_Disconnected(System.Object,System.EventArgs)"> + <summary> + Handles Disconnected event of _client object. + </summary> + <param name="sender">Source of object</param> + <param name="e">Event arguments</param> + </member> + <member name="M:Hik.Communication.ScsServices.Client.ScsServiceClient`1.OnConnected"> + <summary> + Raises Connected event. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Client.ScsServiceClient`1.OnDisconnected"> + <summary> + Raises Disconnected event. + </summary> + </member> + <member name="E:Hik.Communication.ScsServices.Client.ScsServiceClient`1.Connected"> + <summary> + This event is raised when client connected to server. + </summary> + </member> + <member name="E:Hik.Communication.ScsServices.Client.ScsServiceClient`1.Disconnected"> + <summary> + This event is raised when client disconnected from server. + </summary> + </member> + <member name="P:Hik.Communication.ScsServices.Client.ScsServiceClient`1.ConnectTimeout"> + <summary> + Timeout for connecting to a server (as milliseconds). + Default value: 15 seconds (15000 ms). + </summary> + </member> + <member name="P:Hik.Communication.ScsServices.Client.ScsServiceClient`1.CommunicationState"> + <summary> + Gets the current communication state. + </summary> + </member> + <member name="P:Hik.Communication.ScsServices.Client.ScsServiceClient`1.ServiceProxy"> + <summary> + Reference to the service proxy to invoke remote service methods. + </summary> + </member> + <member name="P:Hik.Communication.ScsServices.Client.ScsServiceClient`1.Timeout"> + <summary> + Timeout value when invoking a service method. + If timeout occurs before end of remote method call, an exception is thrown. + Use -1 for no timeout (wait indefinite). + Default value: 60000 (1 minute). + </summary> + </member> + <member name="T:Hik.Communication.Scs.Server.ScsServerManager"> + <summary> + Provides some functionality that are used by servers. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Server.ScsServerManager._lastClientId"> + <summary> + Used to set an auto incremential unique identifier to clients. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Server.ScsServerManager.GetClientId"> + <summary> + Gets an unique number to be used as idenfitier of a client. + </summary> + <returns></returns> + </member> + <member name="T:Hik.Communication.Scs.Communication.Protocols.BinarySerialization.BinarySerializationProtocolFactory"> + <summary> + This class is used to create Binary Serialization Protocol objects. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.Protocols.IScsWireProtocolFactory"> + <summary> + Defines a Wire Protocol Factory class that is used to create Wire Protocol objects. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Protocols.IScsWireProtocolFactory.CreateWireProtocol"> + <summary> + Creates a new Wire Protocol object. + </summary> + <returns>Newly created wire protocol object</returns> + </member> + <member name="M:Hik.Communication.Scs.Communication.Protocols.BinarySerialization.BinarySerializationProtocolFactory.CreateWireProtocol"> + <summary> + Creates a new Wire Protocol object. + </summary> + <returns>Newly created wire protocol object</returns> + </member> + <member name="T:Hik.Communication.Scs.Communication.Messages.ScsTextMessage"> + <summary> + This message is used to send/receive a text as message data. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messages.ScsTextMessage.#ctor"> + <summary> + Creates a new ScsTextMessage object. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messages.ScsTextMessage.#ctor(System.String)"> + <summary> + Creates a new ScsTextMessage object with Text property. + </summary> + <param name="text">Message text that is being transmitted</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messages.ScsTextMessage.#ctor(System.String,System.String)"> + <summary> + Creates a new reply ScsTextMessage object with Text property. + </summary> + <param name="text">Message text that is being transmitted</param> + <param name="repliedMessageId"> + Replied message id if this is a reply for + a message. + </param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messages.ScsTextMessage.ToString"> + <summary> + Creates a string to represents this object. + </summary> + <returns>A string to represents this object</returns> + </member> + <member name="P:Hik.Communication.Scs.Communication.Messages.ScsTextMessage.Text"> + <summary> + Message text that is being transmitted. + </summary> + </member> + <member name="T:Hik.Communication.ScsServices.Service.ScsServiceBuilder"> + <summary> + This class is used to build ScsService applications. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceBuilder.CreateService(Hik.Communication.Scs.Communication.EndPoints.ScsEndPoint)"> + <summary> + Creates a new SCS Service application using an EndPoint. + </summary> + <param name="endPoint">EndPoint that represents address of the service</param> + <returns>Created SCS service application</returns> + </member> + <member name="T:Hik.Communication.Scs.Communication.Messages.ScsPingMessage"> + <summary> + This message is used to send/receive ping messages. + Ping messages is used to keep connection alive between server and client. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messages.ScsPingMessage.#ctor"> + <summary> + Creates a new PingMessage object. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messages.ScsPingMessage.#ctor(System.String)"> + <summary> + Creates a new reply PingMessage object. + </summary> + <param name="repliedMessageId"> + Replied message id if this is a reply for + a message. + </param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messages.ScsPingMessage.ToString"> + <summary> + Creates a string to represents this object. + </summary> + <returns>A string to represents this object</returns> + </member> + <member name="T:Hik.Communication.ScsServices.Communication.Messages.ScsRemoteException"> + <summary> + Represents a SCS Remote Exception. + This exception is used to send an exception from an application to another application. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Communication.Messages.ScsRemoteException.#ctor"> + <summary> + Contstructor. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Communication.Messages.ScsRemoteException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)"> + <summary> + Contstructor. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Communication.Messages.ScsRemoteException.#ctor(System.String)"> + <summary> + Contstructor. + </summary> + <param name="message">Exception message</param> + </member> + <member name="M:Hik.Communication.ScsServices.Communication.Messages.ScsRemoteException.#ctor(System.String,System.Exception)"> + <summary> + Contstructor. + </summary> + <param name="message">Exception message</param> + <param name="innerException">Inner exception</param> + </member> + <member name="T:Hik.Communication.Scs.Server.ScsServerBase"> + <summary> + This class provides base functionality for server classes. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Server.ScsServerBase._connectionListener"> + <summary> + This object is used to listen incoming connections. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Server.ScsServerBase.#ctor"> + <summary> + Constructor. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Server.ScsServerBase.Start"> + <summary> + Starts the server. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Server.ScsServerBase.Stop"> + <summary> + Stops the server. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Server.ScsServerBase.CreateConnectionListener"> + <summary> + This method is implemented by derived classes to create appropriate connection listener to listen incoming connection requets. + </summary> + <returns></returns> + </member> + <member name="M:Hik.Communication.Scs.Server.ScsServerBase.ConnectionListener_CommunicationChannelConnected(System.Object,Hik.Communication.Scs.Communication.Channels.CommunicationChannelEventArgs)"> + <summary> + Handles CommunicationChannelConnected event of _connectionListener object. + </summary> + <param name="sender">Source of event</param> + <param name="e">Event arguments</param> + </member> + <member name="M:Hik.Communication.Scs.Server.ScsServerBase.Client_Disconnected(System.Object,System.EventArgs)"> + <summary> + Handles Disconnected events of all connected clients. + </summary> + <param name="sender">Source of event</param> + <param name="e">Event arguments</param> + </member> + <member name="M:Hik.Communication.Scs.Server.ScsServerBase.OnClientConnected(Hik.Communication.Scs.Server.IScsServerClient)"> + <summary> + Raises ClientConnected event. + </summary> + <param name="client">Connected client</param> + </member> + <member name="M:Hik.Communication.Scs.Server.ScsServerBase.OnClientDisconnected(Hik.Communication.Scs.Server.IScsServerClient)"> + <summary> + Raises ClientDisconnected event. + </summary> + <param name="client">Disconnected client</param> + </member> + <member name="E:Hik.Communication.Scs.Server.ScsServerBase.ClientConnected"> + <summary> + This event is raised when a new client is connected. + </summary> + </member> + <member name="E:Hik.Communication.Scs.Server.ScsServerBase.ClientDisconnected"> + <summary> + This event is raised when a client disconnected from the server. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Server.ScsServerBase.WireProtocolFactory"> + <summary> + Gets/sets wire protocol that is used while reading and writing messages. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Server.ScsServerBase.Clients"> + <summary> + A collection of clients that are connected to the server. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.Messages.ScsRawDataMessage"> + <summary> + This message is used to send/receive a raw byte array as message data. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messages.ScsRawDataMessage.#ctor"> + <summary> + Default empty constructor. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messages.ScsRawDataMessage.#ctor(System.Byte[])"> + <summary> + Creates a new ScsRawDataMessage object with MessageData property. + </summary> + <param name="messageData">Message data that is being transmitted</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messages.ScsRawDataMessage.#ctor(System.Byte[],System.String)"> + <summary> + Creates a new reply ScsRawDataMessage object with MessageData property. + </summary> + <param name="messageData">Message data that is being transmitted</param> + <param name="repliedMessageId"> + Replied message id if this is a reply for + a message. + </param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messages.ScsRawDataMessage.ToString"> + <summary> + Creates a string to represents this object. + </summary> + <returns>A string to represents this object</returns> + </member> + <member name="P:Hik.Communication.Scs.Communication.Messages.ScsRawDataMessage.MessageData"> + <summary> + Message data that is being transmitted. + </summary> + </member> + <member name="T:Hik.Communication.ScsServices.Service.ServiceClientEventArgs"> + <summary> + Stores service client informations to be used by an event. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ServiceClientEventArgs.#ctor(Hik.Communication.ScsServices.Service.IScsServiceClient)"> + <summary> + Creates a new ServiceClientEventArgs object. + </summary> + <param name="client">Client that is associated with this event</param> + </member> + <member name="P:Hik.Communication.ScsServices.Service.ServiceClientEventArgs.Client"> + <summary> + Client that is associated with this event. + </summary> + </member> + <member name="T:Hik.Communication.ScsServices.Service.ScsServiceClient"> + <summary> + Implements IScsServiceClient. + It is used to manage and monitor a service client. + </summary> + </member> + <member name="T:Hik.Communication.ScsServices.Service.IScsServiceClient"> + <summary> + Represents a client that uses a SDS service. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Service.IScsServiceClient.Disconnect"> + <summary> + Closes client connection. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Service.IScsServiceClient.GetClientProxy``1"> + <summary> + Gets the client proxy interface that provides calling client methods remotely. + </summary> + <typeparam name="T">Type of client interface</typeparam> + <returns>Client interface</returns> + </member> + <member name="E:Hik.Communication.ScsServices.Service.IScsServiceClient.Disconnected"> + <summary> + This event is raised when client is disconnected from service. + </summary> + </member> + <member name="P:Hik.Communication.ScsServices.Service.IScsServiceClient.ClientId"> + <summary> + Unique identifier for this client. + </summary> + </member> + <member name="P:Hik.Communication.ScsServices.Service.IScsServiceClient.RemoteEndPoint"> + <summary> + Gets endpoint of remote application. + </summary> + </member> + <member name="P:Hik.Communication.ScsServices.Service.IScsServiceClient.CommunicationState"> + <summary> + Gets the communication state of the Client. + </summary> + </member> + <member name="F:Hik.Communication.ScsServices.Service.ScsServiceClient._serverClient"> + <summary> + Reference to underlying IScsServerClient object. + </summary> + </member> + <member name="F:Hik.Communication.ScsServices.Service.ScsServiceClient._requestReplyMessenger"> + <summary> + This object is used to send messages to client. + </summary> + </member> + <member name="F:Hik.Communication.ScsServices.Service.ScsServiceClient._realProxy"> + <summary> + Last created proxy object to invoke remote medhods. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceClient.#ctor(Hik.Communication.Scs.Server.IScsServerClient,Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger{Hik.Communication.Scs.Server.IScsServerClient})"> + <summary> + Creates a new ScsServiceClient object. + </summary> + <param name="serverClient">Reference to underlying IScsServerClient object</param> + <param name="requestReplyMessenger">RequestReplyMessenger to send messages</param> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceClient.Disconnect"> + <summary> + Closes client connection. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceClient.GetClientProxy``1"> + <summary> + Gets the client proxy interface that provides calling client methods remotely. + </summary> + <typeparam name="T">Type of client interface</typeparam> + <returns>Client interface</returns> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceClient.Client_Disconnected(System.Object,System.EventArgs)"> + <summary> + Handles disconnect event of _serverClient object. + </summary> + <param name="sender">Source of event</param> + <param name="e">Event arguments</param> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceClient.OnDisconnected"> + <summary> + Raises Disconnected event. + </summary> + </member> + <member name="E:Hik.Communication.ScsServices.Service.ScsServiceClient.Disconnected"> + <summary> + This event is raised when this client is disconnected from server. + </summary> + </member> + <member name="P:Hik.Communication.ScsServices.Service.ScsServiceClient.ClientId"> + <summary> + Unique identifier for this client. + </summary> + </member> + <member name="P:Hik.Communication.ScsServices.Service.ScsServiceClient.RemoteEndPoint"> + <summary> + Gets endpoint of remote application. + </summary> + </member> + <member name="P:Hik.Communication.ScsServices.Service.ScsServiceClient.CommunicationState"> + <summary> + Gets the communication state of the Client. + </summary> + </member> + <member name="T:Hik.Collections.ThreadSafeSortedList`2"> + <summary> + This class is used to store key-value based items in a thread safe manner. + It uses System.Collections.Generic.SortedList internally. + </summary> + <typeparam name="TK">Key type</typeparam> + <typeparam name="TV">Value type</typeparam> + </member> + <member name="F:Hik.Collections.ThreadSafeSortedList`2._items"> + <summary> + Internal collection to store items. + </summary> + </member> + <member name="F:Hik.Collections.ThreadSafeSortedList`2._lock"> + <summary> + Used to synchronize access to _items list. + </summary> + </member> + <member name="M:Hik.Collections.ThreadSafeSortedList`2.#ctor"> + <summary> + Creates a new ThreadSafeSortedList object. + </summary> + </member> + <member name="M:Hik.Collections.ThreadSafeSortedList`2.ContainsKey(`0)"> + <summary> + Checks if collection contains spesified key. + </summary> + <param name="key">Key to check</param> + <returns>True; if collection contains given key</returns> + </member> + <member name="M:Hik.Collections.ThreadSafeSortedList`2.ContainsValue(`1)"> + <summary> + Checks if collection contains spesified item. + </summary> + <param name="item">Item to check</param> + <returns>True; if collection contains given item</returns> + </member> + <member name="M:Hik.Collections.ThreadSafeSortedList`2.Remove(`0)"> + <summary> + Removes an item from collection. + </summary> + <param name="key">Key of item to remove</param> + </member> + <member name="M:Hik.Collections.ThreadSafeSortedList`2.GetAllItems"> + <summary> + Gets all items in collection. + </summary> + <returns>Item list</returns> + </member> + <member name="M:Hik.Collections.ThreadSafeSortedList`2.ClearAll"> + <summary> + Removes all items from list. + </summary> + </member> + <member name="M:Hik.Collections.ThreadSafeSortedList`2.GetAndClearAllItems"> + <summary> + Gets then removes all items in collection. + </summary> + <returns>Item list</returns> + </member> + <member name="P:Hik.Collections.ThreadSafeSortedList`2.Item(`0)"> + <summary> + Gets/adds/replaces an item by key. + </summary> + <param name="key">Key to get/set value</param> + <returns>Item associated with this key</returns> + </member> + <member name="P:Hik.Collections.ThreadSafeSortedList`2.Count"> + <summary> + Gets count of items in the collection. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Client.Tcp.TcpHelper"> + <summary> + This class is used to simplify TCP socket operations. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Client.Tcp.TcpHelper.ConnectToServer(System.Net.EndPoint,System.Int32)"> + <summary> + This code is used to connect to a TCP socket with timeout option. + </summary> + <param name="endPoint">IP endpoint of remote server</param> + <param name="timeoutMs">Timeout to wait until connect</param> + <returns>Socket object connected to server</returns> + <exception cref="T:System.Net.Sockets.SocketException">Throws SocketException if can not connect.</exception> + <exception cref="T:System.TimeoutException">Throws TimeoutException if can not connect within specified timeoutMs</exception> + </member> + <member name="T:Hik.Communication.Scs.Client.Tcp.ScsTcpClient"> + <summary> + This class is used to communicate with server over TCP/IP protocol. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Client.ScsClientBase"> + <summary> + This class provides base functionality for client classes. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Client.ScsClientBase.DefaultConnectionAttemptTimeout"> + <summary> + Default timeout value for connecting a server. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Client.ScsClientBase._communicationChannel"> + <summary> + The communication channel that is used by client to send and receive messages. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Client.ScsClientBase._pingTimer"> + <summary> + This timer is used to send PingMessage messages to server periodically. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Client.ScsClientBase.#ctor"> + <summary> + Constructor. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Client.ScsClientBase.Connect"> + <summary> + Connects to server. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Client.ScsClientBase.Disconnect"> + <summary> + Disconnects from server. + Does nothing if already disconnected. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Client.ScsClientBase.Dispose"> + <summary> + Disposes this object and closes underlying connection. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Client.ScsClientBase.SendMessage(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Sends a message to the server. + </summary> + <param name="message">Message to be sent</param> + <exception cref="T:Hik.Communication.Scs.Communication.CommunicationStateException">Throws a CommunicationStateException if client is not connected to the server.</exception> + </member> + <member name="M:Hik.Communication.Scs.Client.ScsClientBase.CreateCommunicationChannel"> + <summary> + This method is implemented by derived classes to create appropriate communication channel. + </summary> + <returns>Ready communication channel to communicate</returns> + </member> + <member name="M:Hik.Communication.Scs.Client.ScsClientBase.CommunicationChannel_MessageReceived(System.Object,Hik.Communication.Scs.Communication.Messages.MessageEventArgs)"> + <summary> + Handles MessageReceived event of _communicationChannel object. + </summary> + <param name="sender">Source of event</param> + <param name="e">Event arguments</param> + </member> + <member name="M:Hik.Communication.Scs.Client.ScsClientBase.CommunicationChannel_MessageSent(System.Object,Hik.Communication.Scs.Communication.Messages.MessageEventArgs)"> + <summary> + Handles MessageSent event of _communicationChannel object. + </summary> + <param name="sender">Source of event</param> + <param name="e">Event arguments</param> + </member> + <member name="M:Hik.Communication.Scs.Client.ScsClientBase.CommunicationChannel_Disconnected(System.Object,System.EventArgs)"> + <summary> + Handles Disconnected event of _communicationChannel object. + </summary> + <param name="sender">Source of event</param> + <param name="e">Event arguments</param> + </member> + <member name="M:Hik.Communication.Scs.Client.ScsClientBase.PingTimer_Elapsed(System.Object,System.EventArgs)"> + <summary> + Handles Elapsed event of _pingTimer to send PingMessage messages to server. + </summary> + <param name="sender">Source of event</param> + <param name="e">Event arguments</param> + </member> + <member name="M:Hik.Communication.Scs.Client.ScsClientBase.OnConnected"> + <summary> + Raises Connected event. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Client.ScsClientBase.OnDisconnected"> + <summary> + Raises Disconnected event. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Client.ScsClientBase.OnMessageReceived(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Raises MessageReceived event. + </summary> + <param name="message">Received message</param> + </member> + <member name="M:Hik.Communication.Scs.Client.ScsClientBase.OnMessageSent(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Raises MessageSent event. + </summary> + <param name="message">Received message</param> + </member> + <member name="E:Hik.Communication.Scs.Client.ScsClientBase.MessageReceived"> + <summary> + This event is raised when a new message is received. + </summary> + </member> + <member name="E:Hik.Communication.Scs.Client.ScsClientBase.MessageSent"> + <summary> + This event is raised when a new message is sent without any error. + It does not guaranties that message is properly handled and processed by remote application. + </summary> + </member> + <member name="E:Hik.Communication.Scs.Client.ScsClientBase.Connected"> + <summary> + This event is raised when communication channel closed. + </summary> + </member> + <member name="E:Hik.Communication.Scs.Client.ScsClientBase.Disconnected"> + <summary> + This event is raised when client disconnected from server. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Client.ScsClientBase.ConnectTimeout"> + <summary> + Timeout for connecting to a server (as milliseconds). + Default value: 15 seconds (15000 ms). + </summary> + </member> + <member name="P:Hik.Communication.Scs.Client.ScsClientBase.WireProtocol"> + <summary> + Gets/sets wire protocol that is used while reading and writing messages. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Client.ScsClientBase.CommunicationState"> + <summary> + Gets the communication state of the Client. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Client.ScsClientBase.LastReceivedMessageTime"> + <summary> + Gets the time of the last succesfully received message. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Client.ScsClientBase.LastSentMessageTime"> + <summary> + Gets the time of the last succesfully received message. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Client.Tcp.ScsTcpClient._serverEndPoint"> + <summary> + The endpoint address of the server. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Client.Tcp.ScsTcpClient.#ctor(Hik.Communication.Scs.Communication.EndPoints.Tcp.ScsTcpEndPoint)"> + <summary> + Creates a new ScsTcpClient object. + </summary> + <param name="serverEndPoint">The endpoint address to connect to the server</param> + </member> + <member name="M:Hik.Communication.Scs.Client.Tcp.ScsTcpClient.CreateCommunicationChannel"> + <summary> + Creates a communication channel using ServerIpAddress and ServerPort. + </summary> + <returns>Ready communication channel to communicate</returns> + </member> + <member name="T:Hik.Communication.Scs.Communication.EndPoints.Tcp.ScsTcpEndPoint"> + <summary> + Represens a TCP end point in SCS. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.EndPoints.ScsEndPoint"> + <summary> + Represents a server side end point in SCS. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.EndPoints.ScsEndPoint.CreateEndPoint(System.String)"> + <summary> + Create a Scs End Point from a string. + Address must be formatted as: protocol://address + For example: tcp://89.43.104.179:10048 for a TCP endpoint with + IP 89.43.104.179 and port 10048. + </summary> + <param name="endPointAddress">Address to create endpoint</param> + <returns>Created end point</returns> + </member> + <member name="M:Hik.Communication.Scs.Communication.EndPoints.ScsEndPoint.CreateServer"> + <summary> + Creates a Scs Server that uses this end point to listen incoming connections. + </summary> + <returns>Scs Server</returns> + </member> + <member name="M:Hik.Communication.Scs.Communication.EndPoints.ScsEndPoint.CreateClient"> + <summary> + Creates a Scs Server that uses this end point to connect to server. + </summary> + <returns>Scs Client</returns> + </member> + <member name="M:Hik.Communication.Scs.Communication.EndPoints.Tcp.ScsTcpEndPoint.#ctor(System.Int32)"> + <summary> + Creates a new ScsTcpEndPoint object with specified port number. + </summary> + <param name="tcpPort">Listening TCP Port for incoming connection requests on server</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.EndPoints.Tcp.ScsTcpEndPoint.#ctor(System.String,System.Int32)"> + <summary> + Creates a new ScsTcpEndPoint object with specified IP address and port number. + </summary> + <param name="ipAddress">IP address of the server</param> + <param name="port">Listening TCP Port for incoming connection requests on server</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.EndPoints.Tcp.ScsTcpEndPoint.#ctor(System.String)"> + <summary> + Creates a new ScsTcpEndPoint from a string address. + Address format must be like IPAddress:Port (For example: 127.0.0.1:10085). + </summary> + <param name="address">TCP end point Address</param> + <returns>Created ScsTcpEndpoint object</returns> + </member> + <member name="M:Hik.Communication.Scs.Communication.EndPoints.Tcp.ScsTcpEndPoint.CreateServer"> + <summary> + Creates a Scs Server that uses this end point to listen incoming connections. + </summary> + <returns>Scs Server</returns> + </member> + <member name="M:Hik.Communication.Scs.Communication.EndPoints.Tcp.ScsTcpEndPoint.CreateClient"> + <summary> + Creates a Scs Client that uses this end point to connect to server. + </summary> + <returns>Scs Client</returns> + </member> + <member name="M:Hik.Communication.Scs.Communication.EndPoints.Tcp.ScsTcpEndPoint.ToString"> + <summary> + Generates a string representation of this end point object. + </summary> + <returns>String representation of this end point object</returns> + </member> + <member name="P:Hik.Communication.Scs.Communication.EndPoints.Tcp.ScsTcpEndPoint.IpAddress"> + <summary> + IP address of the server. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.EndPoints.Tcp.ScsTcpEndPoint.TcpPort"> + <summary> + Listening TCP Port for incoming connection requests on server. + </summary> + </member> + <member name="T:Hik.Communication.ScsServices.Service.ScsServiceAttribute"> + <summary> + Any SCS Service interface class must has this attribute. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceAttribute.#ctor"> + <summary> + Creates a new ScsServiceAttribute object. + </summary> + </member> + <member name="P:Hik.Communication.ScsServices.Service.ScsServiceAttribute.Version"> + <summary> + Service Version. This property can be used to indicate the code version. + This value is sent to client application on an exception, so, client application can know that service version is changed. + Default value: NO_VERSION. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1"> + <summary> + This class adds SendMessageAndWaitForResponse(...) and SendAndReceiveMessage methods + to a IMessenger for synchronous request/response style messaging. + It also adds queued processing of incoming messages. + </summary> + <typeparam name="T">Type of IMessenger object to use as underlying communication</typeparam> + </member> + <member name="F:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.DefaultTimeout"> + <summary> + Default Timeout value. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1._waitingMessages"> + <summary> + This messages are waiting for a response those are used when + SendMessageAndWaitForResponse is called. + Key: MessageID of waiting request message. + Value: A WaitingMessage instance. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1._incomingMessageProcessor"> + <summary> + This object is used to process incoming messages sequentially. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1._syncObj"> + <summary> + This object is used for thread synchronization. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.#ctor(`0)"> + <summary> + Creates a new RequestReplyMessenger. + </summary> + <param name="messenger">IMessenger object to use as underlying communication</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.Start"> + <summary> + Starts the messenger. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.Stop"> + <summary> + Stops the messenger. + Cancels all waiting threads in SendMessageAndWaitForResponse method and stops message queue. + SendMessageAndWaitForResponse method throws exception if there is a thread that is waiting for response message. + Also stops incoming message processing and deletes all messages in incoming message queue. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.Dispose"> + <summary> + Calls Stop method of this object. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.SendMessage(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Sends a message. + </summary> + <param name="message">Message to be sent</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.SendMessageAndWaitForResponse(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Sends a message and waits a response for that message. + </summary> + <remarks> + Response message is matched with RepliedMessageId property, so if + any other message (that is not reply for sent message) is received + from remote application, it is not considered as a reply and is not + returned as return value of this method. + + MessageReceived event is not raised for response messages. + </remarks> + <param name="message">message to send</param> + <returns>Response message</returns> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.SendMessageAndWaitForResponse(Hik.Communication.Scs.Communication.Messages.IScsMessage,System.Int32)"> + <summary> + Sends a message and waits a response for that message. + </summary> + <remarks> + Response message is matched with RepliedMessageId property, so if + any other message (that is not reply for sent message) is received + from remote application, it is not considered as a reply and is not + returned as return value of this method. + + MessageReceived event is not raised for response messages. + </remarks> + <param name="message">message to send</param> + <param name="timeoutMilliseconds">Timeout duration as milliseconds.</param> + <returns>Response message</returns> + <exception cref="T:System.TimeoutException">Throws TimeoutException if can not receive reply message in timeout value</exception> + <exception cref="T:Hik.Communication.Scs.Communication.CommunicationException">Throws CommunicationException if communication fails before reply message.</exception> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.Messenger_MessageReceived(System.Object,Hik.Communication.Scs.Communication.Messages.MessageEventArgs)"> + <summary> + Handles MessageReceived event of Messenger object. + </summary> + <param name="sender">Source of event</param> + <param name="e">Event arguments</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.Messenger_MessageSent(System.Object,Hik.Communication.Scs.Communication.Messages.MessageEventArgs)"> + <summary> + Handles MessageSent event of Messenger object. + </summary> + <param name="sender">Source of event</param> + <param name="e">Event arguments</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.OnMessageReceived(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Raises MessageReceived event. + </summary> + <param name="message">Received message</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.OnMessageSent(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Raises MessageSent event. + </summary> + <param name="message">Received message</param> + </member> + <member name="E:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.MessageReceived"> + <summary> + This event is raised when a new message is received from underlying messenger. + </summary> + </member> + <member name="E:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.MessageSent"> + <summary> + This event is raised when a new message is sent without any error. + It does not guaranties that message is properly handled and processed by remote application. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.WireProtocol"> + <summary> + Gets/sets wire protocol that is used while reading and writing messages. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.LastReceivedMessageTime"> + <summary> + Gets the time of the last succesfully received message. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.LastSentMessageTime"> + <summary> + Gets the time of the last succesfully received message. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.Messenger"> + <summary> + Gets the underlying IMessenger object. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.Timeout"> + <summary> + Timeout value as milliseconds to wait for a receiving message on + SendMessageAndWaitForResponse and SendAndReceiveMessage methods. + Default value: 60000 (1 minute). + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.WaitingMessage"> + <summary> + This class is used to store messaging context for a request message + until response is received. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.WaitingMessage.#ctor"> + <summary> + Creates a new WaitingMessage object. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.WaitingMessage.ResponseMessage"> + <summary> + Response message for request message + (null if response is not received yet). + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.WaitingMessage.WaitEvent"> + <summary> + ManualResetEvent to block thread until response is received. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.WaitingMessage.State"> + <summary> + State of the request message. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.WaitingMessageStates"> + <summary> + This enum is used to store the state of a waiting message. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.WaitingMessageStates.WaitingForResponse"> + <summary> + Still waiting for response. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.WaitingMessageStates.Cancelled"> + <summary> + Message sending is cancelled. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger`1.WaitingMessageStates.ResponseReceived"> + <summary> + Response is properly received. + </summary> + </member> + <member name="T:Hik.Threading.Timer"> + <summary> + This class is a timer that performs some tasks periodically. + </summary> + </member> + <member name="F:Hik.Threading.Timer._taskTimer"> + <summary> + This timer is used to perfom the task at spesified intervals. + </summary> + </member> + <member name="F:Hik.Threading.Timer._running"> + <summary> + Indicates that whether timer is running or stopped. + </summary> + </member> + <member name="F:Hik.Threading.Timer._performingTasks"> + <summary> + Indicates that whether performing the task or _taskTimer is in sleep mode. + This field is used to wait executing tasks when stopping Timer. + </summary> + </member> + <member name="M:Hik.Threading.Timer.#ctor(System.Int32)"> + <summary> + Creates a new Timer. + </summary> + <param name="period">Task period of timer (as milliseconds)</param> + </member> + <member name="M:Hik.Threading.Timer.#ctor(System.Int32,System.Boolean)"> + <summary> + Creates a new Timer. + </summary> + <param name="period">Task period of timer (as milliseconds)</param> + <param name="runOnStart">Indicates whether timer raises Elapsed event on Start method of Timer for once</param> + </member> + <member name="M:Hik.Threading.Timer.Start"> + <summary> + Starts the timer. + </summary> + </member> + <member name="M:Hik.Threading.Timer.Stop"> + <summary> + Stops the timer. + </summary> + </member> + <member name="M:Hik.Threading.Timer.WaitToStop"> + <summary> + Waits the service to stop. + </summary> + </member> + <member name="M:Hik.Threading.Timer.TimerCallBack(System.Object)"> + <summary> + This method is called by _taskTimer. + </summary> + <param name="state">Not used argument</param> + </member> + <member name="E:Hik.Threading.Timer.Elapsed"> + <summary> + This event is raised periodically according to Period of Timer. + </summary> + </member> + <member name="P:Hik.Threading.Timer.Period"> + <summary> + Task period of timer (as milliseconds). + </summary> + </member> + <member name="P:Hik.Threading.Timer.RunOnStart"> + <summary> + Indicates whether timer raises Elapsed event on Start method of Timer for once. + Default: False. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.CommunicationStateException"> + <summary> + This application is thrown if communication is not expected state. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.CommunicationException"> + <summary> + This application is thrown in a communication error. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.CommunicationException.#ctor"> + <summary> + Contstructor. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.CommunicationException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)"> + <summary> + Contstructor for serializing. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.CommunicationException.#ctor(System.String)"> + <summary> + Contstructor. + </summary> + <param name="message">Exception message</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.CommunicationException.#ctor(System.String,System.Exception)"> + <summary> + Contstructor. + </summary> + <param name="message">Exception message</param> + <param name="innerException">Inner exception</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.CommunicationStateException.#ctor"> + <summary> + Contstructor. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.CommunicationStateException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)"> + <summary> + Contstructor for serializing. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.CommunicationStateException.#ctor(System.String)"> + <summary> + Contstructor. + </summary> + <param name="message">Exception message</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.CommunicationStateException.#ctor(System.String,System.Exception)"> + <summary> + Contstructor. + </summary> + <param name="message">Exception message</param> + <param name="innerException">Inner exception</param> + </member> + <member name="T:Hik.Communication.Scs.Server.ServerClientEventArgs"> + <summary> + Stores client information to be used by an event. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Server.ServerClientEventArgs.#ctor(Hik.Communication.Scs.Server.IScsServerClient)"> + <summary> + Creates a new ServerClientEventArgs object. + </summary> + <param name="client">Client that is associated with this event</param> + </member> + <member name="P:Hik.Communication.Scs.Server.ServerClientEventArgs.Client"> + <summary> + Client that is associated with this event. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Server.ScsServerClient"> + <summary> + This class represents a client in server side. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Server.IScsServerClient"> + <summary> + Represents a client from a perspective of a server. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Server.IScsServerClient.Disconnect"> + <summary> + Disconnects from server. + </summary> + </member> + <member name="E:Hik.Communication.Scs.Server.IScsServerClient.Disconnected"> + <summary> + This event is raised when client disconnected from server. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Server.IScsServerClient.ClientId"> + <summary> + Unique identifier for this client in server. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Server.IScsServerClient.RemoteEndPoint"> + <summary> + Gets endpoint of remote application. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Server.IScsServerClient.CommunicationState"> + <summary> + Gets the current communication state. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Server.ScsServerClient._communicationChannel"> + <summary> + The communication channel that is used by client to send and receive messages. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Server.ScsServerClient.#ctor(Hik.Communication.Scs.Communication.Channels.ICommunicationChannel)"> + <summary> + Creates a new ScsClient object. + </summary> + <param name="communicationChannel">The communication channel that is used by client to send and receive messages</param> + </member> + <member name="M:Hik.Communication.Scs.Server.ScsServerClient.Disconnect"> + <summary> + Disconnects from client and closes underlying communication channel. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Server.ScsServerClient.SendMessage(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Sends a message to the client. + </summary> + <param name="message">Message to be sent</param> + </member> + <member name="M:Hik.Communication.Scs.Server.ScsServerClient.CommunicationChannel_Disconnected(System.Object,System.EventArgs)"> + <summary> + Handles Disconnected event of _communicationChannel object. + </summary> + <param name="sender">Source of event</param> + <param name="e">Event arguments</param> + </member> + <member name="M:Hik.Communication.Scs.Server.ScsServerClient.CommunicationChannel_MessageReceived(System.Object,Hik.Communication.Scs.Communication.Messages.MessageEventArgs)"> + <summary> + Handles MessageReceived event of _communicationChannel object. + </summary> + <param name="sender">Source of event</param> + <param name="e">Event arguments</param> + </member> + <member name="M:Hik.Communication.Scs.Server.ScsServerClient.CommunicationChannel_MessageSent(System.Object,Hik.Communication.Scs.Communication.Messages.MessageEventArgs)"> + <summary> + Handles MessageSent event of _communicationChannel object. + </summary> + <param name="sender">Source of event</param> + <param name="e">Event arguments</param> + </member> + <member name="M:Hik.Communication.Scs.Server.ScsServerClient.OnDisconnected"> + <summary> + Raises Disconnected event. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Server.ScsServerClient.OnMessageReceived(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Raises MessageReceived event. + </summary> + <param name="message">Received message</param> + </member> + <member name="M:Hik.Communication.Scs.Server.ScsServerClient.OnMessageSent(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Raises MessageSent event. + </summary> + <param name="message">Received message</param> + </member> + <member name="E:Hik.Communication.Scs.Server.ScsServerClient.MessageReceived"> + <summary> + This event is raised when a new message is received. + </summary> + </member> + <member name="E:Hik.Communication.Scs.Server.ScsServerClient.MessageSent"> + <summary> + This event is raised when a new message is sent without any error. + It does not guaranties that message is properly handled and processed by remote application. + </summary> + </member> + <member name="E:Hik.Communication.Scs.Server.ScsServerClient.Disconnected"> + <summary> + This event is raised when client is disconnected from server. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Server.ScsServerClient.ClientId"> + <summary> + Unique identifier for this client in server. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Server.ScsServerClient.CommunicationState"> + <summary> + Gets the communication state of the Client. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Server.ScsServerClient.WireProtocol"> + <summary> + Gets/sets wire protocol that is used while reading and writing messages. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Server.ScsServerClient.RemoteEndPoint"> + <summary> + Gets endpoint of remote application. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Server.ScsServerClient.LastReceivedMessageTime"> + <summary> + Gets the time of the last succesfully received message. + </summary> + </member> + <member name="P:Hik.Communication.Scs.Server.ScsServerClient.LastSentMessageTime"> + <summary> + Gets the time of the last succesfully received message. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.Channels.Tcp.TcpConnectionListener"> + <summary> + This class is used to listen and accept incoming TCP + connection requests on a TCP port. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.Channels.ConnectionListenerBase"> + <summary> + This class provides base functionality for communication listener classes. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.ConnectionListenerBase.Start"> + <summary> + Starts listening incoming connections. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.ConnectionListenerBase.Stop"> + <summary> + Stops listening incoming connections. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.ConnectionListenerBase.OnCommunicationChannelConnected(Hik.Communication.Scs.Communication.Channels.ICommunicationChannel)"> + <summary> + Raises CommunicationChannelConnected event. + </summary> + <param name="client"></param> + </member> + <member name="E:Hik.Communication.Scs.Communication.Channels.ConnectionListenerBase.CommunicationChannelConnected"> + <summary> + This event is raised when a new communication channel is connected. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Channels.Tcp.TcpConnectionListener._endPoint"> + <summary> + The endpoint address of the server to listen incoming connections. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Channels.Tcp.TcpConnectionListener._listenerSocket"> + <summary> + Server socket to listen incoming connection requests. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Channels.Tcp.TcpConnectionListener._thread"> + <summary> + The thread to listen socket + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Channels.Tcp.TcpConnectionListener._running"> + <summary> + A flag to control thread's running + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.Tcp.TcpConnectionListener.#ctor(Hik.Communication.Scs.Communication.EndPoints.Tcp.ScsTcpEndPoint)"> + <summary> + Creates a new TcpConnectionListener for given endpoint. + </summary> + <param name="endPoint">The endpoint address of the server to listen incoming connections</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.Tcp.TcpConnectionListener.Start"> + <summary> + Starts listening incoming connections. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.Tcp.TcpConnectionListener.Stop"> + <summary> + Stops listening incoming connections. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.Tcp.TcpConnectionListener.StartSocket"> + <summary> + Starts listening socket. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.Tcp.TcpConnectionListener.StopSocket"> + <summary> + Stops listening socket. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Channels.Tcp.TcpConnectionListener.DoListenAsThread"> + <summary> + Entrance point of the thread. + This method is used by the thread to listen incoming requests. + </summary> + </member> + <member name="T:Hik.Communication.ScsServices.Service.ScsServiceApplication"> + <summary> + Implements IScsServiceApplication and provides all functionallity. + </summary> + </member> + <member name="T:Hik.Communication.ScsServices.Service.IScsServiceApplication"> + <summary> + Represents a SCS Service Application that is used to construct and manage a SCS service. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Service.IScsServiceApplication.Start"> + <summary> + Starts service application. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Service.IScsServiceApplication.Stop"> + <summary> + Stops service application. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Service.IScsServiceApplication.AddService``2(``1)"> + <summary> + Adds a service object to this service application. + Only single service object can be added for a service interface type. + </summary> + <typeparam name="TServiceInterface">Service interface type</typeparam> + <typeparam name="TServiceClass">Service class type. Must be delivered from ScsService and must implement TServiceInterface.</typeparam> + <param name="service">An instance of TServiceClass.</param> + </member> + <member name="M:Hik.Communication.ScsServices.Service.IScsServiceApplication.RemoveService``1"> + <summary> + Removes a previously added service object from this service application. + It removes object according to interface type. + </summary> + <typeparam name="TServiceInterface">Service interface type</typeparam> + <returns>True: removed. False: no service object with this interface</returns> + </member> + <member name="E:Hik.Communication.ScsServices.Service.IScsServiceApplication.ClientConnected"> + <summary> + This event is raised when a new client connected to the service. + </summary> + </member> + <member name="E:Hik.Communication.ScsServices.Service.IScsServiceApplication.ClientDisconnected"> + <summary> + This event is raised when a client disconnected from the service. + </summary> + </member> + <member name="F:Hik.Communication.ScsServices.Service.ScsServiceApplication._scsServer"> + <summary> + Underlying IScsServer object to accept and manage client connections. + </summary> + </member> + <member name="F:Hik.Communication.ScsServices.Service.ScsServiceApplication._serviceObjects"> + <summary> + User service objects that is used to invoke incoming method invocation requests. + Key: Service interface type's name. + Value: Service object. + </summary> + </member> + <member name="F:Hik.Communication.ScsServices.Service.ScsServiceApplication._serviceClients"> + <summary> + All connected clients to service. + Key: Client's unique Id. + Value: Reference to the client. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceApplication.#ctor(Hik.Communication.Scs.Server.IScsServer)"> + <summary> + Creates a new ScsServiceApplication object. + </summary> + <param name="scsServer">Underlying IScsServer object to accept and manage client connections</param> + <exception cref="T:System.ArgumentNullException">Throws ArgumentNullException if scsServer argument is null</exception> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceApplication.Start"> + <summary> + Starts service application. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceApplication.Stop"> + <summary> + Stops service application. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceApplication.AddService``2(``1)"> + <summary> + Adds a service object to this service application. + Only single service object can be added for a service interface type. + </summary> + <typeparam name="TServiceInterface">Service interface type</typeparam> + <typeparam name="TServiceClass">Service class type. Must be delivered from ScsService and must implement TServiceInterface.</typeparam> + <param name="service">An instance of TServiceClass.</param> + <exception cref="T:System.ArgumentNullException">Throws ArgumentNullException if service argument is null</exception> + <exception cref="T:System.Exception">Throws Exception if service is already added before</exception> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceApplication.RemoveService``1"> + <summary> + Removes a previously added service object from this service application. + It removes object according to interface type. + </summary> + <typeparam name="TServiceInterface">Service interface type</typeparam> + <returns>True: removed. False: no service object with this interface</returns> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceApplication.ScsServer_ClientConnected(System.Object,Hik.Communication.Scs.Server.ServerClientEventArgs)"> + <summary> + Handles ClientConnected event of _scsServer object. + </summary> + <param name="sender">Source of event</param> + <param name="e">Event arguments</param> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceApplication.ScsServer_ClientDisconnected(System.Object,Hik.Communication.Scs.Server.ServerClientEventArgs)"> + <summary> + Handles ClientDisconnected event of _scsServer object. + </summary> + <param name="sender">Source of event</param> + <param name="e">Event arguments</param> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceApplication.Client_MessageReceived(System.Object,Hik.Communication.Scs.Communication.Messages.MessageEventArgs)"> + <summary> + Handles MessageReceived events of all clients, evaluates each message, + finds appropriate service object and invokes appropriate method. + </summary> + <param name="sender">Source of event</param> + <param name="e">Event arguments</param> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceApplication.SendInvokeResponse(Hik.Communication.Scs.Communication.Messengers.IMessenger,Hik.Communication.Scs.Communication.Messages.IScsMessage,System.Object,Hik.Communication.ScsServices.Communication.Messages.ScsRemoteException)"> + <summary> + Sends response to the remote application that invoked a service method. + </summary> + <param name="client">Client that sent invoke message</param> + <param name="requestMessage">Request message</param> + <param name="returnValue">Return value to send</param> + <param name="exception">Exception to send</param> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceApplication.OnClientConnected(Hik.Communication.ScsServices.Service.IScsServiceClient)"> + <summary> + Raises ClientConnected event. + </summary> + <param name="client"></param> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceApplication.OnClientDisconnected(Hik.Communication.ScsServices.Service.IScsServiceClient)"> + <summary> + Raises ClientDisconnected event. + </summary> + <param name="client"></param> + </member> + <member name="E:Hik.Communication.ScsServices.Service.ScsServiceApplication.ClientConnected"> + <summary> + This event is raised when a new client connected to the service. + </summary> + </member> + <member name="E:Hik.Communication.ScsServices.Service.ScsServiceApplication.ClientDisconnected"> + <summary> + This event is raised when a client disconnected from the service. + </summary> + </member> + <member name="T:Hik.Communication.ScsServices.Service.ScsServiceApplication.ServiceObject"> + <summary> + Represents a user service object. + It is used to invoke methods on a ScsService object. + </summary> + </member> + <member name="F:Hik.Communication.ScsServices.Service.ScsServiceApplication.ServiceObject._methods"> + <summary> + This collection stores a list of all methods of service object. + Key: Method name + Value: Informations about method. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceApplication.ServiceObject.#ctor(System.Type,Hik.Communication.ScsServices.Service.ScsService)"> + <summary> + Creates a new ServiceObject. + </summary> + <param name="serviceInterfaceType">Type of service interface</param> + <param name="service">The service object that is used to invoke methods on</param> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceApplication.ServiceObject.InvokeMethod(System.String,System.Object[])"> + <summary> + Invokes a method of Service object. + </summary> + <param name="methodName">Name of the method to invoke</param> + <param name="parameters">Parameters of method</param> + <returns>Return value of method</returns> + </member> + <member name="P:Hik.Communication.ScsServices.Service.ScsServiceApplication.ServiceObject.Service"> + <summary> + The service object that is used to invoke methods on. + </summary> + </member> + <member name="P:Hik.Communication.ScsServices.Service.ScsServiceApplication.ServiceObject.ServiceAttribute"> + <summary> + ScsService attribute of Service object's class. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.CommunicationStates"> + <summary> + Communication states. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.CommunicationStates.Connected"> + <summary> + Connected. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.CommunicationStates.Disconnected"> + <summary> + Disconnected. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.Messengers.SynchronizedMessenger`1"> + <summary> + This class is a wrapper for IMessenger and is used + to synchronize message receiving operation. + It extends RequestReplyMessenger. + It is suitable to use in applications those want to receive + messages by synchronized method calls instead of asynchronous + MessageReceived event. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Messengers.SynchronizedMessenger`1._receivingMessageQueue"> + <summary> + A queue that is used to store receiving messages until Receive(...) + method is called to get them. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Messengers.SynchronizedMessenger`1._receiveWaiter"> + <summary> + This object is used to synchronize/wait threads. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Communication.Messengers.SynchronizedMessenger`1._running"> + <summary> + This boolean value indicates the running state of this class. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.SynchronizedMessenger`1.#ctor(`0)"> + <summary> + Creates a new SynchronizedMessenger object. + </summary> + <param name="messenger">A IMessenger object to be used to send/receive messages</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.SynchronizedMessenger`1.#ctor(`0,System.Int32)"> + <summary> + Creates a new SynchronizedMessenger object. + </summary> + <param name="messenger">A IMessenger object to be used to send/receive messages</param> + <param name="incomingMessageQueueCapacity">capacity of the incoming message queue</param> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.SynchronizedMessenger`1.Start"> + <summary> + Starts the messenger. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.SynchronizedMessenger`1.Stop"> + <summary> + Stops the messenger. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.SynchronizedMessenger`1.ReceiveMessage"> + <summary> + This method is used to receive a message from remote application. + It waits until a message is received. + </summary> + <returns>Received message</returns> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.SynchronizedMessenger`1.ReceiveMessage(System.Int32)"> + <summary> + This method is used to receive a message from remote application. + It waits until a message is received or timeout occurs. + </summary> + <param name="timeout"> + Timeout value to wait if no message is received. + Use -1 to wait indefinitely. + </param> + <returns>Received message</returns> + <exception cref="T:System.TimeoutException">Throws TimeoutException if timeout occurs</exception> + <exception cref="T:System.Exception">Throws Exception if SynchronizedMessenger stops before a message is received</exception> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.SynchronizedMessenger`1.ReceiveMessage``1"> + <summary> + This method is used to receive a specific type of message from remote application. + It waits until a message is received. + </summary> + <returns>Received message</returns> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.SynchronizedMessenger`1.ReceiveMessage``1(System.Int32)"> + <summary> + This method is used to receive a specific type of message from remote application. + It waits until a message is received or timeout occurs. + </summary> + <param name="timeout"> + Timeout value to wait if no message is received. + Use -1 to wait indefinitely. + </param> + <returns>Received message</returns> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messengers.SynchronizedMessenger`1.OnMessageReceived(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Overrides + </summary> + <param name="message"></param> + </member> + <member name="P:Hik.Communication.Scs.Communication.Messengers.SynchronizedMessenger`1.IncomingMessageQueueCapacity"> + <summary> + Gets/sets capacity of the incoming message queue. + No message is received from remote application if + number of messages in internal queue exceeds this value. + Default value: int.MaxValue (2147483647). + </summary> + </member> + <member name="T:Hik.Communication.Scs.Communication.Messages.MessageEventArgs"> + <summary> + Stores message to be used by an event. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Messages.MessageEventArgs.#ctor(Hik.Communication.Scs.Communication.Messages.IScsMessage)"> + <summary> + Creates a new MessageEventArgs object. + </summary> + <param name="message">Message object that is associated with this event</param> + </member> + <member name="P:Hik.Communication.Scs.Communication.Messages.MessageEventArgs.Message"> + <summary> + Message object that is associated with this event. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Client.ClientReConnecter"> + <summary> + This class is used to automatically re-connect to server if disconnected. + It attempts to reconnect to server periodically until connection established. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Client.ClientReConnecter._client"> + <summary> + Reference to client object. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Client.ClientReConnecter._reconnectTimer"> + <summary> + Timer to attempt ro reconnect periodically. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Client.ClientReConnecter._disposed"> + <summary> + Indicates the dispose state of this object. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Client.ClientReConnecter.#ctor(Hik.Communication.Scs.Client.IConnectableClient)"> + <summary> + Creates a new ClientReConnecter object. + It is not needed to start ClientReConnecter since it automatically + starts when the client disconnected. + </summary> + <param name="client">Reference to client object</param> + <exception cref="T:System.ArgumentNullException">Throws ArgumentNullException if client is null.</exception> + </member> + <member name="M:Hik.Communication.Scs.Client.ClientReConnecter.Dispose"> + <summary> + Disposes this object. + Does nothing if already disposed. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Client.ClientReConnecter.Client_Disconnected(System.Object,System.EventArgs)"> + <summary> + Handles Disconnected event of _client object. + </summary> + <param name="sender">Source of the event</param> + <param name="e">Event arguments</param> + </member> + <member name="M:Hik.Communication.Scs.Client.ClientReConnecter.ReconnectTimer_Elapsed(System.Object,System.EventArgs)"> + <summary> + Hadles Elapsed event of _reconnectTimer. + </summary> + <param name="sender">Source of the event</param> + <param name="e">Event arguments</param> + </member> + <member name="P:Hik.Communication.Scs.Client.ClientReConnecter.ReConnectCheckPeriod"> + <summary> + Reconnect check period. + Default: 20 seconds. + </summary> + </member> + <member name="T:Hik.Communication.ScsServices.Service.ScsServiceClientFactory"> + <summary> + This class is used to create service client objects that is used in server-side. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Service.ScsServiceClientFactory.CreateServiceClient(Hik.Communication.Scs.Server.IScsServerClient,Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger{Hik.Communication.Scs.Server.IScsServerClient})"> + <summary> + Creates a new service client object that is used in server-side. + </summary> + <param name="serverClient">Underlying server client object</param> + <param name="requestReplyMessenger">RequestReplyMessenger object to send/receive messages over serverClient</param> + <returns></returns> + </member> + <member name="T:Hik.Communication.Scs.Server.ScsServerFactory"> + <summary> + This class is used to create SCS servers. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Server.ScsServerFactory.CreateServer(Hik.Communication.Scs.Communication.EndPoints.ScsEndPoint)"> + <summary> + Creates a new SCS Server using an EndPoint. + </summary> + <param name="endPoint">Endpoint that represents address of the server</param> + <returns>Created TCP server</returns> + </member> + <member name="T:Hik.Communication.ScsServices.Client.ScsServiceClientBuilder"> + <summary> + This class is used to build service clients to remotely invoke methods of a SCS service. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Client.ScsServiceClientBuilder.CreateClient``1(Hik.Communication.Scs.Communication.EndPoints.ScsEndPoint,System.Object)"> + <summary> + Creates a client to connect to a SCS service. + </summary> + <typeparam name="T">Type of service interface for remote method call</typeparam> + <param name="endpoint">EndPoint of the server</param> + <param name="clientObject">Client-side object that handles remote method calls from server to client. + May be null if client has no methods to be invoked by server</param> + <returns>Created client object to connect to the server</returns> + </member> + <member name="M:Hik.Communication.ScsServices.Client.ScsServiceClientBuilder.CreateClient``1(System.String,System.Object)"> + <summary> + Creates a client to connect to a SCS service. + </summary> + <typeparam name="T">Type of service interface for remote method call</typeparam> + <param name="endpointAddress">EndPoint address of the server</param> + <param name="clientObject">Client-side object that handles remote method calls from server to client. + May be null if client has no methods to be invoked by server</param> + <returns>Created client object to connect to the server</returns> + </member> + <member name="T:Hik.Threading.SequentialItemProcessor`1"> + <summary> + This class is used to process items sequentially in a multithreaded manner. + </summary> + <typeparam name="TItem">Type of item to process</typeparam> + </member> + <member name="F:Hik.Threading.SequentialItemProcessor`1._processMethod"> + <summary> + The method delegate that is called to actually process items. + </summary> + </member> + <member name="F:Hik.Threading.SequentialItemProcessor`1._queue"> + <summary> + Item queue. Used to process items sequentially. + </summary> + </member> + <member name="F:Hik.Threading.SequentialItemProcessor`1._currentProcessTask"> + <summary> + A reference to the current Task that is processing an item in + ProcessItem method. + </summary> + </member> + <member name="F:Hik.Threading.SequentialItemProcessor`1._isProcessing"> + <summary> + Indicates state of the item processing. + </summary> + </member> + <member name="F:Hik.Threading.SequentialItemProcessor`1._isRunning"> + <summary> + A boolean value to control running of SequentialItemProcessor. + </summary> + </member> + <member name="F:Hik.Threading.SequentialItemProcessor`1._syncObj"> + <summary> + An object to synchronize threads. + </summary> + </member> + <member name="M:Hik.Threading.SequentialItemProcessor`1.#ctor(System.Action{`0})"> + <summary> + Creates a new SequentialItemProcessor object. + </summary> + <param name="processMethod">The method delegate that is called to actually process items</param> + </member> + <member name="M:Hik.Threading.SequentialItemProcessor`1.EnqueueMessage(`0)"> + <summary> + Adds an item to queue to process the item. + </summary> + <param name="item">Item to add to the queue</param> + </member> + <member name="M:Hik.Threading.SequentialItemProcessor`1.Start"> + <summary> + Starts processing of items. + </summary> + </member> + <member name="M:Hik.Threading.SequentialItemProcessor`1.Stop"> + <summary> + Stops processing of items and waits stopping of current item. + </summary> + </member> + <member name="M:Hik.Threading.SequentialItemProcessor`1.ProcessItem"> + <summary> + This method runs on a new seperated Task (thread) to process + items on the queue. + </summary> + </member> + <member name="T:Hik.Communication.Scs.Server.Tcp.ScsTcpServer"> + <summary> + This class is used to create a TCP server. + </summary> + </member> + <member name="F:Hik.Communication.Scs.Server.Tcp.ScsTcpServer._endPoint"> + <summary> + The endpoint address of the server to listen incoming connections. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Server.Tcp.ScsTcpServer.#ctor(Hik.Communication.Scs.Communication.EndPoints.Tcp.ScsTcpEndPoint)"> + <summary> + Creates a new ScsTcpServer object. + </summary> + <param name="endPoint">The endpoint address of the server to listen incoming connections</param> + </member> + <member name="M:Hik.Communication.Scs.Server.Tcp.ScsTcpServer.CreateConnectionListener"> + <summary> + Creates a TCP connection listener. + </summary> + <returns>Created listener object</returns> + </member> + <member name="T:Hik.Communication.Scs.Communication.Protocols.WireProtocolManager"> + <summary> + This class is used to get default protocols. + </summary> + </member> + <member name="M:Hik.Communication.Scs.Communication.Protocols.WireProtocolManager.GetDefaultWireProtocolFactory"> + <summary> + Creates a default wire protocol factory object to be used on communicating of applications. + </summary> + <returns>A new instance of default wire protocol</returns> + </member> + <member name="M:Hik.Communication.Scs.Communication.Protocols.WireProtocolManager.GetDefaultWireProtocol"> + <summary> + Creates a default wire protocol object to be used on communicating of applications. + </summary> + <returns>A new instance of default wire protocol</returns> + </member> + <member name="T:Hik.Communication.ScsServices.Communication.Messages.ScsRemoteInvokeReturnMessage"> + <summary> + This message is sent as response message to a ScsRemoteInvokeMessage. + It is used to send return value of method invocation. + </summary> + </member> + <member name="M:Hik.Communication.ScsServices.Communication.Messages.ScsRemoteInvokeReturnMessage.ToString"> + <summary> + Represents this object as string. + </summary> + <returns>String representation of this object</returns> + </member> + <member name="P:Hik.Communication.ScsServices.Communication.Messages.ScsRemoteInvokeReturnMessage.ReturnValue"> + <summary> + Return value of remote method invocation. + </summary> + </member> + <member name="P:Hik.Communication.ScsServices.Communication.Messages.ScsRemoteInvokeReturnMessage.RemoteException"> + <summary> + If any exception occured during method invocation, this field contains Exception object. + If no exception occured, this field is null. + </summary> + </member> + </members> +</doc> diff --git a/binaries/Scs.dll b/binaries/Scs.dll Binary files differnew file mode 100644 index 0000000..f3f6855 --- /dev/null +++ b/binaries/Scs.dll diff --git a/performance-tests/Messaging/ClientApp/ClientApp.csproj b/performance-tests/Messaging/ClientApp/ClientApp.csproj new file mode 100644 index 0000000..f34a440 --- /dev/null +++ b/performance-tests/Messaging/ClientApp/ClientApp.csproj @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>ClientApp</RootNamespace> + <AssemblyName>ClientApp</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="DuplexClientCustomProtocolSynchronized.cs" /> + <Compile Include="DuplexClientDefaultProtocolSynchronized.cs" /> + <Compile Include="DuplexClientDefaultProtocol.cs" /> + <Compile Include="OneWayClientDefaultProtocol.cs" /> + <Compile Include="DuplexClientCustomProtocol.cs" /> + <Compile Include="OneWayClientCustomProtocol.cs" /> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\CommonLib\CommonLib.csproj"> + <Project>{7F7D3248-4432-4E7B-9CFD-25982668AD5B}</Project> + <Name>CommonLib</Name> + </ProjectReference> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/performance-tests/Messaging/ClientApp/DuplexClientCustomProtocol.cs b/performance-tests/Messaging/ClientApp/DuplexClientCustomProtocol.cs new file mode 100644 index 0000000..016e6c6 --- /dev/null +++ b/performance-tests/Messaging/ClientApp/DuplexClientCustomProtocol.cs @@ -0,0 +1,52 @@ +using System; +using System.Diagnostics; +using CommonLib; +using Hik.Communication.Scs.Client; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.Scs.Communication.Messages; + +namespace ClientApp +{ + class DuplexClientCustomProtocol + { + private static int _messageCount; + private static Stopwatch _stopwatch; + + public static void Run() + { + Console.WriteLine("Press enter to connect to server and send " + Consts.MessageCount + " messages."); + Console.ReadLine(); + + using (var client = ScsClientFactory.CreateClient(new ScsTcpEndPoint("127.0.0.1", 10033))) + { + client.WireProtocol = new MyWireProtocol(); //Set custom wire protocol! + client.MessageReceived += client_MessageReceived; + + client.Connect(); + + for (var i = 0; i < Consts.MessageCount; i++) + { + client.SendMessage(new ScsTextMessage("Hello from client!")); + } + + Console.WriteLine("Press enter to disconnect from server"); + Console.ReadLine(); + } + } + + static void client_MessageReceived(object sender, MessageEventArgs e) + { + ++_messageCount; + + if (_messageCount == 1) + { + _stopwatch = Stopwatch.StartNew(); + } + else if (_messageCount == Consts.MessageCount) + { + _stopwatch.Stop(); + Console.WriteLine(Consts.MessageCount + " message is received in " + _stopwatch.Elapsed.TotalMilliseconds.ToString("0.000") + " ms."); + } + } + } +} diff --git a/performance-tests/Messaging/ClientApp/DuplexClientCustomProtocolSynchronized.cs b/performance-tests/Messaging/ClientApp/DuplexClientCustomProtocolSynchronized.cs new file mode 100644 index 0000000..007fd63 --- /dev/null +++ b/performance-tests/Messaging/ClientApp/DuplexClientCustomProtocolSynchronized.cs @@ -0,0 +1,37 @@ +using System; +using CommonLib; +using Hik.Communication.Scs.Client; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.Scs.Communication.Messages; +using Hik.Communication.Scs.Communication.Messengers; + +namespace ClientApp +{ + class DuplexClientCustomProtocolSynchronized + { + public static void Run() + { + Console.WriteLine("Press enter to connect to server and send " + Consts.MessageCount + " messages."); + Console.ReadLine(); + + using (var client = ScsClientFactory.CreateClient(new ScsTcpEndPoint("127.0.0.1", 10033))) + { + client.WireProtocol = new MyWireProtocol(); + using (var synchronizedMessenger = new SynchronizedMessenger<IScsClient>(client)) + { + synchronizedMessenger.Start(); + client.Connect(); + + for (var i = 0; i < Consts.MessageCount; i++) + { + synchronizedMessenger.SendMessage(new ScsTextMessage("Hello from client!")); + var reply = synchronizedMessenger.ReceiveMessage<ScsTextMessage>(); + } + } + + Console.WriteLine("Press enter to disconnect from server"); + Console.ReadLine(); + } + } + } +} diff --git a/performance-tests/Messaging/ClientApp/DuplexClientDefaultProtocol.cs b/performance-tests/Messaging/ClientApp/DuplexClientDefaultProtocol.cs new file mode 100644 index 0000000..13a6e40 --- /dev/null +++ b/performance-tests/Messaging/ClientApp/DuplexClientDefaultProtocol.cs @@ -0,0 +1,51 @@ +using System; +using System.Diagnostics; +using CommonLib; +using Hik.Communication.Scs.Client; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.Scs.Communication.Messages; + +namespace ClientApp +{ + class DuplexClientDefaultProtocol + { + private static int _messageCount; + private static Stopwatch _stopwatch; + + public static void Run() + { + Console.WriteLine("Press enter to connect to server and send " + Consts.MessageCount + " messages."); + Console.ReadLine(); + + using (var client = ScsClientFactory.CreateClient(new ScsTcpEndPoint("127.0.0.1", 10033))) + { + client.MessageReceived += client_MessageReceived; + + client.Connect(); + + for (var i = 0; i < Consts.MessageCount; i++) + { + client.SendMessage(new ScsTextMessage("Hello from client!")); + } + + Console.WriteLine("Press enter to disconnect from server"); + Console.ReadLine(); + } + } + + static void client_MessageReceived(object sender, MessageEventArgs e) + { + ++_messageCount; + + if (_messageCount == 1) + { + _stopwatch = Stopwatch.StartNew(); + } + else if (_messageCount == Consts.MessageCount) + { + _stopwatch.Stop(); + Console.WriteLine(Consts.MessageCount + " message is received in " + _stopwatch.Elapsed.TotalMilliseconds.ToString("0.000") + " ms."); + } + } + } +} diff --git a/performance-tests/Messaging/ClientApp/DuplexClientDefaultProtocolSynchronized.cs b/performance-tests/Messaging/ClientApp/DuplexClientDefaultProtocolSynchronized.cs new file mode 100644 index 0000000..33d46ba --- /dev/null +++ b/performance-tests/Messaging/ClientApp/DuplexClientDefaultProtocolSynchronized.cs @@ -0,0 +1,36 @@ +using System; +using CommonLib; +using Hik.Communication.Scs.Client; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.Scs.Communication.Messages; +using Hik.Communication.Scs.Communication.Messengers; + +namespace ClientApp +{ + class DuplexClientDefaultProtocolSynchronized + { + public static void Run() + { + Console.WriteLine("Press enter to connect to server and send " + Consts.MessageCount + " messages."); + Console.ReadLine(); + + using (var client = ScsClientFactory.CreateClient(new ScsTcpEndPoint("127.0.0.1", 10033))) + { + using (var synchronizedMessenger = new SynchronizedMessenger<IScsClient>(client)) + { + synchronizedMessenger.Start(); + client.Connect(); + + for (var i = 0; i < Consts.MessageCount; i++) + { + synchronizedMessenger.SendMessage(new ScsTextMessage("Hello from client!")); + var reply = synchronizedMessenger.ReceiveMessage<ScsTextMessage>(); + } + } + + Console.WriteLine("Press enter to disconnect from server"); + Console.ReadLine(); + } + } + } +} diff --git a/performance-tests/Messaging/ClientApp/OneWayClientCustomProtocol.cs b/performance-tests/Messaging/ClientApp/OneWayClientCustomProtocol.cs new file mode 100644 index 0000000..2d83559 --- /dev/null +++ b/performance-tests/Messaging/ClientApp/OneWayClientCustomProtocol.cs @@ -0,0 +1,32 @@ +using System; +using CommonLib; +using Hik.Communication.Scs.Client; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.Scs.Communication.Messages; + +namespace ClientApp +{ + class OneWayClientCustomProtocol + { + public static void Run() + { + Console.WriteLine("Press enter to connect to server and send " + Consts.MessageCount + " messages."); + Console.ReadLine(); + + using (var client = ScsClientFactory.CreateClient(new ScsTcpEndPoint("127.0.0.1", 10033))) + { + client.WireProtocol = new MyWireProtocol(); + + client.Connect(); + + for (var i = 0; i < Consts.MessageCount; i++) + { + client.SendMessage(new ScsTextMessage("Hello from client!")); + } + + Console.WriteLine("Press enter to disconnect from server"); + Console.ReadLine(); + } + } + } +} diff --git a/performance-tests/Messaging/ClientApp/OneWayClientDefaultProtocol.cs b/performance-tests/Messaging/ClientApp/OneWayClientDefaultProtocol.cs new file mode 100644 index 0000000..3d7ce3b --- /dev/null +++ b/performance-tests/Messaging/ClientApp/OneWayClientDefaultProtocol.cs @@ -0,0 +1,30 @@ +using System; +using CommonLib; +using Hik.Communication.Scs.Client; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.Scs.Communication.Messages; + +namespace ClientApp +{ + class OneWayClientDefaultProtocol + { + public static void Run() + { + Console.WriteLine("Press enter to connect to server and send " + Consts.MessageCount + " messages."); + Console.ReadLine(); + + using (var client = ScsClientFactory.CreateClient(new ScsTcpEndPoint("127.0.0.1", 10033))) + { + client.Connect(); + + for (var i = 0; i < Consts.MessageCount; i++) + { + client.SendMessage(new ScsTextMessage("Hello from client!")); + } + + Console.WriteLine("Press enter to disconnect from server"); + Console.ReadLine(); + } + } + } +} diff --git a/performance-tests/Messaging/ClientApp/Program.cs b/performance-tests/Messaging/ClientApp/Program.cs new file mode 100644 index 0000000..cee869d --- /dev/null +++ b/performance-tests/Messaging/ClientApp/Program.cs @@ -0,0 +1,10 @@ +namespace ClientApp +{ + class Program + { + static void Main() + { + DuplexClientCustomProtocolSynchronized.Run(); + } + } +} diff --git a/performance-tests/Messaging/ClientApp/Properties/AssemblyInfo.cs b/performance-tests/Messaging/ClientApp/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..7b4eed4 --- /dev/null +++ b/performance-tests/Messaging/ClientApp/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ClientApp")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("ClientApp")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a9dbae74-bd80-4551-9ca8-bc212ea55174")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/performance-tests/Messaging/CommonLib/CommonLib.csproj b/performance-tests/Messaging/CommonLib/CommonLib.csproj new file mode 100644 index 0000000..7020b77 --- /dev/null +++ b/performance-tests/Messaging/CommonLib/CommonLib.csproj @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{7F7D3248-4432-4E7B-9CFD-25982668AD5B}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>CommonLib</RootNamespace> + <AssemblyName>CommonLib</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Consts.cs" /> + <Compile Include="MyWireProtocol.cs" /> + <Compile Include="MyWireProtocolFactory.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/performance-tests/Messaging/CommonLib/Consts.cs b/performance-tests/Messaging/CommonLib/Consts.cs new file mode 100644 index 0000000..8eb31cf --- /dev/null +++ b/performance-tests/Messaging/CommonLib/Consts.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace CommonLib +{ + public class Consts + { + public const int MessageCount = 1000000; + } +} diff --git a/performance-tests/Messaging/CommonLib/MyWireProtocol.cs b/performance-tests/Messaging/CommonLib/MyWireProtocol.cs new file mode 100644 index 0000000..11227f4 --- /dev/null +++ b/performance-tests/Messaging/CommonLib/MyWireProtocol.cs @@ -0,0 +1,32 @@ +using System.Text; +using Hik.Communication.Scs.Communication.Messages; +using Hik.Communication.Scs.Communication.Protocols.BinarySerialization; + +namespace CommonLib +{ + /// <summary> + /// This class is a sample custom wire protocol to use as wire protocol in SCS framework. + /// It extends BinarySerializationProtocol. + /// It is used just to send/receive ScsTextMessage messages. + /// + /// Since BinarySerializationProtocol automatically writes message length to the beggining + /// of the message, a message format of this class is: + /// + /// [Message length (4 bytes)][UTF-8 encoded text (N bytes)] + /// + /// So, total length of the message = (N + 4) bytes; + /// </summary> + public class MyWireProtocol : BinarySerializationProtocol + { + protected override byte[] SerializeMessage(IScsMessage message) + { + return Encoding.UTF8.GetBytes(((ScsTextMessage)message).Text); + } + + protected override IScsMessage DeserializeMessage(byte[] bytes) + { + //Decode UTF8 encoded text and create a ScsTextMessage object + return new ScsTextMessage(Encoding.UTF8.GetString(bytes)); + } + } +} diff --git a/performance-tests/Messaging/CommonLib/MyWireProtocolFactory.cs b/performance-tests/Messaging/CommonLib/MyWireProtocolFactory.cs new file mode 100644 index 0000000..7f5f1ae --- /dev/null +++ b/performance-tests/Messaging/CommonLib/MyWireProtocolFactory.cs @@ -0,0 +1,12 @@ +using Hik.Communication.Scs.Communication.Protocols; + +namespace CommonLib +{ + public class MyWireProtocolFactory : IScsWireProtocolFactory + { + public IScsWireProtocol CreateWireProtocol() + { + return new MyWireProtocol(); + } + } +} diff --git a/performance-tests/Messaging/CommonLib/Properties/AssemblyInfo.cs b/performance-tests/Messaging/CommonLib/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..8461698 --- /dev/null +++ b/performance-tests/Messaging/CommonLib/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CommonLib")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("CommonLib")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("50d012ed-8149-4bfb-8cb4-0f325628bdf7")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/performance-tests/Messaging/ServerApp.sln b/performance-tests/Messaging/ServerApp.sln new file mode 100644 index 0000000..10eed7d --- /dev/null +++ b/performance-tests/Messaging/ServerApp.sln @@ -0,0 +1,54 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServerApp", "ServerApp\ServerApp.csproj", "{F515CE95-6A3F-4E5E-867A-899FFFC90D43}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClientApp", "ClientApp\ClientApp.csproj", "{8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonLib", "CommonLib\CommonLib.csproj", "{7F7D3248-4432-4E7B-9CFD-25982668AD5B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Debug|Any CPU.ActiveCfg = Debug|x86 + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Debug|x86.ActiveCfg = Debug|x86 + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Debug|x86.Build.0 = Debug|x86 + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Release|Any CPU.ActiveCfg = Release|x86 + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Release|Mixed Platforms.Build.0 = Release|x86 + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Release|x86.ActiveCfg = Release|x86 + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Release|x86.Build.0 = Release|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Debug|Any CPU.ActiveCfg = Debug|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Debug|x86.ActiveCfg = Debug|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Debug|x86.Build.0 = Debug|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Release|Any CPU.ActiveCfg = Release|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Release|Mixed Platforms.Build.0 = Release|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Release|x86.ActiveCfg = Release|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Release|x86.Build.0 = Release|x86 + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Debug|x86.ActiveCfg = Debug|Any CPU + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Release|Any CPU.Build.0 = Release|Any CPU + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Release|x86.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/performance-tests/Messaging/ServerApp/DuplexServerCustomProtocol.cs b/performance-tests/Messaging/ServerApp/DuplexServerCustomProtocol.cs new file mode 100644 index 0000000..88eafd9 --- /dev/null +++ b/performance-tests/Messaging/ServerApp/DuplexServerCustomProtocol.cs @@ -0,0 +1,53 @@ +using System; +using System.Diagnostics; +using CommonLib; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.Scs.Communication.Messages; +using Hik.Communication.Scs.Server; + +namespace ServerApp +{ + public class DuplexServerCustomProtocol + { + private static int _messageCount; + private static Stopwatch _stopwatch; + + public static void Run() + { + var server = ScsServerFactory.CreateServer(new ScsTcpEndPoint(10033)); + + server.WireProtocolFactory = new MyWireProtocolFactory(); + server.ClientConnected += server_ClientConnected; + + server.Start(); + + Console.WriteLine("Press enter to stop server"); + Console.ReadLine(); + + server.Stop(); + } + + static void server_ClientConnected(object sender, ServerClientEventArgs e) + { + e.Client.MessageReceived += Client_MessageReceived; + } + + static void Client_MessageReceived(object sender, MessageEventArgs e) + { + ++_messageCount; + + var client = (IScsServerClient) sender; + client.SendMessage(new ScsTextMessage("Hello from server!")); + + if (_messageCount == 1) + { + _stopwatch = Stopwatch.StartNew(); + } + else if (_messageCount == Consts.MessageCount) + { + _stopwatch.Stop(); + Console.WriteLine(Consts.MessageCount + " message is received in " + _stopwatch.Elapsed.TotalMilliseconds.ToString("0.000") + " ms."); + } + } + } +} diff --git a/performance-tests/Messaging/ServerApp/DuplexServerDefaultProtocol.cs b/performance-tests/Messaging/ServerApp/DuplexServerDefaultProtocol.cs new file mode 100644 index 0000000..8fbce3f --- /dev/null +++ b/performance-tests/Messaging/ServerApp/DuplexServerDefaultProtocol.cs @@ -0,0 +1,51 @@ +using System; +using System.Diagnostics; +using CommonLib; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.Scs.Communication.Messages; +using Hik.Communication.Scs.Server; + +namespace ServerApp +{ + public class DuplexServerDefaultProtocol + { + private static int _messageCount; + private static Stopwatch _stopwatch; + + public static void Run() + { + var server = ScsServerFactory.CreateServer(new ScsTcpEndPoint(10033)); + server.ClientConnected += server_ClientConnected; + + server.Start(); + + Console.WriteLine("Press enter to stop server"); + Console.ReadLine(); + + server.Stop(); + } + + static void server_ClientConnected(object sender, ServerClientEventArgs e) + { + e.Client.MessageReceived += Client_MessageReceived; + } + + static void Client_MessageReceived(object sender, MessageEventArgs e) + { + ++_messageCount; + + var client = (IScsServerClient) sender; + client.SendMessage(new ScsTextMessage("Hello from server!")); + + if (_messageCount == 1) + { + _stopwatch = Stopwatch.StartNew(); + } + else if (_messageCount == Consts.MessageCount) + { + _stopwatch.Stop(); + Console.WriteLine(Consts.MessageCount + " message is received in " + _stopwatch.Elapsed.TotalMilliseconds.ToString("0.000") + " ms."); + } + } + } +} diff --git a/performance-tests/Messaging/ServerApp/OneWayServerCustomProtocol.cs b/performance-tests/Messaging/ServerApp/OneWayServerCustomProtocol.cs new file mode 100644 index 0000000..eb0da5f --- /dev/null +++ b/performance-tests/Messaging/ServerApp/OneWayServerCustomProtocol.cs @@ -0,0 +1,49 @@ +using System; +using System.Diagnostics; +using CommonLib; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.Scs.Communication.Messages; +using Hik.Communication.Scs.Server; + +namespace ServerApp +{ + public class OneWayServerCustomProtocol + { + private static int _messageCount; + private static Stopwatch _stopwatch; + + public static void Run() + { + var server = ScsServerFactory.CreateServer(new ScsTcpEndPoint(10033)); + + server.WireProtocolFactory = new MyWireProtocolFactory(); + server.ClientConnected += server_ClientConnected; + + server.Start(); + + Console.WriteLine("Press enter to stop server"); + Console.ReadLine(); + + server.Stop(); + } + + static void server_ClientConnected(object sender, ServerClientEventArgs e) + { + e.Client.MessageReceived += Client_MessageReceived; + } + + static void Client_MessageReceived(object sender, MessageEventArgs e) + { + ++_messageCount; + if (_messageCount == 1) + { + _stopwatch = Stopwatch.StartNew(); + } + else if (_messageCount == Consts.MessageCount) + { + _stopwatch.Stop(); + Console.WriteLine(Consts.MessageCount + " message is received in " + _stopwatch.Elapsed.TotalMilliseconds.ToString("0.000") + " ms."); + } + } + } +} diff --git a/performance-tests/Messaging/ServerApp/OneWayServerDefaultProtocol.cs b/performance-tests/Messaging/ServerApp/OneWayServerDefaultProtocol.cs new file mode 100644 index 0000000..fdf5887 --- /dev/null +++ b/performance-tests/Messaging/ServerApp/OneWayServerDefaultProtocol.cs @@ -0,0 +1,47 @@ +using System; +using System.Diagnostics; +using CommonLib; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.Scs.Communication.Messages; +using Hik.Communication.Scs.Server; + +namespace ServerApp +{ + public class OneWayServerDefaultProtocol + { + private static int _messageCount; + private static Stopwatch _stopwatch; + + public static void Run() + { + var server = ScsServerFactory.CreateServer(new ScsTcpEndPoint(10033)); + server.ClientConnected += server_ClientConnected; + + server.Start(); + + Console.WriteLine("Press enter to stop server"); + Console.ReadLine(); + + server.Stop(); + } + + static void server_ClientConnected(object sender, ServerClientEventArgs e) + { + e.Client.MessageReceived += Client_MessageReceived; + } + + static void Client_MessageReceived(object sender, MessageEventArgs e) + { + ++_messageCount; + if (_messageCount == 1) + { + _stopwatch = Stopwatch.StartNew(); + } + else if (_messageCount == Consts.MessageCount) + { + _stopwatch.Stop(); + Console.WriteLine(Consts.MessageCount + " message is received in " + _stopwatch.Elapsed.TotalMilliseconds.ToString("0.000") + " ms."); + } + } + } +} diff --git a/performance-tests/Messaging/ServerApp/Program.cs b/performance-tests/Messaging/ServerApp/Program.cs new file mode 100644 index 0000000..0aab3b5 --- /dev/null +++ b/performance-tests/Messaging/ServerApp/Program.cs @@ -0,0 +1,10 @@ +namespace ServerApp +{ + public class Program + { + static void Main() + { + DuplexServerCustomProtocol.Run(); + } + } +} diff --git a/performance-tests/Messaging/ServerApp/Properties/AssemblyInfo.cs b/performance-tests/Messaging/ServerApp/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..125c23c --- /dev/null +++ b/performance-tests/Messaging/ServerApp/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ServerApp")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("ServerApp")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("bae7ad3a-ea6a-44f7-8429-89f23b17abfe")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/performance-tests/Messaging/ServerApp/ServerApp.csproj b/performance-tests/Messaging/ServerApp/ServerApp.csproj new file mode 100644 index 0000000..f5a6c0f --- /dev/null +++ b/performance-tests/Messaging/ServerApp/ServerApp.csproj @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{F515CE95-6A3F-4E5E-867A-899FFFC90D43}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>ServerApp</RootNamespace> + <AssemblyName>ServerApp</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="DuplexServerDefaultProtocol.cs" /> + <Compile Include="OneWayServerCustomProtocol.cs" /> + <Compile Include="DuplexServerCustomProtocol.cs" /> + <Compile Include="OneWayServerDefaultProtocol.cs" /> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\CommonLib\CommonLib.csproj"> + <Project>{7F7D3248-4432-4E7B-9CFD-25982668AD5B}</Project> + <Name>CommonLib</Name> + </ProjectReference> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/performance-tests/RMI/CalculatorClient/CalculatorClient.csproj b/performance-tests/RMI/CalculatorClient/CalculatorClient.csproj new file mode 100644 index 0000000..d9b1a48 --- /dev/null +++ b/performance-tests/RMI/CalculatorClient/CalculatorClient.csproj @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{6DD6F730-E353-4B0C-9655-8370A943A7BF}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>CalculatorClient</RootNamespace> + <AssemblyName>CalculatorClient</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.0.0.1, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\CalculatorCommonLib\CalculatorCommonLib.csproj"> + <Project>{6F2D58C9-0395-4048-A304-17304D12BC63}</Project> + <Name>CalculatorCommonLib</Name> + </ProjectReference> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/performance-tests/RMI/CalculatorClient/Program.cs b/performance-tests/RMI/CalculatorClient/Program.cs new file mode 100644 index 0000000..2532ea3 --- /dev/null +++ b/performance-tests/RMI/CalculatorClient/Program.cs @@ -0,0 +1,34 @@ +using System; +using CalculatorCommonLib; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.ScsServices.Client; +using System.Diagnostics; + +namespace CalculatorClient +{ + class Program + { + static void Main() + { + Console.WriteLine("Press enter to connect to server and call " + Consts.MethodCallCount + " methods..."); + Console.ReadLine(); + + using (var client = ScsServiceClientBuilder.CreateClient<ICalculatorService>(new ScsTcpEndPoint("127.0.0.1", 10083))) + { + client.Connect(); + + var stopwatch = Stopwatch.StartNew(); + for (var i = 0; i < Consts.MethodCallCount; i++) + { + var division = client.ServiceProxy.Add(2, 3); + } + + stopwatch.Stop(); + Console.WriteLine(Consts.MethodCallCount + " remote method call made in " + stopwatch.Elapsed.TotalMilliseconds.ToString("0.000") + " ms."); + } + + Console.WriteLine("Press enter to stop client application"); + Console.ReadLine(); + } + } +} diff --git a/performance-tests/RMI/CalculatorClient/Properties/AssemblyInfo.cs b/performance-tests/RMI/CalculatorClient/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..1c1a455 --- /dev/null +++ b/performance-tests/RMI/CalculatorClient/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CalculatorClient")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("CalculatorClient")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5712ded0-d09a-4e56-8de4-1d9145854ee5")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/performance-tests/RMI/CalculatorCommonLib/CalculatorCommonLib.csproj b/performance-tests/RMI/CalculatorCommonLib/CalculatorCommonLib.csproj new file mode 100644 index 0000000..c5ac4f6 --- /dev/null +++ b/performance-tests/RMI/CalculatorCommonLib/CalculatorCommonLib.csproj @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{6F2D58C9-0395-4048-A304-17304D12BC63}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>CalculatorCommonLib</RootNamespace> + <AssemblyName>CalculatorCommonLib</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.0.0.1, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Consts.cs" /> + <Compile Include="ICalculatorService.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/performance-tests/RMI/CalculatorCommonLib/Consts.cs b/performance-tests/RMI/CalculatorCommonLib/Consts.cs new file mode 100644 index 0000000..c220625 --- /dev/null +++ b/performance-tests/RMI/CalculatorCommonLib/Consts.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace CalculatorCommonLib +{ + public class Consts + { + public const int MethodCallCount = 1000000; + } +} diff --git a/performance-tests/RMI/CalculatorCommonLib/ICalculatorService.cs b/performance-tests/RMI/CalculatorCommonLib/ICalculatorService.cs new file mode 100644 index 0000000..c04013f --- /dev/null +++ b/performance-tests/RMI/CalculatorCommonLib/ICalculatorService.cs @@ -0,0 +1,15 @@ +using Hik.Communication.ScsServices.Service; + +namespace CalculatorCommonLib +{ + /// <summary> + /// This interface defines methods of calculator service that can be called by clients. + /// </summary> + [ScsService] + public interface ICalculatorService + { + int Add(int number1, int number2); + + double Divide(double number1, double number2); + } +} diff --git a/performance-tests/RMI/CalculatorCommonLib/Properties/AssemblyInfo.cs b/performance-tests/RMI/CalculatorCommonLib/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4848095 --- /dev/null +++ b/performance-tests/RMI/CalculatorCommonLib/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CalculatorCommonLib")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("CalculatorCommonLib")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("8a08ef54-dde6-4f7a-8656-57518c5098ea")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/performance-tests/RMI/CalculatorServer/CalculatorServer.csproj b/performance-tests/RMI/CalculatorServer/CalculatorServer.csproj new file mode 100644 index 0000000..259762d --- /dev/null +++ b/performance-tests/RMI/CalculatorServer/CalculatorServer.csproj @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{1BB6B428-E4C3-467F-824F-1DB84E310FF2}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>CalculatorServer</RootNamespace> + <AssemblyName>CalculatorServer</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.0.0.1, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\CalculatorCommonLib\CalculatorCommonLib.csproj"> + <Project>{6F2D58C9-0395-4048-A304-17304D12BC63}</Project> + <Name>CalculatorCommonLib</Name> + </ProjectReference> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/performance-tests/RMI/CalculatorServer/Program.cs b/performance-tests/RMI/CalculatorServer/Program.cs new file mode 100644 index 0000000..8ec07ef --- /dev/null +++ b/performance-tests/RMI/CalculatorServer/Program.cs @@ -0,0 +1,46 @@ +using System; +using CalculatorCommonLib; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.ScsServices.Service; + +namespace CalculatorServer +{ + class Program + { + static void Main() + { + //Create a service application that runs on 10083 TCP port + var serviceApplication = ScsServiceBuilder.CreateService(new ScsTcpEndPoint(10083)); + + //Create a CalculatorService and add it to service application + serviceApplication.AddService<ICalculatorService, CalculatorService>(new CalculatorService()); + + //Start service application + serviceApplication.Start(); + + Console.WriteLine("Calculator service is started. Press enter to stop..."); + Console.ReadLine(); + + //Stop service application + serviceApplication.Stop(); + } + } + + public class CalculatorService : ScsService, ICalculatorService + { + public int Add(int number1, int number2) + { + return number1 + number2; + } + + public double Divide(double number1, double number2) + { + if(number2 == 0.0) + { + throw new DivideByZeroException("number2 can not be zero!"); + } + + return number1 / number2; + } + } +} diff --git a/performance-tests/RMI/CalculatorServer/Properties/AssemblyInfo.cs b/performance-tests/RMI/CalculatorServer/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..46a9398 --- /dev/null +++ b/performance-tests/RMI/CalculatorServer/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CalculatorServer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("CalculatorServer")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("fc3f0ecf-46ea-437e-a535-82dffae3dc9e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/performance-tests/RMI/SimpleCalculatorSystem.sln b/performance-tests/RMI/SimpleCalculatorSystem.sln new file mode 100644 index 0000000..236647f --- /dev/null +++ b/performance-tests/RMI/SimpleCalculatorSystem.sln @@ -0,0 +1,54 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CalculatorServer", "CalculatorServer\CalculatorServer.csproj", "{1BB6B428-E4C3-467F-824F-1DB84E310FF2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CalculatorCommonLib", "CalculatorCommonLib\CalculatorCommonLib.csproj", "{6F2D58C9-0395-4048-A304-17304D12BC63}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CalculatorClient", "CalculatorClient\CalculatorClient.csproj", "{6DD6F730-E353-4B0C-9655-8370A943A7BF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Debug|Any CPU.ActiveCfg = Debug|x86 + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Debug|x86.ActiveCfg = Debug|x86 + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Debug|x86.Build.0 = Debug|x86 + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Release|Any CPU.ActiveCfg = Release|x86 + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Release|Mixed Platforms.Build.0 = Release|x86 + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Release|x86.ActiveCfg = Release|x86 + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Release|x86.Build.0 = Release|x86 + {6F2D58C9-0395-4048-A304-17304D12BC63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6F2D58C9-0395-4048-A304-17304D12BC63}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6F2D58C9-0395-4048-A304-17304D12BC63}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {6F2D58C9-0395-4048-A304-17304D12BC63}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {6F2D58C9-0395-4048-A304-17304D12BC63}.Debug|x86.ActiveCfg = Debug|Any CPU + {6F2D58C9-0395-4048-A304-17304D12BC63}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6F2D58C9-0395-4048-A304-17304D12BC63}.Release|Any CPU.Build.0 = Release|Any CPU + {6F2D58C9-0395-4048-A304-17304D12BC63}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {6F2D58C9-0395-4048-A304-17304D12BC63}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {6F2D58C9-0395-4048-A304-17304D12BC63}.Release|x86.ActiveCfg = Release|Any CPU + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Debug|Any CPU.ActiveCfg = Debug|x86 + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Debug|x86.ActiveCfg = Debug|x86 + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Debug|x86.Build.0 = Debug|x86 + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Release|Any CPU.ActiveCfg = Release|x86 + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Release|Mixed Platforms.Build.0 = Release|x86 + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Release|x86.ActiveCfg = Release|x86 + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/CustomWireProtocol/ClientApp/ClientApp.csproj b/samples/CustomWireProtocol/ClientApp/ClientApp.csproj new file mode 100644 index 0000000..a4f4557 --- /dev/null +++ b/samples/CustomWireProtocol/ClientApp/ClientApp.csproj @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>ClientApp</RootNamespace> + <AssemblyName>ClientApp</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\CommonLib\CommonLib.csproj"> + <Project>{7F7D3248-4432-4E7B-9CFD-25982668AD5B}</Project> + <Name>CommonLib</Name> + </ProjectReference> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/samples/CustomWireProtocol/ClientApp/Program.cs b/samples/CustomWireProtocol/ClientApp/Program.cs new file mode 100644 index 0000000..006c09a --- /dev/null +++ b/samples/CustomWireProtocol/ClientApp/Program.cs @@ -0,0 +1,32 @@ +using System; +using CommonLib; +using Hik.Communication.Scs.Client; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.Scs.Communication.Messages; + +/* This application is build to demonstrate a CUSTOM WIRE PROTOCOL usage with SCS framework. + * This client application connects to a server and sends a message using MyWireProtocol class. + */ + +namespace ClientApp +{ + class Program + { + static void Main() + { + Console.WriteLine("Press enter to connect to server and say Hello world!"); + Console.ReadLine(); + + using (var client = ScsClientFactory.CreateClient(new ScsTcpEndPoint("127.0.0.1", 10033))) + { + client.WireProtocol = new MyWireProtocol(); //Set custom wire protocol! + + client.Connect(); + client.SendMessage(new ScsTextMessage("Hello world!")); + + Console.WriteLine("Press enter to disconnect from server"); + Console.ReadLine(); + } + } + } +} diff --git a/samples/CustomWireProtocol/ClientApp/Properties/AssemblyInfo.cs b/samples/CustomWireProtocol/ClientApp/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..7b4eed4 --- /dev/null +++ b/samples/CustomWireProtocol/ClientApp/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ClientApp")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("ClientApp")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a9dbae74-bd80-4551-9ca8-bc212ea55174")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/CustomWireProtocol/CommonLib/CommonLib.csproj b/samples/CustomWireProtocol/CommonLib/CommonLib.csproj new file mode 100644 index 0000000..93fb6fb --- /dev/null +++ b/samples/CustomWireProtocol/CommonLib/CommonLib.csproj @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{7F7D3248-4432-4E7B-9CFD-25982668AD5B}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>CommonLib</RootNamespace> + <AssemblyName>CommonLib</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="MyWireProtocol.cs" /> + <Compile Include="MyWireProtocolFactory.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/samples/CustomWireProtocol/CommonLib/MyWireProtocol.cs b/samples/CustomWireProtocol/CommonLib/MyWireProtocol.cs new file mode 100644 index 0000000..11227f4 --- /dev/null +++ b/samples/CustomWireProtocol/CommonLib/MyWireProtocol.cs @@ -0,0 +1,32 @@ +using System.Text; +using Hik.Communication.Scs.Communication.Messages; +using Hik.Communication.Scs.Communication.Protocols.BinarySerialization; + +namespace CommonLib +{ + /// <summary> + /// This class is a sample custom wire protocol to use as wire protocol in SCS framework. + /// It extends BinarySerializationProtocol. + /// It is used just to send/receive ScsTextMessage messages. + /// + /// Since BinarySerializationProtocol automatically writes message length to the beggining + /// of the message, a message format of this class is: + /// + /// [Message length (4 bytes)][UTF-8 encoded text (N bytes)] + /// + /// So, total length of the message = (N + 4) bytes; + /// </summary> + public class MyWireProtocol : BinarySerializationProtocol + { + protected override byte[] SerializeMessage(IScsMessage message) + { + return Encoding.UTF8.GetBytes(((ScsTextMessage)message).Text); + } + + protected override IScsMessage DeserializeMessage(byte[] bytes) + { + //Decode UTF8 encoded text and create a ScsTextMessage object + return new ScsTextMessage(Encoding.UTF8.GetString(bytes)); + } + } +} diff --git a/samples/CustomWireProtocol/CommonLib/MyWireProtocolFactory.cs b/samples/CustomWireProtocol/CommonLib/MyWireProtocolFactory.cs new file mode 100644 index 0000000..7f5f1ae --- /dev/null +++ b/samples/CustomWireProtocol/CommonLib/MyWireProtocolFactory.cs @@ -0,0 +1,12 @@ +using Hik.Communication.Scs.Communication.Protocols; + +namespace CommonLib +{ + public class MyWireProtocolFactory : IScsWireProtocolFactory + { + public IScsWireProtocol CreateWireProtocol() + { + return new MyWireProtocol(); + } + } +} diff --git a/samples/CustomWireProtocol/CommonLib/Properties/AssemblyInfo.cs b/samples/CustomWireProtocol/CommonLib/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..8461698 --- /dev/null +++ b/samples/CustomWireProtocol/CommonLib/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CommonLib")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("CommonLib")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("50d012ed-8149-4bfb-8cb4-0f325628bdf7")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/CustomWireProtocol/ServerApp.sln b/samples/CustomWireProtocol/ServerApp.sln new file mode 100644 index 0000000..10eed7d --- /dev/null +++ b/samples/CustomWireProtocol/ServerApp.sln @@ -0,0 +1,54 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServerApp", "ServerApp\ServerApp.csproj", "{F515CE95-6A3F-4E5E-867A-899FFFC90D43}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClientApp", "ClientApp\ClientApp.csproj", "{8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonLib", "CommonLib\CommonLib.csproj", "{7F7D3248-4432-4E7B-9CFD-25982668AD5B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Debug|Any CPU.ActiveCfg = Debug|x86 + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Debug|x86.ActiveCfg = Debug|x86 + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Debug|x86.Build.0 = Debug|x86 + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Release|Any CPU.ActiveCfg = Release|x86 + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Release|Mixed Platforms.Build.0 = Release|x86 + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Release|x86.ActiveCfg = Release|x86 + {F515CE95-6A3F-4E5E-867A-899FFFC90D43}.Release|x86.Build.0 = Release|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Debug|Any CPU.ActiveCfg = Debug|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Debug|x86.ActiveCfg = Debug|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Debug|x86.Build.0 = Debug|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Release|Any CPU.ActiveCfg = Release|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Release|Mixed Platforms.Build.0 = Release|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Release|x86.ActiveCfg = Release|x86 + {8D1CD669-49E3-4F7E-98B1-6E4405BEBAD6}.Release|x86.Build.0 = Release|x86 + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Debug|x86.ActiveCfg = Debug|Any CPU + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Release|Any CPU.Build.0 = Release|Any CPU + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {7F7D3248-4432-4E7B-9CFD-25982668AD5B}.Release|x86.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/CustomWireProtocol/ServerApp/Program.cs b/samples/CustomWireProtocol/ServerApp/Program.cs new file mode 100644 index 0000000..593dadf --- /dev/null +++ b/samples/CustomWireProtocol/ServerApp/Program.cs @@ -0,0 +1,41 @@ +using System; +using CommonLib; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.Scs.Communication.Messages; +using Hik.Communication.Scs.Server; + +/* This application is build to demonstrate a CUSTOM WIRE PROTOCOL usage with SCS framework. + * This server application listens incoming messages from client applications using MyWireProtocol class. + */ + +namespace ServerApp +{ + public class Program + { + static void Main() + { + var server = ScsServerFactory.CreateServer(new ScsTcpEndPoint(10033)); + + server.WireProtocolFactory = new MyWireProtocolFactory(); //Set custom wire protocol factory! + server.ClientConnected += server_ClientConnected; + + server.Start(); + + Console.WriteLine("Press enter to stop server"); + Console.ReadLine(); + + server.Stop(); + } + + static void server_ClientConnected(object sender, ServerClientEventArgs e) + { + Console.WriteLine("A new client is connected. Address: " + e.Client.RemoteEndPoint); + e.Client.MessageReceived += Client_MessageReceived; + } + + static void Client_MessageReceived(object sender, MessageEventArgs e) + { + Console.WriteLine("A client sent a message: " + ((ScsTextMessage) e.Message).Text); + } + } +} diff --git a/samples/CustomWireProtocol/ServerApp/Properties/AssemblyInfo.cs b/samples/CustomWireProtocol/ServerApp/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..125c23c --- /dev/null +++ b/samples/CustomWireProtocol/ServerApp/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ServerApp")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("ServerApp")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("bae7ad3a-ea6a-44f7-8429-89f23b17abfe")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/CustomWireProtocol/ServerApp/ServerApp.csproj b/samples/CustomWireProtocol/ServerApp/ServerApp.csproj new file mode 100644 index 0000000..b624302 --- /dev/null +++ b/samples/CustomWireProtocol/ServerApp/ServerApp.csproj @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{F515CE95-6A3F-4E5E-867A-899FFFC90D43}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>ServerApp</RootNamespace> + <AssemblyName>ServerApp</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\CommonLib\CommonLib.csproj"> + <Project>{7F7D3248-4432-4E7B-9CFD-25982668AD5B}</Project> + <Name>CommonLib</Name> + </ProjectReference> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/samples/IrcChatSystem/ChatClientApp/ChatClientApp.csproj b/samples/IrcChatSystem/ChatClientApp/ChatClientApp.csproj new file mode 100644 index 0000000..6215d05 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/ChatClientApp.csproj @@ -0,0 +1,178 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{6571B5F6-C92F-4266-ACC9-186347994E9F}</ProjectGuid> + <OutputType>WinExe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>Hik.Samples.Scs.IrcChat</RootNamespace> + <AssemblyName>ChatClientApp</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup> + <StartupObject>Hik.Samples.Scs.IrcChat.ChatClientApplication</StartupObject> + </PropertyGroup> + <PropertyGroup> + <ApplicationIcon>Images\app_icon.ico</ApplicationIcon> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Data" /> + <Reference Include="System.Drawing" /> + <Reference Include="System.Windows.Forms" /> + <Reference Include="System.Xml" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Xaml"> + <RequiredTargetFramework>4.0</RequiredTargetFramework> + </Reference> + <Reference Include="WindowsBase" /> + <Reference Include="PresentationCore" /> + <Reference Include="PresentationFramework" /> + </ItemGroup> + <ItemGroup> + <ApplicationDefinition Include="ChatClientApplication.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </ApplicationDefinition> + <Compile Include="Client\ChatClient.cs" /> + <Compile Include="Client\ChatController.cs" /> + <Compile Include="Client\ClientHelper.cs" /> + <Compile Include="Client\IChatController.cs" /> + <Compile Include="Client\IChatRoomView.cs" /> + <Compile Include="Client\ILoginFormView.cs" /> + <Compile Include="Client\UserPreferences.cs" /> + <Compile Include="Client\WindowsHelper.cs" /> + <Compile Include="Controls\IMessagingAreaContainer.xaml.cs" /> + <Compile Include="Controls\MessagingAreaControl.xaml.cs"> + <DependentUpon>MessagingAreaControl.xaml</DependentUpon> + </Compile> + <Compile Include="Controls\UserCardControl.xaml.cs"> + <DependentUpon>UserCardControl.xaml</DependentUpon> + </Compile> + <Page Include="Controls\MessagingAreaControl.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Windows\PrivateChatWindow.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Windows\TextColorPicker.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Windows\MainWindow.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> + <Compile Include="ChatClientApplication.xaml.cs"> + <DependentUpon>ChatClientApplication.xaml</DependentUpon> + <SubType>Code</SubType> + </Compile> + <Compile Include="Windows\PrivateChatWindow.xaml.cs"> + <DependentUpon>PrivateChatWindow.xaml</DependentUpon> + </Compile> + <Compile Include="Windows\TextColorPicker.xaml.cs"> + <DependentUpon>TextColorPicker.xaml</DependentUpon> + </Compile> + <Compile Include="Windows\MainWindow.xaml.cs"> + <DependentUpon>MainWindow.xaml</DependentUpon> + <SubType>Code</SubType> + </Compile> + <Page Include="Controls\UserCardControl.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + </ItemGroup> + <ItemGroup> + <Compile Include="Properties\AssemblyInfo.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="Properties\Resources.Designer.cs"> + <AutoGen>True</AutoGen> + <DesignTime>True</DesignTime> + <DependentUpon>Resources.resx</DependentUpon> + </Compile> + <Compile Include="Properties\Settings.Designer.cs"> + <AutoGen>True</AutoGen> + <DependentUpon>Settings.settings</DependentUpon> + <DesignTimeSharedInput>True</DesignTimeSharedInput> + </Compile> + <EmbeddedResource Include="Properties\Resources.resx"> + <Generator>ResXFileCodeGenerator</Generator> + <LastGenOutput>Resources.Designer.cs</LastGenOutput> + </EmbeddedResource> + <None Include="Properties\Settings.settings"> + <Generator>SettingsSingleFileGenerator</Generator> + <LastGenOutput>Settings.Designer.cs</LastGenOutput> + </None> + <AppDesigner Include="Properties\" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\ChatCommonLib\ChatCommonLib.csproj"> + <Project>{A57047DE-CC39-4C01-955E-D73888A0C83D}</Project> + <Name>ChatCommonLib</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <Content Include="Sounds\incoming_message.wav"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </Content> + <Resource Include="Images\app_icon.ico" /> + <Resource Include="Images\text_color_picker.ico" /> + <Content Include="Images\sound_on.png"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </Content> + <Content Include="Images\sound_off.png"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </Content> + <Content Include="Images\user_female.png"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </Content> + </ItemGroup> + <ItemGroup> + <Content Include="Images\user_male.png"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </Content> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/samples/IrcChatSystem/ChatClientApp/ChatClientApplication.xaml b/samples/IrcChatSystem/ChatClientApp/ChatClientApplication.xaml new file mode 100644 index 0000000..ce81fc7 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/ChatClientApplication.xaml @@ -0,0 +1,16 @@ +<Application x:Class="Hik.Samples.Scs.IrcChat.ChatClientApplication" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> + <Application.Resources> + <Style TargetType="Border"> + <Setter Property="BorderThickness" Value="1"></Setter> + <Setter Property="BorderBrush" Value="#FF878383"></Setter> + <Setter Property="CornerRadius" Value="6"></Setter> + <Setter Property="Background" Value="#FF111111" /> + </Style> + <LinearGradientBrush x:Key="GreenButtonBackGround" EndPoint="0.5,1" StartPoint="0.5,0"> + <GradientStop Color="#FF239032" Offset="0" /> + <GradientStop Color="#FF003205" Offset="1" /> + </LinearGradientBrush> + </Application.Resources> +</Application> diff --git a/samples/IrcChatSystem/ChatClientApp/ChatClientApplication.xaml.cs b/samples/IrcChatSystem/ChatClientApp/ChatClientApplication.xaml.cs new file mode 100644 index 0000000..26a2b21 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/ChatClientApplication.xaml.cs @@ -0,0 +1,26 @@ +using System.Windows; +using Hik.Samples.Scs.IrcChat.Client; +using Hik.Samples.Scs.IrcChat.Windows; + +namespace Hik.Samples.Scs.IrcChat +{ + /// <summary> + /// Interaction logic for App.xaml + /// </summary> + public partial class ChatClientApplication : Application + { + public ChatClientApplication() + { + Startup += AppStartUp; + } + + static void AppStartUp(object sender, StartupEventArgs e) + { + var controller = new ChatController(); + var mainWindow = new MainWindow(controller); + controller.ChatRoom = mainWindow; + controller.LoginForm = mainWindow; + mainWindow.Show(); + } + } +} diff --git a/samples/IrcChatSystem/ChatClientApp/Client/ChatClient.cs b/samples/IrcChatSystem/ChatClientApp/Client/ChatClient.cs new file mode 100644 index 0000000..709df89 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Client/ChatClient.cs @@ -0,0 +1,103 @@ +using System; +using Hik.Samples.Scs.IrcChat.Arguments; +using Hik.Samples.Scs.IrcChat.Contracts; + +namespace Hik.Samples.Scs.IrcChat.Client +{ + /// <summary> + /// This class implements IChatClient to use to be invoked by Chat Server. + /// </summary> + internal class ChatClient : IChatClient + { + #region Private fields + + /// <summary> + /// Reference to Chat Room window. + /// </summary> + private readonly IChatRoomView _chatRoom; + + #endregion + + #region Constructor + + /// <summary> + /// Creates a new ChatClient. + /// </summary> + /// <param name="chatRoom">Reference to Chat Room window</param> + public ChatClient(IChatRoomView chatRoom) + { + _chatRoom = chatRoom; + } + + #endregion + + #region IChatClient implementation + + /// <summary> + /// This method is used to get user list from chat server. + /// It is called by server, once after user logged in to server. + /// </summary> + /// <param name="users">All online user informations</param> + public void GetUserList(UserInfo[] users) + { + foreach (var user in users) + { + _chatRoom.AddUserToList(user); + } + } + + /// <summary> + /// This method is called from chat server to inform that a message + /// is sent to chat room publicly. + /// </summary> + /// <param name="nick">Nick of sender</param> + /// <param name="message">Message text</param> + public void OnMessageToRoom(string nick, ChatMessage message) + { + _chatRoom.OnMessageReceived(nick, message); + } + + /// <summary> + /// This method is called from chat server to inform that a message + /// is sent to the current used privately. + /// </summary> + /// <param name="nick">Nick of sender</param> + /// <param name="message">Message</param> + public void OnPrivateMessage(string nick, ChatMessage message) + { + _chatRoom.OnPrivateMessageReceived(nick, message); + } + + /// <summary> + /// This method is called from chat server to inform that a new user + /// joined to chat room. + /// </summary> + /// <param name="userInfo">Informations of new user</param> + public void OnUserLogin(UserInfo userInfo) + { + _chatRoom.AddUserToList(userInfo); + } + + /// <summary> + /// This method is called from chat server to inform that an existing user + /// has left the chat room. + /// </summary> + /// <param name="nick">Informations of new user</param> + public void OnUserLogout(string nick) + { + _chatRoom.RemoveUserFromList(nick); + } + + /// <summary> + /// This method is called from chat server to inform that a user changed his/her status. + /// </summary> + /// <param name="nick">Nick of the user</param> + /// <param name="newStatus">New status of the user</param> + public void OnUserStatusChange(string nick, UserStatus newStatus) + { + _chatRoom.OnUserStatusChange(nick, newStatus); + } + + #endregion + } +} diff --git a/samples/IrcChatSystem/ChatClientApp/Client/ChatController.cs b/samples/IrcChatSystem/ChatClientApp/Client/ChatController.cs new file mode 100644 index 0000000..91a2241 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Client/ChatController.cs @@ -0,0 +1,155 @@ +using System; +using Hik.Communication.Scs.Communication; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.ScsServices.Client; +using Hik.Communication.ScsServices.Communication.Messages; +using Hik.Samples.Scs.IrcChat.Arguments; +using Hik.Samples.Scs.IrcChat.Contracts; + +namespace Hik.Samples.Scs.IrcChat.Client +{ + /// <summary> + /// This class is a mediator with view and SCS system. + /// </summary> + internal class ChatController : IChatController + { + #region Private fields + + /// <summary> + /// Reference to login form. + /// </summary> + public ILoginFormView LoginForm { get; set; } + + /// <summary> + /// Reference to chat room window. + /// </summary> + public IChatRoomView ChatRoom { get; set; } + + /// <summary> + /// The object which handles remote method calls from server. + /// It implements IChatClient contract. + /// </summary> + private ChatClient _chatClient; + + /// <summary> + /// This object is used to connect to SCS Chat Service as a client. + /// </summary> + private IScsServiceClient<IChatService> _scsClient; + + #endregion + + #region IChatController implementation + + /// <summary> + /// Connects to the server. + /// It automatically Logins to server if connection success. + /// </summary> + public void Connect() + { + //Disconnect if currently connected + Disconnect(); + + //Create a ChatClient to handle remote method invocations by server + _chatClient = new ChatClient(ChatRoom); + + //Create a SCS client to connect to SCS server + _scsClient = ScsServiceClientBuilder.CreateClient<IChatService>(new ScsTcpEndPoint(LoginForm.ServerIpAddress, LoginForm.ServerTcpPort), _chatClient); + + //Register events of SCS client + _scsClient.Connected += ScsClient_Connected; + _scsClient.Disconnected += ScsClient_Disconnected; + + //Connect to the server + _scsClient.Connect(); + } + + /// <summary> + /// Disconnects from server if it is connected. + /// </summary> + public void Disconnect() + { + if (_scsClient != null && _scsClient.CommunicationState == CommunicationStates.Connected) + { + try + { + _scsClient.Disconnect(); + } + catch + { + + } + + _scsClient = null; + } + } + + /// <summary> + /// Sends a public message to room. + /// It will be seen by all users in room. + /// </summary> + /// <param name="message">Message to be sent</param> + public void SendMessageToRoom(ChatMessage message) + { + _scsClient.ServiceProxy.SendMessageToRoom(message); + } + + /// <summary> + /// Change status of user. + /// </summary> + /// <param name="newStatus">New status</param> + public void ChangeStatus(UserStatus newStatus) + { + _scsClient.ServiceProxy.ChangeStatus(newStatus); + } + + /// <summary> + /// Sends a private message to a user. + /// </summary> + /// <param name="nick">Destination nick</param> + /// <param name="message">Message</param> + public void SendPrivateMessage(string nick, ChatMessage message) + { + _scsClient.ServiceProxy.SendPrivateMessage(nick, message); + } + + #endregion + + #region Private methods + + /// <summary> + /// This method handles Connected event of _scsClient. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void ScsClient_Connected(object sender, EventArgs e) + { + try + { + _scsClient.ServiceProxy.Login(LoginForm.CurrentUserInfo); + ChatRoom.OnLoggedIn(); + } + catch (ScsRemoteException ex) + { + Disconnect(); + ChatRoom.OnLoginError(ex.InnerException != null ? ex.InnerException.Message : ex.Message); + } + catch + { + Disconnect(); + ChatRoom.OnLoginError("Can not login to server. Please try again later."); + } + } + + /// <summary> + /// This method handles Disconnected event of _scsClient. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void ScsClient_Disconnected(object sender, EventArgs e) + { + ChatRoom.OnLoggedOut(); + } + + #endregion + } +} diff --git a/samples/IrcChatSystem/ChatClientApp/Client/ClientHelper.cs b/samples/IrcChatSystem/ChatClientApp/Client/ClientHelper.cs new file mode 100644 index 0000000..9b417db --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Client/ClientHelper.cs @@ -0,0 +1,93 @@ +using System.IO; +using System.Media; +using System.Reflection; +using System.Runtime.Serialization.Formatters.Binary; + +namespace Hik.Samples.Scs.IrcChat.Client +{ + /// <summary> + /// This class includes come helper methods that are using in chat client. + /// </summary> + public static class ClientHelper + { + /// <summary> + /// Gets the directory of executing assembly. + /// </summary> + /// <returns>Current directory</returns> + public static string GetCurrentDirectory() + { + return (new FileInfo(Assembly.GetExecutingAssembly().Location)).Directory.FullName; + } + + /// <summary> + /// Gets the size of a file as bytes + /// </summary> + /// <param name="filePath">Path of file</param> + /// <returns>Size of file</returns> + public static long GetFileSize(string filePath) + { + using (var file = File.Open(filePath, FileMode.Open)) + { + var lengthOfFile = file.Length; + file.Close(); + return lengthOfFile; + } + } + + /// <summary> + /// Serializes an object and writes it to a file. + /// Uses .NET binary serialization. + /// </summary> + /// <param name="obj">object to be serialized</param> + /// <param name="filePath">Path of file to serialize</param> + /// <returns>bytes of object</returns> + public static void SerializeObjectToFile(object obj, string filePath) + { + using (var file = new FileStream(filePath, FileMode.Create)) + { + new BinaryFormatter().Serialize(file, obj); + file.Flush(); + } + } + + /// <summary> + /// Deserializes an object from a file. + /// Uses .NET binary deserialization. + /// </summary> + /// <param name="filePath">Path of file to deserialize</param> + /// <returns>deserialized object</returns> + public static object DeserializeObjectFromFile(string filePath) + { + using (var file = new FileStream(filePath, FileMode.Open, FileAccess.Read)) + { + return new BinaryFormatter().Deserialize(file); + } + } + + /// <summary> + /// Plays incoming message sound (if sound is on). + /// </summary> + public static void PlayIncomingMessageSound() + { + if (!UserPreferences.Current.IsSoundOn) + { + return; + } + + try + { + var filePath = Path.Combine(GetCurrentDirectory(), @"Sounds\incoming_message.wav"); + if (!File.Exists(filePath)) + { + return; + } + + new SoundPlayer(filePath).Play(); + } + catch + { + + } + } + } +} diff --git a/samples/IrcChatSystem/ChatClientApp/Client/IChatController.cs b/samples/IrcChatSystem/ChatClientApp/Client/IChatController.cs new file mode 100644 index 0000000..4fd90cf --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Client/IChatController.cs @@ -0,0 +1,41 @@ +using Hik.Samples.Scs.IrcChat.Arguments; + +namespace Hik.Samples.Scs.IrcChat.Client +{ + /// <summary> + /// This interface defines method of chat controller that can be used by views. + /// </summary> + public interface IChatController + { + /// <summary> + /// Connects to the server. + /// It automatically Logins to server if connection success. + /// </summary> + void Connect(); + + /// <summary> + /// Disconnects from server if it is connected. + /// </summary> + void Disconnect(); + + /// <summary> + /// Sends a public message to room. + /// It will be seen all users in room. + /// </summary> + /// <param name="message">Message to be sent</param> + void SendMessageToRoom(ChatMessage message); + + /// <summary> + /// Change status of user. + /// </summary> + /// <param name="newStatus">New status</param> + void ChangeStatus(UserStatus newStatus); + + /// <summary> + /// Sends a private message to a user. + /// </summary> + /// <param name="nick">Destination nick</param> + /// <param name="message">Message</param> + void SendPrivateMessage(string nick, ChatMessage message); + } +}
\ No newline at end of file diff --git a/samples/IrcChatSystem/ChatClientApp/Client/IChatRoomView.cs b/samples/IrcChatSystem/ChatClientApp/Client/IChatRoomView.cs new file mode 100644 index 0000000..b5f11a8 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Client/IChatRoomView.cs @@ -0,0 +1,60 @@ +using Hik.Samples.Scs.IrcChat.Arguments; + +namespace Hik.Samples.Scs.IrcChat.Client +{ + /// <summary> + /// This interface is used to interact with main chat room window by ChatController. + /// It is implemented by main window. + /// </summary> + public interface IChatRoomView + { + /// <summary> + /// This method is called when a message is sent to chat room. + /// </summary> + /// <param name="nick">Nick of sender</param> + /// <param name="message">Message</param> + void OnMessageReceived(string nick, ChatMessage message); + + /// <summary> + /// This method is called when a private message is sent to the current user. + /// </summary> + /// <param name="nick">Nick of sender</param> + /// <param name="message">The message</param> + void OnPrivateMessageReceived(string nick, ChatMessage message); + + /// <summary> + /// This method is called when user successfully logged in to chat server. + /// </summary> + void OnLoggedIn(); + + /// <summary> + /// This method is used to inform view if login is failed. + /// </summary> + /// <param name="errorMessage">Detail of error</param> + void OnLoginError(string errorMessage); + + /// <summary> + /// This method is called when connection to server is closed. + /// </summary> + void OnLoggedOut(); + + /// <summary> + /// This methos is used to add a new user to user list in room view. + /// </summary> + /// <param name="userInfo">Informations of new user</param> + void AddUserToList(UserInfo userInfo); + + /// <summary> + /// This metrhod is used to remove a user (that is disconnected from server) from user list in room view. + /// </summary> + /// <param name="nick">Nick of user to remove</param> + void RemoveUserFromList(string nick); + + /// <summary> + /// This method is called from chat server to inform that a user changed his/her status. + /// </summary> + /// <param name="nick">Nick of the user</param> + /// <param name="newStatus">New status of the user</param> + void OnUserStatusChange(string nick, UserStatus newStatus); + } +}
\ No newline at end of file diff --git a/samples/IrcChatSystem/ChatClientApp/Client/ILoginFormView.cs b/samples/IrcChatSystem/ChatClientApp/Client/ILoginFormView.cs new file mode 100644 index 0000000..1f746d9 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Client/ILoginFormView.cs @@ -0,0 +1,26 @@ +using Hik.Samples.Scs.IrcChat.Arguments; + +namespace Hik.Samples.Scs.IrcChat.Client +{ + /// <summary> + /// This interface is used to interact with login form by ChatController. + /// ChatController gets user informations over this interface. + /// </summary> + public interface ILoginFormView + { + /// <summary> + /// IP address of server to be connected. + /// </summary> + string ServerIpAddress { get; } + + /// <summary> + /// TCP Port number of server to be connected. + /// </summary> + int ServerTcpPort { get; } + + /// <summary> + /// User Login informations to be used while logging on to the server. + /// </summary> + UserInfo CurrentUserInfo { get; } + } +}
\ No newline at end of file diff --git a/samples/IrcChatSystem/ChatClientApp/Client/UserPreferences.cs b/samples/IrcChatSystem/ChatClientApp/Client/UserPreferences.cs new file mode 100644 index 0000000..64143c6 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Client/UserPreferences.cs @@ -0,0 +1,140 @@ +using System; +using System.IO; +using Hik.Samples.Scs.IrcChat.Arguments; + +namespace Hik.Samples.Scs.IrcChat.Client +{ + /// <summary> + /// This class is used to save and load preferences of the user. + /// </summary> + [Serializable] + internal class UserPreferences + { + /// <summary> + /// Gets the singleton instance of this class. + /// </summary> + public static UserPreferences Current + { + get + { + if (_current == null) + { + lock (SyncObj) + { + if (_current == null) + { + _current = LoadPreferences(); + } + } + } + + return _current; + } + } + + /// <summary> + /// Nick of the user. + /// </summary> + public string Nick { get; set; } + + /// <summary> + /// Path of user's avatar file. + /// </summary> + public string AvatarFile { get; set; } + + /// <summary> + /// Sound preference of user. + /// True if sound is on. + /// </summary> + public bool IsSoundOn { get; set; } + + /// <summary> + /// Ip address of the chat server. + /// </summary> + public string ServerIpAddress { get; set; } + + /// <summary> + /// TCP port of the chat server. + /// </summary> + public int ServerTcpPort { get; set; } + + /// <summary> + /// Text style of user. + /// </summary> + public MessageTextStyle TextStyle { get; private set; } + + /// <summary> + /// The singleton instance of this class. + /// </summary> + private static UserPreferences _current; + + /// <summary> + /// Used to synronize threads while creating singleton object. + /// </summary> + private static readonly object SyncObj = new object(); + + /// <summary> + /// Constructor. + /// </summary> + private UserPreferences() + { + IsSoundOn = true; + TextStyle = new MessageTextStyle(); + } + + /// <summary> + /// Saves preferences to the disc. + /// </summary> + public void Save() + { + try + { + ClientHelper.SerializeObjectToFile( + this, + Path.Combine(ClientHelper.GetCurrentDirectory(), "Preferences.bin") + ); + } + catch + { + + } + } + + /// <summary> + /// Load last preferences from the disc. + /// </summary> + /// <returns>Last user preferences (or default values if not found)</returns> + private static UserPreferences LoadPreferences() + { + try + { + var preferenceFile = Path.Combine(ClientHelper.GetCurrentDirectory(), "Preferences.bin"); + if (File.Exists(preferenceFile)) + { + return (UserPreferences)ClientHelper.DeserializeObjectFromFile(preferenceFile); + } + } + catch + { + + } + + return CreateDefault(); + } + + /// <summary> + /// Creates a default-valued instance of this class. + /// </summary> + /// <returns>UserPreferences object with default values</returns> + private static UserPreferences CreateDefault() + { + return new UserPreferences + { + Nick = "User Nick", + AvatarFile = Path.Combine(ClientHelper.GetCurrentDirectory(), @"Images\user_male.png"), + ServerIpAddress = "127.0.0.1", + ServerTcpPort = 10048 + }; + } + } +} diff --git a/samples/IrcChatSystem/ChatClientApp/Client/WindowsHelper.cs b/samples/IrcChatSystem/ChatClientApp/Client/WindowsHelper.cs new file mode 100644 index 0000000..517bc1d --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Client/WindowsHelper.cs @@ -0,0 +1,109 @@ +using System; +using System.Runtime.InteropServices; + +namespace Hik.Samples.Scs.IrcChat.Client +{ + /// <summary> + /// This class is used to flash window caption / taskbar button when a message received + /// and window is not active. + /// </summary> + public static class WindowsHelper + { + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool FlashWindowEx(ref FLASHWINFO pwfi); + + [StructLayout(LayoutKind.Sequential)] + public struct FLASHWINFO + { + /// <summary> + /// The size of the structure in bytes. + /// </summary> + public uint cbSize; + /// <summary> + /// A Handle to the Window to be Flashed. The window can be either opened or minimized. + /// </summary> + public IntPtr hwnd; + /// <summary> + /// The Flash Status. + /// </summary> + public FlashWindowFlags dwFlags; //uint + /// <summary> + /// The number of times to Flash the window. + /// </summary> + public uint uCount; + /// <summary> + /// The rate at which the Window is to be flashed, in milliseconds. If Zero, the function uses the default cursor blink rate. + /// </summary> + public uint dwTimeout; + } + + public enum FlashWindowFlags : uint + { + /// <summary> + /// Stop flashing. The system restores the window to its original state. + /// </summary> + FLASHW_STOP = 0, + + /// <summary> + /// Flash the window caption. + /// </summary> + FLASHW_CAPTION = 1, + + /// <summary> + /// Flash the taskbar button. + /// </summary> + FLASHW_TRAY = 2, + + /// <summary> + /// Flash both the window caption and taskbar button. + /// This is equivalent to setting the FLASHW_CAPTION | FLASHW_TRAY flags. + /// </summary> + FLASHW_ALL = 3, + + /// <summary> + /// Flash continuously, until the FLASHW_STOP flag is set. + /// </summary> + FLASHW_TIMER = 4, + + /// <summary> + /// Flash continuously until the window comes to the foreground. + /// </summary> + FLASHW_TIMERNOFG = 12 + } + + + public static bool FlashWindow(IntPtr hWnd, + FlashWindowFlags fOptions, + uint FlashCount, + uint FlashRate) + { + if (IntPtr.Zero != hWnd) + { + FLASHWINFO fi = new FLASHWINFO(); + fi.cbSize = (uint)Marshal.SizeOf(typeof(FLASHWINFO)); + fi.dwFlags = fOptions; + fi.uCount = FlashCount; + fi.dwTimeout = FlashRate; + fi.hwnd = hWnd; + + return FlashWindowEx(ref fi); + } + return false; + } + + public static bool StopFlashingWindow(IntPtr hWnd) + { + if (IntPtr.Zero != hWnd) + { + FLASHWINFO fi = new FLASHWINFO(); + fi.cbSize = (uint)Marshal.SizeOf(typeof(FLASHWINFO)); + fi.dwFlags = (uint)FlashWindowFlags.FLASHW_STOP; + fi.hwnd = hWnd; + + return FlashWindowEx(ref fi); + } + return false; + } + } +} diff --git a/samples/IrcChatSystem/ChatClientApp/Controls/IMessagingAreaContainer.xaml.cs b/samples/IrcChatSystem/ChatClientApp/Controls/IMessagingAreaContainer.xaml.cs new file mode 100644 index 0000000..d55ee92 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Controls/IMessagingAreaContainer.xaml.cs @@ -0,0 +1,16 @@ +using Hik.Samples.Scs.IrcChat.Arguments; + +namespace Hik.Samples.Scs.IrcChat.Controls +{ + /// <summary> + /// This interface defines methods of windows which contains a MessagingAreaControl. + /// </summary> + public interface IMessagingAreaContainer + { + /// <summary> + /// This method is used by MessagingAreaControl to send messages. + /// </summary> + /// <param name="message">Message to be sent</param> + void SendMessage(ChatMessage message); + } +}
\ No newline at end of file diff --git a/samples/IrcChatSystem/ChatClientApp/Controls/MessagingAreaControl.xaml b/samples/IrcChatSystem/ChatClientApp/Controls/MessagingAreaControl.xaml new file mode 100644 index 0000000..5be12fb --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Controls/MessagingAreaControl.xaml @@ -0,0 +1,61 @@ +<UserControl x:Class="Hik.Samples.Scs.IrcChat.Controls.MessagingAreaControl" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + mc:Ignorable="d" + d:DesignHeight="482" d:DesignWidth="677"> + <Border Grid.Column="0" Margin="5,5,0,5"> + <Grid> + <Grid.RowDefinitions> + <RowDefinition Height="*" /> + <RowDefinition Height="60" /> + </Grid.RowDefinitions> + <DockPanel LastChildFill="True"> + <StackPanel Name="spTextStyleChanging" DockPanel.Dock="Bottom" Height="30" Grid.Row="1" Orientation="Horizontal"> + <Label Name="lblTextColor" Width="30" Margin="5,1" Background="#FF343434" Foreground="#FFDEDEDE" Content="A" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" FontSize="15" Padding="1" MouseLeftButtonUp="lblTextColor_MouseLeftButtonUp" /> + <Label Name="lblTextBold" Width="30" Margin="0,1,5,1" Background="#FF343434" Foreground="#FFDEDEDE" Content="B" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" FontSize="15" Padding="1" MouseLeftButtonUp="lblTextBold_MouseLeftButtonUp" /> + <Label Name="lblTextItalic" Width="30" Margin="0,1,5,1" Background="#FF343434" Foreground="#FFDEDEDE" Content="I" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" FontSize="15" Padding="1" MouseLeftButtonUp="lblTextItalic_MouseLeftButtonUp" /> + <ComboBox Name="cmbTextFont" SelectedIndex="3" Margin="0,1,5,1" VerticalContentAlignment="Center" MinWidth="130" SelectionChanged="cmbTextFont_SelectionChanged"> + <ComboBoxItem FontFamily="Arial" Margin="1">Arial</ComboBoxItem> + <ComboBoxItem FontFamily="Cambria" Margin="1">Cambria</ComboBoxItem> + <ComboBoxItem FontFamily="Segoe UI" Margin="1">Segoe UI</ComboBoxItem> + <ComboBoxItem FontFamily="Verdana" Margin="1">Verdana</ComboBoxItem> + <ComboBoxItem FontFamily="Times New Roman" Margin="1">Times New Roman</ComboBoxItem> + </ComboBox> + <ComboBox Name="cmbTextSize" SelectedIndex="2" Margin="0,1,5,1" VerticalContentAlignment="Center" MinWidth="40" SelectionChanged="cmbTextSize_SelectionChanged"> + <ComboBoxItem Margin="1">8</ComboBoxItem> + <ComboBoxItem Margin="1">10</ComboBoxItem> + <ComboBoxItem Margin="1">12</ComboBoxItem> + <ComboBoxItem Margin="1">14</ComboBoxItem> + <ComboBoxItem Margin="1">16</ComboBoxItem> + </ComboBox> + <Image Source="/ChatClientApp;component/Images/sound_on.png" Name="imgSoundOnOff" MouseLeftButtonUp="imgSoundOnOff_MouseLeftButtonUp" /> + </StackPanel> + <RichTextBox Name="txtMessageHistory" Margin="5" Background="#FF343434" Foreground="#FFDEDEDE" VerticalScrollBarVisibility="Visible"> + <RichTextBox.Resources> + <Style TargetType="{x:Type Paragraph}"> + <Setter Property="Margin" Value="0"/> + </Style> + </RichTextBox.Resources> + </RichTextBox> + </DockPanel> + + <Grid Grid.Row="2"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="100" /> + </Grid.ColumnDefinitions> + <RichTextBox Name="txtWriteMessage" Margin="5" Background="#FF343434" Foreground="#FFDEDEDE" VerticalScrollBarVisibility="Auto" AcceptsReturn="False" KeyDown="txtWriteMessage_KeyDown"> + <RichTextBox.Resources> + <Style TargetType="{x:Type Paragraph}"> + <Setter Property="Margin" Value="0"/> + </Style> + </RichTextBox.Resources> + </RichTextBox> + <Button Grid.Column="1" Content="Send" Margin="5" FontSize="16" Name="btnSendMessage" Click="btnSendMessage_Click" /> + </Grid> + </Grid> + </Border> + +</UserControl> diff --git a/samples/IrcChatSystem/ChatClientApp/Controls/MessagingAreaControl.xaml.cs b/samples/IrcChatSystem/ChatClientApp/Controls/MessagingAreaControl.xaml.cs new file mode 100644 index 0000000..5b92939 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Controls/MessagingAreaControl.xaml.cs @@ -0,0 +1,469 @@ +using System; +using System.IO; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using Hik.Samples.Scs.IrcChat.Arguments; +using Hik.Samples.Scs.IrcChat.Client; +using Hik.Samples.Scs.IrcChat.Windows; + +namespace Hik.Samples.Scs.IrcChat.Controls +{ + /// <summary> + /// This control is used to show incoming messages and write new messages. + /// </summary> + public partial class MessagingAreaControl : UserControl + { + #region Public Properties + + /// <summary> + /// Reference to the container window of this control. + /// </summary> + public IMessagingAreaContainer MessagingAreaContainer { get; set; } + + /// <summary> + /// This property is used to set messaging area is read only or not. + /// </summary> + public bool IsReadOnly + { + get { return _isReadOnly; } + set + { + _isReadOnly = value; + btnSendMessage.IsEnabled = !_isReadOnly; + txtWriteMessage.IsEnabled = !_isReadOnly; + } + } + private bool _isReadOnly; + + private void SetTextStyleControlsVisibility() + { + if (!IsInitialized) + { + return; + } + spTextStyleChanging.Visibility = _isTextStyleChangingEnabled + ? Visibility.Visible + : Visibility.Collapsed; + } + + /// <summary> + /// This property is used to hide or show text style changing controls. + /// </summary> + public bool IsTextStyleChangingEnabled + { + get { return IsTextStyleChangingEnabled; } + set + { + if (_isTextStyleChangingEnabled == value) + { + return; + } + + _isTextStyleChangingEnabled = value; + SetTextStyleControlsVisibility(); ; + } + } + private bool _isTextStyleChangingEnabled = true; + + #endregion + + #region Constructor and initializing methods + + /// <summary> + /// Constructor. + /// </summary> + public MessagingAreaControl() + { + _userPreferences = UserPreferences.Current; + InitializeComponent(); + InitializeControls(); + InitializeUserPreferences(); + } + + /// <summary> + /// Initializes some controls. + /// </summary> + private void InitializeControls() + { + txtMessageHistory.IsReadOnly = true; + } + + /// <summary> + /// Gets user preferences and initializes controls. + /// </summary> + private void InitializeUserPreferences() + { + lblTextBold.FontWeight = _userPreferences.TextStyle.IsBold ? FontWeights.Bold : FontWeights.Normal; + lblTextColor.FontWeight = lblTextBold.FontWeight; + lblTextItalic.FontWeight = lblTextBold.FontWeight; + txtWriteMessage.FontWeight = lblTextBold.FontWeight; + + lblTextItalic.FontStyle = _userPreferences.TextStyle.IsItalic ? FontStyles.Italic : FontStyles.Normal; + lblTextColor.FontStyle = lblTextItalic.FontStyle; + lblTextBold.FontStyle = lblTextItalic.FontStyle; + txtWriteMessage.FontStyle = lblTextItalic.FontStyle; + + lblTextColor.Foreground = + new SolidColorBrush( + Color.FromRgb( + _userPreferences.TextStyle.TextColor.Red, _userPreferences.TextStyle.TextColor.Green, _userPreferences.TextStyle.TextColor.Blue + )); + lblTextBold.Foreground = lblTextColor.Foreground; + lblTextItalic.Foreground = lblTextColor.Foreground; + txtWriteMessage.Foreground = lblTextColor.Foreground; + + for (var i = 0; i < cmbTextFont.Items.Count; i++) + { + if (((string)((ComboBoxItem)cmbTextFont.Items[i]).Content) == _userPreferences.TextStyle.FontFamily) + { + cmbTextFont.SelectedIndex = i; + break; + } + } + + var textSizeAsString = _userPreferences.TextStyle.TextSize.ToString(); + for (var i = 0; i < cmbTextSize.Items.Count; i++) + { + if (((string)((ComboBoxItem)cmbTextSize.Items[i]).Content) == textSizeAsString) + { + cmbTextSize.SelectedIndex = i; + break; + } + } + + txtWriteMessage.FontFamily = new FontFamily(_userPreferences.TextStyle.FontFamily); + txtWriteMessage.FontSize = _userPreferences.TextStyle.TextSize; + + RefreshSoundPicture(); + } + + #endregion + + #region Private fields + + /// <summary> + /// Reference to the user's text style. + /// </summary> + private readonly UserPreferences _userPreferences; + + #endregion + + #region Public methods + + /// <summary> + /// Adds a new message to message history. + /// </summary> + /// <param name="nick">Nick of sender</param> + /// <param name="message">Message</param> + public void MessageReceived(string nick, ChatMessage message) + { + //Create a new paragraph to write new message + var messageParagraph = new Paragraph(); + + //Set message as Bold if needed + if (message.TextStyle.IsBold) + { + messageParagraph.FontWeight = FontWeights.Bold; + } + + //Set message as Italic if needed + if (message.TextStyle.IsItalic) + { + messageParagraph.FontStyle = FontStyles.Italic; + } + + //Set message font if needed + if (!string.IsNullOrEmpty(message.TextStyle.FontFamily)) + { + try + { + messageParagraph.FontFamily = new FontFamily(message.TextStyle.FontFamily); + } + catch + { + + } + } + + //Set message text size if needed + if (message.TextStyle.TextSize > 0) + { + messageParagraph.FontSize = message.TextStyle.TextSize; + } + + //Set message color if needed + if (message.TextStyle.TextColor != null) + { + messageParagraph.Foreground = + new SolidColorBrush( + new Color + { + A = 255, + R = message.TextStyle.TextColor.Red, + G = message.TextStyle.TextColor.Green, + B = message.TextStyle.TextColor.Blue + }); + } + + //Add message to paragraph + messageParagraph.Inlines.Add(new Run(nick + ": " + message.MessageText)); + + //Add new parapraph to message history + txtMessageHistory.Document.Blocks.Add(messageParagraph); + + if (txtMessageHistory.Document.Blocks.Count > 1000) + { + txtMessageHistory.Document.Blocks.Remove(txtMessageHistory.Document.Blocks.FirstBlock); + } + + txtMessageHistory.ScrollToEnd(); + } + + #endregion + + #region Private methods + + #region Sending message + + /// <summary> + /// Handles Client event of Send button. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void btnSendMessage_Click(object sender, RoutedEventArgs e) + { + SendMessage(); + } + + /// <summary> + /// Handles KeyDown event of txtWriteMessage textbox. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void txtWriteMessage_KeyDown(object sender, KeyEventArgs e) + { + //If user pressed to enter in message sending textbox, send message.. + if (e.Key == Key.Enter) + { + SendMessage(); + } + } + + /// <summary> + /// Sends a message to the room. + /// </summary> + private void SendMessage() + { + string messageText = new TextRange(txtWriteMessage.Document.ContentStart, txtWriteMessage.Document.ContentEnd).Text.Trim(); + if (string.IsNullOrEmpty(messageText) || MessagingAreaContainer == null) + { + return; + } + + try + { + MessagingAreaContainer.SendMessage( + new ChatMessage( + messageText, + _userPreferences.TextStyle + )); + txtWriteMessage.Document.Blocks.Clear(); + txtWriteMessage.Focus(); + } + catch (Exception ex) + { + MessageBox.Show("Can not send message to the server. Error Detail: " + ex.Message, "Error!", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + #endregion + + #region Changing / getting text styles + + /// <summary> + /// Handles MouseLeftButtonUp of txtTextColor and opens a text color picker dialog + /// to select text color. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void lblTextColor_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + var colorPicker = new TextColorPicker(); + if (colorPicker.ShowDialog() == true) + { + _userPreferences.TextStyle.TextColor.Red = colorPicker.SelectedColor.R; + _userPreferences.TextStyle.TextColor.Green = colorPicker.SelectedColor.G; + _userPreferences.TextStyle.TextColor.Blue = colorPicker.SelectedColor.B; + + lblTextColor.Foreground = new SolidColorBrush(colorPicker.SelectedColor); + lblTextBold.Foreground = lblTextColor.Foreground; + lblTextItalic.Foreground = lblTextColor.Foreground; + txtWriteMessage.Foreground = lblTextColor.Foreground; + } + } + + /// <summary> + /// Handles MouseLeftButtonUp event of lblTextBold to change Bold text option. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void lblTextBold_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + lblTextBold.FontWeight = lblTextBold.FontWeight == FontWeights.Normal + ? FontWeights.Bold + : FontWeights.Normal; + + _userPreferences.TextStyle.IsBold = (lblTextBold.FontWeight == FontWeights.Bold); + lblTextColor.FontWeight = lblTextBold.FontWeight; + lblTextItalic.FontWeight = lblTextBold.FontWeight; + txtWriteMessage.FontWeight = lblTextBold.FontWeight; + } + + /// <summary> + /// Handles MouseLeftButtonUp event of lblTextItalic to change Italic text option. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void lblTextItalic_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + lblTextItalic.FontStyle = lblTextItalic.FontStyle == FontStyles.Normal + ? FontStyles.Italic + : FontStyles.Normal; + + _userPreferences.TextStyle.IsItalic = (lblTextItalic.FontStyle == FontStyles.Italic); + lblTextColor.FontStyle = lblTextItalic.FontStyle; + lblTextBold.FontStyle = lblTextItalic.FontStyle; + txtWriteMessage.FontStyle = lblTextItalic.FontStyle; + } + + /// <summary> + /// Handles SelectionChanged event of text font combobox. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void cmbTextFont_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (!IsInitialized) + { + return; + } + + var selectedFont = GetSelectedTextFontFamily(); + if (selectedFont == null) + { + return; + } + + try + { + txtWriteMessage.FontFamily = new FontFamily(selectedFont); + _userPreferences.TextStyle.FontFamily = selectedFont; + } + catch + { + + } + } + + /// <summary> + /// Handles SelectionChanged event of text size combobox. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void cmbTextSize_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (!IsInitialized) + { + return; + } + + var selectedTextSize = GetSelectedTextSize(); + txtWriteMessage.FontSize = selectedTextSize; + _userPreferences.TextStyle.TextSize = selectedTextSize; + } + + /// <summary> + /// Handles MouseLeftButtonUp event of Sound image. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void imgSoundOnOff_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + _userPreferences.IsSoundOn = !_userPreferences.IsSoundOn; + RefreshSoundPicture(); + } + + /// <summary> + /// Gets selected font family. + /// </summary> + /// <returns>Selected font family</returns> + private string GetSelectedTextFontFamily() + { + if (cmbTextFont.SelectedIndex < 0) + { + return null; + } + + var selectedItem = cmbTextFont.SelectedItem as ComboBoxItem; + if (selectedItem == null) + { + return null; + } + + return selectedItem.Content as string; + } + + /// <summary> + /// Gets selected text size. + /// </summary> + /// <returns>Text size</returns> + private int GetSelectedTextSize() + { + try + { + if (cmbTextFont.SelectedIndex < 0) + { + return 12; //Default value + } + + var selectedItem = cmbTextSize.SelectedItem as ComboBoxItem; + if (selectedItem != null) + { + return Convert.ToInt32(selectedItem.Content as string); + } + } + catch + { + + } + + return 12; //Default value + } + + /// <summary> + /// Refreshes sound image according to user preference. + /// </summary> + private void RefreshSoundPicture() + { + var imagePath = _userPreferences.IsSoundOn + ? Path.Combine(ClientHelper.GetCurrentDirectory(), @"Images\sound_on.png") + : Path.Combine(ClientHelper.GetCurrentDirectory(), @"Images\sound_off.png"); + try + { + imgSoundOnOff.Source = new BitmapImage(new Uri(imagePath)); + } + catch + { + + } + } + + #endregion + + #endregion + } +} diff --git a/samples/IrcChatSystem/ChatClientApp/Controls/UserCardControl.xaml b/samples/IrcChatSystem/ChatClientApp/Controls/UserCardControl.xaml new file mode 100644 index 0000000..526d2c7 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Controls/UserCardControl.xaml @@ -0,0 +1,55 @@ +<UserControl x:Class="Hik.Samples.Scs.IrcChat.Controls.UserCardControl" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + mc:Ignorable="d" + d:DesignHeight="60" d:DesignWidth="300"> + <Border Margin="0,0,5,5" Cursor="Hand"> + <Border.Style> + <Style> + <Style.Setters> + <Setter Property="Border.BorderThickness" Value="1"></Setter> + <Setter Property="Border.BorderBrush" Value="#FF878383"></Setter> + <Setter Property="Border.CornerRadius" Value="6"></Setter> + <Setter Property="Border.Background" Value="#FF111111" /> + </Style.Setters> + <Style.Triggers> + <Trigger Property="Border.IsMouseOver" Value="False"> + <Setter Property="Border.Background"> + <Setter.Value> + <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1"> + <GradientStop Offset="0" Color="#FF393939"/> + <GradientStop Offset="1" Color="Black"/> + </LinearGradientBrush> + </Setter.Value> + </Setter> + </Trigger> + <Trigger Property="Border.IsMouseOver" Value="True"> + <Setter Property="Border.Background"> + <Setter.Value> + <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1"> + <GradientStop Offset="0" Color="#FF696767"/> + <GradientStop Offset="1" Color="#FF3B3B3B"/> + </LinearGradientBrush> + </Setter.Value> + </Setter> + </Trigger> + </Style.Triggers> + </Style> + </Border.Style> + <Grid> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="60" /> + <ColumnDefinition Width="*" /> + </Grid.ColumnDefinitions> + <Border Margin="3" Grid.Column="0" BorderThickness="1" Background="#FF272626"> + <Image Stretch="UniformToFill" Source="/ChatClientApp;component/Images/user_male.png" Name="imgAvatar" /> + </Border> + <StackPanel Grid.Column="1"> + <Label Content="User Nick" Foreground="White" Height="Auto" Padding="2" Name="lblNick" Margin="3,1"></Label> + <Label Content="Available" Foreground="#FF2BE400" Padding="2" Name="lblStatus" Margin="3,0"></Label> + </StackPanel> + </Grid> + </Border> +</UserControl> diff --git a/samples/IrcChatSystem/ChatClientApp/Controls/UserCardControl.xaml.cs b/samples/IrcChatSystem/ChatClientApp/Controls/UserCardControl.xaml.cs new file mode 100644 index 0000000..6be6422 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Controls/UserCardControl.xaml.cs @@ -0,0 +1,116 @@ +using System; +using System.IO; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using Hik.Samples.Scs.IrcChat.Arguments; +using Hik.Samples.Scs.IrcChat.Client; + +namespace Hik.Samples.Scs.IrcChat.Controls +{ + /// <summary> + /// This control is used to show a User Card in right area of chat room. + /// </summary> + public partial class UserCardControl : UserControl + { + /// <summary> + /// Gets/sets the of the user. + /// </summary> + public string UserNick + { + get { return lblNick.Content.ToString(); } + set { lblNick.Content = value; } + } + + /// <summary> + /// Sets status of the user. + /// </summary> + public UserStatus UserStatus + { + get { return _userStatus; } + set + { + _userStatus = value; + RefreshStatusLabel(); + } + } + private UserStatus _userStatus; + + /// <summary> + /// Sets avatar image of the user. + /// </summary> + public byte[] AvatarBytes + { + set + { + try + { + ChangeAvatar(value); + } + catch + { + + } + } + } + + /// <summary> + /// Gets ImageSource property of user avatar. + /// </summary> + public ImageSource AvatarImageSource + { + get { return imgAvatar.Source; } + } + + /// <summary> + /// Constructor. + /// </summary> + public UserCardControl() + { + InitializeComponent(); + } + + /// <summary> + /// Refreshes status of user on label according to _userStatus. + /// </summary> + private void RefreshStatusLabel() + { + switch (_userStatus) + { + case UserStatus.Busy: + lblStatus.Content = "Busy"; + lblStatus.Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FFFF4E4E")); + break; + case UserStatus.Out: + lblStatus.Content = "Out"; + lblStatus.Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FF3179FE")); + break; + default: //Default: Available + lblStatus.Content = "Available"; + lblStatus.Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FF2BE400")); + break; + } + } + + /// <summary> + /// Changes avatar image of the user. + /// </summary> + /// <param name="bytesOfAvatar">byte of avatar file</param> + private void ChangeAvatar(byte[] bytesOfAvatar) + { + if (bytesOfAvatar == null) + { + var defaultAvatar = Path.Combine((Path.Combine(ClientHelper.GetCurrentDirectory(), @"Images\user_male.png"))); + imgAvatar.Source = new BitmapImage(new Uri(defaultAvatar)); + return; + } + + //Save bytes into a temporary file + var tempSavePath = Path.GetTempFileName(); + File.WriteAllBytes(tempSavePath, bytesOfAvatar); + + //Change avatar picture. + imgAvatar.Source = new BitmapImage(new Uri(tempSavePath)); + } + } +} diff --git a/samples/IrcChatSystem/ChatClientApp/Images/app_icon.ico b/samples/IrcChatSystem/ChatClientApp/Images/app_icon.ico Binary files differnew file mode 100644 index 0000000..dc5af4a --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Images/app_icon.ico diff --git a/samples/IrcChatSystem/ChatClientApp/Images/sound_off.png b/samples/IrcChatSystem/ChatClientApp/Images/sound_off.png Binary files differnew file mode 100644 index 0000000..7a800f3 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Images/sound_off.png diff --git a/samples/IrcChatSystem/ChatClientApp/Images/sound_on.png b/samples/IrcChatSystem/ChatClientApp/Images/sound_on.png Binary files differnew file mode 100644 index 0000000..7bd29d6 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Images/sound_on.png diff --git a/samples/IrcChatSystem/ChatClientApp/Images/text_color_picker.ico b/samples/IrcChatSystem/ChatClientApp/Images/text_color_picker.ico Binary files differnew file mode 100644 index 0000000..887e3ad --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Images/text_color_picker.ico diff --git a/samples/IrcChatSystem/ChatClientApp/Images/user_female.png b/samples/IrcChatSystem/ChatClientApp/Images/user_female.png Binary files differnew file mode 100644 index 0000000..d47e5a8 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Images/user_female.png diff --git a/samples/IrcChatSystem/ChatClientApp/Images/user_male.png b/samples/IrcChatSystem/ChatClientApp/Images/user_male.png Binary files differnew file mode 100644 index 0000000..f9796d7 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Images/user_male.png diff --git a/samples/IrcChatSystem/ChatClientApp/Properties/AssemblyInfo.cs b/samples/IrcChatSystem/ChatClientApp/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f093c9a --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ChatClientApp")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("ChatClientApp")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file +//inside a <PropertyGroup>. For example, if you are using US english +//in your source files, set the <UICulture> to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/IrcChatSystem/ChatClientApp/Properties/Resources.Designer.cs b/samples/IrcChatSystem/ChatClientApp/Properties/Resources.Designer.cs new file mode 100644 index 0000000..6e3255f --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:4.0.30319.1 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace Hik.Samples.Scs.IrcChat.Properties { + using System; + + + /// <summary> + /// A strongly-typed resource class, for looking up localized strings, etc. + /// </summary> + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// <summary> + /// Returns the cached ResourceManager instance used by this class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Hik.Samples.Scs.IrcChat.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// <summary> + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/samples/IrcChatSystem/ChatClientApp/Properties/Resources.resx b/samples/IrcChatSystem/ChatClientApp/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Properties/Resources.resx @@ -0,0 +1,117 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> +</root>
\ No newline at end of file diff --git a/samples/IrcChatSystem/ChatClientApp/Properties/Settings.Designer.cs b/samples/IrcChatSystem/ChatClientApp/Properties/Settings.Designer.cs new file mode 100644 index 0000000..95c7572 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:4.0.30319.1 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace Hik.Samples.Scs.IrcChat.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/samples/IrcChatSystem/ChatClientApp/Properties/Settings.settings b/samples/IrcChatSystem/ChatClientApp/Properties/Settings.settings new file mode 100644 index 0000000..033d7a5 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Properties/Settings.settings @@ -0,0 +1,7 @@ +<?xml version='1.0' encoding='utf-8'?> +<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)"> + <Profiles> + <Profile Name="(Default)" /> + </Profiles> + <Settings /> +</SettingsFile>
\ No newline at end of file diff --git a/samples/IrcChatSystem/ChatClientApp/Sounds/incoming_message.wav b/samples/IrcChatSystem/ChatClientApp/Sounds/incoming_message.wav Binary files differnew file mode 100644 index 0000000..5e5184e --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Sounds/incoming_message.wav diff --git a/samples/IrcChatSystem/ChatClientApp/Windows/MainWindow.xaml b/samples/IrcChatSystem/ChatClientApp/Windows/MainWindow.xaml new file mode 100644 index 0000000..b24b767 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Windows/MainWindow.xaml @@ -0,0 +1,89 @@ +<Window xmlns:my="clr-namespace:Hik.Samples.Scs.IrcChat.Controls" x:Class="Hik.Samples.Scs.IrcChat.Windows.MainWindow" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + Title="SCS Chat Client" Height="517" Width="885" WindowStyle="SingleBorderWindow" WindowStartupLocation="CenterScreen" Closing="Window_Closing" Loaded="Window_Loaded" Icon="/ChatClientApp;component/Images/app_icon.ico"> + <Grid> + <Grid Background="#FF1F1F1F"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="240" /> + </Grid.ColumnDefinitions> + <my:MessagingAreaControl x:Name="messagingArea" /> + <StackPanel Grid.Column="1" Margin="5"> + <Border Margin="0,0,5,5" Height="80"> + <Border.Background> + <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> + <GradientStop Color="#FF393939" Offset="0" /> + <GradientStop Color="Black" Offset="1" /> + </LinearGradientBrush> + </Border.Background> + <Grid> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="80" /> + <ColumnDefinition Width="*" /> + </Grid.ColumnDefinitions> + <Border Margin="3" Grid.Column="0" BorderThickness="1" Background="#FF272626"> + <Image Stretch="UniformToFill" Name="imgCurrentUserAvatar" /> + </Border> + <StackPanel Grid.Column="1"> + <Label Content="User Nick" Foreground="White" Height="Auto" Padding="2" Name="lblCurrentUserNick" Margin="3,1"></Label> + <ComboBox Name="cmbCurrentUserStatus" Margin="3,1" Background="#FF353535" SelectionChanged="cmbCurrentUserStatus_SelectionChanged" SelectedIndex="0" HorizontalContentAlignment="Left" VerticalContentAlignment="Stretch" IsReadOnly="False" BorderBrush="{x:Null}" Foreground="White" BorderThickness="0"> + <ComboBoxItem HorizontalContentAlignment="Stretch" Background="#FF353535" VerticalContentAlignment="Stretch"> + <Label Content="Available" Foreground="#FF2BE400" /> + </ComboBoxItem> + <ComboBoxItem HorizontalContentAlignment="Stretch" Background="#FF353535" VerticalContentAlignment="Stretch"> + <Label Content="Busy" Foreground="#FFFF4E4E" /> + </ComboBoxItem> + <ComboBoxItem HorizontalContentAlignment="Stretch" Background="#FF353535" VerticalContentAlignment="Stretch"> + <Label Content="Out" Foreground="#FF3179FE" /> + </ComboBoxItem> + </ComboBox> + </StackPanel> + </Grid> + </Border> + <ScrollViewer VerticalScrollBarVisibility="Auto"> + <StackPanel Name="spUsers" > + </StackPanel> + </ScrollViewer> + </StackPanel> + </Grid> + <Grid Background="White" Opacity="0.7" Name="grdConnect"></Grid> + <Border Width="300" Height="115" Padding="2" Name="brdConnect" KeyDown="LoginForm_KeyDown"> + <Grid> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="115" /> + <ColumnDefinition Width="*" /> + </Grid.ColumnDefinitions> + <Border Margin="2" BorderThickness="1" Background="#FF272626"> + <Border.ContextMenu> + <ContextMenu> + <MenuItem Header="Change to male" Click="ChangeToMale_Click" /> + <MenuItem Header="Change to female" Click="ChangeToFemale_Click" /> + <MenuItem Header="Select a picture..." Click="SelectAvatar_Click" /> + </ContextMenu> + </Border.ContextMenu> + <Image Grid.Column="0" Stretch="UniformToFill" Name="imgLoginAvatar" StretchDirection="Both" /> + </Border> + <Grid Grid.Column="1"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="80" /> + <ColumnDefinition Width="*" /> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition Height="26"/> + <RowDefinition Height="26"/> + <RowDefinition Height="26"/> + <RowDefinition Height="*"/> + </Grid.RowDefinitions> + <Label Grid.Column="0" Grid.Row="0" Content="Nick:" Foreground="White" VerticalContentAlignment="Center" HorizontalContentAlignment="Right" FontWeight="Bold" /> + <Label Grid.Column="0" Grid.Row="1" Content="Server IP:" Foreground="White" VerticalContentAlignment="Center" HorizontalContentAlignment="Right" FontWeight="Normal" /> + <Label Grid.Column="0" Grid.Row="2" Content="Server Port:" Foreground="White" VerticalContentAlignment="Center" HorizontalContentAlignment="Right" FontWeight="Normal" /> + <TextBox Grid.Column="1" Grid.Row="0" Margin="2" Text="User Nick" FontWeight="Bold" VerticalContentAlignment="Center" Name="txtNick" TextChanged="txtNick_TextChanged"></TextBox> + <TextBox Grid.Column="1" Grid.Row="1" Margin="2" Text="127.0.0.1" VerticalContentAlignment="Center" Name="txtServerIpAddress"></TextBox> + <TextBox Grid.Column="1" Grid.Row="2" Margin="2" Text="10048" VerticalContentAlignment="Center" Name="txtServerPort"></TextBox> + <Button Grid.Column="1" Content="Login" Grid.Row="3" Margin="2" FontSize="15" FontWeight="Bold" Name="btnLogin" Click="btnLogin_Click" /> + </Grid> + </Grid> + </Border> + </Grid> +</Window> diff --git a/samples/IrcChatSystem/ChatClientApp/Windows/MainWindow.xaml.cs b/samples/IrcChatSystem/ChatClientApp/Windows/MainWindow.xaml.cs new file mode 100644 index 0000000..3451da8 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Windows/MainWindow.xaml.cs @@ -0,0 +1,699 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Interop; +using System.Windows.Media.Imaging; +using Hik.Samples.Scs.IrcChat.Arguments; +using Hik.Samples.Scs.IrcChat.Client; +using Hik.Samples.Scs.IrcChat.Controls; +using Microsoft.Win32; + +namespace Hik.Samples.Scs.IrcChat.Windows +{ + /// <summary> + /// Interaction logic for MainWindow.xaml + /// </summary> + public partial class MainWindow : Window, IChatRoomView, ILoginFormView, IMessagingAreaContainer + { + #region ILoginFormView implementation + + /// <summary> + /// IP address of server to be connected. + /// </summary> + public string ServerIpAddress + { + get + { + return (string)Dispatcher.Invoke(new Func<string>(() => txtServerIpAddress.Text)); + } + } + + /// <summary> + /// TCP Port number of server to be connected. + /// </summary> + public int ServerTcpPort + { + get + { + return (int)Dispatcher.Invoke(new Func<int>(() => Convert.ToInt32(txtServerPort.Text))); + } + } + + /// <summary> + /// User Login informations to be used while logging on to the server. + /// </summary> + public UserInfo CurrentUserInfo + { + get + { + return (UserInfo)Dispatcher.Invoke( + new Func<UserInfo>(() => new UserInfo + { + Nick = txtNick.Text, + Status = UserStatus.Available, + AvatarBytes = GetBytesOfCurrentUserAvatar() + })); + } + } + + #endregion + + #region IChatRoomView implementation + + /// <summary> + /// This method is called when a message is sent to chat room. + /// </summary> + /// <param name="nick">Nick of sender</param> + /// <param name="message">Message</param> + public void OnMessageReceived(string nick, ChatMessage message) + { + Dispatcher.Invoke(new Action(() => messagingArea.MessageReceived(nick, message))); + } + + /// <summary> + /// This method is called when a private message is sent to the current user. + /// </summary> + /// <param name="nick">Nick of sender</param> + /// <param name="message">The message</param> + public void OnPrivateMessageReceived(string nick, ChatMessage message) + { + Dispatcher.Invoke(new Action(() => OnPrivateMessageReceivedInternal(nick, message))); + } + + /// <summary> + /// This method is called when user successfully logged in to chat server. + /// </summary> + public void OnLoggedIn() + { + Dispatcher.Invoke(new Action(OnLoggedInInternal)); + } + + /// <summary> + /// This method is used to inform view if login is failed. + /// </summary> + /// <param name="errorMessage">Detail of error</param> + public void OnLoginError(string errorMessage) + { + MessageBox.Show(errorMessage, "Login Error!", MessageBoxButton.OK, MessageBoxImage.Error); + } + + /// <summary> + /// This method is called when connection to server is closed. + /// </summary> + public void OnLoggedOut() + { + Dispatcher.Invoke(new Action(OnLoggedOutInternal)); + } + + /// <summary> + /// This methos is used to add a new user to user list in room view. + /// </summary> + /// <param name="userInfo">Informations of new user</param> + public void AddUserToList(UserInfo userInfo) + { + Dispatcher.Invoke(new Action(() => AddUserToListInternal(userInfo))); + } + + /// <summary> + /// This metrhod is used to remove a user (that is disconnected from server) from user list in room view. + /// </summary> + /// <param name="nick">Nick of user to remove</param> + public void RemoveUserFromList(string nick) + { + Dispatcher.Invoke(new Action(() => RemoveUserFromListInternal(nick))); + } + + /// <summary> + /// This method is called from chat server to inform that a user changed his/her status. + /// </summary> + /// <param name="nick">Nick of the user</param> + /// <param name="newStatus">New status of the user</param> + public void OnUserStatusChange(string nick, UserStatus newStatus) + { + Dispatcher.Invoke(new Action(() => OnUserStatusChangeInternal(nick, newStatus))); + } + + #endregion + + #region IMessagingAreaContainer implementation + + /// <summary> + /// Sends a message to the room. + /// </summary> + public void SendMessage(ChatMessage message) + { + _controller.SendMessageToRoom(message); + } + + #endregion + + #region Private fields + + /// <summary> + /// Reference to the controller object. + /// </summary> + private readonly IChatController _controller; + + /// <summary> + /// List of open private chat windows. + /// </summary> + private readonly SortedList<string, PrivateChatWindow> _privateChatWindows; + + /// <summary> + /// Reference to the user preferences. + /// </summary> + private readonly UserPreferences _userPreferences; + + #endregion + + #region Constructor and Initialize methods + + /// <summary> + /// Creates a new form with a reference to the controller object. + /// </summary> + /// <param name="controller">Reference to the controller object</param> + public MainWindow(IChatController controller) + { + _controller = controller; + _privateChatWindows = new SortedList<string, PrivateChatWindow>(); + _userPreferences = UserPreferences.Current; + + InitializeComponent(); + InitializeControls(); + } + + /// <summary> + /// Initializes some controls. + /// </summary> + private void InitializeControls() + { + messagingArea.MessagingAreaContainer = this; + txtNick.Text = _userPreferences.Nick; + txtServerIpAddress.Text = _userPreferences.ServerIpAddress; + txtServerPort.Text = _userPreferences.ServerTcpPort.ToString(); + InitializeUserAvatar(); + } + + /// <summary> + /// Initializes and shows user avatar. + /// </summary> + private void InitializeUserAvatar() + { + try + { + ChangeCurrentUserAvatar(_userPreferences.AvatarFile); + } + catch (Exception ex) + { + MessageBox.Show("Can not load avatar image. Error Detail: " + ex.Message, "Error!", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + #endregion + + #region Handlers for events of window and controls + + /// <summary> + /// Handles Loaded event of this Window. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void Window_Loaded(object sender, RoutedEventArgs e) + { + txtNick.Focus(); + txtNick.SelectAll(); + } + + /// <summary> + /// Hansles Closing event of this window. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) + { + _userPreferences.Save(); + _controller.Disconnect(); + } + + /// <summary> + /// Handles TextChanged event of txtNick (on login screen). + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void txtNick_TextChanged(object sender, TextChangedEventArgs e) + { + lblCurrentUserNick.Content = txtNick.Text; + } + + /// <summary> + /// Handles Click event of 'Change to female' right menu item of avatar menu. + /// Changes login avatar to default female avatar. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void ChangeToFemale_Click(object sender, RoutedEventArgs e) + { + try + { + ChangeCurrentUserAvatar(Path.Combine(ClientHelper.GetCurrentDirectory(), @"Images\user_female.png")); + } + catch (Exception ex) + { + MessageBox.Show("Can not load avatar image. Error Detail: " + ex.Message, "Error!", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + /// <summary> + /// Handles Click event of 'Change to male' right menu item of avatar menu. + /// Changes login avatar to default male avatar. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void ChangeToMale_Click(object sender, RoutedEventArgs e) + { + try + { + ChangeCurrentUserAvatar(Path.Combine(ClientHelper.GetCurrentDirectory(), @"Images\user_male.png")); + } + catch (Exception ex) + { + MessageBox.Show("Can not load avatar image. Error Detail: " + ex.Message, "Error!", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + /// <summary> + /// Handles Click event of 'Select a picture...' menu item. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void SelectAvatar_Click(object sender, RoutedEventArgs e) + { + try + { + var avatarSelectDialog = new OpenFileDialog(); + avatarSelectDialog.Filter = "JPG Files|*.jpg|JPEG Files|*.jpeg|GIF Files|*.gif|PNG files|*.png|BMP Files|*.bmp"; + if (avatarSelectDialog.ShowDialog() == true) + { + var selectedFile = avatarSelectDialog.FileName; + if (ClientHelper.GetFileSize(selectedFile) > (100 * 1024)) + { + MessageBox.Show("You can not select avatar file larger than 100 KB.", "Warning!", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + + ChangeCurrentUserAvatar(selectedFile); + } + } + catch (Exception ex) + { + MessageBox.Show("Can not load avatar image. Error Detail: " + ex.Message, "Error!", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + /// <summary> + /// Handles Client event of Login button. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void btnLogin_Click(object sender, RoutedEventArgs e) + { + ConnectToServer(); + } + + /// <summary> + /// Handles KeyDown of Login form (actually the Border named brdConnect that contains login controls) + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void LoginForm_KeyDown(object sender, KeyEventArgs e) + { + //If user pressed to enter in login form, connect to server + if (e.Key == Key.Enter) + { + ConnectToServer(); + } + } + + /// <summary> + /// Handles SelectionChanged event of user status combobox + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void cmbCurrentUserStatus_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (!IsInitialized || cmbCurrentUserStatus.SelectedIndex < 0 || _controller == null) + { + return; + } + + try + { + var newStatus = GetCurrentUserStatus(); + + _controller.ChangeStatus(newStatus); + + //Change user's status on all open private chat windows + foreach (var chatWindow in _privateChatWindows.Values.ToList()) + { + chatWindow.CurrentUserStatus = newStatus; + } + } + catch (Exception ex) + { + MessageBox.Show("Can not changes status. Error Detail: " + ex.Message, "Error!", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + /// <summary> + /// Handles MouseDoubleClick event of all User cards. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void UserCard_MouseDoubleClick(object sender, MouseButtonEventArgs e) + { + if (e.ChangedButton != MouseButton.Left) + { + return; + } + + var userCard = e.Source as UserCardControl; + if (userCard == null) + { + return; + } + + if (_privateChatWindows.ContainsKey(userCard.UserNick)) + { + _privateChatWindows[userCard.UserNick].Activate(); + } + else + { + _privateChatWindows[userCard.UserNick] = CreatePrivateChatWindow(userCard); + } + } + + /// <summary> + /// Handles Closed event of Private chat windows. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void PrivateChatWindow_Closed(object sender, EventArgs e) + { + var privateChatWindow = sender as PrivateChatWindow; + if (privateChatWindow == null) + { + return; + } + + if (_privateChatWindows.ContainsKey(privateChatWindow.RemoteUserNick)) + { + _privateChatWindows.Remove(privateChatWindow.RemoteUserNick); + } + } + + #endregion + + #region Private methods + + /// <summary> + /// Connects to the server. + /// This method is called on login. + /// </summary> + private void ConnectToServer() + { + if(string.IsNullOrEmpty(txtNick.Text)) + { + MessageBox.Show("You must enter a nick to login to server.", "Warning!", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + + if (string.IsNullOrEmpty(txtServerIpAddress.Text)) + { + MessageBox.Show("You must enter IP address to connect to server.", "Warning!", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + + if (string.IsNullOrEmpty(txtServerPort.Text)) + { + MessageBox.Show("You must enter TCP port to connect to server.", "Warning!", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + + try + { + _controller.Connect(); + _userPreferences.Nick = txtNick.Text; + _userPreferences.ServerIpAddress = txtServerIpAddress.Text; + try { _userPreferences.ServerTcpPort = Convert.ToInt32(txtServerPort.Text); } catch { } + _userPreferences.Save(); + } + catch (Exception ex) + { + MessageBox.Show("Can not connected to the server. Check Server IP and port. Error Detail: " + ex.Message, "Error!", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + /// <summary> + /// This method is used to hide Login form when user succussfully logged into server. + /// </summary> + private void OnLoggedInInternal() + { + grdConnect.Visibility = Visibility.Collapsed; + brdConnect.Visibility = Visibility.Collapsed; + } + + /// <summary> + /// This method is used to show Login form when connection to server is broken/closed. + /// </summary> + private void OnLoggedOutInternal() + { + foreach (var privateChatWindow in _privateChatWindows.Values.ToList()) + { + privateChatWindow.Close(); + } + + spUsers.Children.Clear(); + grdConnect.Visibility = Visibility.Visible; + brdConnect.Visibility = Visibility.Visible; + } + + /// <summary> + /// This method is used to send private message to proper private messaging window. + /// </summary> + /// <param name="nick">Nick of sender</param> + /// <param name="message">Message</param> + private void OnPrivateMessageReceivedInternal(string nick, ChatMessage message) + { + var userCard = FindUserInList(nick); + if (userCard == null) + { + return; + } + + if (!_privateChatWindows.ContainsKey(nick)) + { + //Create new private chat window + _privateChatWindows[nick] = CreatePrivateChatWindow(userCard); + + //Set initial state as minimized + _privateChatWindows[nick].WindowState = WindowState.Minimized; + + //Flash the window button on taskbar to inform user + WindowsHelper.FlashWindow(new WindowInteropHelper(_privateChatWindows[nick]).Handle, WindowsHelper.FlashWindowFlags.FLASHW_ALL, 2, 1000); + } + + _privateChatWindows[nick].MessageReceived(message); + } + + /// <summary> + /// Creates a new PrivateChatWindow from a user card. + /// </summary> + /// <param name="userCard">User card to use while creating window</param> + /// <returns>Created window</returns> + private PrivateChatWindow CreatePrivateChatWindow(UserCardControl userCard) + { + var window = new PrivateChatWindow(_controller) + { + CurrentUserNick = txtNick.Text, + CurrentUserStatus = GetCurrentUserStatus(), + CurrentUserAvatar = imgCurrentUserAvatar.Source, + RemoteUserNick = userCard.UserNick, + RemoteUserStatus = userCard.UserStatus, + RemoteUserAvatar = userCard.AvatarImageSource + }; + window.Closed += PrivateChatWindow_Closed; + window.Show(); + return window; + } + + /// <summary> + /// Adds user to user list in right area of the window. + /// </summary> + /// <param name="userInfo">New user informations</param> + private void AddUserToListInternal(UserInfo userInfo) + { + //Do not add the current user (that is using the application) to user list + if (userInfo.Nick == CurrentUserInfo.Nick) + { + return; + } + + //Do not add user to list if it is already exists. + if (FindUserInList(userInfo.Nick) != null) + { + return; + } + + //Find correct order (by name) to insert the user + var orderedIndex = 0; + foreach (UserCardControl userCardControl in spUsers.Children) + { + if (userInfo.Nick.CompareTo(userCardControl.UserNick) < 0) + { + break; + } + orderedIndex++; + } + + //Create user control + var userCard = new UserCardControl + { + UserNick = userInfo.Nick, + UserStatus = userInfo.Status, + AvatarBytes = userInfo.AvatarBytes, + Height = 60 + }; + userCard.MouseDoubleClick += UserCard_MouseDoubleClick; + + //Insert user to user list + spUsers.Children.Insert( + orderedIndex, + userCard + ); + + //Enable private messaging window if any open with that user + if (_privateChatWindows.ContainsKey(userInfo.Nick)) + { + _privateChatWindows[userInfo.Nick].UserLoggedIn(); + _privateChatWindows[userInfo.Nick].RemoteUserStatus = userInfo.Status; + _privateChatWindows[userInfo.Nick].RemoteUserAvatar = userCard.AvatarImageSource; + } + } + + /// <summary> + /// Removes an existing user from user list. + /// </summary> + /// <param name="nick"></param> + private void RemoveUserFromListInternal(string nick) + { + //Enable private messaging window is any open with that user + if (_privateChatWindows.ContainsKey(nick)) + { + _privateChatWindows[nick].UserLoggedOut(); + } + + //Find user in list + var userCard = FindUserInList(nick); + + //Remove if found + if (userCard != null) + { + spUsers.Children.Remove(userCard); + userCard.MouseDoubleClick -= UserCard_MouseDoubleClick; + } + } + + /// <summary> + /// Changes status of a user in user list. + /// </summary> + /// <param name="nick">Nick of the user</param> + /// <param name="newStatus">New status of the user</param> + public void OnUserStatusChangeInternal(string nick, UserStatus newStatus) + { + //Find user in list + var userCard = FindUserInList(nick); + + //Change status of user if found + if (userCard != null) + { + userCard.UserStatus = newStatus; + } + + //Change status of user if any private chat window is open + if (_privateChatWindows.ContainsKey(nick)) + { + _privateChatWindows[nick].RemoteUserStatus = newStatus; + } + } + + /// <summary> + /// Searches a user (by nick) in user list and gets user card control of user. + /// </summary> + /// <param name="nick">Nick to search</param> + /// <returns>Found user card of user</returns> + private UserCardControl FindUserInList(string nick) + { + return spUsers.Children.Cast<UserCardControl>().FirstOrDefault(userCardControl => userCardControl.UserNick == nick); + } + + /// <summary> + /// Changes avatar of the current user by a file. + /// </summary> + /// <param name="avatarPath">File path of new avatar</param> + private void ChangeCurrentUserAvatar(string avatarPath) + { + imgLoginAvatar.Source = new BitmapImage(new Uri(avatarPath)); + imgCurrentUserAvatar.Source = imgLoginAvatar.Source; + _userPreferences.AvatarFile = avatarPath; + } + + /// <summary> + /// Gets status of the current user from combobox. + /// </summary> + /// <returns>Status of current user</returns> + private UserStatus GetCurrentUserStatus() + { + switch (cmbCurrentUserStatus.SelectedIndex) + { + case 0: + return UserStatus.Available; + case 1: + return UserStatus.Busy; + default: + return UserStatus.Out; + } + } + + /// <summary> + /// Gets bytes of current user avatar. + /// </summary> + /// <returns>Bytes of user avatar file</returns> + private byte[] GetBytesOfCurrentUserAvatar() + { + if (string.IsNullOrEmpty(_userPreferences.AvatarFile)) + { + return null; + } + + try + { + if (!File.Exists(_userPreferences.AvatarFile)) + { + return null; + } + + return File.ReadAllBytes(_userPreferences.AvatarFile); + } + catch (Exception) + { + return null; + } + } + + #endregion + } +} diff --git a/samples/IrcChatSystem/ChatClientApp/Windows/PrivateChatWindow.xaml b/samples/IrcChatSystem/ChatClientApp/Windows/PrivateChatWindow.xaml new file mode 100644 index 0000000..83dfd27 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Windows/PrivateChatWindow.xaml @@ -0,0 +1,29 @@ +<Window xmlns:my="clr-namespace:Hik.Samples.Scs.IrcChat.Controls" x:Class="Hik.Samples.Scs.IrcChat.Windows.PrivateChatWindow" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + Title="Remote User Nick" Height="441" Width="555" Icon="/ChatClientApp;component/Images/app_icon.ico"> + <Grid Background="#FF1F1F1F"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="115" /> + </Grid.ColumnDefinitions> + <my:MessagingAreaControl x:Name="MessageHistory" /> + <Grid Grid.Column="1"> + <Grid.RowDefinitions> + <RowDefinition Height="115" /> + <RowDefinition Height="32"/> + <RowDefinition Height="*" /> + <RowDefinition Height="32"/> + <RowDefinition Height="115" /> + </Grid.RowDefinitions> + <Border Margin="5" BorderThickness="1" Background="#FF272626"> + <Image Grid.Row="0" Stretch="UniformToFill" Name="imgRemoteUserAvatar" StretchDirection="Both" /> + </Border> + <Label Grid.Row="1" Content="Available" Foreground="#FF2BE400" Padding="1" Name="lblRemoteUserStatus" HorizontalContentAlignment="Left" VerticalAlignment="Top" Margin="5,1"></Label> + <Label Grid.Row="3" Content="Available" Foreground="#FF2BE400" Padding="1" Name="lblCurrentUserStatus" HorizontalContentAlignment="Left" VerticalAlignment="Bottom" Margin="5,1"></Label> + <Border Grid.Row="4" Margin="5" BorderThickness="1" Background="#FF272626"> + <Image Stretch="UniformToFill" Name="imgCurrentUserAvatar" StretchDirection="Both" /> + </Border> + </Grid> + </Grid> +</Window> diff --git a/samples/IrcChatSystem/ChatClientApp/Windows/PrivateChatWindow.xaml.cs b/samples/IrcChatSystem/ChatClientApp/Windows/PrivateChatWindow.xaml.cs new file mode 100644 index 0000000..c801d54 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Windows/PrivateChatWindow.xaml.cs @@ -0,0 +1,190 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Interop; +using System.Windows.Media; +using Hik.Samples.Scs.IrcChat.Arguments; +using Hik.Samples.Scs.IrcChat.Client; +using Hik.Samples.Scs.IrcChat.Controls; + +namespace Hik.Samples.Scs.IrcChat.Windows +{ + /// <summary> + /// Interaction logic for PrivateChatWindow.xaml + /// </summary> + public partial class PrivateChatWindow : Window, IMessagingAreaContainer + { + #region Public properties + + /// <summary> + /// Nick of the current user. + /// </summary> + public string CurrentUserNick { set; get; } + + /// <summary> + /// Sets the status of the current user. + /// </summary> + public UserStatus CurrentUserStatus + { + set { SetStatus(lblCurrentUserStatus, value); } + } + + /// <summary> + /// Sets the avatar picture of current user. + /// </summary> + public ImageSource CurrentUserAvatar + { + set { imgCurrentUserAvatar.Source = value; } + } + + /// <summary> + /// Gets/Sets the nick of the remote user. + /// </summary> + public string RemoteUserNick + { + set + { + _remoteUserNick = value; + Title = _remoteUserNick; + } + + get { return _remoteUserNick; } + } + private string _remoteUserNick; + + /// <summary> + /// Sets the status of the remote user. + /// </summary> + public UserStatus RemoteUserStatus + { + set + { + _remoteUserStatus = value; + SetStatus(lblRemoteUserStatus, _remoteUserStatus); + } + } + private UserStatus _remoteUserStatus; + + /// <summary> + /// Sets the avatar picture of the remote user. + /// </summary> + public ImageSource RemoteUserAvatar + { + set { imgRemoteUserAvatar.Source = value; } + } + + #endregion + + #region Private fields + + /// <summary> + /// Reference to chat controller to send private messages to remote user. + /// </summary> + private readonly IChatController _controller; + + /// <summary> + /// WindowInteropHelper object that is used to get a Handle to this window. + /// </summary> + private readonly WindowInteropHelper _windowInteropHelper; + + #endregion + + #region Contructor and initializing methods + + /// <summary> + /// Constructor. + /// </summary> + /// <param name="controller">Reference to chat controller to send private messages to remote user</param> + public PrivateChatWindow(IChatController controller) + { + _controller = controller; + _windowInteropHelper = new WindowInteropHelper(this); + InitializeComponent(); + InitializeControls(); + } + + private void InitializeControls() + { + MessageHistory.MessagingAreaContainer = this; + MessageHistory.IsTextStyleChangingEnabled = false; + } + + #endregion + + #region Public methods + + /// <summary> + /// This method is used to add a new message to message history of that window. + /// </summary> + /// <param name="message">Message</param> + public void MessageReceived(ChatMessage message) + { + MessageHistory.MessageReceived(_remoteUserNick, message); + if (!IsActive) + { + //Flash taskbar button if this window is not active + WindowsHelper.FlashWindow(_windowInteropHelper.Handle, WindowsHelper.FlashWindowFlags.FLASHW_TRAY, 1, 1000); + ClientHelper.PlayIncomingMessageSound(); + } + } + + /// <summary> + /// This method is called when remote user has logged off. + /// </summary> + public void UserLoggedOut() + { + Title = RemoteUserNick + " - offline"; + MessageHistory.IsReadOnly = true; + lblRemoteUserStatus.Content = "Offline"; + lblRemoteUserStatus.Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FFDDDDDD")); + } + + /// <summary> + /// This method is called when remote user has logged in again. + /// </summary> + public void UserLoggedIn() + { + Title = RemoteUserNick; + MessageHistory.IsReadOnly = false; + } + + /// <summary> + /// This method is called by MessagingAreaControl to send messages. + /// </summary> + /// <param name="message">Message to be sent</param> + public void SendMessage(ChatMessage message) + { + _controller.SendPrivateMessage(RemoteUserNick, message); + MessageHistory.MessageReceived(CurrentUserNick, message); + } + + #endregion + + #region Private methods + + /// <summary> + /// Sets status of a user to a label. + /// </summary> + /// <param name="statusLabel">Label to show user status</param> + /// <param name="status">New status of the user</param> + private static void SetStatus(Label statusLabel, UserStatus status) + { + switch (status) + { + case UserStatus.Busy: + statusLabel.Content = "Busy"; + statusLabel.Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FFFF4E4E")); + break; + case UserStatus.Out: + statusLabel.Content = "Out"; + statusLabel.Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FF3179FE")); + break; + default: //Default: Available + statusLabel.Content = "Available"; + statusLabel.Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FF2BE400")); + break; + } + } + + #endregion + } +} diff --git a/samples/IrcChatSystem/ChatClientApp/Windows/TextColorPicker.xaml b/samples/IrcChatSystem/ChatClientApp/Windows/TextColorPicker.xaml new file mode 100644 index 0000000..ee16d2c --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Windows/TextColorPicker.xaml @@ -0,0 +1,25 @@ +<Window x:Class="Hik.Samples.Scs.IrcChat.Windows.TextColorPicker" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + Title="Select text color" Height="211" Width="339" Icon="/ChatClientApp;component/Images/text_color_picker.ico"> + <Grid Background="#FF606060"> + <Grid.RowDefinitions> + <RowDefinition Height="*"/> + <RowDefinition Height="*"/> + <RowDefinition Height="*"/> + <RowDefinition Height="*"/> + </Grid.RowDefinitions> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="*" /> + </Grid.ColumnDefinitions> + <Label Background="#FF343434" Grid.Column="0" Grid.Row="0" Content="Sample text" Foreground="White" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Margin="1" Padding="3" MouseLeftButtonUp="Label_MouseLeftButtonUp" /> + <Label Background="#FF343434" Grid.Column="1" Grid.Row="0" Content="Sample text" Foreground="#FFFF5C5C" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Margin="1" Padding="3" MouseLeftButtonUp="Label_MouseLeftButtonUp" /> + <Label Background="#FF343434" Grid.Column="0" Grid.Row="1" Content="Sample text" Foreground="#FF3EA2FF" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Margin="1" Padding="3" MouseLeftButtonUp="Label_MouseLeftButtonUp" /> + <Label Background="#FF343434" Grid.Column="1" Grid.Row="1" Content="Sample text" Foreground="#FFEAFE44" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Margin="1" Padding="3" MouseLeftButtonUp="Label_MouseLeftButtonUp" /> + <Label Background="#FF343434" Grid.Column="0" Grid.Row="2" Content="Sample text" Foreground="Lime" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Margin="1" Padding="3" MouseLeftButtonUp="Label_MouseLeftButtonUp" /> + <Label Background="#FF343434" Grid.Column="1" Grid.Row="2" Content="Sample text" Foreground="#FFFF41FA" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Margin="1" Padding="3" MouseLeftButtonUp="Label_MouseLeftButtonUp" /> + <Label Background="#FF343434" Grid.Column="0" Grid.Row="3" Content="Sample text" Foreground="#FF47F1E9" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Margin="1" Padding="3" MouseLeftButtonUp="Label_MouseLeftButtonUp" /> + <Label Background="#FF343434" Grid.Column="1" Grid.Row="3" Content="Sample text" Foreground="#FFFFBA41" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Margin="1" Padding="3" MouseLeftButtonUp="Label_MouseLeftButtonUp" /> + </Grid> +</Window> diff --git a/samples/IrcChatSystem/ChatClientApp/Windows/TextColorPicker.xaml.cs b/samples/IrcChatSystem/ChatClientApp/Windows/TextColorPicker.xaml.cs new file mode 100644 index 0000000..5ff4374 --- /dev/null +++ b/samples/IrcChatSystem/ChatClientApp/Windows/TextColorPicker.xaml.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +namespace Hik.Samples.Scs.IrcChat.Windows +{ + /// <summary> + /// Interaction logic for ColorPicker.xaml + /// </summary> + public partial class TextColorPicker : Window + { + public Color SelectedColor { get; private set; } + + public TextColorPicker() + { + InitializeComponent(); + } + + private void Label_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + var selectedLabel = sender as Label; + if (selectedLabel == null) + { + return; + } + + var brush = selectedLabel.Foreground as SolidColorBrush; + if(brush == null) + { + return; + } + + SelectedColor = brush.Color; + + DialogResult = true; + } + } +} diff --git a/samples/IrcChatSystem/ChatCommonLib/ChatCommonLib.csproj b/samples/IrcChatSystem/ChatCommonLib/ChatCommonLib.csproj new file mode 100644 index 0000000..ff95d88 --- /dev/null +++ b/samples/IrcChatSystem/ChatCommonLib/ChatCommonLib.csproj @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{A57047DE-CC39-4C01-955E-D73888A0C83D}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>Hik.Samples.Scs</RootNamespace> + <AssemblyName>ChatCommonLib</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <DocumentationFile>bin\Debug\ChatCommonLib.XML</DocumentationFile> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <DocumentationFile>bin\Release\ChatCommonLib.XML</DocumentationFile> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="IrcChat\Arguments\ChatMessage.cs" /> + <Compile Include="IrcChat\Arguments\MessageTextStyle.cs" /> + <Compile Include="IrcChat\Exceptions\NickInUseException.cs" /> + <Compile Include="IrcChat\Arguments\UserStatus.cs" /> + <Compile Include="IrcChat\Contracts\IChatClient.cs" /> + <Compile Include="IrcChat\Contracts\IChatService.cs" /> + <Compile Include="IrcChat\Arguments\UserInfo.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/samples/IrcChatSystem/ChatCommonLib/IrcChat/Arguments/ChatMessage.cs b/samples/IrcChatSystem/ChatCommonLib/IrcChat/Arguments/ChatMessage.cs new file mode 100644 index 0000000..3fe595e --- /dev/null +++ b/samples/IrcChatSystem/ChatCommonLib/IrcChat/Arguments/ChatMessage.cs @@ -0,0 +1,51 @@ +using System; + +namespace Hik.Samples.Scs.IrcChat.Arguments +{ + /// <summary> + /// Represents a chat message that can be sent and received by chat users. + /// </summary> + [Serializable] + public class ChatMessage + { + /// <summary> + /// Message text. + /// </summary> + public string MessageText { get; set; } + + ///<summary> + /// Text style of this message. + ///</summary> + public MessageTextStyle TextStyle { get; set; } + + /// <summary> + /// Creates a new ChatMessage. + /// </summary> + public ChatMessage() + { + TextStyle = new MessageTextStyle(); + MessageText = ""; + } + + /// <summary> + /// Creates a new ChatMessage. + /// </summary> + /// <param name="messageText">Message text</param> + public ChatMessage(string messageText) + { + TextStyle = new MessageTextStyle(); + MessageText = messageText; + } + + /// <summary> + /// Creates a new ChatMessage. + /// </summary> + /// <param name="messageText">Message text</param> + /// <param name="textStyle">Text style of this message</param> + public ChatMessage(string messageText, MessageTextStyle textStyle) + { + TextStyle = textStyle; + MessageText = messageText; + } + } +}
\ No newline at end of file diff --git a/samples/IrcChatSystem/ChatCommonLib/IrcChat/Arguments/MessageTextStyle.cs b/samples/IrcChatSystem/ChatCommonLib/IrcChat/Arguments/MessageTextStyle.cs new file mode 100644 index 0000000..4467c22 --- /dev/null +++ b/samples/IrcChatSystem/ChatCommonLib/IrcChat/Arguments/MessageTextStyle.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Hik.Samples.Scs.IrcChat.Arguments +{ + /// <summary> + /// Represents text style of messages. + /// </summary> + [Serializable] + public class MessageTextStyle + { + /// <summary> + /// True, if message is sent as Bold. + /// </summary> + public bool IsBold { get; set; } + + /// <summary> + /// True, if message is sent as italic. + /// </summary> + public bool IsItalic { get; set; } + + /// <summary> + /// Font family of message. + /// </summary> + public string FontFamily { get; set; } + + /// <summary> + /// Message text color. + /// </summary> + public Color TextColor { get; set; } + + /// <summary> + /// Size of message text. + /// </summary> + public int TextSize { get; set; } + + /// <summary> + /// Constructor. + /// </summary> + public MessageTextStyle() + { + FontFamily = "Verdana"; + TextColor = new Color {Blue = 255, Green = 255, Red = 255}; + TextSize = 12; + } + + /// <summary> + /// Represents a color. + /// </summary> + [Serializable] + public class Color + { + /// <summary> + /// Red value of color. + /// </summary> + public byte Red { get; set; } + + /// <summary> + /// Green value of color. + /// </summary> + public byte Green { get; set; } + + /// <summary> + /// Blue value of color. + /// </summary> + public byte Blue { get; set; } + } + } +} diff --git a/samples/IrcChatSystem/ChatCommonLib/IrcChat/Arguments/UserInfo.cs b/samples/IrcChatSystem/ChatCommonLib/IrcChat/Arguments/UserInfo.cs new file mode 100644 index 0000000..c228e8b --- /dev/null +++ b/samples/IrcChatSystem/ChatCommonLib/IrcChat/Arguments/UserInfo.cs @@ -0,0 +1,27 @@ +using System; + +namespace Hik.Samples.Scs.IrcChat.Arguments +{ + /// <summary> + /// Represents a chat user. + /// This object particularly used in Login of a user. + /// </summary> + [Serializable] + public class UserInfo + { + /// <summary> + /// Nick of user. + /// </summary> + public string Nick { get; set; } + + /// <summary> + /// Bytes of avatar of user. + /// </summary> + public byte[] AvatarBytes { get; set; } + + /// <summary> + /// Status of user. + /// </summary> + public UserStatus Status { get; set; } + } +} diff --git a/samples/IrcChatSystem/ChatCommonLib/IrcChat/Arguments/UserStatus.cs b/samples/IrcChatSystem/ChatCommonLib/IrcChat/Arguments/UserStatus.cs new file mode 100644 index 0000000..2644f62 --- /dev/null +++ b/samples/IrcChatSystem/ChatCommonLib/IrcChat/Arguments/UserStatus.cs @@ -0,0 +1,23 @@ +namespace Hik.Samples.Scs.IrcChat.Arguments +{ + /// <summary> + /// Represents state of a chat user. + /// </summary> + public enum UserStatus + { + /// <summary> + /// User if online and available for incoming messages. + /// </summary> + Available, + + /// <summary> + /// User is busy and may not answer to messages. + /// </summary> + Busy, + + /// <summary> + /// User is out. + /// </summary> + Out + } +} diff --git a/samples/IrcChatSystem/ChatCommonLib/IrcChat/Contracts/IChatClient.cs b/samples/IrcChatSystem/ChatCommonLib/IrcChat/Contracts/IChatClient.cs new file mode 100644 index 0000000..bf24c2f --- /dev/null +++ b/samples/IrcChatSystem/ChatCommonLib/IrcChat/Contracts/IChatClient.cs @@ -0,0 +1,56 @@ +using Hik.Communication.ScsServices.Service; +using Hik.Samples.Scs.IrcChat.Arguments; + +namespace Hik.Samples.Scs.IrcChat.Contracts +{ + /// <summary> + /// This interface defines methods of chat client. + /// Defined methods are called by chat server. + /// </summary> + public interface IChatClient + { + /// <summary> + /// This method is used to get user list from chat server. + /// It is called by server once after user logged in to server. + /// </summary> + /// <param name="users">All online user informations</param> + void GetUserList(UserInfo[] users); + + /// <summary> + /// This method is called from chat server to inform that a message + /// is sent to chat room publicly. + /// </summary> + /// <param name="nick">Nick of sender</param> + /// <param name="message">Message</param> + void OnMessageToRoom(string nick, ChatMessage message); + + /// <summary> + /// This method is called from chat server to inform that a message + /// is sent to the current user privately. + /// </summary> + /// <param name="nick">Nick of sender</param> + /// <param name="message">Message</param> + void OnPrivateMessage(string nick, ChatMessage message); + + /// <summary> + /// This method is called from chat server to inform that a new user + /// joined to chat room. + /// </summary> + /// <param name="userInfo">Informations of new user</param> + void OnUserLogin(UserInfo userInfo); + + /// <summary> + /// This method is called from chat server to inform that an existing user + /// has left the chat room. + /// </summary> + /// <param name="nick">Informations of new user</param> + void OnUserLogout(string nick); + + /// <summary> + /// This method is called from chat server to inform that a user changed his/her status. + /// </summary> + /// <param name="nick">Nick of the user</param> + /// <param name="newStatus">New status of the user</param> + void OnUserStatusChange(string nick, UserStatus newStatus); + } +} diff --git a/samples/IrcChatSystem/ChatCommonLib/IrcChat/Contracts/IChatService.cs b/samples/IrcChatSystem/ChatCommonLib/IrcChat/Contracts/IChatService.cs new file mode 100644 index 0000000..5f554b2 --- /dev/null +++ b/samples/IrcChatSystem/ChatCommonLib/IrcChat/Contracts/IChatService.cs @@ -0,0 +1,49 @@ +using Hik.Communication.ScsServices.Service; +using Hik.Samples.Scs.IrcChat.Arguments; + +namespace Hik.Samples.Scs.IrcChat.Contracts +{ + /// <summary> + /// This interface defines Chat Service Contract. + /// It is used by Chat clients to interact with Chat Server. + /// </summary> + [ScsService(Version = "1.0.0.0")] + public interface IChatService + { + /// <summary> + /// Used to login to chat service. + /// </summary> + /// <param name="userInfo">User informations</param> + void Login(UserInfo userInfo); + + /// <summary> + /// Sends a public message to room. + /// It will be seen by all users in room. + /// </summary> + /// <param name="message">Message to be sent</param> + void SendMessageToRoom(ChatMessage message); + + /// <summary> + /// Sends a private message to a specific user. + /// Message will be seen only by destination user. + /// </summary> + /// <param name="destinationNick">Nick of the destination user + /// who will receive the message</param> + /// <param name="message">Message to be sent</param> + void SendPrivateMessage(string destinationNick, ChatMessage message); + + /// <summary> + /// Changes status of a user and inform all other users. + /// </summary> + /// <param name="newStatus">New status of user</param> + void ChangeStatus(UserStatus newStatus); + + /// <summary> + /// Used to logout from chat service. + /// Client may not call this method while logging out (in an application crash situation), + /// it will also be logged out automatically when connection fails between + /// client and server. + /// </summary> + void Logout(); + } +} diff --git a/samples/IrcChatSystem/ChatCommonLib/IrcChat/Exceptions/NickInUseException.cs b/samples/IrcChatSystem/ChatCommonLib/IrcChat/Exceptions/NickInUseException.cs new file mode 100644 index 0000000..41f3424 --- /dev/null +++ b/samples/IrcChatSystem/ChatCommonLib/IrcChat/Exceptions/NickInUseException.cs @@ -0,0 +1,40 @@ +using System; +using System.Runtime.Serialization; + +namespace Hik.Samples.Scs.IrcChat.Exceptions +{ + /// <summary> + /// This exception is thrown by Chat server if a user wants to login + /// with a nick that is being used by another user. + /// </summary> + [Serializable] + public class NickInUseException : ApplicationException + { + /// <summary> + /// Contstructor. + /// </summary> + public NickInUseException() + { + + } + + /// <summary> + /// Contstructor. + /// </summary> + public NickInUseException(SerializationInfo serializationInfo, StreamingContext context) + : base(serializationInfo, context) + { + + } + + /// <summary> + /// Contstructor. + /// </summary> + /// <param name="message">Exception message</param> + public NickInUseException(string message) + : base(message) + { + + } + } +} diff --git a/samples/IrcChatSystem/ChatCommonLib/Properties/AssemblyInfo.cs b/samples/IrcChatSystem/ChatCommonLib/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..ffe4eba --- /dev/null +++ b/samples/IrcChatSystem/ChatCommonLib/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ChatCommonLib")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("ChatCommonLib")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c57972ac-fbe0-4cfa-ad54-70e1a3fc7dbc")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/IrcChatSystem/ChatServerApp/App.xaml b/samples/IrcChatSystem/ChatServerApp/App.xaml new file mode 100644 index 0000000..e7ee178 --- /dev/null +++ b/samples/IrcChatSystem/ChatServerApp/App.xaml @@ -0,0 +1,8 @@ +<Application x:Class="ChatServerApp.App" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + StartupUri="IrcChat/Server/MainWindow.xaml"> + <Application.Resources> + + </Application.Resources> +</Application> diff --git a/samples/IrcChatSystem/ChatServerApp/App.xaml.cs b/samples/IrcChatSystem/ChatServerApp/App.xaml.cs new file mode 100644 index 0000000..9baf508 --- /dev/null +++ b/samples/IrcChatSystem/ChatServerApp/App.xaml.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Windows; + +namespace ChatServerApp +{ + /// <summary> + /// Interaction logic for App.xaml + /// </summary> + public partial class App : Application + { + } +} diff --git a/samples/IrcChatSystem/ChatServerApp/ChatServerApp.csproj b/samples/IrcChatSystem/ChatServerApp/ChatServerApp.csproj new file mode 100644 index 0000000..25e6b31 --- /dev/null +++ b/samples/IrcChatSystem/ChatServerApp/ChatServerApp.csproj @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{277B1094-3C64-4EDE-A17E-A975D797A30B}</ProjectGuid> + <OutputType>WinExe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>Hik.Samples.Scs</RootNamespace> + <AssemblyName>ChatServerApp</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup> + <ApplicationIcon>app_icon.ico</ApplicationIcon> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="System.Xaml"> + <RequiredTargetFramework>4.0</RequiredTargetFramework> + </Reference> + <Reference Include="WindowsBase" /> + <Reference Include="PresentationCore" /> + <Reference Include="PresentationFramework" /> + </ItemGroup> + <ItemGroup> + <ApplicationDefinition Include="App.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </ApplicationDefinition> + <Page Include="IrcChat\Server\MainWindow.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> + <Compile Include="App.xaml.cs"> + <DependentUpon>App.xaml</DependentUpon> + <SubType>Code</SubType> + </Compile> + <Compile Include="IrcChat\Server\ChatService.cs" /> + <Compile Include="IrcChat\Server\MainWindow.xaml.cs"> + <DependentUpon>MainWindow.xaml</DependentUpon> + <SubType>Code</SubType> + </Compile> + </ItemGroup> + <ItemGroup> + <Compile Include="Properties\AssemblyInfo.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="Properties\Resources.Designer.cs"> + <AutoGen>True</AutoGen> + <DesignTime>True</DesignTime> + <DependentUpon>Resources.resx</DependentUpon> + </Compile> + <Compile Include="Properties\Settings.Designer.cs"> + <AutoGen>True</AutoGen> + <DependentUpon>Settings.settings</DependentUpon> + <DesignTimeSharedInput>True</DesignTimeSharedInput> + </Compile> + <EmbeddedResource Include="Properties\Resources.resx"> + <Generator>ResXFileCodeGenerator</Generator> + <LastGenOutput>Resources.Designer.cs</LastGenOutput> + </EmbeddedResource> + <None Include="Properties\Settings.settings"> + <Generator>SettingsSingleFileGenerator</Generator> + <LastGenOutput>Settings.Designer.cs</LastGenOutput> + </None> + <AppDesigner Include="Properties\" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\ChatCommonLib\ChatCommonLib.csproj"> + <Project>{A57047DE-CC39-4C01-955E-D73888A0C83D}</Project> + <Name>ChatCommonLib</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <Resource Include="Images\app_icon.ico" /> + </ItemGroup> + <ItemGroup> + <Resource Include="app_icon.ico" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/samples/IrcChatSystem/ChatServerApp/Images/app_icon.ico b/samples/IrcChatSystem/ChatServerApp/Images/app_icon.ico Binary files differnew file mode 100644 index 0000000..dc5af4a --- /dev/null +++ b/samples/IrcChatSystem/ChatServerApp/Images/app_icon.ico diff --git a/samples/IrcChatSystem/ChatServerApp/IrcChat/Server/ChatService.cs b/samples/IrcChatSystem/ChatServerApp/IrcChat/Server/ChatService.cs new file mode 100644 index 0000000..9ba3bca --- /dev/null +++ b/samples/IrcChatSystem/ChatServerApp/IrcChat/Server/ChatService.cs @@ -0,0 +1,385 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Hik.Collections; +using Hik.Communication.ScsServices.Service; +using Hik.Samples.Scs.IrcChat.Arguments; +using Hik.Samples.Scs.IrcChat.Contracts; +using Hik.Samples.Scs.IrcChat.Exceptions; + +namespace Hik.Samples.Scs.IrcChat.Server +{ + /// <summary> + /// This class implements Chat Service Contract. + /// </summary> + internal class ChatService : ScsService, IChatService + { + #region Public Events + + /// <summary> + /// This event is raised when online user list is changes. + /// It is usually raised when a new user log in or a user log out. + /// </summary> + public event EventHandler UserListChanged; + + #endregion + + #region Public Properties + + /// <summary> + /// Gets a list of online users. + /// </summary> + public List<UserInfo> UserList + { + get + { + return (from client in _clients.GetAllItems() + select client.User).ToList(); + } + } + + #endregion + + #region Private Fields + + /// <summary> + /// List of all connected clients. + /// </summary> + private readonly ThreadSafeSortedList<long, ChatClient> _clients; + + #endregion + + #region Constructor + + /// <summary> + /// Constructor. + /// </summary> + public ChatService() + { + _clients = new ThreadSafeSortedList<long, ChatClient>(); + } + + #endregion + + #region IChatService methods + + /// <summary> + /// Used to login to chat service. + /// </summary> + /// <param name="userInfo">User informations</param> + public void Login(UserInfo userInfo) + { + //Check nick if it is being used by another user + if (FindClientByNick(userInfo.Nick) != null) + { + throw new NickInUseException("The nick '" + userInfo.Nick + "' is being used by another user. Please select another one."); + } + + //Get a reference to the current client that is calling this method + var client = CurrentClient; + + //Get a proxy object to call methods of client when needed + var clientProxy = client.GetClientProxy<IChatClient>(); + + //Create a ChatClient and store it in a collection + var chatClient = new ChatClient(client, clientProxy, userInfo); + _clients[client.ClientId] = chatClient; + + //Register to Disconnected event to know when user connection is closed + client.Disconnected += Client_Disconnected; + + //Start a new task to send user list to new user and to inform + //all users that a new user joined to room + Task.Factory.StartNew( + () => + { + OnUserListChanged(); + SendUserListToClient(chatClient); + SendUserLoginInfoToAllClients(userInfo); + }); + } + + /// <summary> + /// Sends a public message to room. + /// It will be seen all users in room. + /// </summary> + /// <param name="message">Message to be sent</param> + public void SendMessageToRoom(ChatMessage message) + { + //Get ChatClient object + var senderClient = _clients[CurrentClient.ClientId]; + if (senderClient == null) + { + throw new ApplicationException("Can not send message before login."); + } + + //Send message to all online users + Task.Factory.StartNew( + () => + { + foreach (var chatClient in _clients.GetAllItems()) + { + try + { + chatClient.ClientProxy.OnMessageToRoom(senderClient.User.Nick, message); + } + catch + { + + } + } + }); + } + + /// <summary> + /// Sends a private message to a specific user. + /// Message will be seen only by destination user. + /// </summary> + /// <param name="destinationNick">Nick of the destination user who will receive message</param> + /// <param name="message">Message to be sent</param> + public void SendPrivateMessage(string destinationNick, ChatMessage message) + { + //Get ChatClient object for sender user + var senderClient = _clients[CurrentClient.ClientId]; + if (senderClient == null) + { + throw new ApplicationException("Can not send message before login."); + } + + //Get ChatClient object for destination user + var receiverClient = FindClientByNick(destinationNick); + if (receiverClient == null) + { + throw new ApplicationException("There is no online user with nick " + destinationNick); + } + + //Send message to destination user + receiverClient.ClientProxy.OnPrivateMessage(senderClient.User.Nick, message); + } + + /// <summary> + /// Changes status of a user and inform all other users. + /// </summary> + /// <param name="newStatus">New status of user</param> + public void ChangeStatus(UserStatus newStatus) + { + //Get ChatClient object + var senderClient = _clients[CurrentClient.ClientId]; + if (senderClient == null) + { + throw new ApplicationException("Can not change state before login."); + } + + //Set new status + senderClient.User.Status = newStatus; + + //Send status of user to all online users + Task.Factory.StartNew( + () => + { + foreach (var chatClient in _clients.GetAllItems()) + { + try + { + chatClient.ClientProxy.OnUserStatusChange(senderClient.User.Nick, newStatus); + } + catch + { + + } + } + }); + } + + /// <summary> + /// Used to logout from chat service. + /// Client may not call this method while logging out (in an application crash situation), + /// it will also be logged out automatically when connection fails between client and server. + /// </summary> + public void Logout() + { + ClientLogout(CurrentClient.ClientId); + } + + #endregion + + #region Private methods + + /// <summary> + /// Handles Disconnected event of all clients. + /// </summary> + /// <param name="sender">Client object that is disconnected</param> + /// <param name="e">Event arguments (not used in this event)</param> + private void Client_Disconnected(object sender, EventArgs e) + { + //Get client object + var client = (IScsServiceClient)sender; + + //Perform logout (so, if client did not call Logout method before close, + //we do logout automatically. + ClientLogout(client.ClientId); + } + + /// <summary> + /// This method is used to send list of all online users to a new joined user. + /// </summary> + /// <param name="client">New user that is joined to service</param> + private void SendUserListToClient(ChatClient client) + { + //Get all users except new user + var userList = UserList.Where((user) => (user.Nick != client.User.Nick)).ToArray(); + + //Do not send list if no user available (except the new user) + if (userList.Length <= 0) + { + return; + } + + client.ClientProxy.GetUserList(userList); + } + + /// <summary> + /// This method is called when a client Calls Logout method of service or a client + /// connection fails. + /// </summary> + /// <param name="clientId">Unique Id of client that is logged out</param> + private void ClientLogout(long clientId) + { + //Get client from client list, if not in list do not continue + var client = _clients[clientId]; + if (client == null) + { + return; + } + + //Remove client from online clients list + _clients.Remove(client.Client.ClientId); + + //Unregister to Disconnected event (not needed really) + client.Client.Disconnected -= Client_Disconnected; + + //Start a new task to inform all other users + Task.Factory.StartNew( + () => + { + OnUserListChanged(); + SendUserLogoutInfoToAllClients(client.User.Nick); + }); + } + + /// <summary> + /// This method is used to inform all online clients + /// that a new user joined to room. + /// </summary> + /// <param name="userInfo">New joined user's informations</param> + private void SendUserLoginInfoToAllClients(UserInfo userInfo) + { + foreach (var client in _clients.GetAllItems()) + { + //Do not send informations to user that is logged in. + if (client.User.Nick == userInfo.Nick) + { + continue; + } + + try + { + client.ClientProxy.OnUserLogin(userInfo); + } + catch + { + + } + } + } + + /// <summary> + /// This method is used to inform all online clients + /// that a user disconnected from chat server. + /// </summary> + /// <param name="nick">Nick of disconnected user</param> + private void SendUserLogoutInfoToAllClients(string nick) + { + foreach (var client in _clients.GetAllItems()) + { + try + { + client.ClientProxy.OnUserLogout(nick); + } + catch + { + + } + } + } + + /// <summary> + /// Finds ChatClient ojbect by given nick. + /// </summary> + /// <param name="nick">Nick to search</param> + /// <returns>Found ChatClient for that nick, or null if not found</returns> + private ChatClient FindClientByNick(string nick) + { + return (from client in _clients.GetAllItems() + where client.User.Nick == nick + select client).FirstOrDefault(); + } + + #endregion + + #region Event raising methods + + /// <summary> + /// Raises UserListChanged event. + /// </summary> + private void OnUserListChanged() + { + var handler = UserListChanged; + if (handler != null) + { + handler(this, EventArgs.Empty); + } + } + + #endregion + + #region Sub classes + + /// <summary> + /// This class is used to store informations for a connected client. + /// </summary> + private sealed class ChatClient + { + /// <summary> + /// Scs client reference. + /// </summary> + public IScsServiceClient Client { get; private set; } + + /// <summary> + /// Proxy object to call remote methods of chat client. + /// </summary> + public IChatClient ClientProxy { get; private set; } + + /// <summary> + /// User informations of client. + /// </summary> + public UserInfo User { get; private set; } + + /// <summary> + /// Creates a new ChatClient object. + /// </summary> + /// <param name="client">Scs client reference</param> + /// <param name="clientProxy">Proxy object to call remote methods of chat client</param> + /// <param name="userInfo">User informations of client</param> + public ChatClient(IScsServiceClient client, IChatClient clientProxy, UserInfo userInfo) + { + Client = client; + ClientProxy = clientProxy; + User = userInfo; + } + } + + #endregion + } +} diff --git a/samples/IrcChatSystem/ChatServerApp/IrcChat/Server/MainWindow.xaml b/samples/IrcChatSystem/ChatServerApp/IrcChat/Server/MainWindow.xaml new file mode 100644 index 0000000..cf5f454 --- /dev/null +++ b/samples/IrcChatSystem/ChatServerApp/IrcChat/Server/MainWindow.xaml @@ -0,0 +1,50 @@ +<Window x:Class="Hik.Samples.Scs.IrcChat.Server.MainWindow" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + Title="SCS Chat Server" Height="300" Width="500" Icon="/ChatServerApp;component/app_icon.ico"> + <Grid Background="#FF1F1F1F"> + <Grid.RowDefinitions> + <RowDefinition Height="70"></RowDefinition> + <RowDefinition Height="*"></RowDefinition> + </Grid.RowDefinitions> + <Border Grid.Row="0" BorderThickness="1" Padding="5" Margin="10" BorderBrush="#FF878383" CornerRadius="10"> + <Border.Background> + <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> + <GradientStop Color="Black" Offset="0" /> + <GradientStop Color="#FF323232" Offset="1" /> + </LinearGradientBrush> + </Border.Background> + <Grid UseLayoutRounding="True"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto"/> + <ColumnDefinition Width="*"/> + <ColumnDefinition Width="Auto"/> + </Grid.ColumnDefinitions> + <StackPanel Orientation="Horizontal"> + <Label Content="Server Port: " VerticalAlignment="Stretch" VerticalContentAlignment="Center" HorizontalAlignment="Left" Padding="2" Margin="3" Foreground="White" /> + <TextBox Name="txtPort" Text="10048" VerticalAlignment="Center" Width="60" TextAlignment="Center" Margin="3" Background="White" /> + </StackPanel> + <StackPanel Orientation="Horizontal" Grid.Column="2" HorizontalAlignment="Right"> + <Button Name="btnStartServer" Content="Start Server" VerticalAlignment="Center" Margin="3,0" Padding="4" Click="btnStartServer_Click"></Button> + <Button Name="btnStopServer" Content="Stop Server" VerticalAlignment="Center" Margin="3,0" Padding="4" Click="btnStopServer_Click" IsEnabled="False" /> + </StackPanel> + </Grid> + </Border> + <Border Grid.Row="1" BorderThickness="1" Padding="5" Margin="10,0,10,10" BorderBrush="#FF878383" CornerRadius="10"> + <Border.Background> + <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> + <GradientStop Color="Black" Offset="0" /> + <GradientStop Color="#FF323232" Offset="1" /> + </LinearGradientBrush> + </Border.Background> + <Grid> + <Grid.RowDefinitions> + <RowDefinition Height="25"></RowDefinition> + <RowDefinition Height="*"></RowDefinition> + </Grid.RowDefinitions> + <Label Content="Online Users" Foreground="Lime" HorizontalContentAlignment="Center" FontWeight="Normal" FontSize="13" FontStyle="Normal" FontStretch="Normal" /> + <TextBlock Grid.Row="1" Name="lblUsers" TextWrapping="Wrap" Text="user1, user2, user3" Margin="5" FontSize="12" Foreground="Gainsboro"/> + </Grid> + </Border> + </Grid> +</Window> diff --git a/samples/IrcChatSystem/ChatServerApp/IrcChat/Server/MainWindow.xaml.cs b/samples/IrcChatSystem/ChatServerApp/IrcChat/Server/MainWindow.xaml.cs new file mode 100644 index 0000000..6ccefd5 --- /dev/null +++ b/samples/IrcChatSystem/ChatServerApp/IrcChat/Server/MainWindow.xaml.cs @@ -0,0 +1,119 @@ +using System; +using System.Text; +using System.Windows; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.ScsServices.Service; +using Hik.Samples.Scs.IrcChat.Contracts; + +namespace Hik.Samples.Scs.IrcChat.Server +{ + /// <summary> + /// Interaction logic for MainWindow.xaml + /// </summary> + public partial class MainWindow : Window + { + /// <summary> + /// This object is used to host Chat Service on a SCS server. + /// </summary> + private IScsServiceApplication _serviceApplication; + + /// <summary> + /// Chat Service object that serves clients. + /// </summary> + private ChatService _chatService; + + /// <summary> + /// Constructor. + /// </summary> + public MainWindow() + { + InitializeComponent(); + lblUsers.Text = ""; + } + + /// <summary> + /// Handles Client event of 'Start Server' button. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void btnStartServer_Click(object sender, RoutedEventArgs e) + { + //Get TCP port number from textbox + int port; + try + { + port = Convert.ToInt32(txtPort.Text); + if (port <= 0 || port > 65536) + { + throw new Exception(port + " is not a valid TCP port number."); + } + } + catch (Exception ex) + { + MessageBox.Show("TCP port must be a positive number. Exception detail: " + ex.Message); + return; + } + + try + { + _serviceApplication = ScsServiceBuilder.CreateService(new ScsTcpEndPoint(port)); + _chatService = new ChatService(); + _serviceApplication.AddService<IChatService, ChatService>(_chatService); + _chatService.UserListChanged += chatService_UserListChanged; + _serviceApplication.Start(); + } + catch (Exception ex) + { + MessageBox.Show("Service can not be started. Exception detail: " + ex.Message); + return; + } + + btnStartServer.IsEnabled = false; + btnStopServer.IsEnabled = true; + txtPort.IsEnabled = false; + } + + private void chatService_UserListChanged(object sender, EventArgs e) + { + Dispatcher.Invoke(new Action(UpdateUserList)); + } + + /// <summary> + /// Handles Client event of 'Stop Server' button. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void btnStopServer_Click(object sender, RoutedEventArgs e) + { + if (_serviceApplication == null) + { + return; + } + + _serviceApplication.Stop(); + + btnStartServer.IsEnabled = true; + btnStopServer.IsEnabled = false; + txtPort.IsEnabled = true; + } + + /// <summary> + /// Updates user list on GUI. + /// </summary> + private void UpdateUserList() + { + var users = new StringBuilder(); + foreach (var user in _chatService.UserList) + { + if (users.Length > 0) + { + users.Append(", "); + } + + users.Append(user.Nick); + } + + lblUsers.Text = users.ToString(); + } + } +} diff --git a/samples/IrcChatSystem/ChatServerApp/Properties/AssemblyInfo.cs b/samples/IrcChatSystem/ChatServerApp/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..6854d1e --- /dev/null +++ b/samples/IrcChatSystem/ChatServerApp/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ChatServerApp")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("ChatServerApp")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file +//inside a <PropertyGroup>. For example, if you are using US english +//in your source files, set the <UICulture> to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/IrcChatSystem/ChatServerApp/Properties/Resources.Designer.cs b/samples/IrcChatSystem/ChatServerApp/Properties/Resources.Designer.cs new file mode 100644 index 0000000..97d941c --- /dev/null +++ b/samples/IrcChatSystem/ChatServerApp/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:4.0.30319.1 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace Hik.Samples.Scs.Properties { + using System; + + + /// <summary> + /// A strongly-typed resource class, for looking up localized strings, etc. + /// </summary> + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// <summary> + /// Returns the cached ResourceManager instance used by this class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Hik.Samples.Scs.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// <summary> + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/samples/IrcChatSystem/ChatServerApp/Properties/Resources.resx b/samples/IrcChatSystem/ChatServerApp/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/samples/IrcChatSystem/ChatServerApp/Properties/Resources.resx @@ -0,0 +1,117 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> +</root>
\ No newline at end of file diff --git a/samples/IrcChatSystem/ChatServerApp/Properties/Settings.Designer.cs b/samples/IrcChatSystem/ChatServerApp/Properties/Settings.Designer.cs new file mode 100644 index 0000000..6e716de --- /dev/null +++ b/samples/IrcChatSystem/ChatServerApp/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:4.0.30319.1 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace Hik.Samples.Scs.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/samples/IrcChatSystem/ChatServerApp/Properties/Settings.settings b/samples/IrcChatSystem/ChatServerApp/Properties/Settings.settings new file mode 100644 index 0000000..033d7a5 --- /dev/null +++ b/samples/IrcChatSystem/ChatServerApp/Properties/Settings.settings @@ -0,0 +1,7 @@ +<?xml version='1.0' encoding='utf-8'?> +<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)"> + <Profiles> + <Profile Name="(Default)" /> + </Profiles> + <Settings /> +</SettingsFile>
\ No newline at end of file diff --git a/samples/IrcChatSystem/ChatServerApp/app_icon.ico b/samples/IrcChatSystem/ChatServerApp/app_icon.ico Binary files differnew file mode 100644 index 0000000..dc5af4a --- /dev/null +++ b/samples/IrcChatSystem/ChatServerApp/app_icon.ico diff --git a/samples/IrcChatSystem/IrcChatSystem.sln b/samples/IrcChatSystem/IrcChatSystem.sln new file mode 100644 index 0000000..90fbb76 --- /dev/null +++ b/samples/IrcChatSystem/IrcChatSystem.sln @@ -0,0 +1,54 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatCommonLib", "ChatCommonLib\ChatCommonLib.csproj", "{A57047DE-CC39-4C01-955E-D73888A0C83D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatServerApp", "ChatServerApp\ChatServerApp.csproj", "{277B1094-3C64-4EDE-A17E-A975D797A30B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatClientApp", "ChatClientApp\ChatClientApp.csproj", "{6571B5F6-C92F-4266-ACC9-186347994E9F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A57047DE-CC39-4C01-955E-D73888A0C83D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A57047DE-CC39-4C01-955E-D73888A0C83D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A57047DE-CC39-4C01-955E-D73888A0C83D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {A57047DE-CC39-4C01-955E-D73888A0C83D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {A57047DE-CC39-4C01-955E-D73888A0C83D}.Debug|x86.ActiveCfg = Debug|Any CPU + {A57047DE-CC39-4C01-955E-D73888A0C83D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A57047DE-CC39-4C01-955E-D73888A0C83D}.Release|Any CPU.Build.0 = Release|Any CPU + {A57047DE-CC39-4C01-955E-D73888A0C83D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {A57047DE-CC39-4C01-955E-D73888A0C83D}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {A57047DE-CC39-4C01-955E-D73888A0C83D}.Release|x86.ActiveCfg = Release|Any CPU + {277B1094-3C64-4EDE-A17E-A975D797A30B}.Debug|Any CPU.ActiveCfg = Debug|x86 + {277B1094-3C64-4EDE-A17E-A975D797A30B}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {277B1094-3C64-4EDE-A17E-A975D797A30B}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {277B1094-3C64-4EDE-A17E-A975D797A30B}.Debug|x86.ActiveCfg = Debug|x86 + {277B1094-3C64-4EDE-A17E-A975D797A30B}.Debug|x86.Build.0 = Debug|x86 + {277B1094-3C64-4EDE-A17E-A975D797A30B}.Release|Any CPU.ActiveCfg = Release|x86 + {277B1094-3C64-4EDE-A17E-A975D797A30B}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {277B1094-3C64-4EDE-A17E-A975D797A30B}.Release|Mixed Platforms.Build.0 = Release|x86 + {277B1094-3C64-4EDE-A17E-A975D797A30B}.Release|x86.ActiveCfg = Release|x86 + {277B1094-3C64-4EDE-A17E-A975D797A30B}.Release|x86.Build.0 = Release|x86 + {6571B5F6-C92F-4266-ACC9-186347994E9F}.Debug|Any CPU.ActiveCfg = Debug|x86 + {6571B5F6-C92F-4266-ACC9-186347994E9F}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {6571B5F6-C92F-4266-ACC9-186347994E9F}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {6571B5F6-C92F-4266-ACC9-186347994E9F}.Debug|x86.ActiveCfg = Debug|x86 + {6571B5F6-C92F-4266-ACC9-186347994E9F}.Debug|x86.Build.0 = Debug|x86 + {6571B5F6-C92F-4266-ACC9-186347994E9F}.Release|Any CPU.ActiveCfg = Release|x86 + {6571B5F6-C92F-4266-ACC9-186347994E9F}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {6571B5F6-C92F-4266-ACC9-186347994E9F}.Release|Mixed Platforms.Build.0 = Release|x86 + {6571B5F6-C92F-4266-ACC9-186347994E9F}.Release|x86.ActiveCfg = Release|x86 + {6571B5F6-C92F-4266-ACC9-186347994E9F}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/OnlinePhoneBook/OnlinePhoneBook.sln b/samples/OnlinePhoneBook/OnlinePhoneBook.sln new file mode 100644 index 0000000..4bcd0fc --- /dev/null +++ b/samples/OnlinePhoneBook/OnlinePhoneBook.sln @@ -0,0 +1,66 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhoneBookCommonLib", "PhoneBookCommonLib\PhoneBookCommonLib.csproj", "{10ECC585-8B5F-499E-B65F-F6B0DA17DEA2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhoneBookServer", "PhoneBookServer\PhoneBookServer.csproj", "{739C7AC7-A88F-482D-A459-831600D03E4D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhoneBookClient", "PhoneBookClient\PhoneBookClient.csproj", "{03750D57-CFAC-4262-9C3F-C06A6265361B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimlifiedPhoneBookClient", "SimlifiedPhoneBookClient\SimlifiedPhoneBookClient.csproj", "{C37B1CDC-3F1E-4694-AFAD-235725A9A811}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {10ECC585-8B5F-499E-B65F-F6B0DA17DEA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {10ECC585-8B5F-499E-B65F-F6B0DA17DEA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {10ECC585-8B5F-499E-B65F-F6B0DA17DEA2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {10ECC585-8B5F-499E-B65F-F6B0DA17DEA2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {10ECC585-8B5F-499E-B65F-F6B0DA17DEA2}.Debug|x86.ActiveCfg = Debug|Any CPU + {10ECC585-8B5F-499E-B65F-F6B0DA17DEA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {10ECC585-8B5F-499E-B65F-F6B0DA17DEA2}.Release|Any CPU.Build.0 = Release|Any CPU + {10ECC585-8B5F-499E-B65F-F6B0DA17DEA2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {10ECC585-8B5F-499E-B65F-F6B0DA17DEA2}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {10ECC585-8B5F-499E-B65F-F6B0DA17DEA2}.Release|x86.ActiveCfg = Release|Any CPU + {739C7AC7-A88F-482D-A459-831600D03E4D}.Debug|Any CPU.ActiveCfg = Debug|x86 + {739C7AC7-A88F-482D-A459-831600D03E4D}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {739C7AC7-A88F-482D-A459-831600D03E4D}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {739C7AC7-A88F-482D-A459-831600D03E4D}.Debug|x86.ActiveCfg = Debug|x86 + {739C7AC7-A88F-482D-A459-831600D03E4D}.Debug|x86.Build.0 = Debug|x86 + {739C7AC7-A88F-482D-A459-831600D03E4D}.Release|Any CPU.ActiveCfg = Release|x86 + {739C7AC7-A88F-482D-A459-831600D03E4D}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {739C7AC7-A88F-482D-A459-831600D03E4D}.Release|Mixed Platforms.Build.0 = Release|x86 + {739C7AC7-A88F-482D-A459-831600D03E4D}.Release|x86.ActiveCfg = Release|x86 + {739C7AC7-A88F-482D-A459-831600D03E4D}.Release|x86.Build.0 = Release|x86 + {03750D57-CFAC-4262-9C3F-C06A6265361B}.Debug|Any CPU.ActiveCfg = Debug|x86 + {03750D57-CFAC-4262-9C3F-C06A6265361B}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {03750D57-CFAC-4262-9C3F-C06A6265361B}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {03750D57-CFAC-4262-9C3F-C06A6265361B}.Debug|x86.ActiveCfg = Debug|x86 + {03750D57-CFAC-4262-9C3F-C06A6265361B}.Debug|x86.Build.0 = Debug|x86 + {03750D57-CFAC-4262-9C3F-C06A6265361B}.Release|Any CPU.ActiveCfg = Release|x86 + {03750D57-CFAC-4262-9C3F-C06A6265361B}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {03750D57-CFAC-4262-9C3F-C06A6265361B}.Release|Mixed Platforms.Build.0 = Release|x86 + {03750D57-CFAC-4262-9C3F-C06A6265361B}.Release|x86.ActiveCfg = Release|x86 + {03750D57-CFAC-4262-9C3F-C06A6265361B}.Release|x86.Build.0 = Release|x86 + {C37B1CDC-3F1E-4694-AFAD-235725A9A811}.Debug|Any CPU.ActiveCfg = Debug|x86 + {C37B1CDC-3F1E-4694-AFAD-235725A9A811}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {C37B1CDC-3F1E-4694-AFAD-235725A9A811}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {C37B1CDC-3F1E-4694-AFAD-235725A9A811}.Debug|x86.ActiveCfg = Debug|x86 + {C37B1CDC-3F1E-4694-AFAD-235725A9A811}.Debug|x86.Build.0 = Debug|x86 + {C37B1CDC-3F1E-4694-AFAD-235725A9A811}.Release|Any CPU.ActiveCfg = Release|x86 + {C37B1CDC-3F1E-4694-AFAD-235725A9A811}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {C37B1CDC-3F1E-4694-AFAD-235725A9A811}.Release|Mixed Platforms.Build.0 = Release|x86 + {C37B1CDC-3F1E-4694-AFAD-235725A9A811}.Release|x86.ActiveCfg = Release|x86 + {C37B1CDC-3F1E-4694-AFAD-235725A9A811}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/OnlinePhoneBook/PhoneBookClient/PhoneBookClient.csproj b/samples/OnlinePhoneBook/PhoneBookClient/PhoneBookClient.csproj new file mode 100644 index 0000000..19e7acf --- /dev/null +++ b/samples/OnlinePhoneBook/PhoneBookClient/PhoneBookClient.csproj @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{03750D57-CFAC-4262-9C3F-C06A6265361B}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>PhoneBookClient</RootNamespace> + <AssemblyName>PhoneBookClient</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.0.2.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\PhoneBookCommonLib\PhoneBookCommonLib.csproj"> + <Project>{10ECC585-8B5F-499E-B65F-F6B0DA17DEA2}</Project> + <Name>PhoneBookCommonLib</Name> + </ProjectReference> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/samples/OnlinePhoneBook/PhoneBookClient/Program.cs b/samples/OnlinePhoneBook/PhoneBookClient/Program.cs new file mode 100644 index 0000000..d34fa05 --- /dev/null +++ b/samples/OnlinePhoneBook/PhoneBookClient/Program.cs @@ -0,0 +1,52 @@ +using System; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.ScsServices.Client; +using PhoneBookCommonLib; + +/* This is a simple client application that uses phone book server. + */ + +namespace PhoneBookClient +{ + class Program + { + static void Main() + { + //Create a client to connecto to phone book service on local server and 10048 TCP port. + var client = ScsServiceClientBuilder.CreateClient<IPhoneBookService>( + new ScsTcpEndPoint("127.0.0.1", 10048)); + + Console.WriteLine("Press enter to connect to phone book service..."); + Console.ReadLine(); + + //Connect to the server + client.Connect(); + + var person1 = new PhoneBookRecord { Name = "Halil ibrahim", Phone = "5881112233" }; + var person2 = new PhoneBookRecord { Name = "John Nash", Phone = "58833322211" }; + + //Add some persons + client.ServiceProxy.AddPerson(person1); + client.ServiceProxy.AddPerson(person2); + + //Search for a person + var person = client.ServiceProxy.FindPerson("Halil"); + if (person != null) + { + Console.WriteLine("Person is found:"); + Console.WriteLine(person); + } + else + { + Console.WriteLine("Can not find person!"); + } + + Console.WriteLine(); + Console.WriteLine("Press enter to disconnect from phone book service..."); + Console.ReadLine(); + + //Disconnect from server + client.Disconnect(); + } + } +} diff --git a/samples/OnlinePhoneBook/PhoneBookClient/Properties/AssemblyInfo.cs b/samples/OnlinePhoneBook/PhoneBookClient/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..26c72ec --- /dev/null +++ b/samples/OnlinePhoneBook/PhoneBookClient/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhoneBookClient")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("PhoneBookClient")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c28c191a-1ca4-4049-97aa-3dd515ba6603")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/OnlinePhoneBook/PhoneBookCommonLib/IPhoneBookService.cs b/samples/OnlinePhoneBook/PhoneBookCommonLib/IPhoneBookService.cs new file mode 100644 index 0000000..9f73c49 --- /dev/null +++ b/samples/OnlinePhoneBook/PhoneBookCommonLib/IPhoneBookService.cs @@ -0,0 +1,33 @@ +using Hik.Communication.ScsServices.Service; + +namespace PhoneBookCommonLib +{ + /// <summary> + /// This interface defines methods of Phone Book Service + /// that can be called remotely by client applications. + /// </summary> + [ScsService(Version = "1.0.0.0")] + public interface IPhoneBookService + { + /// <summary> + /// Adds a new person to phone book. + /// </summary> + /// <param name="recordToAdd">Person informations to add</param> + void AddPerson(PhoneBookRecord recordToAdd); + + /// <summary> + /// Deletes a person from phone book. + /// </summary> + /// <param name="name">Name of the person to delete</param> + /// <returns>True, if a person is deleted, false if person is not found</returns> + bool DeletePerson(string name); + + /// <summary> + /// Searches a person in phone book by name of person. + /// </summary> + /// <param name="name">Name of person to search. + /// Name might not fully match, it can be a part of person's name</param> + /// <returns>Person informations if found, else null</returns> + PhoneBookRecord FindPerson(string name); + } +} diff --git a/samples/OnlinePhoneBook/PhoneBookCommonLib/PhoneBookCommonLib.csproj b/samples/OnlinePhoneBook/PhoneBookCommonLib/PhoneBookCommonLib.csproj new file mode 100644 index 0000000..0210926 --- /dev/null +++ b/samples/OnlinePhoneBook/PhoneBookCommonLib/PhoneBookCommonLib.csproj @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{10ECC585-8B5F-499E-B65F-F6B0DA17DEA2}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>PhoneBookCommonLib</RootNamespace> + <AssemblyName>PhoneBookCommonLib</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.0.2.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="IPhoneBookService.cs" /> + <Compile Include="PhoneBookRecord.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/samples/OnlinePhoneBook/PhoneBookCommonLib/PhoneBookRecord.cs b/samples/OnlinePhoneBook/PhoneBookCommonLib/PhoneBookRecord.cs new file mode 100644 index 0000000..a1c5706 --- /dev/null +++ b/samples/OnlinePhoneBook/PhoneBookCommonLib/PhoneBookRecord.cs @@ -0,0 +1,43 @@ +using System; + +namespace PhoneBookCommonLib +{ + /// <summary> + /// Represents a record in phone book. + /// </summary> + [Serializable] + public class PhoneBookRecord + { + /// <summary> + /// Name of the person. + /// </summary> + public string Name { get; set; } + + /// <summary> + /// Phone number of the person. + /// </summary> + public string Phone { get; set; } + + /// <summary> + /// Creation date of this record. + /// </summary> + public DateTime CreationDate { get; set; } + + /// <summary> + /// Creates a new PhoneBookRecord object. + /// </summary> + public PhoneBookRecord() + { + CreationDate = DateTime.Now; + } + + /// <summary> + /// Generates a string representation of this object. + /// </summary> + /// <returns>String representation of this object</returns> + public override string ToString() + { + return string.Format("Name = {0}, Phone = {1}", Name, Phone); + } + } +}
\ No newline at end of file diff --git a/samples/OnlinePhoneBook/PhoneBookCommonLib/Properties/AssemblyInfo.cs b/samples/OnlinePhoneBook/PhoneBookCommonLib/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..e685388 --- /dev/null +++ b/samples/OnlinePhoneBook/PhoneBookCommonLib/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhoneBookCommonLib")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("PhoneBookCommonLib")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("14d99672-f6af-4ef8-8613-49f23b49636a")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/OnlinePhoneBook/PhoneBookServer/PhoneBookServer.csproj b/samples/OnlinePhoneBook/PhoneBookServer/PhoneBookServer.csproj new file mode 100644 index 0000000..5cd77d9 --- /dev/null +++ b/samples/OnlinePhoneBook/PhoneBookServer/PhoneBookServer.csproj @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{739C7AC7-A88F-482D-A459-831600D03E4D}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>PhoneBookServer</RootNamespace> + <AssemblyName>PhoneBookServer</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.0.2.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="PhoneBookService.cs" /> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\PhoneBookCommonLib\PhoneBookCommonLib.csproj"> + <Project>{10ECC585-8B5F-499E-B65F-F6B0DA17DEA2}</Project> + <Name>PhoneBookCommonLib</Name> + </ProjectReference> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/samples/OnlinePhoneBook/PhoneBookServer/PhoneBookService.cs b/samples/OnlinePhoneBook/PhoneBookServer/PhoneBookService.cs new file mode 100644 index 0000000..d9b3389 --- /dev/null +++ b/samples/OnlinePhoneBook/PhoneBookServer/PhoneBookService.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using Hik.Communication.ScsServices.Service; +using PhoneBookCommonLib; + +namespace PhoneBookServer +{ + /// <summary> + /// This class implements Phone Book Service contract. + /// </summary> + class PhoneBookService : ScsService, IPhoneBookService + { + /// <summary> + /// Current records that are added to phone book service. + /// Key: Name of the person. + /// Value: PhoneBookRecord object. + /// </summary> + private readonly SortedList<string, PhoneBookRecord> _records; + + /// <summary> + /// Creates a new PhoneBookService object. + /// </summary> + public PhoneBookService() + { + _records = new SortedList<string, PhoneBookRecord>(); + } + + /// <summary> + /// Adds a new person to phone book. + /// </summary> + /// <param name="recordToAdd">Person informations to add</param> + public void AddPerson(PhoneBookRecord recordToAdd) + { + if (recordToAdd == null) + { + throw new ArgumentNullException("recordToAdd"); + } + + _records[recordToAdd.Name] = recordToAdd; + Console.WriteLine("A new person is added: "+ recordToAdd.Name + " (" + recordToAdd.Phone + ")"); + } + + /// <summary> + /// Deletes a person from phone book. + /// </summary> + /// <param name="name">Name of the person to delete</param> + /// <returns>True, if a person is deleted, false if person is not found</returns> + public bool DeletePerson(string name) + { + if (!_records.ContainsKey(name)) + { + return false; + } + + _records.Remove(name); + return true; + } + + /// <summary> + /// Searches a person in phone book by name of person. + /// </summary> + /// <param name="name">Name of person to search. + /// Name might not fully match, it can be a part of person's name</param> + /// <returns>Person informations if found, else null</returns> + public PhoneBookRecord FindPerson(string name) + { + //Get recods by name if there is a record exactly match to given name + if (_records.ContainsKey(name)) + { + return _records[name]; + } + + //Search all records to check if there is a name string that contains given name + foreach (var record in _records) + { + if (record.Key.ToLower().Contains(name.ToLower())) + { + return record.Value; + } + } + + //Not found + return null; + } + } +} diff --git a/samples/OnlinePhoneBook/PhoneBookServer/Program.cs b/samples/OnlinePhoneBook/PhoneBookServer/Program.cs new file mode 100644 index 0000000..56ae262 --- /dev/null +++ b/samples/OnlinePhoneBook/PhoneBookServer/Program.cs @@ -0,0 +1,32 @@ +using System; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.ScsServices.Service; +using PhoneBookCommonLib; + +/* This is a simple phone book server application that runs on SCS framework. + */ + +namespace PhoneBookServer +{ + class Program + { + static void Main() + { + //Create a Scs Service application that runs on 10048 TCP port. + var server = ScsServiceBuilder.CreateService(new ScsTcpEndPoint(10048)); + + //Add Phone Book Service to service application + server.AddService<IPhoneBookService, PhoneBookService>(new PhoneBookService()); + + //Start server + server.Start(); + + //Wait user to stop server by pressing Enter + Console.WriteLine("Phone Book Server started successfully. Press enter to stop..."); + Console.ReadLine(); + + //Stop server + server.Stop(); + } + } +} diff --git a/samples/OnlinePhoneBook/PhoneBookServer/Properties/AssemblyInfo.cs b/samples/OnlinePhoneBook/PhoneBookServer/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c706336 --- /dev/null +++ b/samples/OnlinePhoneBook/PhoneBookServer/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhoneBookServer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("PhoneBookServer")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f3344e62-7cde-4cf2-8982-d93ee153dcd9")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/OnlinePhoneBook/SimlifiedPhoneBookClient/Program.cs b/samples/OnlinePhoneBook/SimlifiedPhoneBookClient/Program.cs new file mode 100644 index 0000000..370e58b --- /dev/null +++ b/samples/OnlinePhoneBook/SimlifiedPhoneBookClient/Program.cs @@ -0,0 +1,27 @@ +using System; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.ScsServices.Client; +using PhoneBookCommonLib; + +/* This is the simplest client application that uses phone book server. + * (Just 2 lines of code to connect to the server and call a method. + */ + +namespace SimlifiedPhoneBookClient +{ + class Program + { + static void Main() + { + Console.ReadLine(); + + //Create a client to connecto to phone book service on local server and 10048 TCP port. + var client = ScsServiceClientBuilder.CreateClient<IPhoneBookService>(new ScsTcpEndPoint("127.0.0.1", 10048)); + + //Directly call a method (it automatically connects, calls and disconnects) + client.ServiceProxy.AddPerson(new PhoneBookRecord { Name = "Halil ibrahim", Phone = "5881112233" }); + + Console.ReadLine(); + } + } +} diff --git a/samples/OnlinePhoneBook/SimlifiedPhoneBookClient/Properties/AssemblyInfo.cs b/samples/OnlinePhoneBook/SimlifiedPhoneBookClient/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f4e779a --- /dev/null +++ b/samples/OnlinePhoneBook/SimlifiedPhoneBookClient/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SimlifiedPhoneBookClient")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("SimlifiedPhoneBookClient")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f37932c6-8c52-456c-9fc9-e26c17e3d186")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/OnlinePhoneBook/SimlifiedPhoneBookClient/SimlifiedPhoneBookClient.csproj b/samples/OnlinePhoneBook/SimlifiedPhoneBookClient/SimlifiedPhoneBookClient.csproj new file mode 100644 index 0000000..6ed9344 --- /dev/null +++ b/samples/OnlinePhoneBook/SimlifiedPhoneBookClient/SimlifiedPhoneBookClient.csproj @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{C37B1CDC-3F1E-4694-AFAD-235725A9A811}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>SimlifiedPhoneBookClient</RootNamespace> + <AssemblyName>SimlifiedPhoneBookClient</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs"> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\PhoneBookCommonLib\PhoneBookCommonLib.csproj"> + <Project>{10ECC585-8B5F-499E-B65F-F6B0DA17DEA2}</Project> + <Name>PhoneBookCommonLib</Name> + </ProjectReference> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/samples/SimpleCalculatorSystem/CalculatorClient/CalculatorClient.csproj b/samples/SimpleCalculatorSystem/CalculatorClient/CalculatorClient.csproj new file mode 100644 index 0000000..d9b1a48 --- /dev/null +++ b/samples/SimpleCalculatorSystem/CalculatorClient/CalculatorClient.csproj @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{6DD6F730-E353-4B0C-9655-8370A943A7BF}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>CalculatorClient</RootNamespace> + <AssemblyName>CalculatorClient</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.0.0.1, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\CalculatorCommonLib\CalculatorCommonLib.csproj"> + <Project>{6F2D58C9-0395-4048-A304-17304D12BC63}</Project> + <Name>CalculatorCommonLib</Name> + </ProjectReference> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/samples/SimpleCalculatorSystem/CalculatorClient/Program.cs b/samples/SimpleCalculatorSystem/CalculatorClient/Program.cs new file mode 100644 index 0000000..09b209a --- /dev/null +++ b/samples/SimpleCalculatorSystem/CalculatorClient/Program.cs @@ -0,0 +1,33 @@ +using System; +using CalculatorCommonLib; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.ScsServices.Client; + +namespace CalculatorClient +{ + class Program + { + static void Main() + { + Console.WriteLine("Press enter to connect to server and call methods..."); + Console.ReadLine(); + + //Create a client that can call methods of Calculator Service that is running on local computer and 10083 TCP port + //Since IScsServiceClient is IDisposible, it closes connection at the end of the using block + using (var client = ScsServiceClientBuilder.CreateClient<ICalculatorService>(new ScsTcpEndPoint("127.0.0.1", 10083))) + { + //Connect to the server + client.Connect(); + + //Call a remote method of server + var division = client.ServiceProxy.Divide(42, 3); + + //Write the result to the screen + Console.WriteLine("Result: " + division); + } + + Console.WriteLine("Press enter to stop client application"); + Console.ReadLine(); + } + } +} diff --git a/samples/SimpleCalculatorSystem/CalculatorClient/Properties/AssemblyInfo.cs b/samples/SimpleCalculatorSystem/CalculatorClient/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..1c1a455 --- /dev/null +++ b/samples/SimpleCalculatorSystem/CalculatorClient/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CalculatorClient")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("CalculatorClient")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5712ded0-d09a-4e56-8de4-1d9145854ee5")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/SimpleCalculatorSystem/CalculatorCommonLib/CalculatorCommonLib.csproj b/samples/SimpleCalculatorSystem/CalculatorCommonLib/CalculatorCommonLib.csproj new file mode 100644 index 0000000..90eca61 --- /dev/null +++ b/samples/SimpleCalculatorSystem/CalculatorCommonLib/CalculatorCommonLib.csproj @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{6F2D58C9-0395-4048-A304-17304D12BC63}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>CalculatorCommonLib</RootNamespace> + <AssemblyName>CalculatorCommonLib</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.0.0.1, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="ICalculatorService.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/samples/SimpleCalculatorSystem/CalculatorCommonLib/ICalculatorService.cs b/samples/SimpleCalculatorSystem/CalculatorCommonLib/ICalculatorService.cs new file mode 100644 index 0000000..c04013f --- /dev/null +++ b/samples/SimpleCalculatorSystem/CalculatorCommonLib/ICalculatorService.cs @@ -0,0 +1,15 @@ +using Hik.Communication.ScsServices.Service; + +namespace CalculatorCommonLib +{ + /// <summary> + /// This interface defines methods of calculator service that can be called by clients. + /// </summary> + [ScsService] + public interface ICalculatorService + { + int Add(int number1, int number2); + + double Divide(double number1, double number2); + } +} diff --git a/samples/SimpleCalculatorSystem/CalculatorCommonLib/Properties/AssemblyInfo.cs b/samples/SimpleCalculatorSystem/CalculatorCommonLib/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4848095 --- /dev/null +++ b/samples/SimpleCalculatorSystem/CalculatorCommonLib/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CalculatorCommonLib")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("CalculatorCommonLib")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("8a08ef54-dde6-4f7a-8656-57518c5098ea")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/SimpleCalculatorSystem/CalculatorServer/CalculatorServer.csproj b/samples/SimpleCalculatorSystem/CalculatorServer/CalculatorServer.csproj new file mode 100644 index 0000000..259762d --- /dev/null +++ b/samples/SimpleCalculatorSystem/CalculatorServer/CalculatorServer.csproj @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{1BB6B428-E4C3-467F-824F-1DB84E310FF2}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>CalculatorServer</RootNamespace> + <AssemblyName>CalculatorServer</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.0.0.1, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\CalculatorCommonLib\CalculatorCommonLib.csproj"> + <Project>{6F2D58C9-0395-4048-A304-17304D12BC63}</Project> + <Name>CalculatorCommonLib</Name> + </ProjectReference> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/samples/SimpleCalculatorSystem/CalculatorServer/Program.cs b/samples/SimpleCalculatorSystem/CalculatorServer/Program.cs new file mode 100644 index 0000000..8ec07ef --- /dev/null +++ b/samples/SimpleCalculatorSystem/CalculatorServer/Program.cs @@ -0,0 +1,46 @@ +using System; +using CalculatorCommonLib; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.ScsServices.Service; + +namespace CalculatorServer +{ + class Program + { + static void Main() + { + //Create a service application that runs on 10083 TCP port + var serviceApplication = ScsServiceBuilder.CreateService(new ScsTcpEndPoint(10083)); + + //Create a CalculatorService and add it to service application + serviceApplication.AddService<ICalculatorService, CalculatorService>(new CalculatorService()); + + //Start service application + serviceApplication.Start(); + + Console.WriteLine("Calculator service is started. Press enter to stop..."); + Console.ReadLine(); + + //Stop service application + serviceApplication.Stop(); + } + } + + public class CalculatorService : ScsService, ICalculatorService + { + public int Add(int number1, int number2) + { + return number1 + number2; + } + + public double Divide(double number1, double number2) + { + if(number2 == 0.0) + { + throw new DivideByZeroException("number2 can not be zero!"); + } + + return number1 / number2; + } + } +} diff --git a/samples/SimpleCalculatorSystem/CalculatorServer/Properties/AssemblyInfo.cs b/samples/SimpleCalculatorSystem/CalculatorServer/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..46a9398 --- /dev/null +++ b/samples/SimpleCalculatorSystem/CalculatorServer/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CalculatorServer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("CalculatorServer")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("fc3f0ecf-46ea-437e-a535-82dffae3dc9e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/SimpleCalculatorSystem/SimpleCalculatorSystem.sln b/samples/SimpleCalculatorSystem/SimpleCalculatorSystem.sln new file mode 100644 index 0000000..236647f --- /dev/null +++ b/samples/SimpleCalculatorSystem/SimpleCalculatorSystem.sln @@ -0,0 +1,54 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CalculatorServer", "CalculatorServer\CalculatorServer.csproj", "{1BB6B428-E4C3-467F-824F-1DB84E310FF2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CalculatorCommonLib", "CalculatorCommonLib\CalculatorCommonLib.csproj", "{6F2D58C9-0395-4048-A304-17304D12BC63}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CalculatorClient", "CalculatorClient\CalculatorClient.csproj", "{6DD6F730-E353-4B0C-9655-8370A943A7BF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Debug|Any CPU.ActiveCfg = Debug|x86 + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Debug|x86.ActiveCfg = Debug|x86 + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Debug|x86.Build.0 = Debug|x86 + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Release|Any CPU.ActiveCfg = Release|x86 + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Release|Mixed Platforms.Build.0 = Release|x86 + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Release|x86.ActiveCfg = Release|x86 + {1BB6B428-E4C3-467F-824F-1DB84E310FF2}.Release|x86.Build.0 = Release|x86 + {6F2D58C9-0395-4048-A304-17304D12BC63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6F2D58C9-0395-4048-A304-17304D12BC63}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6F2D58C9-0395-4048-A304-17304D12BC63}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {6F2D58C9-0395-4048-A304-17304D12BC63}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {6F2D58C9-0395-4048-A304-17304D12BC63}.Debug|x86.ActiveCfg = Debug|Any CPU + {6F2D58C9-0395-4048-A304-17304D12BC63}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6F2D58C9-0395-4048-A304-17304D12BC63}.Release|Any CPU.Build.0 = Release|Any CPU + {6F2D58C9-0395-4048-A304-17304D12BC63}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {6F2D58C9-0395-4048-A304-17304D12BC63}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {6F2D58C9-0395-4048-A304-17304D12BC63}.Release|x86.ActiveCfg = Release|Any CPU + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Debug|Any CPU.ActiveCfg = Debug|x86 + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Debug|x86.ActiveCfg = Debug|x86 + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Debug|x86.Build.0 = Debug|x86 + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Release|Any CPU.ActiveCfg = Release|x86 + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Release|Mixed Platforms.Build.0 = Release|x86 + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Release|x86.ActiveCfg = Release|x86 + {6DD6F730-E353-4B0C-9655-8370A943A7BF}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/SimpleMessaging/ClientApp/ClientApp.csproj b/samples/SimpleMessaging/ClientApp/ClientApp.csproj new file mode 100644 index 0000000..58743d4 --- /dev/null +++ b/samples/SimpleMessaging/ClientApp/ClientApp.csproj @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{5F6A7126-4996-41AF-A4C1-13DA3D54C71B}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>ClientApp</RootNamespace> + <AssemblyName>ClientApp</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/samples/SimpleMessaging/ClientApp/Program.cs b/samples/SimpleMessaging/ClientApp/Program.cs new file mode 100644 index 0000000..cfec50d --- /dev/null +++ b/samples/SimpleMessaging/ClientApp/Program.cs @@ -0,0 +1,51 @@ +using System; +using Hik.Communication.Scs.Client; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.Scs.Communication.Messages; + +/* This program is build to demonstrate a client application that connects to a server + * and sends/receives messages in basic way of SCS framework. + */ + +namespace ClientApp +{ + class Program + { + static void Main() + { + //Create a client object to connect a server on 127.0.0.1 (local) IP and listens 10085 TCP port + var client = ScsClientFactory.CreateClient(new ScsTcpEndPoint("127.0.0.1", 10085)); + + //Register to MessageReceived event to receive messages from server. + client.MessageReceived += Client_MessageReceived; + + Console.WriteLine("Press enter to connect to the server..."); + Console.ReadLine(); //Wait user to press enter + + client.Connect(); //Connect to the server + + Console.Write("Write some message to be sent to server: "); + var messageText = Console.ReadLine(); //Get a message from user + + //Send message to the server + client.SendMessage(new ScsTextMessage(messageText)); + + Console.WriteLine("Press enter to disconnect from server..."); + Console.ReadLine(); //Wait user to press enter + + client.Disconnect(); //Close connection to server + } + + static void Client_MessageReceived(object sender, MessageEventArgs e) + { + //Client only accepts text messages + var message = e.Message as ScsTextMessage; + if (message == null) + { + return; + } + + Console.WriteLine("Server sent a message: " + message.Text); + } + } +}
\ No newline at end of file diff --git a/samples/SimpleMessaging/ClientApp/Properties/AssemblyInfo.cs b/samples/SimpleMessaging/ClientApp/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..a10a169 --- /dev/null +++ b/samples/SimpleMessaging/ClientApp/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ClientApp")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("ClientApp")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("eee05ea3-074b-45e7-8cbf-8c4cf2ad4cf5")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/SimpleMessaging/RequestReplyStyleClient/Program.cs b/samples/SimpleMessaging/RequestReplyStyleClient/Program.cs new file mode 100644 index 0000000..7916b96 --- /dev/null +++ b/samples/SimpleMessaging/RequestReplyStyleClient/Program.cs @@ -0,0 +1,43 @@ +using System; +using Hik.Communication.Scs.Client; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.Scs.Communication.Messages; +using Hik.Communication.Scs.Communication.Messengers; + +/* This program is build to demonstrate a client application that connects to a server + * and sends/receives messages in using RequestReplyMessenger. + */ + +namespace RequestReplyStyleClient +{ + class Program + { + static void Main() + { + Console.WriteLine("Press enter to connect to the server..."); + Console.ReadLine(); //Wait user to press enter + + //Create a client object to connect a server on 127.0.0.1 (local) IP and listens 10085 TCP port + using (var client = ScsClientFactory.CreateClient(new ScsTcpEndPoint("127.0.0.1", 10085))) + { + //Create a RequestReplyMessenger that uses the client as internal messenger. + using (var requestReplyMessenger = new RequestReplyMessenger<IScsClient>(client)) + { + requestReplyMessenger.Start(); //Start request/reply messenger + client.Connect(); //Connect to the server + + Console.Write("Write some message to be sent to server: "); + var messageText = Console.ReadLine(); //Get a message from user + + //Send user message to the server and get response + var response = requestReplyMessenger.SendMessageAndWaitForResponse(new ScsTextMessage(messageText)); + + Console.WriteLine("Response to message: " + ((ScsTextMessage) response).Text); + + Console.WriteLine("Press enter to disconnect from server..."); + Console.ReadLine(); //Wait user to press enter + } + } + } + } +} diff --git a/samples/SimpleMessaging/RequestReplyStyleClient/Properties/AssemblyInfo.cs b/samples/SimpleMessaging/RequestReplyStyleClient/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..6112008 --- /dev/null +++ b/samples/SimpleMessaging/RequestReplyStyleClient/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("RequestReplyStyleClient")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("RequestReplyStyleClient")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("70a9a155-d522-4415-b673-b42003f8186f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/SimpleMessaging/RequestReplyStyleClient/RequestReplyStyleClient.csproj b/samples/SimpleMessaging/RequestReplyStyleClient/RequestReplyStyleClient.csproj new file mode 100644 index 0000000..b098f39 --- /dev/null +++ b/samples/SimpleMessaging/RequestReplyStyleClient/RequestReplyStyleClient.csproj @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{3671E987-CA41-4DAF-8D43-CF86E9AD9519}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>RequestReplyStyleClient</RootNamespace> + <AssemblyName>RequestReplyStyleClient</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/samples/SimpleMessaging/ServerApp/Program.cs b/samples/SimpleMessaging/ServerApp/Program.cs new file mode 100644 index 0000000..449cf0c --- /dev/null +++ b/samples/SimpleMessaging/ServerApp/Program.cs @@ -0,0 +1,66 @@ +using System; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.Scs.Communication.Messages; +using Hik.Communication.Scs.Server; + +/* This program is build to demonstrate a server application that listens incoming + * client connections and reply messages. + */ + +namespace ServerApp +{ + class Program + { + static void Main() + { + //Create a server that listens 10085 TCP port for incoming connections + var server = ScsServerFactory.CreateServer(new ScsTcpEndPoint(10085)); + + //Register events of the server to be informed about clients + server.ClientConnected += Server_ClientConnected; + server.ClientDisconnected += Server_ClientDisconnected; + + server.Start(); //Start the server + + Console.WriteLine("Server is started successfully. Press enter to stop..."); + Console.ReadLine(); //Wait user to press enter + + server.Stop(); //Stop the server + } + + static void Server_ClientConnected(object sender, ServerClientEventArgs e) + { + Console.WriteLine("A new client is connected. Client Id = " + e.Client.ClientId); + + //Register to MessageReceived event to receive messages from new client + e.Client.MessageReceived += Client_MessageReceived; + } + + static void Server_ClientDisconnected(object sender, ServerClientEventArgs e) + { + Console.WriteLine("A client is disconnected! Client Id = " + e.Client.ClientId); + } + + static void Client_MessageReceived(object sender, MessageEventArgs e) + { + var message = e.Message as ScsTextMessage; //Server only accepts text messages + if (message == null) + { + return; + } + + //Get a reference to the client + var client = (IScsServerClient)sender; + + Console.WriteLine("Client sent a message: " + message.Text + + " (Cliend Id = " + client.ClientId + ")"); + + //Send reply message to the client + client.SendMessage( + new ScsTextMessage( + "Hello client. I got your message (" + message.Text + ")", + message.MessageId //Set first message's id as replied message id + )); + } + } +} diff --git a/samples/SimpleMessaging/ServerApp/Properties/AssemblyInfo.cs b/samples/SimpleMessaging/ServerApp/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c0a3988 --- /dev/null +++ b/samples/SimpleMessaging/ServerApp/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ServerApp")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("ServerApp")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("849b296f-ea34-47ab-a0e1-d8a178496264")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/SimpleMessaging/ServerApp/ServerApp.csproj b/samples/SimpleMessaging/ServerApp/ServerApp.csproj new file mode 100644 index 0000000..2c79b88 --- /dev/null +++ b/samples/SimpleMessaging/ServerApp/ServerApp.csproj @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{3731733F-5B49-4677-B353-43475305644D}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>ServerApp</RootNamespace> + <AssemblyName>ServerApp</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/samples/SimpleMessaging/SimpleMessaging.sln b/samples/SimpleMessaging/SimpleMessaging.sln new file mode 100644 index 0000000..663cd07 --- /dev/null +++ b/samples/SimpleMessaging/SimpleMessaging.sln @@ -0,0 +1,66 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServerApp", "ServerApp\ServerApp.csproj", "{3731733F-5B49-4677-B353-43475305644D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClientApp", "ClientApp\ClientApp.csproj", "{5F6A7126-4996-41AF-A4C1-13DA3D54C71B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RequestReplyStyleClient", "RequestReplyStyleClient\RequestReplyStyleClient.csproj", "{3671E987-CA41-4DAF-8D43-CF86E9AD9519}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SynchronizedClient", "SynchronizedClient\SynchronizedClient.csproj", "{256CA4BD-6131-4BD6-8EDB-BA9C2C706DA4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3731733F-5B49-4677-B353-43475305644D}.Debug|Any CPU.ActiveCfg = Debug|x86 + {3731733F-5B49-4677-B353-43475305644D}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {3731733F-5B49-4677-B353-43475305644D}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {3731733F-5B49-4677-B353-43475305644D}.Debug|x86.ActiveCfg = Debug|x86 + {3731733F-5B49-4677-B353-43475305644D}.Debug|x86.Build.0 = Debug|x86 + {3731733F-5B49-4677-B353-43475305644D}.Release|Any CPU.ActiveCfg = Release|x86 + {3731733F-5B49-4677-B353-43475305644D}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {3731733F-5B49-4677-B353-43475305644D}.Release|Mixed Platforms.Build.0 = Release|x86 + {3731733F-5B49-4677-B353-43475305644D}.Release|x86.ActiveCfg = Release|x86 + {3731733F-5B49-4677-B353-43475305644D}.Release|x86.Build.0 = Release|x86 + {5F6A7126-4996-41AF-A4C1-13DA3D54C71B}.Debug|Any CPU.ActiveCfg = Debug|x86 + {5F6A7126-4996-41AF-A4C1-13DA3D54C71B}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {5F6A7126-4996-41AF-A4C1-13DA3D54C71B}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {5F6A7126-4996-41AF-A4C1-13DA3D54C71B}.Debug|x86.ActiveCfg = Debug|x86 + {5F6A7126-4996-41AF-A4C1-13DA3D54C71B}.Debug|x86.Build.0 = Debug|x86 + {5F6A7126-4996-41AF-A4C1-13DA3D54C71B}.Release|Any CPU.ActiveCfg = Release|x86 + {5F6A7126-4996-41AF-A4C1-13DA3D54C71B}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {5F6A7126-4996-41AF-A4C1-13DA3D54C71B}.Release|Mixed Platforms.Build.0 = Release|x86 + {5F6A7126-4996-41AF-A4C1-13DA3D54C71B}.Release|x86.ActiveCfg = Release|x86 + {5F6A7126-4996-41AF-A4C1-13DA3D54C71B}.Release|x86.Build.0 = Release|x86 + {3671E987-CA41-4DAF-8D43-CF86E9AD9519}.Debug|Any CPU.ActiveCfg = Debug|x86 + {3671E987-CA41-4DAF-8D43-CF86E9AD9519}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {3671E987-CA41-4DAF-8D43-CF86E9AD9519}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {3671E987-CA41-4DAF-8D43-CF86E9AD9519}.Debug|x86.ActiveCfg = Debug|x86 + {3671E987-CA41-4DAF-8D43-CF86E9AD9519}.Debug|x86.Build.0 = Debug|x86 + {3671E987-CA41-4DAF-8D43-CF86E9AD9519}.Release|Any CPU.ActiveCfg = Release|x86 + {3671E987-CA41-4DAF-8D43-CF86E9AD9519}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {3671E987-CA41-4DAF-8D43-CF86E9AD9519}.Release|Mixed Platforms.Build.0 = Release|x86 + {3671E987-CA41-4DAF-8D43-CF86E9AD9519}.Release|x86.ActiveCfg = Release|x86 + {3671E987-CA41-4DAF-8D43-CF86E9AD9519}.Release|x86.Build.0 = Release|x86 + {256CA4BD-6131-4BD6-8EDB-BA9C2C706DA4}.Debug|Any CPU.ActiveCfg = Debug|x86 + {256CA4BD-6131-4BD6-8EDB-BA9C2C706DA4}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {256CA4BD-6131-4BD6-8EDB-BA9C2C706DA4}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {256CA4BD-6131-4BD6-8EDB-BA9C2C706DA4}.Debug|x86.ActiveCfg = Debug|x86 + {256CA4BD-6131-4BD6-8EDB-BA9C2C706DA4}.Debug|x86.Build.0 = Debug|x86 + {256CA4BD-6131-4BD6-8EDB-BA9C2C706DA4}.Release|Any CPU.ActiveCfg = Release|x86 + {256CA4BD-6131-4BD6-8EDB-BA9C2C706DA4}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {256CA4BD-6131-4BD6-8EDB-BA9C2C706DA4}.Release|Mixed Platforms.Build.0 = Release|x86 + {256CA4BD-6131-4BD6-8EDB-BA9C2C706DA4}.Release|x86.ActiveCfg = Release|x86 + {256CA4BD-6131-4BD6-8EDB-BA9C2C706DA4}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/SimpleMessaging/SynchronizedClient/Program.cs b/samples/SimpleMessaging/SynchronizedClient/Program.cs new file mode 100644 index 0000000..aa7e3d2 --- /dev/null +++ b/samples/SimpleMessaging/SynchronizedClient/Program.cs @@ -0,0 +1,46 @@ +using System; +using Hik.Communication.Scs.Client; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.Scs.Communication.Messages; +using Hik.Communication.Scs.Communication.Messengers; + +/* This program is build to demonstrate a client application that connects to a server + * and sends/receives messages in using SynchronizedMessenger. + */ + +namespace SynchronizedClient +{ + class Program + { + static void Main() + { + Console.WriteLine("Press enter to connect to the server..."); + Console.ReadLine(); //Wait user to press enter + + //Create a client object to connect a server on 127.0.0.1 (local) IP and listens 10085 TCP port + using (var client = ScsClientFactory.CreateClient(new ScsTcpEndPoint("127.0.0.1", 10085))) + { + //Create a SynchronizedMessenger that uses the client as internal messenger. + using (var synchronizedMessenger = new SynchronizedMessenger<IScsClient>(client)) + { + synchronizedMessenger.Start(); //Start synchronized messenger messenger + client.Connect(); //Connect to the server + + Console.Write("Write some message to be sent to server: "); + var messageText = Console.ReadLine(); //Get a message from user + + //Send a message to the server + synchronizedMessenger.SendMessage(new ScsTextMessage(messageText)); + + //Receive a message from the server + var receivedMessage = synchronizedMessenger.ReceiveMessage<ScsTextMessage>(); + + Console.WriteLine("Response to message: " + (receivedMessage.Text)); + + Console.WriteLine("Press enter to disconnect from server..."); + Console.ReadLine(); //Wait user to press enter + } + } + } + } +} diff --git a/samples/SimpleMessaging/SynchronizedClient/Properties/AssemblyInfo.cs b/samples/SimpleMessaging/SynchronizedClient/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..6731277 --- /dev/null +++ b/samples/SimpleMessaging/SynchronizedClient/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SynchronizedClient")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("SynchronizedClient")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c705458e-5ba3-49fb-93e8-a3a813fb15b7")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/SimpleMessaging/SynchronizedClient/SynchronizedClient.csproj b/samples/SimpleMessaging/SynchronizedClient/SynchronizedClient.csproj new file mode 100644 index 0000000..ae29c57 --- /dev/null +++ b/samples/SimpleMessaging/SynchronizedClient/SynchronizedClient.csproj @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{256CA4BD-6131-4BD6-8EDB-BA9C2C706DA4}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>SynchronizedClient</RootNamespace> + <AssemblyName>SynchronizedClient</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Scs"> + <HintPath>..\..\..\Scs-Binaries\Scs.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/src/Scs.sln b/src/Scs.sln new file mode 100644 index 0000000..dcbc4c2 --- /dev/null +++ b/src/Scs.sln @@ -0,0 +1,30 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scs", "Scs\Scs.csproj", "{0DC81B09-3ABF-4BB3-8C08-4E8EE4432BDC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0DC81B09-3ABF-4BB3-8C08-4E8EE4432BDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0DC81B09-3ABF-4BB3-8C08-4E8EE4432BDC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0DC81B09-3ABF-4BB3-8C08-4E8EE4432BDC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {0DC81B09-3ABF-4BB3-8C08-4E8EE4432BDC}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {0DC81B09-3ABF-4BB3-8C08-4E8EE4432BDC}.Debug|x86.ActiveCfg = Debug|Any CPU + {0DC81B09-3ABF-4BB3-8C08-4E8EE4432BDC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0DC81B09-3ABF-4BB3-8C08-4E8EE4432BDC}.Release|Any CPU.Build.0 = Release|Any CPU + {0DC81B09-3ABF-4BB3-8C08-4E8EE4432BDC}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {0DC81B09-3ABF-4BB3-8C08-4E8EE4432BDC}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {0DC81B09-3ABF-4BB3-8C08-4E8EE4432BDC}.Release|x86.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/Scs/Changes.txt b/src/Scs/Changes.txt new file mode 100644 index 0000000..574ae60 --- /dev/null +++ b/src/Scs/Changes.txt @@ -0,0 +1,37 @@ +# Version 1.1.0.1 - 13.06.2011 - Halil ibrahim Kalkan + # Bugfix: + # Ping message must not be raised by messaging layer. + +# Version 1.1.0.0 - 28.05.2011 - Halil ibrahim Kalkan + # Additions: + # ClientDisconnected event added to IScsServiceApplication and IScsServer classes. + # MessageSent event is added to IMessenger interface. + # SynchronizedMessenger class is added to receive messages as synchronized. + # Changes/Improvements: + # Changed background thread mechanism to provide more scalable framework. + Used TPL Tasks and Async sockets instead of directly use of threads and blocking sockets (Added SequentialItemProcessor class). + # Added IScsWireProtocolFactory interface and changed IScsServer.WireProtocol to IScsServer.WireProtocolFactory. + Also, IScsWireProtocol is completely changed. + (This change is not backward compatible) + # BinarySerializationProtocol class is made public to allow user to override serialization methods. + # Codes completely revised, some parts refactored and commented. + # BugFix: + # Fixed a potential minor bug in Timer. + +# Version 1.0.2.0 - 11.05.2011 - Halil ibrahim Kalkan + Feature: + # Added RemoteEndPoint property to get address of client application in server side. + (Added to ICommunicationChannel, IScsServerClient and IScsServiceClient) + +# Version 1.0.1.0 - 10.04.2011 - Halil ibrahim Kalkan + Feature: + # Added ConnectTimeout property to IConnectableClient to provide a way of setting + timeout value while connecting to a server. + +# Version 1.0.0.1 - 10.04.2011 - Halil ibrahim Kalkan + BugFix: + # RequestReplyMessenger starts when a client is created. It must start when connected to server. + Otherwise, if user does not connect to client, a thread remains running. + +# Version 1.0.0.0 - 01.02.2011 - Halil ibrahim Kalkan + First stable release.
\ No newline at end of file diff --git a/src/Scs/Collections/ThreadSafeSortedList.cs b/src/Scs/Collections/ThreadSafeSortedList.cs new file mode 100644 index 0000000..10a980d --- /dev/null +++ b/src/Scs/Collections/ThreadSafeSortedList.cs @@ -0,0 +1,197 @@ +using System.Collections.Generic; +using System.Threading; + +namespace Hik.Collections +{ + /// <summary> + /// This class is used to store key-value based items in a thread safe manner. + /// It uses System.Collections.Generic.SortedList internally. + /// </summary> + /// <typeparam name="TK">Key type</typeparam> + /// <typeparam name="TV">Value type</typeparam> + public class ThreadSafeSortedList<TK, TV> + { + /// <summary> + /// Gets/adds/replaces an item by key. + /// </summary> + /// <param name="key">Key to get/set value</param> + /// <returns>Item associated with this key</returns> + public TV this[TK key] + { + get + { + _lock.EnterReadLock(); + try + { + return _items.ContainsKey(key) ? _items[key] : default(TV); + } + finally + { + _lock.ExitReadLock(); + } + } + + set + { + _lock.EnterWriteLock(); + try + { + _items[key] = value; + } + finally + { + _lock.ExitWriteLock(); + } + } + } + + /// <summary> + /// Gets count of items in the collection. + /// </summary> + public int Count + { + get + { + _lock.EnterReadLock(); + try + { + return _items.Count; + } + finally + { + _lock.ExitReadLock(); + } + } + } + + /// <summary> + /// Internal collection to store items. + /// </summary> + protected readonly SortedList<TK, TV> _items; + + /// <summary> + /// Used to synchronize access to _items list. + /// </summary> + protected readonly ReaderWriterLockSlim _lock; + + /// <summary> + /// Creates a new ThreadSafeSortedList object. + /// </summary> + public ThreadSafeSortedList() + { + _items = new SortedList<TK, TV>(); + _lock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); + } + + /// <summary> + /// Checks if collection contains spesified key. + /// </summary> + /// <param name="key">Key to check</param> + /// <returns>True; if collection contains given key</returns> + public bool ContainsKey(TK key) + { + _lock.EnterReadLock(); + try + { + return _items.ContainsKey(key); + } + finally + { + _lock.ExitReadLock(); + } + } + + /// <summary> + /// Checks if collection contains spesified item. + /// </summary> + /// <param name="item">Item to check</param> + /// <returns>True; if collection contains given item</returns> + public bool ContainsValue(TV item) + { + _lock.EnterReadLock(); + try + { + return _items.ContainsValue(item); + } + finally + { + _lock.ExitReadLock(); + } + } + + /// <summary> + /// Removes an item from collection. + /// </summary> + /// <param name="key">Key of item to remove</param> + public bool Remove(TK key) + { + _lock.EnterWriteLock(); + try + { + if (!_items.ContainsKey(key)) + { + return false; + } + + _items.Remove(key); + return true; + } + finally + { + _lock.ExitWriteLock(); + } + } + + /// <summary> + /// Gets all items in collection. + /// </summary> + /// <returns>Item list</returns> + public List<TV> GetAllItems() + { + _lock.EnterReadLock(); + try + { + return new List<TV>(_items.Values); + } + finally + { + _lock.ExitReadLock(); + } + } + + /// <summary> + /// Removes all items from list. + /// </summary> + public void ClearAll() + { + _lock.EnterWriteLock(); + try + { + _items.Clear(); + } + finally + { + _lock.ExitWriteLock(); + } + } + + /// <summary> + /// Gets then removes all items in collection. + /// </summary> + /// <returns>Item list</returns> + public List<TV> GetAndClearAllItems() + { + _lock.EnterWriteLock(); + try + { + var list = new List<TV>(_items.Values); + _items.Clear(); + return list; + } + finally + { + _lock.ExitWriteLock(); + } + } + } +} diff --git a/src/Scs/Communication/Scs/Client/ClientReConnecter.cs b/src/Scs/Communication/Scs/Client/ClientReConnecter.cs new file mode 100644 index 0000000..88f0159 --- /dev/null +++ b/src/Scs/Communication/Scs/Client/ClientReConnecter.cs @@ -0,0 +1,109 @@ +using System; +using Hik.Communication.Scs.Communication; +using Hik.Threading; + +namespace Hik.Communication.Scs.Client +{ + /// <summary> + /// This class is used to automatically re-connect to server if disconnected. + /// It attempts to reconnect to server periodically until connection established. + /// </summary> + public class ClientReConnecter : IDisposable + { + /// <summary> + /// Reconnect check period. + /// Default: 20 seconds. + /// </summary> + public int ReConnectCheckPeriod + { + get { return _reconnectTimer.Period; } + set { _reconnectTimer.Period = value; } + } + + /// <summary> + /// Reference to client object. + /// </summary> + private readonly IConnectableClient _client; + + /// <summary> + /// Timer to attempt ro reconnect periodically. + /// </summary> + private readonly Timer _reconnectTimer; + + /// <summary> + /// Indicates the dispose state of this object. + /// </summary> + private volatile bool _disposed; + + /// <summary> + /// Creates a new ClientReConnecter object. + /// It is not needed to start ClientReConnecter since it automatically + /// starts when the client disconnected. + /// </summary> + /// <param name="client">Reference to client object</param> + /// <exception cref="ArgumentNullException">Throws ArgumentNullException if client is null.</exception> + public ClientReConnecter(IConnectableClient client) + { + if (client == null) + { + throw new ArgumentNullException("client"); + } + + _client = client; + _client.Disconnected += Client_Disconnected; + _reconnectTimer = new Timer(20000); + _reconnectTimer.Elapsed += ReconnectTimer_Elapsed; + _reconnectTimer.Start(); + } + + /// <summary> + /// Disposes this object. + /// Does nothing if already disposed. + /// </summary> + public void Dispose() + { + if (_disposed) + { + return; + } + + _disposed = true; + _client.Disconnected -= Client_Disconnected; + _reconnectTimer.Stop(); + } + + /// <summary> + /// Handles Disconnected event of _client object. + /// </summary> + /// <param name="sender">Source of the event</param> + /// <param name="e">Event arguments</param> + private void Client_Disconnected(object sender, EventArgs e) + { + _reconnectTimer.Start(); + } + + /// <summary> + /// Hadles Elapsed event of _reconnectTimer. + /// </summary> + /// <param name="sender">Source of the event</param> + /// <param name="e">Event arguments</param> + private void ReconnectTimer_Elapsed(object sender, EventArgs e) + { + if (_disposed || _client.CommunicationState == CommunicationStates.Connected) + { + _reconnectTimer.Stop(); + return; + } + + try + { + _client.Connect(); + _reconnectTimer.Stop(); + } + catch + { + //No need to catch since it will try to re-connect again + } + } + } +} diff --git a/src/Scs/Communication/Scs/Client/IConnectableClient.cs b/src/Scs/Communication/Scs/Client/IConnectableClient.cs new file mode 100644 index 0000000..9bbf7c0 --- /dev/null +++ b/src/Scs/Communication/Scs/Client/IConnectableClient.cs @@ -0,0 +1,43 @@ +using System; +using Hik.Communication.Scs.Communication; + +namespace Hik.Communication.Scs.Client +{ + /// <summary> + /// Represents a client for SCS servers. + /// </summary> + public interface IConnectableClient : IDisposable + { + /// <summary> + /// This event is raised when client connected to server. + /// </summary> + event EventHandler Connected; + + /// <summary> + /// This event is raised when client disconnected from server. + /// </summary> + event EventHandler Disconnected; + + /// <summary> + /// Timeout for connecting to a server (as milliseconds). + /// Default value: 15 seconds (15000 ms). + /// </summary> + int ConnectTimeout { get; set; } + + /// <summary> + /// Gets the current communication state. + /// </summary> + CommunicationStates CommunicationState { get; } + + /// <summary> + /// Connects to server. + /// </summary> + void Connect(); + + /// <summary> + /// Disconnects from server. + /// Does nothing if already disconnected. + /// </summary> + void Disconnect(); + } +} diff --git a/src/Scs/Communication/Scs/Client/IScsClient.cs b/src/Scs/Communication/Scs/Client/IScsClient.cs new file mode 100644 index 0000000..27cafe2 --- /dev/null +++ b/src/Scs/Communication/Scs/Client/IScsClient.cs @@ -0,0 +1,13 @@ +using Hik.Communication.Scs.Communication; +using Hik.Communication.Scs.Communication.Messengers; + +namespace Hik.Communication.Scs.Client +{ + /// <summary> + /// Represents a client to connect to server. + /// </summary> + public interface IScsClient : IMessenger, IConnectableClient + { + //Does not define any additional member + } +} diff --git a/src/Scs/Communication/Scs/Client/ScsClientBase.cs b/src/Scs/Communication/Scs/Client/ScsClientBase.cs new file mode 100644 index 0000000..11cf673 --- /dev/null +++ b/src/Scs/Communication/Scs/Client/ScsClientBase.cs @@ -0,0 +1,330 @@ +using System; +using Hik.Communication.Scs.Communication; +using Hik.Communication.Scs.Communication.Messages; +using Hik.Communication.Scs.Communication.Channels; +using Hik.Communication.Scs.Communication.Protocols; +using Hik.Threading; + +namespace Hik.Communication.Scs.Client +{ + /// <summary> + /// This class provides base functionality for client classes. + /// </summary> + internal abstract class ScsClientBase : IScsClient + { + #region Public events + + /// <summary> + /// This event is raised when a new message is received. + /// </summary> + public event EventHandler<MessageEventArgs> MessageReceived; + + /// <summary> + /// This event is raised when a new message is sent without any error. + /// It does not guaranties that message is properly handled and processed by remote application. + /// </summary> + public event EventHandler<MessageEventArgs> MessageSent; + + /// <summary> + /// This event is raised when communication channel closed. + /// </summary> + public event EventHandler Connected; + + /// <summary> + /// This event is raised when client disconnected from server. + /// </summary> + public event EventHandler Disconnected; + + #endregion + + #region Public properties + + /// <summary> + /// Timeout for connecting to a server (as milliseconds). + /// Default value: 15 seconds (15000 ms). + /// </summary> + public int ConnectTimeout { get; set; } + + /// <summary> + /// Gets/sets wire protocol that is used while reading and writing messages. + /// </summary> + public IScsWireProtocol WireProtocol + { + get { return _wireProtocol; } + set + { + if (CommunicationState == CommunicationStates.Connected) + { + throw new ApplicationException("Wire protocol can not be changed while connected to server."); + } + + _wireProtocol = value; + } + } + private IScsWireProtocol _wireProtocol; + + /// <summary> + /// Gets the communication state of the Client. + /// </summary> + public CommunicationStates CommunicationState + { + get + { + return _communicationChannel != null + ? _communicationChannel.CommunicationState + : CommunicationStates.Disconnected; + } + } + + /// <summary> + /// Gets the time of the last succesfully received message. + /// </summary> + public DateTime LastReceivedMessageTime + { + get + { + return _communicationChannel != null + ? _communicationChannel.LastReceivedMessageTime + : DateTime.MinValue; + } + } + + /// <summary> + /// Gets the time of the last succesfully received message. + /// </summary> + public DateTime LastSentMessageTime + { + get + { + return _communicationChannel != null + ? _communicationChannel.LastSentMessageTime + : DateTime.MinValue; + } + } + + #endregion + + #region Private fields + + /// <summary> + /// Default timeout value for connecting a server. + /// </summary> + private const int DefaultConnectionAttemptTimeout = 15000; //15 seconds. + + /// <summary> + /// The communication channel that is used by client to send and receive messages. + /// </summary> + private ICommunicationChannel _communicationChannel; + + /// <summary> + /// This timer is used to send PingMessage messages to server periodically. + /// </summary> + private readonly Timer _pingTimer; + + #endregion + + #region Constructor + + /// <summary> + /// Constructor. + /// </summary> + protected ScsClientBase() + { + _pingTimer = new Timer(30000); + _pingTimer.Elapsed += PingTimer_Elapsed; + ConnectTimeout = DefaultConnectionAttemptTimeout; + WireProtocol = WireProtocolManager.GetDefaultWireProtocol(); + } + + #endregion + + #region Public methods + + /// <summary> + /// Connects to server. + /// </summary> + public void Connect() + { + WireProtocol.Reset(); + _communicationChannel = CreateCommunicationChannel(); + _communicationChannel.WireProtocol = WireProtocol; + _communicationChannel.Disconnected += CommunicationChannel_Disconnected; + _communicationChannel.MessageReceived += CommunicationChannel_MessageReceived; + _communicationChannel.MessageSent += CommunicationChannel_MessageSent; + _communicationChannel.Start(); + _pingTimer.Start(); + OnConnected(); + } + + /// <summary> + /// Disconnects from server. + /// Does nothing if already disconnected. + /// </summary> + public void Disconnect() + { + if (CommunicationState != CommunicationStates.Connected) + { + return; + } + + _communicationChannel.Disconnect(); + } + + /// <summary> + /// Disposes this object and closes underlying connection. + /// </summary> + public void Dispose() + { + Disconnect(); + } + + /// <summary> + /// Sends a message to the server. + /// </summary> + /// <param name="message">Message to be sent</param> + /// <exception cref="CommunicationStateException">Throws a CommunicationStateException if client is not connected to the server.</exception> + public void SendMessage(IScsMessage message) + { + if (CommunicationState != CommunicationStates.Connected) + { + throw new CommunicationStateException("Client is not connected to the server."); + } + + _communicationChannel.SendMessage(message); + } + + #endregion + + #region Abstract methods + + /// <summary> + /// This method is implemented by derived classes to create appropriate communication channel. + /// </summary> + /// <returns>Ready communication channel to communicate</returns> + protected abstract ICommunicationChannel CreateCommunicationChannel(); + + #endregion + + #region Private methods + + /// <summary> + /// Handles MessageReceived event of _communicationChannel object. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void CommunicationChannel_MessageReceived(object sender, MessageEventArgs e) + { + if (e.Message is ScsPingMessage) + { + return; + } + + OnMessageReceived(e.Message); + } + + /// <summary> + /// Handles MessageSent event of _communicationChannel object. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void CommunicationChannel_MessageSent(object sender, MessageEventArgs e) + { + OnMessageSent(e.Message); + } + + /// <summary> + /// Handles Disconnected event of _communicationChannel object. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void CommunicationChannel_Disconnected(object sender, EventArgs e) + { + _pingTimer.Stop(); + OnDisconnected(); + } + + /// <summary> + /// Handles Elapsed event of _pingTimer to send PingMessage messages to server. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void PingTimer_Elapsed(object sender, EventArgs e) + { + if (CommunicationState != CommunicationStates.Connected) + { + return; + } + + try + { + var lastMinute = DateTime.Now.AddMinutes(-1); + if (_communicationChannel.LastReceivedMessageTime > lastMinute || _communicationChannel.LastSentMessageTime > lastMinute) + { + return; + } + + _communicationChannel.SendMessage(new ScsPingMessage()); + } + catch + { + + } + } + + #endregion + + #region Event raising methods + + /// <summary> + /// Raises Connected event. + /// </summary> + protected virtual void OnConnected() + { + var handler = Connected; + if (handler != null) + { + handler(this, EventArgs.Empty); + } + } + + /// <summary> + /// Raises Disconnected event. + /// </summary> + protected virtual void OnDisconnected() + { + var handler = Disconnected; + if (handler != null) + { + handler(this, EventArgs.Empty); + } + } + + /// <summary> + /// Raises MessageReceived event. + /// </summary> + /// <param name="message">Received message</param> + protected virtual void OnMessageReceived(IScsMessage message) + { + var handler = MessageReceived; + if (handler != null) + { + handler(this, new MessageEventArgs(message)); + } + } + + /// <summary> + /// Raises MessageSent event. + /// </summary> + /// <param name="message">Received message</param> + protected virtual void OnMessageSent(IScsMessage message) + { + var handler = MessageSent; + if (handler != null) + { + handler(this, new MessageEventArgs(message)); + } + } + + #endregion + } +} diff --git a/src/Scs/Communication/Scs/Client/ScsClientFactory.cs b/src/Scs/Communication/Scs/Client/ScsClientFactory.cs new file mode 100644 index 0000000..877e8dd --- /dev/null +++ b/src/Scs/Communication/Scs/Client/ScsClientFactory.cs @@ -0,0 +1,30 @@ +using Hik.Communication.Scs.Communication.EndPoints; + +namespace Hik.Communication.Scs.Client +{ + /// <summary> + /// This class is used to create SCS Clients to connect to a SCS server. + /// </summary> + public static class ScsClientFactory + { + /// <summary> + /// Creates a new client to connect to a server using an end point. + /// </summary> + /// <param name="endpoint">End point of the server to connect it</param> + /// <returns>Created TCP client</returns> + public static IScsClient CreateClient(ScsEndPoint endpoint) + { + return endpoint.CreateClient(); + } + + /// <summary> + /// Creates a new client to connect to a server using an end point. + /// </summary> + /// <param name="endpointAddress">End point address of the server to connect it</param> + /// <returns>Created TCP client</returns> + public static IScsClient CreateClient(string endpointAddress) + { + return CreateClient(ScsEndPoint.CreateEndPoint(endpointAddress)); + } + } +} diff --git a/src/Scs/Communication/Scs/Client/Tcp/ScsTcpClient.cs b/src/Scs/Communication/Scs/Client/Tcp/ScsTcpClient.cs new file mode 100644 index 0000000..20ee206 --- /dev/null +++ b/src/Scs/Communication/Scs/Client/Tcp/ScsTcpClient.cs @@ -0,0 +1,40 @@ +using Hik.Communication.Scs.Communication.Channels; +using Hik.Communication.Scs.Communication.Channels.Tcp; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using System.Net; + +namespace Hik.Communication.Scs.Client.Tcp +{ + /// <summary> + /// This class is used to communicate with server over TCP/IP protocol. + /// </summary> + internal class ScsTcpClient : ScsClientBase + { + /// <summary> + /// The endpoint address of the server. + /// </summary> + private readonly ScsTcpEndPoint _serverEndPoint; + + /// <summary> + /// Creates a new ScsTcpClient object. + /// </summary> + /// <param name="serverEndPoint">The endpoint address to connect to the server</param> + public ScsTcpClient(ScsTcpEndPoint serverEndPoint) + { + _serverEndPoint = serverEndPoint; + } + + /// <summary> + /// Creates a communication channel using ServerIpAddress and ServerPort. + /// </summary> + /// <returns>Ready communication channel to communicate</returns> + protected override ICommunicationChannel CreateCommunicationChannel() + { + return new TcpCommunicationChannel( + TcpHelper.ConnectToServer( + new IPEndPoint(IPAddress.Parse(_serverEndPoint.IpAddress), _serverEndPoint.TcpPort), + ConnectTimeout + )); + } + } +} diff --git a/src/Scs/Communication/Scs/Client/Tcp/TcpHelper.cs b/src/Scs/Communication/Scs/Client/Tcp/TcpHelper.cs new file mode 100644 index 0000000..f0cd38b --- /dev/null +++ b/src/Scs/Communication/Scs/Client/Tcp/TcpHelper.cs @@ -0,0 +1,49 @@ +using System; +using System.Net; +using System.Net.Sockets; + +namespace Hik.Communication.Scs.Client.Tcp +{ + /// <summary> + /// This class is used to simplify TCP socket operations. + /// </summary> + internal static class TcpHelper + { + /// <summary> + /// This code is used to connect to a TCP socket with timeout option. + /// </summary> + /// <param name="endPoint">IP endpoint of remote server</param> + /// <param name="timeoutMs">Timeout to wait until connect</param> + /// <returns>Socket object connected to server</returns> + /// <exception cref="SocketException">Throws SocketException if can not connect.</exception> + /// <exception cref="TimeoutException">Throws TimeoutException if can not connect within specified timeoutMs</exception> + public static Socket ConnectToServer(EndPoint endPoint, int timeoutMs) + { + var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + try + { + socket.Blocking = false; + socket.Connect(endPoint); + socket.Blocking = true; + return socket; + } + catch (SocketException socketException) + { + if (socketException.ErrorCode != 10035) + { + socket.Close(); + throw; + } + + if (!socket.Poll(timeoutMs * 1000, SelectMode.SelectWrite)) + { + socket.Close(); + throw new TimeoutException("The host failed to connect. Timeout occured."); + } + + socket.Blocking = true; + return socket; + } + } + } +} diff --git a/src/Scs/Communication/Scs/Communication/Channels/CommunicationChannelBase.cs b/src/Scs/Communication/Scs/Communication/Channels/CommunicationChannelBase.cs new file mode 100644 index 0000000..506dce5 --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Channels/CommunicationChannelBase.cs @@ -0,0 +1,176 @@ +using System; +using Hik.Communication.Scs.Communication.EndPoints; +using Hik.Communication.Scs.Communication.Messages; +using Hik.Communication.Scs.Communication.Protocols; + +namespace Hik.Communication.Scs.Communication.Channels +{ + /// <summary> + /// This class provides base functionality for all communication channel classes. + /// </summary> + internal abstract class CommunicationChannelBase : ICommunicationChannel + { + #region Public events + + /// <summary> + /// This event is raised when a new message is received. + /// </summary> + public event EventHandler<MessageEventArgs> MessageReceived; + + /// <summary> + /// This event is raised when a new message is sent without any error. + /// It does not guaranties that message is properly handled and processed by remote application. + /// </summary> + public event EventHandler<MessageEventArgs> MessageSent; + + /// <summary> + /// This event is raised when communication channel closed. + /// </summary> + public event EventHandler Disconnected; + + #endregion + + #region Public abstract properties + + ///<summary> + /// Gets endpoint of remote application. + ///</summary> + public abstract ScsEndPoint RemoteEndPoint { get; } + + #endregion + + #region Public properties + + /// <summary> + /// Gets the current communication state. + /// </summary> + public CommunicationStates CommunicationState { get; protected set; } + + /// <summary> + /// Gets the time of the last succesfully received message. + /// </summary> + public DateTime LastReceivedMessageTime { get; protected set; } + + /// <summary> + /// Gets the time of the last succesfully sent message. + /// </summary> + public DateTime LastSentMessageTime { get; protected set; } + + /// <summary> + /// Gets/sets wire protocol that the channel uses. + /// This property must set before first communication. + /// </summary> + public IScsWireProtocol WireProtocol { get; set; } + + #endregion + + #region Constructor + + /// <summary> + /// Constructor. + /// </summary> + protected CommunicationChannelBase() + { + CommunicationState = CommunicationStates.Disconnected; + LastReceivedMessageTime = DateTime.MinValue; + LastSentMessageTime = DateTime.MinValue; + } + + #endregion + + #region Public abstract methods + + /// <summary> + /// Disconnects from remote application and closes this channel. + /// </summary> + public abstract void Disconnect(); + + #endregion + + #region Public methods + + /// <summary> + /// Starts the communication with remote application. + /// </summary> + public void Start() + { + StartInternal(); + CommunicationState = CommunicationStates.Connected; + } + + /// <summary> + /// Sends a message to the remote application. + /// </summary> + /// <param name="message">Message to be sent</param> + /// <exception cref="ArgumentNullException">Throws ArgumentNullException if message is null</exception> + public void SendMessage(IScsMessage message) + { + if (message == null) + { + throw new ArgumentNullException("message"); + } + + SendMessageInternal(message); + } + + #endregion + + #region Protected abstract methods + + /// <summary> + /// Starts the communication with remote application really. + /// </summary> + protected abstract void StartInternal(); + + /// <summary> + /// Sends a message to the remote application. + /// This method is overrided by derived classes to really send to message. + /// </summary> + /// <param name="message">Message to be sent</param> + protected abstract void SendMessageInternal(IScsMessage message); + + #endregion + + #region Event raising methods + + /// <summary> + /// Raises Disconnected event. + /// </summary> + protected virtual void OnDisconnected() + { + var handler = Disconnected; + if (handler != null) + { + handler(this, EventArgs.Empty); + } + } + + /// <summary> + /// Raises MessageReceived event. + /// </summary> + /// <param name="message">Received message</param> + protected virtual void OnMessageReceived(IScsMessage message) + { + var handler = MessageReceived; + if (handler != null) + { + handler(this, new MessageEventArgs(message)); + } + } + + /// <summary> + /// Raises MessageSent event. + /// </summary> + /// <param name="message">Received message</param> + protected virtual void OnMessageSent(IScsMessage message) + { + var handler = MessageSent; + if (handler != null) + { + handler(this, new MessageEventArgs(message)); + } + } + + #endregion + } +} diff --git a/src/Scs/Communication/Scs/Communication/Channels/CommunicationChannelEventArgs.cs b/src/Scs/Communication/Scs/Communication/Channels/CommunicationChannelEventArgs.cs new file mode 100644 index 0000000..e40849c --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Channels/CommunicationChannelEventArgs.cs @@ -0,0 +1,24 @@ +using System; + +namespace Hik.Communication.Scs.Communication.Channels +{ + /// <summary> + /// Stores communication channel information to be used by an event. + /// </summary> + internal class CommunicationChannelEventArgs : EventArgs + { + /// <summary> + /// Communication channel that is associated with this event. + /// </summary> + public ICommunicationChannel Channel { get; private set; } + + /// <summary> + /// Creates a new CommunicationChannelEventArgs object. + /// </summary> + /// <param name="channel">Communication channel that is associated with this event</param> + public CommunicationChannelEventArgs(ICommunicationChannel channel) + { + Channel = channel; + } + } +} diff --git a/src/Scs/Communication/Scs/Communication/Channels/ConnectionListenerBase.cs b/src/Scs/Communication/Scs/Communication/Channels/ConnectionListenerBase.cs new file mode 100644 index 0000000..f630ce4 --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Channels/ConnectionListenerBase.cs @@ -0,0 +1,38 @@ +using System; + +namespace Hik.Communication.Scs.Communication.Channels +{ + /// <summary> + /// This class provides base functionality for communication listener classes. + /// </summary> + internal abstract class ConnectionListenerBase : IConnectionListener + { + /// <summary> + /// This event is raised when a new communication channel is connected. + /// </summary> + public event EventHandler<CommunicationChannelEventArgs> CommunicationChannelConnected; + + /// <summary> + /// Starts listening incoming connections. + /// </summary> + public abstract void Start(); + + /// <summary> + /// Stops listening incoming connections. + /// </summary> + public abstract void Stop(); + + /// <summary> + /// Raises CommunicationChannelConnected event. + /// </summary> + /// <param name="client"></param> + protected virtual void OnCommunicationChannelConnected(ICommunicationChannel client) + { + var handler = CommunicationChannelConnected; + if (handler != null) + { + handler(this, new CommunicationChannelEventArgs(client)); + } + } + } +} diff --git a/src/Scs/Communication/Scs/Communication/Channels/ICommunicationChannel.cs b/src/Scs/Communication/Scs/Communication/Channels/ICommunicationChannel.cs new file mode 100644 index 0000000..cf9e89c --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Channels/ICommunicationChannel.cs @@ -0,0 +1,38 @@ +using System; +using Hik.Communication.Scs.Communication.EndPoints; +using Hik.Communication.Scs.Communication.Messengers; + +namespace Hik.Communication.Scs.Communication.Channels +{ + /// <summary> + /// Represents a communication channel. + /// A communication channel is used to communicate (send/receive messages) with a remote application. + /// </summary> + internal interface ICommunicationChannel : IMessenger + { + /// <summary> + /// This event is raised when client disconnected from server. + /// </summary> + event EventHandler Disconnected; + + ///<summary> + /// Gets endpoint of remote application. + ///</summary> + ScsEndPoint RemoteEndPoint { get; } + + /// <summary> + /// Gets the current communication state. + /// </summary> + CommunicationStates CommunicationState { get; } + + /// <summary> + /// Starts the communication with remote application. + /// </summary> + void Start(); + + /// <summary> + /// Closes messenger. + /// </summary> + void Disconnect(); + } +} diff --git a/src/Scs/Communication/Scs/Communication/Channels/IConnectionListener.cs b/src/Scs/Communication/Scs/Communication/Channels/IConnectionListener.cs new file mode 100644 index 0000000..2245941 --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Channels/IConnectionListener.cs @@ -0,0 +1,26 @@ +using System; + +namespace Hik.Communication.Scs.Communication.Channels +{ + /// <summary> + /// Represents a communication listener. + /// A connection listener is used to accept incoming client connection requests. + /// </summary> + internal interface IConnectionListener + { + /// <summary> + /// This event is raised when a new communication channel connected. + /// </summary> + event EventHandler<CommunicationChannelEventArgs> CommunicationChannelConnected; + + /// <summary> + /// Starts listening incoming connections. + /// </summary> + void Start(); + + /// <summary> + /// Stops listening incoming connections. + /// </summary> + void Stop(); + } +} diff --git a/src/Scs/Communication/Scs/Communication/Channels/Tcp/TcpCommunicationChannel.cs b/src/Scs/Communication/Scs/Communication/Channels/Tcp/TcpCommunicationChannel.cs new file mode 100644 index 0000000..0b3e310 --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Channels/Tcp/TcpCommunicationChannel.cs @@ -0,0 +1,210 @@ +using System; +using System.Net; +using System.Net.Sockets; +using Hik.Communication.Scs.Communication.EndPoints; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.Scs.Communication.Messages; + +namespace Hik.Communication.Scs.Communication.Channels.Tcp +{ + /// <summary> + /// This class is used to communicate with a remote application over TCP/IP protocol. + /// </summary> + internal class TcpCommunicationChannel : CommunicationChannelBase + { + #region Public properties + + ///<summary> + /// Gets the endpoint of remote application. + ///</summary> + public override ScsEndPoint RemoteEndPoint + { + get + { + return _remoteEndPoint; + } + } + private readonly ScsTcpEndPoint _remoteEndPoint; + + #endregion + + #region Private fields + + /// <summary> + /// Size of the buffer that is used to receive bytes from TCP socket. + /// </summary> + private const int ReceiveBufferSize = 4 * 1024; //4KB + + /// <summary> + /// This buffer is used to receive bytes + /// </summary> + private readonly byte[] _buffer; + + /// <summary> + /// Socket object to send/reveice messages. + /// </summary> + private readonly Socket _clientSocket; + + /// <summary> + /// A flag to control thread's running + /// </summary> + private volatile bool _running; + + /// <summary> + /// This object is just used for thread synchronizing (locking). + /// </summary> + private readonly object _syncLock; + + #endregion + + #region Constructor + + /// <summary> + /// Creates a new TcpCommunicationChannel object. + /// </summary> + /// <param name="clientSocket">A connected Socket object that is + /// used to communicate over network</param> + public TcpCommunicationChannel(Socket clientSocket) + { + _clientSocket = clientSocket; + _clientSocket.NoDelay = true; + + var ipEndPoint = (IPEndPoint)_clientSocket.RemoteEndPoint; + _remoteEndPoint = new ScsTcpEndPoint(ipEndPoint.Address.ToString(), ipEndPoint.Port); + + _buffer = new byte[ReceiveBufferSize]; + _syncLock = new object(); + } + + #endregion + + #region Public methods + + /// <summary> + /// Disconnects from remote application and closes channel. + /// </summary> + public override void Disconnect() + { + if (CommunicationState != CommunicationStates.Connected) + { + return; + } + + _running = false; + try + { + if (_clientSocket.Connected) + { + _clientSocket.Close(); + } + + _clientSocket.Dispose(); + } + catch + { + + } + + CommunicationState = CommunicationStates.Disconnected; + OnDisconnected(); + } + + #endregion + + #region Protected methods + + /// <summary> + /// Starts the thread to receive messages from socket. + /// </summary> + protected override void StartInternal() + { + _running = true; + _clientSocket.BeginReceive(_buffer, 0, _buffer.Length, 0, new AsyncCallback(ReceiveCallback), null); + } + + /// <summary> + /// Sends a message to the remote application. + /// </summary> + /// <param name="message">Message to be sent</param> + protected override void SendMessageInternal(IScsMessage message) + { + //Send message + var totalSent = 0; + lock (_syncLock) + { + //Create a byte array from message according to current protocol + var messageBytes = WireProtocol.GetBytes(message); + //Send all bytes to the remote application + while (totalSent < messageBytes.Length) + { + var sent = _clientSocket.Send(messageBytes, totalSent, messageBytes.Length - totalSent, SocketFlags.None); + if (sent <= 0) + { + throw new CommunicationException("Message could not be sent via TCP socket. Only " + totalSent + " bytes of " + messageBytes.Length + " bytes are sent."); + } + + totalSent += sent; + } + + LastSentMessageTime = DateTime.Now; + OnMessageSent(message); + } + } + + #endregion + + #region Private methods + + /// <summary> + /// This method is used as callback method in _clientSocket's BeginReceive method. + /// It reveives bytes from socker. + /// </summary> + /// <param name="ar">Asyncronous call result</param> + private void ReceiveCallback(IAsyncResult ar) + { + if(!_running) + { + return; + } + + try + { + //Get received bytes count + var bytesRead = _clientSocket.EndReceive(ar); + if (bytesRead > 0) + { + LastReceivedMessageTime = DateTime.Now; + + //Copy received bytes to a new byte array + var receivedBytes = new byte[bytesRead]; + Array.Copy(_buffer, 0, receivedBytes, 0, bytesRead); + + //Read messages according to current wire protocol + var messages = WireProtocol.CreateMessages(receivedBytes); + + //Raise MessageReceived event for all received messages + foreach (var message in messages) + { + OnMessageReceived(message); + } + } + else + { + throw new CommunicationException("Tcp socket is closed"); + } + + //Read more bytes if still running + if (_running) + { + _clientSocket.BeginReceive(_buffer, 0, _buffer.Length, 0, new AsyncCallback(ReceiveCallback), null); + } + } + catch + { + Disconnect(); + } + } + + #endregion + } +} diff --git a/src/Scs/Communication/Scs/Communication/Channels/Tcp/TcpConnectionListener.cs b/src/Scs/Communication/Scs/Communication/Channels/Tcp/TcpConnectionListener.cs new file mode 100644 index 0000000..773ff80 --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Channels/Tcp/TcpConnectionListener.cs @@ -0,0 +1,124 @@ +using System.Net.Sockets; +using System.Threading; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; + +namespace Hik.Communication.Scs.Communication.Channels.Tcp +{ + /// <summary> + /// This class is used to listen and accept incoming TCP + /// connection requests on a TCP port. + /// </summary> + internal class TcpConnectionListener : ConnectionListenerBase + { + /// <summary> + /// The endpoint address of the server to listen incoming connections. + /// </summary> + private readonly ScsTcpEndPoint _endPoint; + + /// <summary> + /// Server socket to listen incoming connection requests. + /// </summary> + private TcpListener _listenerSocket; + + /// <summary> + /// The thread to listen socket + /// </summary> + private Thread _thread; + + /// <summary> + /// A flag to control thread's running + /// </summary> + private volatile bool _running; + + /// <summary> + /// Creates a new TcpConnectionListener for given endpoint. + /// </summary> + /// <param name="endPoint">The endpoint address of the server to listen incoming connections</param> + public TcpConnectionListener(ScsTcpEndPoint endPoint) + { + _endPoint = endPoint; + } + + /// <summary> + /// Starts listening incoming connections. + /// </summary> + public override void Start() + { + StartSocket(); + _running = true; + _thread = new Thread(DoListenAsThread); + _thread.Start(); + } + + /// <summary> + /// Stops listening incoming connections. + /// </summary> + public override void Stop() + { + _running = false; + StopSocket(); + } + + /// <summary> + /// Starts listening socket. + /// </summary> + private void StartSocket() + { + _listenerSocket = new TcpListener(System.Net.IPAddress.Any, _endPoint.TcpPort); + _listenerSocket.Start(); + } + + /// <summary> + /// Stops listening socket. + /// </summary> + private void StopSocket() + { + try + { + _listenerSocket.Stop(); + } + catch + { + + } + } + + /// <summary> + /// Entrance point of the thread. + /// This method is used by the thread to listen incoming requests. + /// </summary> + private void DoListenAsThread() + { + while (_running) + { + try + { + var clientSocket = _listenerSocket.AcceptSocket(); + if (clientSocket.Connected) + { + OnCommunicationChannelConnected(new TcpCommunicationChannel(clientSocket)); + } + } + catch + { + //Disconnect, wait for a while and connect again. + StopSocket(); + Thread.Sleep(1000); + if (!_running) + { + return; + } + + try + { + StartSocket(); + } + catch + { + + } + } + } + } + } +} diff --git a/src/Scs/Communication/Scs/Communication/CommunicationException.cs b/src/Scs/Communication/Scs/Communication/CommunicationException.cs new file mode 100644 index 0000000..4a8c9c3 --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/CommunicationException.cs @@ -0,0 +1,50 @@ +using System; +using System.Runtime.Serialization; + +namespace Hik.Communication.Scs.Communication +{ + /// <summary> + /// This application is thrown in a communication error. + /// </summary> + [Serializable] + public class CommunicationException : Exception + { + /// <summary> + /// Contstructor. + /// </summary> + public CommunicationException() + { + + } + + /// <summary> + /// Contstructor for serializing. + /// </summary> + public CommunicationException(SerializationInfo serializationInfo, StreamingContext context) + : base(serializationInfo, context) + { + + } + + /// <summary> + /// Contstructor. + /// </summary> + /// <param name="message">Exception message</param> + public CommunicationException(string message) + : base(message) + { + + } + + /// <summary> + /// Contstructor. + /// </summary> + /// <param name="message">Exception message</param> + /// <param name="innerException">Inner exception</param> + public CommunicationException(string message, Exception innerException) + : base(message, innerException) + { + + } + } +} diff --git a/src/Scs/Communication/Scs/Communication/CommunicationStateException.cs b/src/Scs/Communication/Scs/Communication/CommunicationStateException.cs new file mode 100644 index 0000000..6501e6b --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/CommunicationStateException.cs @@ -0,0 +1,50 @@ +using System; +using System.Runtime.Serialization; + +namespace Hik.Communication.Scs.Communication +{ + /// <summary> + /// This application is thrown if communication is not expected state. + /// </summary> + [Serializable] + public class CommunicationStateException : CommunicationException + { + /// <summary> + /// Contstructor. + /// </summary> + public CommunicationStateException() + { + + } + + /// <summary> + /// Contstructor for serializing. + /// </summary> + public CommunicationStateException(SerializationInfo serializationInfo, StreamingContext context) + : base(serializationInfo, context) + { + + } + + /// <summary> + /// Contstructor. + /// </summary> + /// <param name="message">Exception message</param> + public CommunicationStateException(string message) + : base(message) + { + + } + + /// <summary> + /// Contstructor. + /// </summary> + /// <param name="message">Exception message</param> + /// <param name="innerException">Inner exception</param> + public CommunicationStateException(string message, Exception innerException) + : base(message, innerException) + { + + } + } +} diff --git a/src/Scs/Communication/Scs/Communication/CommunicationStates.cs b/src/Scs/Communication/Scs/Communication/CommunicationStates.cs new file mode 100644 index 0000000..0e2da97 --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/CommunicationStates.cs @@ -0,0 +1,18 @@ +namespace Hik.Communication.Scs.Communication +{ + /// <summary> + /// Communication states. + /// </summary> + public enum CommunicationStates + { + /// <summary> + /// Connected. + /// </summary> + Connected, + + /// <summary> + /// Disconnected. + /// </summary> + Disconnected + } +} diff --git a/src/Scs/Communication/Scs/Communication/EndPoints/ScsEndPoint.cs b/src/Scs/Communication/Scs/Communication/EndPoints/ScsEndPoint.cs new file mode 100644 index 0000000..f731a93 --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/EndPoints/ScsEndPoint.cs @@ -0,0 +1,67 @@ +using System; +using Hik.Communication.Scs.Client; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; +using Hik.Communication.Scs.Server; + +namespace Hik.Communication.Scs.Communication.EndPoints +{ + ///<summary> + /// Represents a server side end point in SCS. + ///</summary> + public abstract class ScsEndPoint + { + /// <summary> + /// Create a Scs End Point from a string. + /// Address must be formatted as: protocol://address + /// For example: tcp://89.43.104.179:10048 for a TCP endpoint with + /// IP 89.43.104.179 and port 10048. + /// </summary> + /// <param name="endPointAddress">Address to create endpoint</param> + /// <returns>Created end point</returns> + public static ScsEndPoint CreateEndPoint(string endPointAddress) + { + //Check if end point address is null + if (string.IsNullOrEmpty(endPointAddress)) + { + throw new ArgumentNullException("endPointAddress"); + } + + //If not protocol specified, assume TCP. + var endPointAddr = endPointAddress; + if (!endPointAddr.Contains("://")) + { + endPointAddr = "tcp://" + endPointAddr; + } + + //Split protocol and address parts + var splittedEndPoint = endPointAddr.Split(new[] { "://" }, StringSplitOptions.RemoveEmptyEntries); + if (splittedEndPoint.Length != 2) + { + throw new ApplicationException(endPointAddress + " is not a valid endpoint address."); + } + + //Split end point, find protocol and address + var protocol = splittedEndPoint[0].Trim().ToLower(); + var address = splittedEndPoint[1].Trim(); + switch (protocol) + { + case "tcp": + return new ScsTcpEndPoint(address); + default: + throw new ApplicationException("Unsupported protocol " + protocol + " in end point " + endPointAddress); + } + } + + /// <summary> + /// Creates a Scs Server that uses this end point to listen incoming connections. + /// </summary> + /// <returns>Scs Server</returns> + internal abstract IScsServer CreateServer(); + + /// <summary> + /// Creates a Scs Server that uses this end point to connect to server. + /// </summary> + /// <returns>Scs Client</returns> + internal abstract IScsClient CreateClient(); + } +}
\ No newline at end of file diff --git a/src/Scs/Communication/Scs/Communication/EndPoints/Tcp/ScsTcpEndPoint.cs b/src/Scs/Communication/Scs/Communication/EndPoints/Tcp/ScsTcpEndPoint.cs new file mode 100644 index 0000000..df1bca8 --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/EndPoints/Tcp/ScsTcpEndPoint.cs @@ -0,0 +1,84 @@ +using System; +using Hik.Communication.Scs.Client; +using Hik.Communication.Scs.Client.Tcp; +using Hik.Communication.Scs.Server; +using Hik.Communication.Scs.Server.Tcp; + +namespace Hik.Communication.Scs.Communication.EndPoints.Tcp +{ + /// <summary> + /// Represens a TCP end point in SCS. + /// </summary> + public sealed class ScsTcpEndPoint : ScsEndPoint + { + ///<summary> + /// IP address of the server. + ///</summary> + public string IpAddress { get; set; } + + ///<summary> + /// Listening TCP Port for incoming connection requests on server. + ///</summary> + public int TcpPort { get; private set; } + + /// <summary> + /// Creates a new ScsTcpEndPoint object with specified port number. + /// </summary> + /// <param name="tcpPort">Listening TCP Port for incoming connection requests on server</param> + public ScsTcpEndPoint(int tcpPort) + { + TcpPort = tcpPort; + } + + /// <summary> + /// Creates a new ScsTcpEndPoint object with specified IP address and port number. + /// </summary> + /// <param name="ipAddress">IP address of the server</param> + /// <param name="port">Listening TCP Port for incoming connection requests on server</param> + public ScsTcpEndPoint(string ipAddress, int port) + { + IpAddress = ipAddress; + TcpPort = port; + } + + /// <summary> + /// Creates a new ScsTcpEndPoint from a string address. + /// Address format must be like IPAddress:Port (For example: 127.0.0.1:10085). + /// </summary> + /// <param name="address">TCP end point Address</param> + /// <returns>Created ScsTcpEndpoint object</returns> + public ScsTcpEndPoint(string address) + { + var splittedAddress = address.Trim().Split(':'); + IpAddress = splittedAddress[0].Trim(); + TcpPort = Convert.ToInt32(splittedAddress[1].Trim()); + } + + /// <summary> + /// Creates a Scs Server that uses this end point to listen incoming connections. + /// </summary> + /// <returns>Scs Server</returns> + internal override IScsServer CreateServer() + { + return new ScsTcpServer(this); + } + + /// <summary> + /// Creates a Scs Client that uses this end point to connect to server. + /// </summary> + /// <returns>Scs Client</returns> + internal override IScsClient CreateClient() + { + return new ScsTcpClient(this); + } + + /// <summary> + /// Generates a string representation of this end point object. + /// </summary> + /// <returns>String representation of this end point object</returns> + public override string ToString() + { + return string.IsNullOrEmpty(IpAddress) ? ("tcp://" + TcpPort) : ("tcp://" + IpAddress + ":" + TcpPort); + } + } +}
\ No newline at end of file diff --git a/src/Scs/Communication/Scs/Communication/Messages/IScsMessage.cs b/src/Scs/Communication/Scs/Communication/Messages/IScsMessage.cs new file mode 100644 index 0000000..5fd5ac3 --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Messages/IScsMessage.cs @@ -0,0 +1,18 @@ +namespace Hik.Communication.Scs.Communication.Messages +{ + /// <summary> + /// Represents a message that is sent and received by server and client. + /// </summary> + public interface IScsMessage + { + /// <summary> + /// Unique identified for this message. + /// </summary> + string MessageId { get; } + + /// <summary> + /// Unique identified for this message. + /// </summary> + string RepliedMessageId { get; set; } + } +} diff --git a/src/Scs/Communication/Scs/Communication/Messages/MessageEventArgs.cs b/src/Scs/Communication/Scs/Communication/Messages/MessageEventArgs.cs new file mode 100644 index 0000000..dab8639 --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Messages/MessageEventArgs.cs @@ -0,0 +1,24 @@ +using System; + +namespace Hik.Communication.Scs.Communication.Messages +{ + /// <summary> + /// Stores message to be used by an event. + /// </summary> + public class MessageEventArgs : EventArgs + { + /// <summary> + /// Message object that is associated with this event. + /// </summary> + public IScsMessage Message { get; private set; } + + /// <summary> + /// Creates a new MessageEventArgs object. + /// </summary> + /// <param name="message">Message object that is associated with this event</param> + public MessageEventArgs(IScsMessage message) + { + Message = message; + } + } +} diff --git a/src/Scs/Communication/Scs/Communication/Messages/PingMessage.cs b/src/Scs/Communication/Scs/Communication/Messages/PingMessage.cs new file mode 100644 index 0000000..6f153ba --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Messages/PingMessage.cs @@ -0,0 +1,44 @@ +using System; + +namespace Hik.Communication.Scs.Communication.Messages +{ + /// <summary> + /// This message is used to send/receive ping messages. + /// Ping messages is used to keep connection alive between server and client. + /// </summary> + [Serializable] + public sealed class ScsPingMessage : ScsMessage + { + ///<summary> + /// Creates a new PingMessage object. + ///</summary> + public ScsPingMessage() + { + + } + + /// <summary> + /// Creates a new reply PingMessage object. + /// </summary> + /// <param name="repliedMessageId"> + /// Replied message id if this is a reply for + /// a message. + /// </param> + public ScsPingMessage(string repliedMessageId) + : this() + { + RepliedMessageId = repliedMessageId; + } + + /// <summary> + /// Creates a string to represents this object. + /// </summary> + /// <returns>A string to represents this object</returns> + public override string ToString() + { + return string.IsNullOrEmpty(RepliedMessageId) + ? string.Format("ScsPingMessage [{0}]", MessageId) + : string.Format("ScsPingMessage [{0}] Replied To [{1}]", MessageId, RepliedMessageId); + } + } +} diff --git a/src/Scs/Communication/Scs/Communication/Messages/ScsMessage.cs b/src/Scs/Communication/Scs/Communication/Messages/ScsMessage.cs new file mode 100644 index 0000000..240f149 --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Messages/ScsMessage.cs @@ -0,0 +1,59 @@ +using System; + +namespace Hik.Communication.Scs.Communication.Messages +{ + /// <summary> + /// Represents a message that is sent and received by server and client. + /// This is the base class for all messages. + /// </summary> + [Serializable] + public class ScsMessage : IScsMessage + { + /// <summary> + /// Unique identified for this message. + /// Default value: New GUID. + /// Do not change if you do not want to do low level changes + /// such as custom wire protocols. + /// </summary> + public string MessageId { get; set; } + + /// <summary> + /// This property is used to indicate that this is + /// a Reply message to a message. + /// It may be null if this is not a reply message. + /// </summary> + public string RepliedMessageId { get; set; } + + /// <summary> + /// Creates a new ScsMessage. + /// </summary> + public ScsMessage() + { + MessageId = Guid.NewGuid().ToString(); + } + + /// <summary> + /// Creates a new reply ScsMessage. + /// </summary> + /// <param name="repliedMessageId"> + /// Replied message id if this is a reply for + /// a message. + /// </param> + public ScsMessage(string repliedMessageId) + : this() + { + RepliedMessageId = repliedMessageId; + } + + /// <summary> + /// Creates a string to represents this object. + /// </summary> + /// <returns>A string to represents this object</returns> + public override string ToString() + { + return string.IsNullOrEmpty(RepliedMessageId) + ? string.Format("ScsMessage [{0}]", MessageId) + : string.Format("ScsMessage [{0}] Replied To [{1}]", MessageId, RepliedMessageId); + } + } +} diff --git a/src/Scs/Communication/Scs/Communication/Messages/ScsRawDataMessage.cs b/src/Scs/Communication/Scs/Communication/Messages/ScsRawDataMessage.cs new file mode 100644 index 0000000..0382c55 --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Messages/ScsRawDataMessage.cs @@ -0,0 +1,59 @@ +using System; + +namespace Hik.Communication.Scs.Communication.Messages +{ + /// <summary> + /// This message is used to send/receive a raw byte array as message data. + /// </summary> + [Serializable] + public class ScsRawDataMessage : ScsMessage + { + /// <summary> + /// Message data that is being transmitted. + /// </summary> + public byte[] MessageData { get; set; } + + /// <summary> + /// Default empty constructor. + /// </summary> + public ScsRawDataMessage() + { + + } + + /// <summary> + /// Creates a new ScsRawDataMessage object with MessageData property. + /// </summary> + /// <param name="messageData">Message data that is being transmitted</param> + public ScsRawDataMessage(byte[] messageData) + { + MessageData = messageData; + } + + /// <summary> + /// Creates a new reply ScsRawDataMessage object with MessageData property. + /// </summary> + /// <param name="messageData">Message data that is being transmitted</param> + /// <param name="repliedMessageId"> + /// Replied message id if this is a reply for + /// a message. + /// </param> + public ScsRawDataMessage(byte[] messageData, string repliedMessageId) + : this(messageData) + { + RepliedMessageId = repliedMessageId; + } + + /// <summary> + /// Creates a string to represents this object. + /// </summary> + /// <returns>A string to represents this object</returns> + public override string ToString() + { + var messageLength = MessageData == null ? 0 : MessageData.Length; + return string.IsNullOrEmpty(RepliedMessageId) + ? string.Format("ScsRawDataMessage [{0}]: {1} bytes", MessageId, messageLength) + : string.Format("ScsRawDataMessage [{0}] Replied To [{1}]: {2} bytes", MessageId, RepliedMessageId, messageLength); + } + } +} diff --git a/src/Scs/Communication/Scs/Communication/Messages/ScsTextMessage.cs b/src/Scs/Communication/Scs/Communication/Messages/ScsTextMessage.cs new file mode 100644 index 0000000..b5665fa --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Messages/ScsTextMessage.cs @@ -0,0 +1,58 @@ +using System; + +namespace Hik.Communication.Scs.Communication.Messages +{ + /// <summary> + /// This message is used to send/receive a text as message data. + /// </summary> + [Serializable] + public class ScsTextMessage : ScsMessage + { + /// <summary> + /// Message text that is being transmitted. + /// </summary> + public string Text { get; set; } + + /// <summary> + /// Creates a new ScsTextMessage object. + /// </summary> + public ScsTextMessage() + { + + } + + /// <summary> + /// Creates a new ScsTextMessage object with Text property. + /// </summary> + /// <param name="text">Message text that is being transmitted</param> + public ScsTextMessage(string text) + { + Text = text; + } + + /// <summary> + /// Creates a new reply ScsTextMessage object with Text property. + /// </summary> + /// <param name="text">Message text that is being transmitted</param> + /// <param name="repliedMessageId"> + /// Replied message id if this is a reply for + /// a message. + /// </param> + public ScsTextMessage(string text, string repliedMessageId) + : this(text) + { + RepliedMessageId = repliedMessageId; + } + + /// <summary> + /// Creates a string to represents this object. + /// </summary> + /// <returns>A string to represents this object</returns> + public override string ToString() + { + return string.IsNullOrEmpty(RepliedMessageId) + ? string.Format("ScsTextMessage [{0}]: {1}", MessageId, Text) + : string.Format("ScsTextMessage [{0}] Replied To [{1}]: {2}", MessageId, RepliedMessageId, Text); + } + } +} diff --git a/src/Scs/Communication/Scs/Communication/Messengers/IMessenger.cs b/src/Scs/Communication/Scs/Communication/Messengers/IMessenger.cs new file mode 100644 index 0000000..176b479 --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Messengers/IMessenger.cs @@ -0,0 +1,44 @@ +using System; +using Hik.Communication.Scs.Communication.Messages; +using Hik.Communication.Scs.Communication.Protocols; + +namespace Hik.Communication.Scs.Communication.Messengers +{ + /// <summary> + /// Represents an object that can send and receive messages. + /// </summary> + public interface IMessenger + { + /// <summary> + /// This event is raised when a new message is received. + /// </summary> + event EventHandler<MessageEventArgs> MessageReceived; + + /// <summary> + /// This event is raised when a new message is sent without any error. + /// It does not guaranties that message is properly handled and processed by remote application. + /// </summary> + event EventHandler<MessageEventArgs> MessageSent; + + /// <summary> + /// Gets/sets wire protocol that is used while reading and writing messages. + /// </summary> + IScsWireProtocol WireProtocol { get; set; } + + /// <summary> + /// Gets the time of the last succesfully received message. + /// </summary> + DateTime LastReceivedMessageTime { get; } + + /// <summary> + /// Gets the time of the last succesfully sent message. + /// </summary> + DateTime LastSentMessageTime { get; } + + /// <summary> + /// Sends a message to the remote application. + /// </summary> + /// <param name="message">Message to be sent</param> + void SendMessage(IScsMessage message); + } +} diff --git a/src/Scs/Communication/Scs/Communication/Messengers/RequestReplyMessenger.cs b/src/Scs/Communication/Scs/Communication/Messengers/RequestReplyMessenger.cs new file mode 100644 index 0000000..f346c9e --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Messengers/RequestReplyMessenger.cs @@ -0,0 +1,387 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using Hik.Communication.Scs.Communication.Messages; +using Hik.Communication.Scs.Communication.Protocols; +using Hik.Threading; + +namespace Hik.Communication.Scs.Communication.Messengers +{ + /// <summary> + /// This class adds SendMessageAndWaitForResponse(...) and SendAndReceiveMessage methods + /// to a IMessenger for synchronous request/response style messaging. + /// It also adds queued processing of incoming messages. + /// </summary> + /// <typeparam name="T">Type of IMessenger object to use as underlying communication</typeparam> + public class RequestReplyMessenger<T> : IMessenger, IDisposable where T : IMessenger + { + #region Public events + + /// <summary> + /// This event is raised when a new message is received from underlying messenger. + /// </summary> + public event EventHandler<MessageEventArgs> MessageReceived; + + /// <summary> + /// This event is raised when a new message is sent without any error. + /// It does not guaranties that message is properly handled and processed by remote application. + /// </summary> + public event EventHandler<MessageEventArgs> MessageSent; + + #endregion + + #region Public properties + + /// <summary> + /// Gets/sets wire protocol that is used while reading and writing messages. + /// </summary> + public IScsWireProtocol WireProtocol + { + get { return Messenger.WireProtocol; } + set { Messenger.WireProtocol = value; } + } + + /// <summary> + /// Gets the time of the last succesfully received message. + /// </summary> + public DateTime LastReceivedMessageTime + { + get + { + return Messenger.LastReceivedMessageTime; + } + } + + /// <summary> + /// Gets the time of the last succesfully received message. + /// </summary> + public DateTime LastSentMessageTime + { + get + { + return Messenger.LastSentMessageTime; + } + } + + /// <summary> + /// Gets the underlying IMessenger object. + /// </summary> + public T Messenger { get; private set; } + + /// <summary> + /// Timeout value as milliseconds to wait for a receiving message on + /// SendMessageAndWaitForResponse and SendAndReceiveMessage methods. + /// Default value: 60000 (1 minute). + /// </summary> + public int Timeout { get; set; } + + #endregion + + #region Private fields + + /// <summary> + /// Default Timeout value. + /// </summary> + private const int DefaultTimeout = 60000; + + /// <summary> + /// This messages are waiting for a response those are used when + /// SendMessageAndWaitForResponse is called. + /// Key: MessageID of waiting request message. + /// Value: A WaitingMessage instance. + /// </summary> + private readonly SortedList<string, WaitingMessage> _waitingMessages; + + /// <summary> + /// This object is used to process incoming messages sequentially. + /// </summary> + private readonly SequentialItemProcessor<IScsMessage> _incomingMessageProcessor; + + /// <summary> + /// This object is used for thread synchronization. + /// </summary> + private readonly object _syncObj = new object(); + + #endregion + + #region Constructor + + /// <summary> + /// Creates a new RequestReplyMessenger. + /// </summary> + /// <param name="messenger">IMessenger object to use as underlying communication</param> + public RequestReplyMessenger(T messenger) + { + Messenger = messenger; + messenger.MessageReceived += Messenger_MessageReceived; + messenger.MessageSent += Messenger_MessageSent; + _incomingMessageProcessor = new SequentialItemProcessor<IScsMessage>(OnMessageReceived); + _waitingMessages = new SortedList<string, WaitingMessage>(); + Timeout = DefaultTimeout; + } + + #endregion + + #region Public methods + + /// <summary> + /// Starts the messenger. + /// </summary> + public virtual void Start() + { + _incomingMessageProcessor.Start(); + } + + /// <summary> + /// Stops the messenger. + /// Cancels all waiting threads in SendMessageAndWaitForResponse method and stops message queue. + /// SendMessageAndWaitForResponse method throws exception if there is a thread that is waiting for response message. + /// Also stops incoming message processing and deletes all messages in incoming message queue. + /// </summary> + public virtual void Stop() + { + _incomingMessageProcessor.Stop(); + + //Pulse waiting threads for incoming messages, since underlying messenger is disconnected + //and can not receive messages anymore. + lock (_syncObj) + { + foreach (var waitingMessage in _waitingMessages.Values) + { + waitingMessage.State = WaitingMessageStates.Cancelled; + waitingMessage.WaitEvent.Set(); + } + + _waitingMessages.Clear(); + } + } + + /// <summary> + /// Calls Stop method of this object. + /// </summary> + public void Dispose() + { + Stop(); + } + + /// <summary> + /// Sends a message. + /// </summary> + /// <param name="message">Message to be sent</param> + public void SendMessage(IScsMessage message) + { + Messenger.SendMessage(message); + } + + /// <summary> + /// Sends a message and waits a response for that message. + /// </summary> + /// <remarks> + /// Response message is matched with RepliedMessageId property, so if + /// any other message (that is not reply for sent message) is received + /// from remote application, it is not considered as a reply and is not + /// returned as return value of this method. + /// + /// MessageReceived event is not raised for response messages. + /// </remarks> + /// <param name="message">message to send</param> + /// <returns>Response message</returns> + public IScsMessage SendMessageAndWaitForResponse(IScsMessage message) + { + return SendMessageAndWaitForResponse(message, Timeout); + } + + /// <summary> + /// Sends a message and waits a response for that message. + /// </summary> + /// <remarks> + /// Response message is matched with RepliedMessageId property, so if + /// any other message (that is not reply for sent message) is received + /// from remote application, it is not considered as a reply and is not + /// returned as return value of this method. + /// + /// MessageReceived event is not raised for response messages. + /// </remarks> + /// <param name="message">message to send</param> + /// <param name="timeoutMilliseconds">Timeout duration as milliseconds.</param> + /// <returns>Response message</returns> + /// <exception cref="TimeoutException">Throws TimeoutException if can not receive reply message in timeout value</exception> + /// <exception cref="CommunicationException">Throws CommunicationException if communication fails before reply message.</exception> + public IScsMessage SendMessageAndWaitForResponse(IScsMessage message, int timeoutMilliseconds) + { + //Create a waiting message record and add to list + var waitingMessage = new WaitingMessage(); + lock (_syncObj) + { + _waitingMessages[message.MessageId] = waitingMessage; + } + + try + { + //Send message + Messenger.SendMessage(message); + + //Wait for response + waitingMessage.WaitEvent.Wait(timeoutMilliseconds); + + //Check for exceptions + switch (waitingMessage.State) + { + case WaitingMessageStates.WaitingForResponse: + throw new TimeoutException("Timeout occured. Can not received response."); + case WaitingMessageStates.Cancelled: + throw new CommunicationException("Disconnected before response received."); + } + + //return response message + return waitingMessage.ResponseMessage; + } + finally + { + //Remove message from waiting messages + lock (_syncObj) + { + if (_waitingMessages.ContainsKey(message.MessageId)) + { + _waitingMessages.Remove(message.MessageId); + } + } + } + } + + #endregion + + #region Private methods + + /// <summary> + /// Handles MessageReceived event of Messenger object. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void Messenger_MessageReceived(object sender, MessageEventArgs e) + { + //Check if there is a waiting thread for this message in SendMessageAndWaitForResponse method + if (!string.IsNullOrEmpty(e.Message.RepliedMessageId)) + { + WaitingMessage waitingMessage = null; + lock (_syncObj) + { + if (_waitingMessages.ContainsKey(e.Message.RepliedMessageId)) + { + waitingMessage = _waitingMessages[e.Message.RepliedMessageId]; + } + } + + //If there is a thread waiting for this response message, pulse it + if (waitingMessage != null) + { + waitingMessage.ResponseMessage = e.Message; + waitingMessage.State = WaitingMessageStates.ResponseReceived; + waitingMessage.WaitEvent.Set(); + return; + } + } + + _incomingMessageProcessor.EnqueueMessage(e.Message); + } + + /// <summary> + /// Handles MessageSent event of Messenger object. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void Messenger_MessageSent(object sender, MessageEventArgs e) + { + OnMessageSent(e.Message); + } + + #endregion + + #region Event raising methods + + /// <summary> + /// Raises MessageReceived event. + /// </summary> + /// <param name="message">Received message</param> + protected virtual void OnMessageReceived(IScsMessage message) + { + var handler = MessageReceived; + if (handler != null) + { + handler(this, new MessageEventArgs(message)); + } + } + + /// <summary> + /// Raises MessageSent event. + /// </summary> + /// <param name="message">Received message</param> + protected virtual void OnMessageSent(IScsMessage message) + { + var handler = MessageSent; + if (handler != null) + { + handler(this, new MessageEventArgs(message)); + } + } + + #endregion + + #region WaitingMessage class + + /// <summary> + /// This class is used to store messaging context for a request message + /// until response is received. + /// </summary> + private sealed class WaitingMessage + { + /// <summary> + /// Response message for request message + /// (null if response is not received yet). + /// </summary> + public IScsMessage ResponseMessage { get; set; } + + /// <summary> + /// ManualResetEvent to block thread until response is received. + /// </summary> + public ManualResetEventSlim WaitEvent { get; private set; } + + /// <summary> + /// State of the request message. + /// </summary> + public WaitingMessageStates State { get; set; } + + /// <summary> + /// Creates a new WaitingMessage object. + /// </summary> + public WaitingMessage() + { + WaitEvent = new ManualResetEventSlim(false); + State = WaitingMessageStates.WaitingForResponse; + } + } + + /// <summary> + /// This enum is used to store the state of a waiting message. + /// </summary> + private enum WaitingMessageStates + { + /// <summary> + /// Still waiting for response. + /// </summary> + WaitingForResponse, + + /// <summary> + /// Message sending is cancelled. + /// </summary> + Cancelled, + + /// <summary> + /// Response is properly received. + /// </summary> + ResponseReceived + } + + #endregion + } +} diff --git a/src/Scs/Communication/Scs/Communication/Messengers/SynchronizedMessenger.cs b/src/Scs/Communication/Scs/Communication/Messengers/SynchronizedMessenger.cs new file mode 100644 index 0000000..065cfd4 --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Messengers/SynchronizedMessenger.cs @@ -0,0 +1,216 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using Hik.Communication.Scs.Communication.Messages; + +namespace Hik.Communication.Scs.Communication.Messengers +{ + /// <summary> + /// This class is a wrapper for IMessenger and is used + /// to synchronize message receiving operation. + /// It extends RequestReplyMessenger. + /// It is suitable to use in applications those want to receive + /// messages by synchronized method calls instead of asynchronous + /// MessageReceived event. + /// </summary> + public class SynchronizedMessenger<T> : RequestReplyMessenger<T> where T : IMessenger + { + #region Public properties + + ///<summary> + /// Gets/sets capacity of the incoming message queue. + /// No message is received from remote application if + /// number of messages in internal queue exceeds this value. + /// Default value: int.MaxValue (2147483647). + ///</summary> + public int IncomingMessageQueueCapacity { get; set; } + + #endregion + + #region Private fields + + /// <summary> + /// A queue that is used to store receiving messages until Receive(...) + /// method is called to get them. + /// </summary> + private readonly Queue<IScsMessage> _receivingMessageQueue; + + /// <summary> + /// This object is used to synchronize/wait threads. + /// </summary> + private readonly ManualResetEventSlim _receiveWaiter; + + /// <summary> + /// This boolean value indicates the running state of this class. + /// </summary> + private volatile bool _running; + + #endregion + + #region Constructors + + ///<summary> + /// Creates a new SynchronizedMessenger object. + ///</summary> + ///<param name="messenger">A IMessenger object to be used to send/receive messages</param> + public SynchronizedMessenger(T messenger) + : this(messenger, int.MaxValue) + { + + } + + ///<summary> + /// Creates a new SynchronizedMessenger object. + ///</summary> + ///<param name="messenger">A IMessenger object to be used to send/receive messages</param> + ///<param name="incomingMessageQueueCapacity">capacity of the incoming message queue</param> + public SynchronizedMessenger(T messenger, int incomingMessageQueueCapacity) + : base(messenger) + { + _receiveWaiter = new ManualResetEventSlim(); + _receivingMessageQueue = new Queue<IScsMessage>(); + IncomingMessageQueueCapacity = incomingMessageQueueCapacity; + } + + #endregion + + #region Public methods + + /// <summary> + /// Starts the messenger. + /// </summary> + public override void Start() + { + lock (_receivingMessageQueue) + { + _running = true; + } + + base.Start(); + } + + /// <summary> + /// Stops the messenger. + /// </summary> + public override void Stop() + { + base.Stop(); + + lock (_receivingMessageQueue) + { + _running = false; + _receiveWaiter.Set(); + } + } + + /// <summary> + /// This method is used to receive a message from remote application. + /// It waits until a message is received. + /// </summary> + /// <returns>Received message</returns> + public IScsMessage ReceiveMessage() + { + return ReceiveMessage(System.Threading.Timeout.Infinite); + } + + /// <summary> + /// This method is used to receive a message from remote application. + /// It waits until a message is received or timeout occurs. + /// </summary> + /// <param name="timeout"> + /// Timeout value to wait if no message is received. + /// Use -1 to wait indefinitely. + /// </param> + /// <returns>Received message</returns> + /// <exception cref="TimeoutException">Throws TimeoutException if timeout occurs</exception> + /// <exception cref="Exception">Throws Exception if SynchronizedMessenger stops before a message is received</exception> + public IScsMessage ReceiveMessage(int timeout) + { + while (_running) + { + lock (_receivingMessageQueue) + { + //Check if SynchronizedMessenger is running + if (!_running) + { + throw new Exception("SynchronizedMessenger is stopped. Can not receive message."); + } + + //Get a message immediately if any message does exists + if (_receivingMessageQueue.Count > 0) + { + return _receivingMessageQueue.Dequeue(); + } + + _receiveWaiter.Reset(); + } + + //Wait for a message + var signalled = _receiveWaiter.Wait(timeout); + + //If not signalled, throw exception + if (!signalled) + { + throw new TimeoutException("Timeout occured. Can not received any message"); + } + } + + throw new Exception("SynchronizedMessenger is stopped. Can not receive message."); + } + + /// <summary> + /// This method is used to receive a specific type of message from remote application. + /// It waits until a message is received. + /// </summary> + /// <returns>Received message</returns> + public TMessage ReceiveMessage<TMessage>() where TMessage : IScsMessage + { + return ReceiveMessage<TMessage>(System.Threading.Timeout.Infinite); + } + + /// <summary> + /// This method is used to receive a specific type of message from remote application. + /// It waits until a message is received or timeout occurs. + /// </summary> + /// <param name="timeout"> + /// Timeout value to wait if no message is received. + /// Use -1 to wait indefinitely. + /// </param> + /// <returns>Received message</returns> + public TMessage ReceiveMessage<TMessage>(int timeout) where TMessage : IScsMessage + { + var receivedMessage = ReceiveMessage(timeout); + if (!(receivedMessage is TMessage)) + { + throw new Exception("Unexpected message received." + + " Expected type: " + typeof(TMessage).Name + + ". Received message type: " + receivedMessage.GetType().Name); + } + + return (TMessage)receivedMessage; + } + + #endregion + + #region Protected methods + + /// <summary> + /// Overrides + /// </summary> + /// <param name="message"></param> + protected override void OnMessageReceived(IScsMessage message) + { + lock (_receivingMessageQueue) + { + if (_receivingMessageQueue.Count < IncomingMessageQueueCapacity) + { + _receivingMessageQueue.Enqueue(message); + } + + _receiveWaiter.Set(); + } + } + + #endregion + } +} diff --git a/src/Scs/Communication/Scs/Communication/Protocols/BinarySerialization/BinarySerializationProtocol.cs b/src/Scs/Communication/Scs/Communication/Protocols/BinarySerialization/BinarySerializationProtocol.cs new file mode 100644 index 0000000..a84784b --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Protocols/BinarySerialization/BinarySerializationProtocol.cs @@ -0,0 +1,315 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using Hik.Communication.Scs.Communication.Messages; + +namespace Hik.Communication.Scs.Communication.Protocols.BinarySerialization +{ + /// <summary> + /// Default communication protocol between server and clients to send and receive a message. + /// It uses .NET binary serialization to write and read messages. + /// + /// A Message format: + /// [Message Length (4 bytes)][Serialized Message Content] + /// + /// If a message is serialized to byte array as N bytes, this protocol + /// adds 4 bytes size information to head of the message bytes, so total length is (4 + N) bytes. + /// + /// This class can be derived to change serializer (default: BinaryFormatter). To do this, + /// SerializeMessage and DeserializeMessage methods must be overrided. + /// </summary> + public class BinarySerializationProtocol : IScsWireProtocol + { + #region Private fields + + /// <summary> + /// Maximum length of a message. + /// </summary> + private const int MaxMessageLength = 128 * 1024 * 1024; //128 Megabytes. + + /// <summary> + /// This MemoryStream object is used to collect receiving bytes to build messages. + /// </summary> + private MemoryStream _receiveMemoryStream; + + #endregion + + #region Constructor + + /// <summary> + /// Creates a new instance of BinarySerializationProtocol. + /// </summary> + public BinarySerializationProtocol() + { + _receiveMemoryStream = new MemoryStream(); + } + + #endregion + + #region IScsWireProtocol implementation + + /// <summary> + /// Serializes a message to a byte array to send to remote application. + /// This method is synchronized. So, only one thread can call it concurrently. + /// </summary> + /// <param name="message">Message to be serialized</param> + /// <exception cref="CommunicationException">Throws CommunicationException if message is bigger than maximum allowed message length.</exception> + public byte[] GetBytes(IScsMessage message) + { + //Serialize the message to a byte array + var serializedMessage = SerializeMessage(message); + + //Check for message length + var messageLength = serializedMessage.Length; + if (messageLength > MaxMessageLength) + { + throw new CommunicationException("Message is too big (" + messageLength + " bytes). Max allowed length is " + MaxMessageLength + " bytes."); + } + + //Create a byte array including the length of the message (4 bytes) and serialized message content + var bytes = new byte[messageLength + 4]; + WriteInt32(bytes, 0, messageLength); + Array.Copy(serializedMessage, 0, bytes, 4, messageLength); + + //Return serialized message by this protocol + return bytes; + } + + /// <summary> + /// Builds messages from a byte array that is received from remote application. + /// The Byte array may contain just a part of a message, the protocol must + /// cumulate bytes to build messages. + /// This method is synchronized. So, only one thread can call it concurrently. + /// </summary> + /// <param name="receivedBytes">Received bytes from remote application</param> + /// <returns> + /// List of messages. + /// Protocol can generate more than one message from a byte array. + /// Also, if received bytes are not sufficient to build a message, the protocol + /// may return an empty list (and save bytes to combine with next method call). + /// </returns> + public IEnumerable<IScsMessage> CreateMessages(byte[] receivedBytes) + { + //Write all received bytes to the _receiveMemoryStream + _receiveMemoryStream.Write(receivedBytes, 0, receivedBytes.Length); + //Create a list to collect messages + var messages = new List<IScsMessage>(); + //Read all available messages and add to messages collection + while (ReadSingleMessage(messages)) { } + //Return message list + return messages; + } + + /// <summary> + /// This method is called when connection with remote application is reset (connection is renewing or first connecting). + /// So, wire protocol must reset itself. + /// </summary> + public void Reset() + { + if (_receiveMemoryStream.Length > 0) + { + _receiveMemoryStream = new MemoryStream(); + } + } + + #endregion + + #region Proptected virtual methods + + /// <summary> + /// This method is used to serialize a IScsMessage to a byte array. + /// This method can be overrided by derived classes to change serialization strategy. + /// It is a couple with DeserializeMessage method and must be overrided together. + /// </summary> + /// <param name="message">Message to be serialized</param> + /// <returns> + /// Serialized message bytes. + /// Does not include length of the message. + /// </returns> + protected virtual byte[] SerializeMessage(IScsMessage message) + { + using (var memoryStream = new MemoryStream()) + { + new BinaryFormatter().Serialize(memoryStream, message); + return memoryStream.ToArray(); + } + } + + /// <summary> + /// This method is used to deserialize a IScsMessage from it's bytes. + /// This method can be overrided by derived classes to change deserialization strategy. + /// It is a couple with SerializeMessage method and must be overrided together. + /// </summary> + /// <param name="bytes"> + /// Bytes of message to be deserialized (does not include message length. It consist + /// of a single whole message) + /// </param> + /// <returns>Deserialized message</returns> + protected virtual IScsMessage DeserializeMessage(byte[] bytes) + { + //Create a MemoryStream to convert bytes to a stream + using (var deserializeMemoryStream = new MemoryStream(bytes)) + { + //Go to head of the stream + deserializeMemoryStream.Position = 0; + + //Deserialize the message + var binaryFormatter = new BinaryFormatter + { + AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple, + Binder = new DeserializationAppDomainBinder() + }; + + //Return the deserialized message + return (IScsMessage) binaryFormatter.Deserialize(deserializeMemoryStream); + } + } + + #endregion + + #region Private methods + + /// <summary> + /// This method tries to read a single message and add to the messages collection. + /// </summary> + /// <param name="messages">Messages collection to collect messages</param> + /// <returns> + /// Returns a boolean value indicates that if there is a need to re-call this method. + /// </returns> + /// <exception cref="CommunicationException">Throws CommunicationException if message is bigger than maximum allowed message length.</exception> + private bool ReadSingleMessage(ICollection<IScsMessage> messages) + { + //Go to the begining of the stream + _receiveMemoryStream.Position = 0; + + //If stream has less than 4 bytes, that means we can not even read length of the message + //So, return false to wait more bytes from remore application. + if (_receiveMemoryStream.Length < 4) + { + return false; + } + + //Read length of the message + var messageLength = ReadInt32(_receiveMemoryStream); + if (messageLength > MaxMessageLength) + { + throw new Exception("Message is too big (" + messageLength + " bytes). Max allowed length is " + MaxMessageLength + " bytes."); + } + + //If message is zero-length (It must not be but good approach to check it) + if (messageLength == 0) + { + //if no more bytes, return immediately + if (_receiveMemoryStream.Length == 4) + { + _receiveMemoryStream = new MemoryStream(); //Clear the stream + return false; + } + + //Create a new memory stream from current except first 4-bytes. + var bytes = _receiveMemoryStream.ToArray(); + _receiveMemoryStream = new MemoryStream(); + _receiveMemoryStream.Write(bytes, 4, bytes.Length - 4); + return true; + } + + //If all bytes of the message is not received yet, return to wait more bytes + if (_receiveMemoryStream.Length < (4 + messageLength)) + { + _receiveMemoryStream.Position = _receiveMemoryStream.Length; + return false; + } + + //Read bytes of serialized message and deserialize it + var serializedMessageBytes = ReadByteArray(_receiveMemoryStream, messageLength); + messages.Add(DeserializeMessage(serializedMessageBytes)); + + //Read remaining bytes to an array + var remainingBytes = ReadByteArray(_receiveMemoryStream, (int)(_receiveMemoryStream.Length - (4 + messageLength))); + + //Re-create the receive memory stream and write remaining bytes + _receiveMemoryStream = new MemoryStream(); + _receiveMemoryStream.Write(remainingBytes, 0, remainingBytes.Length); + + //Return true to re-call this method to try to read next message + return (remainingBytes.Length > 4); + } + + /// <summary> + /// Writes a int value to a byte array from a starting index. + /// </summary> + /// <param name="buffer">Byte array to write int value</param> + /// <param name="startIndex">Start index of byte array to write</param> + /// <param name="number">An integer value to write</param> + private static void WriteInt32(byte[] buffer, int startIndex, int number) + { + buffer[startIndex] = (byte)((number >> 24) & 0xFF); + buffer[startIndex + 1] = (byte)((number >> 16) & 0xFF); + buffer[startIndex + 2] = (byte)((number >> 8) & 0xFF); + buffer[startIndex + 3] = (byte)((number) & 0xFF); + } + + /// <summary> + /// Deserializes and returns a serialized integer. + /// </summary> + /// <returns>Deserialized integer</returns> + private static int ReadInt32(Stream stream) + { + var buffer = ReadByteArray(stream, 4); + return ((buffer[0] << 24) | + (buffer[1] << 16) | + (buffer[2] << 8) | + (buffer[3]) + ); + } + + /// <summary> + /// Reads a byte array with specified length. + /// </summary> + /// <param name="stream">Stream to read from</param> + /// <param name="length">Length of the byte array to read</param> + /// <returns>Read byte array</returns> + /// <exception cref="EndOfStreamException">Throws EndOfStreamException if can not read from stream.</exception> + private static byte[] ReadByteArray(Stream stream, int length) + { + var buffer = new byte[length]; + var totalRead = 0; + while (totalRead < length) + { + var read = stream.Read(buffer, totalRead, length - totalRead); + if (read <= 0) + { + throw new EndOfStreamException("Can not read from stream! Input stream is closed."); + } + + totalRead += read; + } + + return buffer; + } + + #endregion + + #region Nested classes + + /// <summary> + /// This class is used in deserializing to allow deserializing objects that are defined + /// in assemlies that are load in runtime (like PlugIns). + /// </summary> + protected sealed class DeserializationAppDomainBinder : SerializationBinder + { + public override Type BindToType(string assemblyName, string typeName) + { + var toAssemblyName = assemblyName.Split(',')[0]; + return (from assembly in AppDomain.CurrentDomain.GetAssemblies() + where assembly.FullName.Split(',')[0] == toAssemblyName + select assembly.GetType(typeName)).FirstOrDefault(); + } + } + + #endregion + } +} diff --git a/src/Scs/Communication/Scs/Communication/Protocols/BinarySerialization/BinarySerializationProtocolFactory.cs b/src/Scs/Communication/Scs/Communication/Protocols/BinarySerialization/BinarySerializationProtocolFactory.cs new file mode 100644 index 0000000..ded08ae --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Protocols/BinarySerialization/BinarySerializationProtocolFactory.cs @@ -0,0 +1,17 @@ +namespace Hik.Communication.Scs.Communication.Protocols.BinarySerialization +{ + /// <summary> + /// This class is used to create Binary Serialization Protocol objects. + /// </summary> + public class BinarySerializationProtocolFactory : IScsWireProtocolFactory + { + /// <summary> + /// Creates a new Wire Protocol object. + /// </summary> + /// <returns>Newly created wire protocol object</returns> + public IScsWireProtocol CreateWireProtocol() + { + return new BinarySerializationProtocol(); + } + } +} diff --git a/src/Scs/Communication/Scs/Communication/Protocols/IScsWireProtocol.cs b/src/Scs/Communication/Scs/Communication/Protocols/IScsWireProtocol.cs new file mode 100644 index 0000000..0ea3fb6 --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Protocols/IScsWireProtocol.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using Hik.Communication.Scs.Communication.Messages; + +namespace Hik.Communication.Scs.Communication.Protocols +{ + /// <summary> + /// Represents a byte-level communication protocol between applications. + /// </summary> + public interface IScsWireProtocol + { + /// <summary> + /// Serializes a message to a byte array to send to remote application. + /// This method is synchronized. So, only one thread can call it concurrently. + /// </summary> + /// <param name="message">Message to be serialized</param> + byte[] GetBytes(IScsMessage message); + + /// <summary> + /// Builds messages from a byte array that is received from remote application. + /// The Byte array may contain just a part of a message, the protocol must + /// cumulate bytes to build messages. + /// This method is synchronized. So, only one thread can call it concurrently. + /// </summary> + /// <param name="receivedBytes">Received bytes from remote application</param> + /// <returns> + /// List of messages. + /// Protocol can generate more than one message from a byte array. + /// Also, if received bytes are not sufficient to build a message, the protocol + /// may return an empty list (and save bytes to combine with next method call). + /// </returns> + IEnumerable<IScsMessage> CreateMessages(byte[] receivedBytes); + + /// <summary> + /// This method is called when connection with remote application is reset (connection is renewing or first connecting). + /// So, wire protocol must reset itself. + /// </summary> + void Reset(); + } +} diff --git a/src/Scs/Communication/Scs/Communication/Protocols/IScsWireProtocolFactory.cs b/src/Scs/Communication/Scs/Communication/Protocols/IScsWireProtocolFactory.cs new file mode 100644 index 0000000..3cc2489 --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Protocols/IScsWireProtocolFactory.cs @@ -0,0 +1,14 @@ +namespace Hik.Communication.Scs.Communication.Protocols +{ + ///<summary> + /// Defines a Wire Protocol Factory class that is used to create Wire Protocol objects. + ///</summary> + public interface IScsWireProtocolFactory + { + /// <summary> + /// Creates a new Wire Protocol object. + /// </summary> + /// <returns>Newly created wire protocol object</returns> + IScsWireProtocol CreateWireProtocol(); + } +} diff --git a/src/Scs/Communication/Scs/Communication/Protocols/WireProtocolManager.cs b/src/Scs/Communication/Scs/Communication/Protocols/WireProtocolManager.cs new file mode 100644 index 0000000..0685046 --- /dev/null +++ b/src/Scs/Communication/Scs/Communication/Protocols/WireProtocolManager.cs @@ -0,0 +1,28 @@ +using Hik.Communication.Scs.Communication.Protocols.BinarySerialization; + +namespace Hik.Communication.Scs.Communication.Protocols +{ + /// <summary> + /// This class is used to get default protocols. + /// </summary> + internal static class WireProtocolManager + { + /// <summary> + /// Creates a default wire protocol factory object to be used on communicating of applications. + /// </summary> + /// <returns>A new instance of default wire protocol</returns> + public static IScsWireProtocolFactory GetDefaultWireProtocolFactory() + { + return new BinarySerializationProtocolFactory(); + } + + /// <summary> + /// Creates a default wire protocol object to be used on communicating of applications. + /// </summary> + /// <returns>A new instance of default wire protocol</returns> + public static IScsWireProtocol GetDefaultWireProtocol() + { + return new BinarySerializationProtocol(); + } + } +} diff --git a/src/Scs/Communication/Scs/Server/IScsServer.cs b/src/Scs/Communication/Scs/Server/IScsServer.cs new file mode 100644 index 0000000..a87e7a1 --- /dev/null +++ b/src/Scs/Communication/Scs/Server/IScsServer.cs @@ -0,0 +1,42 @@ +using System; +using Hik.Collections; +using Hik.Communication.Scs.Communication.Protocols; + +namespace Hik.Communication.Scs.Server +{ + /// <summary> + /// Represents a SCS server that is used to accept and manage client connections. + /// </summary> + public interface IScsServer + { + /// <summary> + /// This event is raised when a new client connected to the server. + /// </summary> + event EventHandler<ServerClientEventArgs> ClientConnected; + + /// <summary> + /// This event is raised when a client disconnected from the server. + /// </summary> + event EventHandler<ServerClientEventArgs> ClientDisconnected; + + /// <summary> + /// Gets/sets wire protocol factory to create IWireProtocol objects. + /// </summary> + IScsWireProtocolFactory WireProtocolFactory { get; set; } + + /// <summary> + /// A collection of clients that are connected to the server. + /// </summary> + ThreadSafeSortedList<long, IScsServerClient> Clients { get; } + + /// <summary> + /// Starts the server. + /// </summary> + void Start(); + + /// <summary> + /// Stops the server. + /// </summary> + void Stop(); + } +} diff --git a/src/Scs/Communication/Scs/Server/IScsServerClient.cs b/src/Scs/Communication/Scs/Server/IScsServerClient.cs new file mode 100644 index 0000000..3e60bef --- /dev/null +++ b/src/Scs/Communication/Scs/Server/IScsServerClient.cs @@ -0,0 +1,38 @@ +using System; +using Hik.Communication.Scs.Communication; +using Hik.Communication.Scs.Communication.EndPoints; +using Hik.Communication.Scs.Communication.Messengers; + +namespace Hik.Communication.Scs.Server +{ + /// <summary> + /// Represents a client from a perspective of a server. + /// </summary> + public interface IScsServerClient : IMessenger + { + /// <summary> + /// This event is raised when client disconnected from server. + /// </summary> + event EventHandler Disconnected; + + /// <summary> + /// Unique identifier for this client in server. + /// </summary> + long ClientId { get; } + + ///<summary> + /// Gets endpoint of remote application. + ///</summary> + ScsEndPoint RemoteEndPoint { get; } + + /// <summary> + /// Gets the current communication state. + /// </summary> + CommunicationStates CommunicationState { get; } + + /// <summary> + /// Disconnects from server. + /// </summary> + void Disconnect(); + } +} diff --git a/src/Scs/Communication/Scs/Server/ScsServerBase.cs b/src/Scs/Communication/Scs/Server/ScsServerBase.cs new file mode 100644 index 0000000..d5019ea --- /dev/null +++ b/src/Scs/Communication/Scs/Server/ScsServerBase.cs @@ -0,0 +1,168 @@ +using System; +using Hik.Collections; +using Hik.Communication.Scs.Communication.Channels; +using Hik.Communication.Scs.Communication.Protocols; + +namespace Hik.Communication.Scs.Server +{ + /// <summary> + /// This class provides base functionality for server classes. + /// </summary> + internal abstract class ScsServerBase : IScsServer + { + #region Public events + + /// <summary> + /// This event is raised when a new client is connected. + /// </summary> + public event EventHandler<ServerClientEventArgs> ClientConnected; + + /// <summary> + /// This event is raised when a client disconnected from the server. + /// </summary> + public event EventHandler<ServerClientEventArgs> ClientDisconnected; + + #endregion + + #region Public properties + + /// <summary> + /// Gets/sets wire protocol that is used while reading and writing messages. + /// </summary> + public IScsWireProtocolFactory WireProtocolFactory { get; set; } + + /// <summary> + /// A collection of clients that are connected to the server. + /// </summary> + public ThreadSafeSortedList<long, IScsServerClient> Clients { get; private set; } + + #endregion + + #region Private properties + + /// <summary> + /// This object is used to listen incoming connections. + /// </summary> + private IConnectionListener _connectionListener; + + #endregion + + #region Constructor + + /// <summary> + /// Constructor. + /// </summary> + protected ScsServerBase() + { + Clients = new ThreadSafeSortedList<long, IScsServerClient>(); + WireProtocolFactory = WireProtocolManager.GetDefaultWireProtocolFactory(); + } + + #endregion + + #region Public methods + + /// <summary> + /// Starts the server. + /// </summary> + public virtual void Start() + { + _connectionListener = CreateConnectionListener(); + _connectionListener.CommunicationChannelConnected += ConnectionListener_CommunicationChannelConnected; + _connectionListener.Start(); + } + + /// <summary> + /// Stops the server. + /// </summary> + public virtual void Stop() + { + if (_connectionListener != null) + { + _connectionListener.Stop(); + } + + foreach (var client in Clients.GetAllItems()) + { + client.Disconnect(); + } + } + + #endregion + + #region Protected abstract methods + + /// <summary> + /// This method is implemented by derived classes to create appropriate connection listener to listen incoming connection requets. + /// </summary> + /// <returns></returns> + protected abstract IConnectionListener CreateConnectionListener(); + + #endregion + + #region Private methods + + /// <summary> + /// Handles CommunicationChannelConnected event of _connectionListener object. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void ConnectionListener_CommunicationChannelConnected(object sender, CommunicationChannelEventArgs e) + { + var client = new ScsServerClient(e.Channel) + { + ClientId = ScsServerManager.GetClientId(), + WireProtocol = WireProtocolFactory.CreateWireProtocol() + }; + + client.Disconnected += Client_Disconnected; + Clients[client.ClientId] = client; + OnClientConnected(client); + e.Channel.Start(); + } + + /// <summary> + /// Handles Disconnected events of all connected clients. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void Client_Disconnected(object sender, EventArgs e) + { + var client = (IScsServerClient) sender; + Clients.Remove(client.ClientId); + OnClientDisconnected(client); + } + + #endregion + + #region Event raising methods + + /// <summary> + /// Raises ClientConnected event. + /// </summary> + /// <param name="client">Connected client</param> + protected virtual void OnClientConnected(IScsServerClient client) + { + var handler = ClientConnected; + if (handler != null) + { + handler(this, new ServerClientEventArgs(client)); + } + } + + /// <summary> + /// Raises ClientDisconnected event. + /// </summary> + /// <param name="client">Disconnected client</param> + protected virtual void OnClientDisconnected(IScsServerClient client) + { + var handler = ClientDisconnected; + if (handler != null) + { + handler(this, new ServerClientEventArgs(client)); + } + } + + #endregion + } +} diff --git a/src/Scs/Communication/Scs/Server/ScsServerClient.cs b/src/Scs/Communication/Scs/Server/ScsServerClient.cs new file mode 100644 index 0000000..398ec79 --- /dev/null +++ b/src/Scs/Communication/Scs/Server/ScsServerClient.cs @@ -0,0 +1,223 @@ +using System; +using Hik.Communication.Scs.Communication; +using Hik.Communication.Scs.Communication.EndPoints; +using Hik.Communication.Scs.Communication.Messages; +using Hik.Communication.Scs.Communication.Channels; +using Hik.Communication.Scs.Communication.Protocols; + +namespace Hik.Communication.Scs.Server +{ + /// <summary> + /// This class represents a client in server side. + /// </summary> + internal class ScsServerClient : IScsServerClient + { + #region Public events + + /// <summary> + /// This event is raised when a new message is received. + /// </summary> + public event EventHandler<MessageEventArgs> MessageReceived; + + /// <summary> + /// This event is raised when a new message is sent without any error. + /// It does not guaranties that message is properly handled and processed by remote application. + /// </summary> + public event EventHandler<MessageEventArgs> MessageSent; + + /// <summary> + /// This event is raised when client is disconnected from server. + /// </summary> + public event EventHandler Disconnected; + + #endregion + + #region Public properties + + /// <summary> + /// Unique identifier for this client in server. + /// </summary> + public long ClientId { get; set; } + + /// <summary> + /// Gets the communication state of the Client. + /// </summary> + public CommunicationStates CommunicationState + { + get + { + return _communicationChannel.CommunicationState; + } + } + + /// <summary> + /// Gets/sets wire protocol that is used while reading and writing messages. + /// </summary> + public IScsWireProtocol WireProtocol + { + get { return _communicationChannel.WireProtocol; } + set { _communicationChannel.WireProtocol = value; } + } + + ///<summary> + /// Gets endpoint of remote application. + ///</summary> + public ScsEndPoint RemoteEndPoint + { + get { return _communicationChannel.RemoteEndPoint; } + } + + /// <summary> + /// Gets the time of the last succesfully received message. + /// </summary> + public DateTime LastReceivedMessageTime + { + get + { + return _communicationChannel.LastReceivedMessageTime; + } + } + + /// <summary> + /// Gets the time of the last succesfully received message. + /// </summary> + public DateTime LastSentMessageTime + { + get + { + return _communicationChannel.LastSentMessageTime; + } + } + + #endregion + + #region Private fields + + /// <summary> + /// The communication channel that is used by client to send and receive messages. + /// </summary> + private readonly ICommunicationChannel _communicationChannel; + + #endregion + + #region Constructor + + /// <summary> + /// Creates a new ScsClient object. + /// </summary> + /// <param name="communicationChannel">The communication channel that is used by client to send and receive messages</param> + public ScsServerClient(ICommunicationChannel communicationChannel) + { + _communicationChannel = communicationChannel; + _communicationChannel.MessageReceived += CommunicationChannel_MessageReceived; + _communicationChannel.MessageSent += CommunicationChannel_MessageSent; + _communicationChannel.Disconnected += CommunicationChannel_Disconnected; + } + + #endregion + + #region Public methods + + /// <summary> + /// Disconnects from client and closes underlying communication channel. + /// </summary> + public void Disconnect() + { + _communicationChannel.Disconnect(); + } + + /// <summary> + /// Sends a message to the client. + /// </summary> + /// <param name="message">Message to be sent</param> + public void SendMessage(IScsMessage message) + { + _communicationChannel.SendMessage(message); + } + + #endregion + + #region Private methods + + /// <summary> + /// Handles Disconnected event of _communicationChannel object. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void CommunicationChannel_Disconnected(object sender, EventArgs e) + { + OnDisconnected(); + } + + /// <summary> + /// Handles MessageReceived event of _communicationChannel object. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void CommunicationChannel_MessageReceived(object sender, MessageEventArgs e) + { + var message = e.Message; + if (message is ScsPingMessage) + { + _communicationChannel.SendMessage(new ScsPingMessage { RepliedMessageId = message.MessageId }); + return; + } + + OnMessageReceived(message); + } + + /// <summary> + /// Handles MessageSent event of _communicationChannel object. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void CommunicationChannel_MessageSent(object sender, MessageEventArgs e) + { + OnMessageSent(e.Message); + } + + #endregion + + #region Event raising methods + + /// <summary> + /// Raises Disconnected event. + /// </summary> + private void OnDisconnected() + { + var handler = Disconnected; + if (handler != null) + { + handler(this, EventArgs.Empty); + } + } + + /// <summary> + /// Raises MessageReceived event. + /// </summary> + /// <param name="message">Received message</param> + private void OnMessageReceived(IScsMessage message) + { + var handler = MessageReceived; + if (handler != null) + { + handler(this, new MessageEventArgs(message)); + } + } + + /// <summary> + /// Raises MessageSent event. + /// </summary> + /// <param name="message">Received message</param> + protected virtual void OnMessageSent(IScsMessage message) + { + var handler = MessageSent; + if (handler != null) + { + handler(this, new MessageEventArgs(message)); + } + } + + #endregion + } +}
\ No newline at end of file diff --git a/src/Scs/Communication/Scs/Server/ScsServerFactory.cs b/src/Scs/Communication/Scs/Server/ScsServerFactory.cs new file mode 100644 index 0000000..d03b832 --- /dev/null +++ b/src/Scs/Communication/Scs/Server/ScsServerFactory.cs @@ -0,0 +1,20 @@ +using Hik.Communication.Scs.Communication.EndPoints; + +namespace Hik.Communication.Scs.Server +{ + /// <summary> + /// This class is used to create SCS servers. + /// </summary> + public static class ScsServerFactory + { + /// <summary> + /// Creates a new SCS Server using an EndPoint. + /// </summary> + /// <param name="endPoint">Endpoint that represents address of the server</param> + /// <returns>Created TCP server</returns> + public static IScsServer CreateServer(ScsEndPoint endPoint) + { + return endPoint.CreateServer(); + } + } +} diff --git a/src/Scs/Communication/Scs/Server/ScsServerManager.cs b/src/Scs/Communication/Scs/Server/ScsServerManager.cs new file mode 100644 index 0000000..dd2505a --- /dev/null +++ b/src/Scs/Communication/Scs/Server/ScsServerManager.cs @@ -0,0 +1,24 @@ +using System.Threading; + +namespace Hik.Communication.Scs.Server +{ + /// <summary> + /// Provides some functionality that are used by servers. + /// </summary> + internal static class ScsServerManager + { + /// <summary> + /// Used to set an auto incremential unique identifier to clients. + /// </summary> + private static long _lastClientId; + + /// <summary> + /// Gets an unique number to be used as idenfitier of a client. + /// </summary> + /// <returns></returns> + public static long GetClientId() + { + return Interlocked.Increment(ref _lastClientId); + } + } +} diff --git a/src/Scs/Communication/Scs/Server/ServerClientEventArgs.cs b/src/Scs/Communication/Scs/Server/ServerClientEventArgs.cs new file mode 100644 index 0000000..875b8e0 --- /dev/null +++ b/src/Scs/Communication/Scs/Server/ServerClientEventArgs.cs @@ -0,0 +1,24 @@ +using System; + +namespace Hik.Communication.Scs.Server +{ + /// <summary> + /// Stores client information to be used by an event. + /// </summary> + public class ServerClientEventArgs : EventArgs + { + /// <summary> + /// Client that is associated with this event. + /// </summary> + public IScsServerClient Client { get; private set; } + + /// <summary> + /// Creates a new ServerClientEventArgs object. + /// </summary> + /// <param name="client">Client that is associated with this event</param> + public ServerClientEventArgs(IScsServerClient client) + { + Client = client; + } + } +} diff --git a/src/Scs/Communication/Scs/Server/Tcp/ScsTcpServer.cs b/src/Scs/Communication/Scs/Server/Tcp/ScsTcpServer.cs new file mode 100644 index 0000000..fe8a3f7 --- /dev/null +++ b/src/Scs/Communication/Scs/Server/Tcp/ScsTcpServer.cs @@ -0,0 +1,35 @@ +using Hik.Communication.Scs.Communication.Channels; +using Hik.Communication.Scs.Communication.Channels.Tcp; +using Hik.Communication.Scs.Communication.EndPoints.Tcp; + +namespace Hik.Communication.Scs.Server.Tcp +{ + /// <summary> + /// This class is used to create a TCP server. + /// </summary> + internal class ScsTcpServer : ScsServerBase + { + /// <summary> + /// The endpoint address of the server to listen incoming connections. + /// </summary> + private readonly ScsTcpEndPoint _endPoint; + + /// <summary> + /// Creates a new ScsTcpServer object. + /// </summary> + /// <param name="endPoint">The endpoint address of the server to listen incoming connections</param> + public ScsTcpServer(ScsTcpEndPoint endPoint) + { + _endPoint = endPoint; + } + + /// <summary> + /// Creates a TCP connection listener. + /// </summary> + /// <returns>Created listener object</returns> + protected override IConnectionListener CreateConnectionListener() + { + return new TcpConnectionListener(_endPoint); + } + } +} diff --git a/src/Scs/Communication/ScsServices/Client/IScsServiceClient.cs b/src/Scs/Communication/ScsServices/Client/IScsServiceClient.cs new file mode 100644 index 0000000..414d0c9 --- /dev/null +++ b/src/Scs/Communication/ScsServices/Client/IScsServiceClient.cs @@ -0,0 +1,24 @@ +using Hik.Communication.Scs.Client; + +namespace Hik.Communication.ScsServices.Client +{ + /// <summary> + /// Represents a service client that consumes a SCS service. + /// </summary> + /// <typeparam name="T">Type of service interface</typeparam> + public interface IScsServiceClient<out T> : IConnectableClient where T : class + { + /// <summary> + /// Reference to the service proxy to invoke remote service methods. + /// </summary> + T ServiceProxy { get; } + + /// <summary> + /// Timeout value when invoking a service method. + /// If timeout occurs before end of remote method call, an exception is thrown. + /// Use -1 for no timeout (wait indefinite). + /// Default value: 60000 (1 minute). + /// </summary> + int Timeout { get; set; } + } +} diff --git a/src/Scs/Communication/ScsServices/Client/ScsServiceClient.cs b/src/Scs/Communication/ScsServices/Client/ScsServiceClient.cs new file mode 100644 index 0000000..32ddee1 --- /dev/null +++ b/src/Scs/Communication/ScsServices/Client/ScsServiceClient.cs @@ -0,0 +1,274 @@ +using System; +using System.Reflection; +using Hik.Communication.Scs.Client; +using Hik.Communication.Scs.Communication; +using Hik.Communication.Scs.Communication.Messages; +using Hik.Communication.Scs.Communication.Messengers; +using Hik.Communication.ScsServices.Communication; +using Hik.Communication.ScsServices.Communication.Messages; + +namespace Hik.Communication.ScsServices.Client +{ + /// <summary> + /// Represents a service client that consumes a SCS service. + /// </summary> + /// <typeparam name="T">Type of service interface</typeparam> + internal class ScsServiceClient<T> : IScsServiceClient<T> where T : class + { + #region Public events + + /// <summary> + /// This event is raised when client connected to server. + /// </summary> + public event EventHandler Connected; + + /// <summary> + /// This event is raised when client disconnected from server. + /// </summary> + public event EventHandler Disconnected; + + #endregion + + #region Public properties + + /// <summary> + /// Timeout for connecting to a server (as milliseconds). + /// Default value: 15 seconds (15000 ms). + /// </summary> + public int ConnectTimeout + { + get { return _client.ConnectTimeout; } + set { _client.ConnectTimeout = value; } + } + + /// <summary> + /// Gets the current communication state. + /// </summary> + public CommunicationStates CommunicationState + { + get { return _client.CommunicationState; } + } + + /// <summary> + /// Reference to the service proxy to invoke remote service methods. + /// </summary> + public T ServiceProxy { get; private set; } + + /// <summary> + /// Timeout value when invoking a service method. + /// If timeout occurs before end of remote method call, an exception is thrown. + /// Use -1 for no timeout (wait indefinite). + /// Default value: 60000 (1 minute). + /// </summary> + public int Timeout + { + get { return _requestReplyMessenger.Timeout; } + set { _requestReplyMessenger.Timeout = value; } + } + + #endregion + + #region Private fields + + /// <summary> + /// Underlying IScsClient object to communicate with server. + /// </summary> + private readonly IScsClient _client; + + /// <summary> + /// Messenger object to send/receive messages over _client. + /// </summary> + private readonly RequestReplyMessenger<IScsClient> _requestReplyMessenger; + + /// <summary> + /// This object is used to create a transparent proxy to invoke remote methods on server. + /// </summary> + private readonly AutoConnectRemoteInvokeProxy<T, IScsClient> _realServiceProxy; + + /// <summary> + /// The client object that is used to call method invokes in client side. + /// May be null if client has no methods to be invoked by server. + /// </summary> + private readonly object _clientObject; + + #endregion + + #region Constructor + + /// <summary> + /// Creates a new ScsServiceClient object. + /// </summary> + /// <param name="client">Underlying IScsClient object to communicate with server</param> + /// <param name="clientObject">The client object that is used to call method invokes in client side. + /// May be null if client has no methods to be invoked by server.</param> + public ScsServiceClient(IScsClient client, object clientObject) + { + _client = client; + _clientObject = clientObject; + + _client.Connected += Client_Connected; + _client.Disconnected += Client_Disconnected; + + _requestReplyMessenger = new RequestReplyMessenger<IScsClient>(client); + _requestReplyMessenger.MessageReceived += RequestReplyMessenger_MessageReceived; + + _realServiceProxy = new AutoConnectRemoteInvokeProxy<T, IScsClient>(_requestReplyMessenger, this); + ServiceProxy = (T)_realServiceProxy.GetTransparentProxy(); + } + + #endregion + + #region Public methods + + /// <summary> + /// Connects to server. + /// </summary> + public void Connect() + { + _client.Connect(); + } + + /// <summary> + /// Disconnects from server. + /// Does nothing if already disconnected. + /// </summary> + public void Disconnect() + { + _client.Disconnect(); + } + + /// <summary> + /// Calls Disconnect method. + /// </summary> + public void Dispose() + { + Disconnect(); + } + + #endregion + + #region Private methods + + /// <summary> + /// Handles MessageReceived event of messenger. + /// It gets messages from server and invokes appropriate method. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void RequestReplyMessenger_MessageReceived(object sender, MessageEventArgs e) + { + //Cast message to ScsRemoteInvokeMessage and check it + var invokeMessage = e.Message as ScsRemoteInvokeMessage; + if (invokeMessage == null) + { + return; + } + + //Check client object. + if(_clientObject == null) + { + SendInvokeResponse(invokeMessage, null, new ScsRemoteException("Client does not wait for method invocations by server.")); + return; + } + + //Invoke method + object returnValue; + try + { + var type = _clientObject.GetType(); + var method = type.GetMethod(invokeMessage.MethodName); + returnValue = method.Invoke(_clientObject, invokeMessage.Parameters); + } + catch (TargetInvocationException ex) + { + var innerEx = ex.InnerException; + SendInvokeResponse(invokeMessage, null, new ScsRemoteException(innerEx.Message, innerEx)); + return; + } + catch (Exception ex) + { + SendInvokeResponse(invokeMessage, null, new ScsRemoteException(ex.Message, ex)); + return; + } + + //Send return value + SendInvokeResponse(invokeMessage, returnValue, null); + } + + /// <summary> + /// Sends response to the remote application that invoked a service method. + /// </summary> + /// <param name="requestMessage">Request message</param> + /// <param name="returnValue">Return value to send</param> + /// <param name="exception">Exception to send</param> + private void SendInvokeResponse(IScsMessage requestMessage, object returnValue, ScsRemoteException exception) + { + try + { + _requestReplyMessenger.SendMessage( + new ScsRemoteInvokeReturnMessage + { + RepliedMessageId = requestMessage.MessageId, + ReturnValue = returnValue, + RemoteException = exception + }); + } + catch + { + + } + } + + /// <summary> + /// Handles Connected event of _client object. + /// </summary> + /// <param name="sender">Source of object</param> + /// <param name="e">Event arguments</param> + private void Client_Connected(object sender, EventArgs e) + { + _requestReplyMessenger.Start(); + OnConnected(); + } + + /// <summary> + /// Handles Disconnected event of _client object. + /// </summary> + /// <param name="sender">Source of object</param> + /// <param name="e">Event arguments</param> + private void Client_Disconnected(object sender, EventArgs e) + { + _requestReplyMessenger.Stop(); + OnDisconnected(); + } + + #endregion + + #region Private methods + + /// <summary> + /// Raises Connected event. + /// </summary> + private void OnConnected() + { + var handler = Connected; + if (handler != null) + { + handler(this, EventArgs.Empty); + } + } + + /// <summary> + /// Raises Disconnected event. + /// </summary> + private void OnDisconnected() + { + var handler = Disconnected; + if (handler != null) + { + handler(this, EventArgs.Empty); + } + } + + #endregion + } +}
\ No newline at end of file diff --git a/src/Scs/Communication/ScsServices/Client/ScsServiceClientBuilder.cs b/src/Scs/Communication/ScsServices/Client/ScsServiceClientBuilder.cs new file mode 100644 index 0000000..ee9280e --- /dev/null +++ b/src/Scs/Communication/ScsServices/Client/ScsServiceClientBuilder.cs @@ -0,0 +1,36 @@ +using Hik.Communication.Scs.Communication.EndPoints; + +namespace Hik.Communication.ScsServices.Client +{ + /// <summary> + /// This class is used to build service clients to remotely invoke methods of a SCS service. + /// </summary> + public class ScsServiceClientBuilder + { + /// <summary> + /// Creates a client to connect to a SCS service. + /// </summary> + /// <typeparam name="T">Type of service interface for remote method call</typeparam> + /// <param name="endpoint">EndPoint of the server</param> + /// <param name="clientObject">Client-side object that handles remote method calls from server to client. + /// May be null if client has no methods to be invoked by server</param> + /// <returns>Created client object to connect to the server</returns> + public static IScsServiceClient<T> CreateClient<T>(ScsEndPoint endpoint, object clientObject = null) where T : class + { + return new ScsServiceClient<T>(endpoint.CreateClient(), clientObject); + } + + /// <summary> + /// Creates a client to connect to a SCS service. + /// </summary> + /// <typeparam name="T">Type of service interface for remote method call</typeparam> + /// <param name="endpointAddress">EndPoint address of the server</param> + /// <param name="clientObject">Client-side object that handles remote method calls from server to client. + /// May be null if client has no methods to be invoked by server</param> + /// <returns>Created client object to connect to the server</returns> + public static IScsServiceClient<T> CreateClient<T>(string endpointAddress, object clientObject = null) where T : class + { + return CreateClient<T>(ScsEndPoint.CreateEndPoint(endpointAddress), clientObject); + } + } +} diff --git a/src/Scs/Communication/ScsServices/Communication/AutoConnectRemoteInvokeProxy.cs b/src/Scs/Communication/ScsServices/Communication/AutoConnectRemoteInvokeProxy.cs new file mode 100644 index 0000000..42b24c5 --- /dev/null +++ b/src/Scs/Communication/ScsServices/Communication/AutoConnectRemoteInvokeProxy.cs @@ -0,0 +1,57 @@ +using System.Runtime.Remoting.Messaging; +using Hik.Communication.Scs.Client; +using Hik.Communication.Scs.Communication; +using Hik.Communication.Scs.Communication.Messengers; + +namespace Hik.Communication.ScsServices.Communication +{ + /// <summary> + /// This class extends RemoteInvokeProxy to provide auto connect/disconnect mechanism + /// if client is not connected to the server when a service method is called. + /// </summary> + /// <typeparam name="TProxy">Type of the proxy class/interface</typeparam> + /// <typeparam name="TMessenger">Type of the messenger object that is used to send/receive messages</typeparam> + internal class AutoConnectRemoteInvokeProxy<TProxy, TMessenger> : RemoteInvokeProxy<TProxy, TMessenger> where TMessenger : IMessenger + { + /// <summary> + /// Reference to the client object that is used to connect/disconnect. + /// </summary> + private readonly IConnectableClient _client; + + /// <summary> + /// Creates a new AutoConnectRemoteInvokeProxy object. + /// </summary> + /// <param name="clientMessenger">Messenger object that is used to send/receive messages</param> + /// <param name="client">Reference to the client object that is used to connect/disconnect</param> + public AutoConnectRemoteInvokeProxy(RequestReplyMessenger<TMessenger> clientMessenger, IConnectableClient client) + : base(clientMessenger) + { + _client = client; + } + + /// <summary> + /// Overrides message calls and translates them to messages to remote application. + /// </summary> + /// <param name="msg">Method invoke message (from RealProxy base class)</param> + /// <returns>Method invoke return message (to RealProxy base class)</returns> + public override IMessage Invoke(IMessage msg) + { + if (_client.CommunicationState == CommunicationStates.Connected) + { + //If already connected, behave as base class (RemoteInvokeProxy). + return base.Invoke(msg); + } + + //Connect, call method and finally disconnect + _client.Connect(); + try + { + return base.Invoke(msg); + } + finally + { + _client.Disconnect(); + } + } + } +} diff --git a/src/Scs/Communication/ScsServices/Communication/Messages/ScsRemoteException.cs b/src/Scs/Communication/ScsServices/Communication/Messages/ScsRemoteException.cs new file mode 100644 index 0000000..3383368 --- /dev/null +++ b/src/Scs/Communication/ScsServices/Communication/Messages/ScsRemoteException.cs @@ -0,0 +1,51 @@ +using System; +using System.Runtime.Serialization; + +namespace Hik.Communication.ScsServices.Communication.Messages +{ + /// <summary> + /// Represents a SCS Remote Exception. + /// This exception is used to send an exception from an application to another application. + /// </summary> + [Serializable] + public class ScsRemoteException : Exception + { + /// <summary> + /// Contstructor. + /// </summary> + public ScsRemoteException() + { + + } + + /// <summary> + /// Contstructor. + /// </summary> + public ScsRemoteException(SerializationInfo serializationInfo, StreamingContext context) + : base(serializationInfo, context) + { + + } + + /// <summary> + /// Contstructor. + /// </summary> + /// <param name="message">Exception message</param> + public ScsRemoteException(string message) + : base(message) + { + + } + + /// <summary> + /// Contstructor. + /// </summary> + /// <param name="message">Exception message</param> + /// <param name="innerException">Inner exception</param> + public ScsRemoteException(string message, Exception innerException) + : base(message, innerException) + { + + } + } +} diff --git a/src/Scs/Communication/ScsServices/Communication/Messages/ScsRemoteInvokeMessage.cs b/src/Scs/Communication/ScsServices/Communication/Messages/ScsRemoteInvokeMessage.cs new file mode 100644 index 0000000..b482f3a --- /dev/null +++ b/src/Scs/Communication/ScsServices/Communication/Messages/ScsRemoteInvokeMessage.cs @@ -0,0 +1,36 @@ +using System; +using Hik.Communication.Scs.Communication.Messages; + +namespace Hik.Communication.ScsServices.Communication.Messages +{ + /// <summary> + /// This message is sent to invoke a method of a remote application. + /// </summary> + [Serializable] + public class ScsRemoteInvokeMessage : ScsMessage + { + /// <summary> + /// Name of the remove service class. + /// </summary> + public string ServiceClassName { get; set; } + + /// <summary> + /// Method of remote application to invoke. + /// </summary> + public string MethodName { get; set; } + + /// <summary> + /// Parameters of method. + /// </summary> + public object[] Parameters { get; set; } + + /// <summary> + /// Represents this object as string. + /// </summary> + /// <returns>String representation of this object</returns> + public override string ToString() + { + return string.Format("ScsRemoteInvokeMessage: {0}.{1}(...)", ServiceClassName, MethodName); + } + } +} diff --git a/src/Scs/Communication/ScsServices/Communication/Messages/ScsRemoteInvokeReturnMessage.cs b/src/Scs/Communication/ScsServices/Communication/Messages/ScsRemoteInvokeReturnMessage.cs new file mode 100644 index 0000000..7d4f14f --- /dev/null +++ b/src/Scs/Communication/ScsServices/Communication/Messages/ScsRemoteInvokeReturnMessage.cs @@ -0,0 +1,33 @@ +using System; +using Hik.Communication.Scs.Communication.Messages; + +namespace Hik.Communication.ScsServices.Communication.Messages +{ + /// <summary> + /// This message is sent as response message to a ScsRemoteInvokeMessage. + /// It is used to send return value of method invocation. + /// </summary> + [Serializable] + public class ScsRemoteInvokeReturnMessage : ScsMessage + { + /// <summary> + /// Return value of remote method invocation. + /// </summary> + public object ReturnValue { get; set; } + + /// <summary> + /// If any exception occured during method invocation, this field contains Exception object. + /// If no exception occured, this field is null. + /// </summary> + public ScsRemoteException RemoteException { get; set; } + + /// <summary> + /// Represents this object as string. + /// </summary> + /// <returns>String representation of this object</returns> + public override string ToString() + { + return string.Format("ScsRemoteInvokeReturnMessage: Returns {0}, Exception = {1}", ReturnValue, RemoteException); + } + } +} diff --git a/src/Scs/Communication/ScsServices/Communication/RemoteInvokeProxy.cs b/src/Scs/Communication/ScsServices/Communication/RemoteInvokeProxy.cs new file mode 100644 index 0000000..b6f0caa --- /dev/null +++ b/src/Scs/Communication/ScsServices/Communication/RemoteInvokeProxy.cs @@ -0,0 +1,63 @@ +using System.Runtime.Remoting.Messaging; +using System.Runtime.Remoting.Proxies; +using Hik.Communication.Scs.Communication; +using Hik.Communication.Scs.Communication.Messengers; +using Hik.Communication.ScsServices.Communication.Messages; + +namespace Hik.Communication.ScsServices.Communication +{ + /// <summary> + /// This class is used to generate a dynamic proxy to invoke remote methods. + /// It translates method invocations to messaging. + /// </summary> + /// <typeparam name="TProxy">Type of the proxy class/interface</typeparam> + /// <typeparam name="TMessenger">Type of the messenger object that is used to send/receive messages</typeparam> + internal class RemoteInvokeProxy<TProxy, TMessenger> : RealProxy where TMessenger : IMessenger + { + /// <summary> + /// Messenger object that is used to send/receive messages. + /// </summary> + private readonly RequestReplyMessenger<TMessenger> _clientMessenger; + + /// <summary> + /// Creates a new RemoteInvokeProxy object. + /// </summary> + /// <param name="clientMessenger">Messenger object that is used to send/receive messages</param> + public RemoteInvokeProxy(RequestReplyMessenger<TMessenger> clientMessenger) + : base(typeof(TProxy)) + { + _clientMessenger = clientMessenger; + } + + /// <summary> + /// Overrides message calls and translates them to messages to remote application. + /// </summary> + /// <param name="msg">Method invoke message (from RealProxy base class)</param> + /// <returns>Method invoke return message (to RealProxy base class)</returns> + public override IMessage Invoke(IMessage msg) + { + var message = msg as IMethodCallMessage; + if (message == null) + { + return null; + } + + var requestMessage = new ScsRemoteInvokeMessage + { + ServiceClassName = typeof (TProxy).Name, + MethodName = message.MethodName, + Parameters = message.InArgs + }; + + var responseMessage = _clientMessenger.SendMessageAndWaitForResponse(requestMessage) as ScsRemoteInvokeReturnMessage; + if (responseMessage == null) + { + return null; + } + + return responseMessage.RemoteException != null + ? new ReturnMessage(responseMessage.RemoteException, message) + : new ReturnMessage(responseMessage.ReturnValue, null, 0, message.LogicalCallContext, message); + } + } +}
\ No newline at end of file diff --git a/src/Scs/Communication/ScsServices/Service/IScsServiceApplication.cs b/src/Scs/Communication/ScsServices/Service/IScsServiceApplication.cs new file mode 100644 index 0000000..8fdb2f0 --- /dev/null +++ b/src/Scs/Communication/ScsServices/Service/IScsServiceApplication.cs @@ -0,0 +1,49 @@ +using System; + +namespace Hik.Communication.ScsServices.Service +{ + /// <summary> + /// Represents a SCS Service Application that is used to construct and manage a SCS service. + /// </summary> + public interface IScsServiceApplication + { + /// <summary> + /// This event is raised when a new client connected to the service. + /// </summary> + event EventHandler<ServiceClientEventArgs> ClientConnected; + + /// <summary> + /// This event is raised when a client disconnected from the service. + /// </summary> + event EventHandler<ServiceClientEventArgs> ClientDisconnected; + + /// <summary> + /// Starts service application. + /// </summary> + void Start(); + + /// <summary> + /// Stops service application. + /// </summary> + void Stop(); + + /// <summary> + /// Adds a service object to this service application. + /// Only single service object can be added for a service interface type. + /// </summary> + /// <typeparam name="TServiceInterface">Service interface type</typeparam> + /// <typeparam name="TServiceClass">Service class type. Must be delivered from ScsService and must implement TServiceInterface.</typeparam> + /// <param name="service">An instance of TServiceClass.</param> + void AddService<TServiceInterface, TServiceClass>(TServiceClass service) + where TServiceClass : ScsService, TServiceInterface + where TServiceInterface : class; + + /// <summary> + /// Removes a previously added service object from this service application. + /// It removes object according to interface type. + /// </summary> + /// <typeparam name="TServiceInterface">Service interface type</typeparam> + /// <returns>True: removed. False: no service object with this interface</returns> + bool RemoveService<TServiceInterface>() where TServiceInterface : class; + } +} diff --git a/src/Scs/Communication/ScsServices/Service/IScsServiceClient.cs b/src/Scs/Communication/ScsServices/Service/IScsServiceClient.cs new file mode 100644 index 0000000..e60f91d --- /dev/null +++ b/src/Scs/Communication/ScsServices/Service/IScsServiceClient.cs @@ -0,0 +1,44 @@ +using System; +using Hik.Communication.Scs.Communication; +using Hik.Communication.Scs.Communication.EndPoints; + +namespace Hik.Communication.ScsServices.Service +{ + /// <summary> + /// Represents a client that uses a SDS service. + /// </summary> + public interface IScsServiceClient + { + /// <summary> + /// This event is raised when client is disconnected from service. + /// </summary> + event EventHandler Disconnected; + + /// <summary> + /// Unique identifier for this client. + /// </summary> + long ClientId { get; } + + ///<summary> + /// Gets endpoint of remote application. + ///</summary> + ScsEndPoint RemoteEndPoint { get; } + + /// <summary> + /// Gets the communication state of the Client. + /// </summary> + CommunicationStates CommunicationState { get; } + + /// <summary> + /// Closes client connection. + /// </summary> + void Disconnect(); + + /// <summary> + /// Gets the client proxy interface that provides calling client methods remotely. + /// </summary> + /// <typeparam name="T">Type of client interface</typeparam> + /// <returns>Client interface</returns> + T GetClientProxy<T>() where T : class; + } +} diff --git a/src/Scs/Communication/ScsServices/Service/ScsService.cs b/src/Scs/Communication/ScsServices/Service/ScsService.cs new file mode 100644 index 0000000..2321343 --- /dev/null +++ b/src/Scs/Communication/ScsServices/Service/ScsService.cs @@ -0,0 +1,43 @@ +using System; + +namespace Hik.Communication.ScsServices.Service +{ + /// <summary> + /// Base class for all services that is serviced by IScsServiceApplication. + /// A class must be derived from ScsService to serve as a SCS service. + /// </summary> + public abstract class ScsService + { + /// <summary> + /// The current client for a thread that called service method. + /// </summary> + [ThreadStatic] + private static IScsServiceClient _currentClient; + + /// <summary> + /// Gets the current client which called this service method. + /// </summary> + /// <remarks> + /// This property is thread-safe, if returns correct client when + /// called in a service method if the method is called by SCS system, + /// else throws exception. + /// </remarks> + protected internal IScsServiceClient CurrentClient + { + get + { + if (_currentClient == null) + { + throw new Exception("Client channel can not be obtained. CurrentClient property must be called by the thread which runs the service method."); + } + + return _currentClient; + } + + internal set + { + _currentClient = value; + } + } + } +} diff --git a/src/Scs/Communication/ScsServices/Service/ScsServiceApplication.cs b/src/Scs/Communication/ScsServices/Service/ScsServiceApplication.cs new file mode 100644 index 0000000..2faa20b --- /dev/null +++ b/src/Scs/Communication/ScsServices/Service/ScsServiceApplication.cs @@ -0,0 +1,370 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using Hik.Collections; +using Hik.Communication.Scs.Communication.Messages; +using Hik.Communication.Scs.Communication.Messengers; +using Hik.Communication.Scs.Server; +using Hik.Communication.ScsServices.Communication.Messages; + +namespace Hik.Communication.ScsServices.Service +{ + /// <summary> + /// Implements IScsServiceApplication and provides all functionallity. + /// </summary> + internal class ScsServiceApplication : IScsServiceApplication + { + #region Public events + + /// <summary> + /// This event is raised when a new client connected to the service. + /// </summary> + public event EventHandler<ServiceClientEventArgs> ClientConnected; + + /// <summary> + /// This event is raised when a client disconnected from the service. + /// </summary> + public event EventHandler<ServiceClientEventArgs> ClientDisconnected; + + #endregion + + #region Private fields + + /// <summary> + /// Underlying IScsServer object to accept and manage client connections. + /// </summary> + private readonly IScsServer _scsServer; + + /// <summary> + /// User service objects that is used to invoke incoming method invocation requests. + /// Key: Service interface type's name. + /// Value: Service object. + /// </summary> + private readonly ThreadSafeSortedList<string, ServiceObject> _serviceObjects; + + /// <summary> + /// All connected clients to service. + /// Key: Client's unique Id. + /// Value: Reference to the client. + /// </summary> + private readonly ThreadSafeSortedList<long, IScsServiceClient> _serviceClients; + + #endregion + + #region Constructors + + /// <summary> + /// Creates a new ScsServiceApplication object. + /// </summary> + /// <param name="scsServer">Underlying IScsServer object to accept and manage client connections</param> + /// <exception cref="ArgumentNullException">Throws ArgumentNullException if scsServer argument is null</exception> + public ScsServiceApplication(IScsServer scsServer) + { + if (scsServer == null) + { + throw new ArgumentNullException("scsServer"); + } + + _scsServer = scsServer; + _scsServer.ClientConnected += ScsServer_ClientConnected; + _scsServer.ClientDisconnected += ScsServer_ClientDisconnected; + _serviceObjects = new ThreadSafeSortedList<string, ServiceObject>(); + _serviceClients = new ThreadSafeSortedList<long, IScsServiceClient>(); + } + + #endregion + + #region Public methods + + /// <summary> + /// Starts service application. + /// </summary> + public void Start() + { + _scsServer.Start(); + } + + /// <summary> + /// Stops service application. + /// </summary> + public void Stop() + { + _scsServer.Stop(); + } + + /// <summary> + /// Adds a service object to this service application. + /// Only single service object can be added for a service interface type. + /// </summary> + /// <typeparam name="TServiceInterface">Service interface type</typeparam> + /// <typeparam name="TServiceClass">Service class type. Must be delivered from ScsService and must implement TServiceInterface.</typeparam> + /// <param name="service">An instance of TServiceClass.</param> + /// <exception cref="ArgumentNullException">Throws ArgumentNullException if service argument is null</exception> + /// <exception cref="Exception">Throws Exception if service is already added before</exception> + public void AddService<TServiceInterface, TServiceClass>(TServiceClass service) + where TServiceClass : ScsService, TServiceInterface + where TServiceInterface : class + { + if (service == null) + { + throw new ArgumentNullException("service"); + } + + var type = typeof(TServiceInterface); + if(_serviceObjects[type.Name] != null) + { + throw new Exception("Service '" + type.Name + "' is already added before."); + } + + _serviceObjects[type.Name] = new ServiceObject(type, service); + } + + /// <summary> + /// Removes a previously added service object from this service application. + /// It removes object according to interface type. + /// </summary> + /// <typeparam name="TServiceInterface">Service interface type</typeparam> + /// <returns>True: removed. False: no service object with this interface</returns> + public bool RemoveService<TServiceInterface>() + where TServiceInterface : class + { + return _serviceObjects.Remove(typeof(TServiceInterface).Name); + } + + #endregion + + #region Private methods + + /// <summary> + /// Handles ClientConnected event of _scsServer object. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void ScsServer_ClientConnected(object sender, ServerClientEventArgs e) + { + var requestReplyMessenger = new RequestReplyMessenger<IScsServerClient>(e.Client); + requestReplyMessenger.MessageReceived += Client_MessageReceived; + requestReplyMessenger.Start(); + + var serviceClient = ScsServiceClientFactory.CreateServiceClient(e.Client, requestReplyMessenger); + _serviceClients[serviceClient.ClientId] = serviceClient; + OnClientConnected(serviceClient); + } + + /// <summary> + /// Handles ClientDisconnected event of _scsServer object. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void ScsServer_ClientDisconnected(object sender, ServerClientEventArgs e) + { + var serviceClient = _serviceClients[e.Client.ClientId]; + if (serviceClient == null) + { + return; + } + + _serviceClients.Remove(e.Client.ClientId); + OnClientDisconnected(serviceClient); + } + + /// <summary> + /// Handles MessageReceived events of all clients, evaluates each message, + /// finds appropriate service object and invokes appropriate method. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void Client_MessageReceived(object sender, MessageEventArgs e) + { + //Get RequestReplyMessenger object (sender of event) to get client + var requestReplyMessenger = (RequestReplyMessenger<IScsServerClient>) sender; + + //Cast message to ScsRemoteInvokeMessage and check it + var invokeMessage = e.Message as ScsRemoteInvokeMessage; + if (invokeMessage == null) + { + return; + } + + try + { + //Get client object + var client = _serviceClients[requestReplyMessenger.Messenger.ClientId]; + if (client == null) + { + requestReplyMessenger.Messenger.Disconnect(); + return; + } + + //Get service object + var serviceObject = _serviceObjects[invokeMessage.ServiceClassName]; + if (serviceObject == null) + { + SendInvokeResponse(requestReplyMessenger, invokeMessage, null, new ScsRemoteException("There is no service with name '" + invokeMessage.ServiceClassName + "'")); + return; + } + + //Invoke method + try + { + object returnValue; + //Set client to service, so user service can get client + //in service method using CurrentClient property. + serviceObject.Service.CurrentClient = client; + try + { + returnValue = serviceObject.InvokeMethod(invokeMessage.MethodName, invokeMessage.Parameters); + } + finally + { + //Set CurrentClient as null since method call completed + serviceObject.Service.CurrentClient = null; + } + + //Send method invocation return value to the client + SendInvokeResponse(requestReplyMessenger, invokeMessage, returnValue, null); + } + catch (TargetInvocationException ex) + { + var innerEx = ex.InnerException; + SendInvokeResponse(requestReplyMessenger, invokeMessage, null, new ScsRemoteException(innerEx.Message + Environment.NewLine + "Service Version: " + serviceObject.ServiceAttribute.Version, innerEx)); + return; + } + catch (Exception ex) + { + SendInvokeResponse(requestReplyMessenger, invokeMessage, null, new ScsRemoteException(ex.Message + Environment.NewLine + "Service Version: " + serviceObject.ServiceAttribute.Version, ex)); + return; + } + } + catch (Exception ex) + { + SendInvokeResponse(requestReplyMessenger, invokeMessage, null, new ScsRemoteException("An error occured during remote service method call.", ex)); + return; + } + } + + /// <summary> + /// Sends response to the remote application that invoked a service method. + /// </summary> + /// <param name="client">Client that sent invoke message</param> + /// <param name="requestMessage">Request message</param> + /// <param name="returnValue">Return value to send</param> + /// <param name="exception">Exception to send</param> + private static void SendInvokeResponse(IMessenger client, IScsMessage requestMessage, object returnValue, ScsRemoteException exception) + { + try + { + client.SendMessage( + new ScsRemoteInvokeReturnMessage + { + RepliedMessageId = requestMessage.MessageId, + ReturnValue = returnValue, + RemoteException = exception + }); + } + catch + { + + } + } + + /// <summary> + /// Raises ClientConnected event. + /// </summary> + /// <param name="client"></param> + private void OnClientConnected(IScsServiceClient client) + { + var handler = ClientConnected; + if (handler != null) + { + handler(this, new ServiceClientEventArgs(client)); + } + } + + /// <summary> + /// Raises ClientDisconnected event. + /// </summary> + /// <param name="client"></param> + private void OnClientDisconnected(IScsServiceClient client) + { + var handler = ClientDisconnected; + if (handler != null) + { + handler(this, new ServiceClientEventArgs(client)); + } + } + + #endregion + + #region ServiceObject class + + /// <summary> + /// Represents a user service object. + /// It is used to invoke methods on a ScsService object. + /// </summary> + private sealed class ServiceObject + { + /// <summary> + /// The service object that is used to invoke methods on. + /// </summary> + public ScsService Service { get; private set; } + + /// <summary> + /// ScsService attribute of Service object's class. + /// </summary> + public ScsServiceAttribute ServiceAttribute { get; private set; } + + /// <summary> + /// This collection stores a list of all methods of service object. + /// Key: Method name + /// Value: Informations about method. + /// </summary> + private readonly SortedList<string, MethodInfo> _methods; + + /// <summary> + /// Creates a new ServiceObject. + /// </summary> + /// <param name="serviceInterfaceType">Type of service interface</param> + /// <param name="service">The service object that is used to invoke methods on</param> + public ServiceObject(Type serviceInterfaceType, ScsService service) + { + Service = service; + var classAttributes = serviceInterfaceType.GetCustomAttributes(typeof(ScsServiceAttribute), true); + if (classAttributes.Length <= 0) + { + throw new Exception("Service interface (" + serviceInterfaceType.Name + ") must has ScsService attribute."); + } + + ServiceAttribute = classAttributes[0] as ScsServiceAttribute; + _methods = new SortedList<string, MethodInfo>(); + foreach (var methodInfo in serviceInterfaceType.GetMethods()) + { + _methods.Add(methodInfo.Name, methodInfo); + } + } + + /// <summary> + /// Invokes a method of Service object. + /// </summary> + /// <param name="methodName">Name of the method to invoke</param> + /// <param name="parameters">Parameters of method</param> + /// <returns>Return value of method</returns> + public object InvokeMethod(string methodName, params object[] parameters) + { + //Check if there is a method with name methodName + if (!_methods.ContainsKey(methodName)) + { + throw new Exception("There is not a method with name '" + methodName + "' in service class."); + } + + //Get method + var method = _methods[methodName]; + + //Invoke method and return invoke result + return method.Invoke(Service, parameters); + } + } + + #endregion + } +} diff --git a/src/Scs/Communication/ScsServices/Service/ScsServiceAttribute.cs b/src/Scs/Communication/ScsServices/Service/ScsServiceAttribute.cs new file mode 100644 index 0000000..e73a2d4 --- /dev/null +++ b/src/Scs/Communication/ScsServices/Service/ScsServiceAttribute.cs @@ -0,0 +1,26 @@ +using System; + +namespace Hik.Communication.ScsServices.Service +{ + /// <summary> + /// Any SCS Service interface class must has this attribute. + /// </summary> + [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class)] + public class ScsServiceAttribute : Attribute + { + /// <summary> + /// Service Version. This property can be used to indicate the code version. + /// This value is sent to client application on an exception, so, client application can know that service version is changed. + /// Default value: NO_VERSION. + /// </summary> + public string Version { get; set; } + + /// <summary> + /// Creates a new ScsServiceAttribute object. + /// </summary> + public ScsServiceAttribute() + { + Version = "NO_VERSION"; + } + } +} diff --git a/src/Scs/Communication/ScsServices/Service/ScsServiceBuilder.cs b/src/Scs/Communication/ScsServices/Service/ScsServiceBuilder.cs new file mode 100644 index 0000000..1860532 --- /dev/null +++ b/src/Scs/Communication/ScsServices/Service/ScsServiceBuilder.cs @@ -0,0 +1,21 @@ +using Hik.Communication.Scs.Communication.EndPoints; +using Hik.Communication.Scs.Server; + +namespace Hik.Communication.ScsServices.Service +{ + /// <summary> + /// This class is used to build ScsService applications. + /// </summary> + public static class ScsServiceBuilder + { + /// <summary> + /// Creates a new SCS Service application using an EndPoint. + /// </summary> + /// <param name="endPoint">EndPoint that represents address of the service</param> + /// <returns>Created SCS service application</returns> + public static IScsServiceApplication CreateService(ScsEndPoint endPoint) + { + return new ScsServiceApplication(ScsServerFactory.CreateServer(endPoint)); + } + } +} diff --git a/src/Scs/Communication/ScsServices/Service/ScsServiceClient.cs b/src/Scs/Communication/ScsServices/Service/ScsServiceClient.cs new file mode 100644 index 0000000..eda5caa --- /dev/null +++ b/src/Scs/Communication/ScsServices/Service/ScsServiceClient.cs @@ -0,0 +1,146 @@ +using System; +using System.Runtime.Remoting.Proxies; +using Hik.Communication.Scs.Communication; +using Hik.Communication.Scs.Communication.EndPoints; +using Hik.Communication.Scs.Communication.Messengers; +using Hik.Communication.Scs.Server; +using Hik.Communication.ScsServices.Communication; + +namespace Hik.Communication.ScsServices.Service +{ + /// <summary> + /// Implements IScsServiceClient. + /// It is used to manage and monitor a service client. + /// </summary> + internal class ScsServiceClient : IScsServiceClient + { + #region Public events + + /// <summary> + /// This event is raised when this client is disconnected from server. + /// </summary> + public event EventHandler Disconnected; + + #endregion + + #region Public properties + + /// <summary> + /// Unique identifier for this client. + /// </summary> + public long ClientId + { + get { return _serverClient.ClientId; } + } + + ///<summary> + /// Gets endpoint of remote application. + ///</summary> + public ScsEndPoint RemoteEndPoint + { + get { return _serverClient.RemoteEndPoint; } + } + + /// <summary> + /// Gets the communication state of the Client. + /// </summary> + public CommunicationStates CommunicationState + { + get + { + return _serverClient.CommunicationState; + } + } + + #endregion + + #region Private fields + + /// <summary> + /// Reference to underlying IScsServerClient object. + /// </summary> + private readonly IScsServerClient _serverClient; + + /// <summary> + /// This object is used to send messages to client. + /// </summary> + private readonly RequestReplyMessenger<IScsServerClient> _requestReplyMessenger; + + /// <summary> + /// Last created proxy object to invoke remote medhods. + /// </summary> + private RealProxy _realProxy; + + #endregion + + #region Constructor + + /// <summary> + /// Creates a new ScsServiceClient object. + /// </summary> + /// <param name="serverClient">Reference to underlying IScsServerClient object</param> + /// <param name="requestReplyMessenger">RequestReplyMessenger to send messages</param> + public ScsServiceClient(IScsServerClient serverClient, RequestReplyMessenger<IScsServerClient> requestReplyMessenger) + { + _serverClient = serverClient; + _serverClient.Disconnected += Client_Disconnected; + _requestReplyMessenger = requestReplyMessenger; + } + + #endregion + + #region Public methods + + /// <summary> + /// Closes client connection. + /// </summary> + public void Disconnect() + { + _serverClient.Disconnect(); + } + + /// <summary> + /// Gets the client proxy interface that provides calling client methods remotely. + /// </summary> + /// <typeparam name="T">Type of client interface</typeparam> + /// <returns>Client interface</returns> + public T GetClientProxy<T>() where T : class + { + _realProxy = new RemoteInvokeProxy<T, IScsServerClient>(_requestReplyMessenger); + return (T)_realProxy.GetTransparentProxy(); + } + + #endregion + + #region Private methods + + /// <summary> + /// Handles disconnect event of _serverClient object. + /// </summary> + /// <param name="sender">Source of event</param> + /// <param name="e">Event arguments</param> + private void Client_Disconnected(object sender, EventArgs e) + { + _requestReplyMessenger.Stop(); + OnDisconnected(); + } + + #endregion + + #region Event raising methods + + /// <summary> + /// Raises Disconnected event. + /// </summary> + private void OnDisconnected() + { + var handler = Disconnected; + if (handler != null) + { + handler(this, EventArgs.Empty); + } + } + + #endregion + } +} diff --git a/src/Scs/Communication/ScsServices/Service/ScsServiceClientFactory.cs b/src/Scs/Communication/ScsServices/Service/ScsServiceClientFactory.cs new file mode 100644 index 0000000..abbd955 --- /dev/null +++ b/src/Scs/Communication/ScsServices/Service/ScsServiceClientFactory.cs @@ -0,0 +1,23 @@ +using Hik.Communication.Scs.Communication; +using Hik.Communication.Scs.Communication.Messengers; +using Hik.Communication.Scs.Server; + +namespace Hik.Communication.ScsServices.Service +{ + /// <summary> + /// This class is used to create service client objects that is used in server-side. + /// </summary> + internal static class ScsServiceClientFactory + { + /// <summary> + /// Creates a new service client object that is used in server-side. + /// </summary> + /// <param name="serverClient">Underlying server client object</param> + /// <param name="requestReplyMessenger">RequestReplyMessenger object to send/receive messages over serverClient</param> + /// <returns></returns> + public static IScsServiceClient CreateServiceClient(IScsServerClient serverClient, RequestReplyMessenger<IScsServerClient> requestReplyMessenger) + { + return new ScsServiceClient(serverClient, requestReplyMessenger); + } + } +} diff --git a/src/Scs/Communication/ScsServices/Service/ServiceClientEventArgs.cs b/src/Scs/Communication/ScsServices/Service/ServiceClientEventArgs.cs new file mode 100644 index 0000000..deab72a --- /dev/null +++ b/src/Scs/Communication/ScsServices/Service/ServiceClientEventArgs.cs @@ -0,0 +1,24 @@ +using System; + +namespace Hik.Communication.ScsServices.Service +{ + /// <summary> + /// Stores service client informations to be used by an event. + /// </summary> + public class ServiceClientEventArgs : EventArgs + { + /// <summary> + /// Client that is associated with this event. + /// </summary> + public IScsServiceClient Client { get; private set; } + + /// <summary> + /// Creates a new ServiceClientEventArgs object. + /// </summary> + /// <param name="client">Client that is associated with this event</param> + public ServiceClientEventArgs(IScsServiceClient client) + { + Client = client; + } + } +} diff --git a/src/Scs/Diagrams/ChannelsDiagram.cd b/src/Scs/Diagrams/ChannelsDiagram.cd new file mode 100644 index 0000000..55ddc50 --- /dev/null +++ b/src/Scs/Diagrams/ChannelsDiagram.cd @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<ClassDiagram MajorVersion="1" MinorVersion="1" MembersFormat="FullSignature"> + <Class Name="Hik.Communication.Scs.Communication.Channels.CommunicationChannelBase" Collapsed="true"> + <Position X="4" Y="0.75" Width="2" /> + <TypeIdentifier> + <HashCode>AAQAAAIAQCAAIC4QACAAAAQAAAAgAAAAAAEAAgAAAgA=</HashCode> + <FileName>Communication\Scs\Communication\Channels\CommunicationChannelBase.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Class Name="Hik.Communication.Scs.Communication.Channels.Tcp.TcpCommunicationChannel" Collapsed="true"> + <Position X="4" Y="1.75" Width="2" /> + <Compartments> + <Compartment Name="Fields" Collapsed="true" /> + <Compartment Name="Methods" Collapsed="true" /> + </Compartments> + <TypeIdentifier> + <HashCode>AAQAAAAgAAABAgIAAAAAAAAAAAAgAAAAAAMAAABgAQA=</HashCode> + <FileName>Communication\Scs\Communication\Channels\Tcp\TcpCommunicationChannel.cs</FileName> + </TypeIdentifier> + </Class> + <Interface Name="Hik.Communication.Scs.Communication.Channels.ICommunicationChannel"> + <Position X="0.5" Y="3.5" Width="3.25" /> + <TypeIdentifier> + <HashCode>AAQAAAAAACAAAAgAAAAAAAAAAAAAAAAAAAEAAgAAAAA=</HashCode> + <FileName>Communication\Scs\Communication\Channels\ICommunicationChannel.cs</FileName> + </TypeIdentifier> + </Interface> + <Interface Name="Hik.Communication.Scs.Communication.IMessenger"> + <Position X="0.5" Y="0.5" Width="3.25" /> + <TypeIdentifier> + <HashCode>AAAAAAAAQAAAIAQQACAAAAQAAAAAAAAAAAAAAAAAAAA=</HashCode> + <FileName>Communication\Scs\Communication\IMessenger.cs</FileName> + </TypeIdentifier> + </Interface> + <Font Name="Segoe UI" Size="9" /> +</ClassDiagram>
\ No newline at end of file diff --git a/src/Scs/Diagrams/ConnListenerDiagram.cd b/src/Scs/Diagrams/ConnListenerDiagram.cd new file mode 100644 index 0000000..b84ed96 --- /dev/null +++ b/src/Scs/Diagrams/ConnListenerDiagram.cd @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<ClassDiagram MajorVersion="1" MinorVersion="1" MembersFormat="FullSignature"> + <Class Name="Hik.Communication.Scs.Communication.Channels.ConnectionListenerBase" Collapsed="true"> + <Position X="3.75" Y="0.75" Width="2" /> + <TypeIdentifier> + <HashCode>EAAAAACAACAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAA=</HashCode> + <FileName>Communication\Scs\Communication\Channels\ConnectionListenerBase.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Class Name="Hik.Communication.Scs.Communication.Channels.Tcp.TcpConnectionListener" Collapsed="true"> + <Position X="3.75" Y="1.75" Width="2" /> + <Compartments> + <Compartment Name="Fields" Collapsed="true" /> + <Compartment Name="Methods" Collapsed="true" /> + </Compartments> + <TypeIdentifier> + <HashCode>BAAAAQAAACAAAAACAAABAAAACAAAAAAAIAAAAEAAAQA=</HashCode> + <FileName>Communication\Scs\Communication\Channels\Tcp\TcpConnectionListener.cs</FileName> + </TypeIdentifier> + </Class> + <Interface Name="Hik.Communication.Scs.Communication.Channels.IConnectionListener"> + <Position X="0.5" Y="0.75" Width="3" /> + <TypeIdentifier> + <HashCode>EAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAA=</HashCode> + <FileName>Communication\Scs\Communication\Channels\IConnectionListener.cs</FileName> + </TypeIdentifier> + </Interface> + <Font Name="Segoe UI" Size="9" /> +</ClassDiagram>
\ No newline at end of file diff --git a/src/Scs/Diagrams/EndPointsDiagram.cd b/src/Scs/Diagrams/EndPointsDiagram.cd new file mode 100644 index 0000000..cf37040 --- /dev/null +++ b/src/Scs/Diagrams/EndPointsDiagram.cd @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<ClassDiagram MajorVersion="1" MinorVersion="1" MembersFormat="FullSignature"> + <Class Name="Hik.Communication.Scs.Communication.EndPoints.ScsEndPoint"> + <Position X="1.25" Y="1.25" Width="3.75" /> + <TypeIdentifier> + <HashCode>AAACAAAAAAAAAAAAAAAAAAAAAABABAAAAAAAAAAAAAA=</HashCode> + <FileName>Communication\Scs\Communication\EndPoints\ScsEndPoint.cs</FileName> + </TypeIdentifier> + </Class> + <Class Name="Hik.Communication.Scs.Communication.EndPoints.Tcp.ScsTcpEndPoint"> + <Position X="5.75" Y="1.25" Width="3" /> + <InheritanceLine Type="Hik.Communication.Scs.Communication.EndPoints.ScsEndPoint" FixedFromPoint="true"> + <Path> + <Point X="5" Y="1.875" /> + <Point X="5.75" Y="1.875" /> + </Path> + </InheritanceLine> + <TypeIdentifier> + <HashCode>AAACAAAAAAAAAAAAAACAAAAAAABAAAAAAAAAAAAAAEA=</HashCode> + <FileName>Communication\Scs\Communication\EndPoints\Tcp\ScsTcpEndPoint.cs</FileName> + </TypeIdentifier> + </Class> + <Font Name="Segoe UI" Size="9" /> +</ClassDiagram>
\ No newline at end of file diff --git a/src/Scs/Diagrams/MessageObjectsDiagram.cd b/src/Scs/Diagrams/MessageObjectsDiagram.cd new file mode 100644 index 0000000..e7c64fd --- /dev/null +++ b/src/Scs/Diagrams/MessageObjectsDiagram.cd @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<ClassDiagram MajorVersion="1" MinorVersion="1" MembersFormat="NameAndType"> + <Class Name="Hik.Communication.Scs.Communication.Messages.ScsTextMessage"> + <Position X="5" Y="3.5" Width="1.5" /> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAA=</HashCode> + <FileName>Communication\Scs\Communication\Messages\ScsTextMessage.cs</FileName> + </TypeIdentifier> + </Class> + <Class Name="Hik.Communication.Scs.Communication.Messages.PingMessage"> + <Position X="2.75" Y="3.5" Width="1.5" /> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode> + <FileName>Communication\Scs\Communication\Messages\PingMessage.cs</FileName> + </TypeIdentifier> + </Class> + <Class Name="Hik.Communication.Scs.Communication.Messages.ScsMessage"> + <Position X="4.75" Y="1" Width="2" /> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAgAA=</HashCode> + <FileName>Communication\Scs\Communication\Messages\ScsMessage.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Class Name="Hik.Communication.Scs.Communication.Messages.ScsRawDataMessage"> + <Position X="7.25" Y="3.5" Width="1.75" /> + <TypeIdentifier> + <HashCode>BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode> + <FileName>Communication\Scs\Communication\Messages\ScsRawDataMessage.cs</FileName> + </TypeIdentifier> + </Class> + <Interface Name="Hik.Communication.Scs.Communication.Messages.IScsMessage"> + <Position X="2.75" Y="1" Width="1.75" /> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAgAA=</HashCode> + <FileName>Communication\Scs\Communication\Messages\IScsMessage.cs</FileName> + </TypeIdentifier> + </Interface> + <Font Name="Segoe UI" Size="9" /> +</ClassDiagram>
\ No newline at end of file diff --git a/src/Scs/Diagrams/RequestReplyMessengerDiagram.cd b/src/Scs/Diagrams/RequestReplyMessengerDiagram.cd new file mode 100644 index 0000000..79a0471 --- /dev/null +++ b/src/Scs/Diagrams/RequestReplyMessengerDiagram.cd @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<ClassDiagram MajorVersion="1" MinorVersion="1" MembersFormat="FullSignature"> + <Class Name="Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger<T>"> + <Position X="0.5" Y="3.75" Width="5.5" /> + <Members> + <Method Name="Dispose" Hidden="true" /> + <Property Name="LastReceivedMessageTime" Hidden="true" /> + <Property Name="LastSentMessageTime" Hidden="true" /> + <Property Name="Messenger" Hidden="true" /> + <Method Name="Messenger_MessageReceived" Hidden="true" /> + <Method Name="Messenger_MessageSent" Hidden="true" /> + <Method Name="OnMessageReceived" Hidden="true" /> + <Method Name="OnMessageSent" Hidden="true" /> + <Method Name="RequestReplyMessenger" Hidden="true" /> + <Property Name="WireProtocol" Hidden="true" /> + </Members> + <Compartments> + <Compartment Name="Fields" Collapsed="true" /> + <Compartment Name="Events" Collapsed="true" /> + </Compartments> + <NestedTypes> + <Class Name="Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger<T>.WaitingMessage" Collapsed="true"> + <TypeIdentifier> + <NewMemberFileName>Communication\Scs\Communication\Messengers\RequestReplyMessenger.cs</NewMemberFileName> + </TypeIdentifier> + </Class> + <Enum Name="Hik.Communication.Scs.Communication.Messengers.RequestReplyMessenger<T>.WaitingMessageStates" Collapsed="true"> + <TypeIdentifier> + <NewMemberFileName>Communication\Scs\Communication\Messengers\RequestReplyMessenger.cs</NewMemberFileName> + </TypeIdentifier> + </Enum> + </NestedTypes> + <TypeIdentifier> + <HashCode>ABAEABBgQDAAICYQACAAACQAAAAAAEIAIAAAAAAAAgg=</HashCode> + <FileName>Communication\Scs\Communication\Messengers\RequestReplyMessenger.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Interface Name="Hik.Communication.Scs.Communication.Messengers.IMessenger"> + <Position X="0.5" Y="0.5" Width="3.25" /> + <TypeIdentifier> + <HashCode>AAAAAAAAQAAAIAQQACAAAAQAAAAAAAAAAAAAAAAAAAA=</HashCode> + <FileName>Communication\Scs\Communication\Messengers\IMessenger.cs</FileName> + </TypeIdentifier> + </Interface> + <Font Name="Segoe UI" Size="9" /> +</ClassDiagram>
\ No newline at end of file diff --git a/src/Scs/Diagrams/RmiMessagesDiagram.cd b/src/Scs/Diagrams/RmiMessagesDiagram.cd new file mode 100644 index 0000000..1e8fdfb --- /dev/null +++ b/src/Scs/Diagrams/RmiMessagesDiagram.cd @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<ClassDiagram MajorVersion="1" MinorVersion="1" MembersFormat="FullSignature"> + <Class Name="Hik.Communication.ScsServices.Communication.Messages.ScsRemoteInvokeMessage"> + <Position X="0.5" Y="2.5" Width="2.75" /> + <Compartments> + <Compartment Name="Methods" Collapsed="true" /> + </Compartments> + <TypeIdentifier> + <HashCode>AAAAAgAAAAAAAAAEAAAAAAAAAAAAAAAAAIACAAAAAAA=</HashCode> + <FileName>Communication\ScsServices\Communication\Messages\ScsRemoteInvokeMessage.cs</FileName> + </TypeIdentifier> + </Class> + <Class Name="Hik.Communication.ScsServices.Communication.Messages.ScsRemoteInvokeReturnMessage"> + <Position X="3.5" Y="2.5" Width="3.5" /> + <Compartments> + <Compartment Name="Methods" Collapsed="true" /> + </Compartments> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAAAEEAAAAAAAAAgAAAAAAAAAAAAAAAAA=</HashCode> + <FileName>Communication\ScsServices\Communication\Messages\ScsRemoteInvokeReturnMessage.cs</FileName> + </TypeIdentifier> + </Class> + <Class Name="Hik.Communication.Scs.Communication.Messages.ScsMessage"> + <Position X="2" Y="0.5" Width="2.75" /> + <Compartments> + <Compartment Name="Methods" Collapsed="true" /> + </Compartments> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAgAA=</HashCode> + <FileName>Communication\Scs\Communication\Messages\ScsMessage.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Font Name="Segoe UI" Size="9" /> +</ClassDiagram>
\ No newline at end of file diff --git a/src/Scs/Diagrams/ScsClientDiagram.cd b/src/Scs/Diagrams/ScsClientDiagram.cd new file mode 100644 index 0000000..42f4042 --- /dev/null +++ b/src/Scs/Diagrams/ScsClientDiagram.cd @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<ClassDiagram MajorVersion="1" MinorVersion="1" MembersFormat="FullSignature"> + <Class Name="Hik.Communication.Scs.Client.ScsClientBase" Collapsed="true"> + <Position X="1" Y="4.75" Width="4" /> + <Compartments> + <Compartment Name="Fields" Collapsed="true" /> + <Compartment Name="Properties" Collapsed="true" /> + <Compartment Name="Events" Collapsed="true" /> + </Compartments> + <TypeIdentifier> + <HashCode>CAQAAAIAQCABZCwQACAAAKQAAAAQAAIAAQEAAgAEQgA=</HashCode> + <FileName>Communication\Scs\Client\ScsClientBase.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Class Name="Hik.Communication.Scs.Client.Tcp.ScsTcpClient"> + <Position X="1" Y="5.75" Width="4" /> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAQAAAA=</HashCode> + <FileName>Communication\Scs\Client\Tcp\ScsTcpClient.cs</FileName> + </TypeIdentifier> + </Class> + <Interface Name="Hik.Communication.Scs.Client.IConnectableClient"> + <Position X="3.5" Y="0.5" Width="2" /> + <TypeIdentifier> + <HashCode>AAQAAAAAAAAAQAgAAAAAAIAAAAAAAAAAAAAAAgAEAAA=</HashCode> + <FileName>Communication\Scs\Client\IConnectableClient.cs</FileName> + </TypeIdentifier> + </Interface> + <Interface Name="Hik.Communication.Scs.Client.IScsClient" Collapsed="true"> + <Position X="2" Y="3.75" Width="2" /> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode> + <FileName>Communication\Scs\Client\IScsClient.cs</FileName> + </TypeIdentifier> + </Interface> + <Interface Name="Hik.Communication.Scs.Communication.IMessenger"> + <Position X="0.5" Y="0.5" Width="2.75" /> + <TypeIdentifier> + <HashCode>AAAAAAAAQAAAIAQQACAAAAQAAAAAAAAAAAAAAAAAAAA=</HashCode> + <FileName>Communication\Scs\Communication\IMessenger.cs</FileName> + </TypeIdentifier> + </Interface> + <Font Name="Segoe UI" Size="9" /> +</ClassDiagram>
\ No newline at end of file diff --git a/src/Scs/Diagrams/ScsServerClientDiagram.cd b/src/Scs/Diagrams/ScsServerClientDiagram.cd new file mode 100644 index 0000000..67c39cf --- /dev/null +++ b/src/Scs/Diagrams/ScsServerClientDiagram.cd @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<ClassDiagram MajorVersion="1" MinorVersion="1" MembersFormat="FullSignature"> + <Class Name="Hik.Communication.Scs.Server.ScsServerClient" Collapsed="true"> + <Position X="4" Y="3.5" Width="3" /> + <TypeIdentifier> + <HashCode>CAQAAAIAQAAAICwQgCAAACQAAAAQAAAAAAEAAgAAAgA=</HashCode> + <FileName>Communication\Scs\Server\ScsServerClient.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Interface Name="Hik.Communication.Scs.Server.IScsServerClient"> + <Position X="4" Y="0.5" Width="3" /> + <TypeIdentifier> + <HashCode>AAQAAAAAAAAAAAgAgAAAAAAAAAAAAAAAAAEAAgAAAAA=</HashCode> + <FileName>Communication\Scs\Server\IScsServerClient.cs</FileName> + </TypeIdentifier> + </Interface> + <Interface Name="Hik.Communication.Scs.Communication.IMessenger"> + <Position X="0.5" Y="0.5" Width="3.25" /> + <TypeIdentifier> + <HashCode>AAAAAAAAQAAAIAQQACAAAAQAAAAAAAAAAAAAAAAAAAA=</HashCode> + <FileName>Communication\Scs\Communication\IMessenger.cs</FileName> + </TypeIdentifier> + </Interface> + <Font Name="Segoe UI" Size="9" /> +</ClassDiagram>
\ No newline at end of file diff --git a/src/Scs/Diagrams/ScsServerDiagram.cd b/src/Scs/Diagrams/ScsServerDiagram.cd new file mode 100644 index 0000000..5a35b95 --- /dev/null +++ b/src/Scs/Diagrams/ScsServerDiagram.cd @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<ClassDiagram MajorVersion="1" MinorVersion="1" MembersFormat="FullSignature"> + <Class Name="Hik.Communication.Scs.Server.Tcp.ScsTcpServer"> + <Position X="0.5" Y="4.5" Width="3.75" /> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAAAAAAAAAQAAAAAAAIAAAAAAAAAAAAAA=</HashCode> + <FileName>Communication\Scs\Server\Tcp\ScsTcpServer.cs</FileName> + </TypeIdentifier> + </Class> + <Class Name="Hik.Communication.Scs.Server.ScsServerBase" Collapsed="true"> + <Position X="0.5" Y="3.5" Width="3.75" /> + <TypeIdentifier> + <HashCode>AAAAAAAAAGEIBAAAAKAAQAAAAAAAAAAAJAAAIAAAACA=</HashCode> + <FileName>Communication\Scs\Server\ScsServerBase.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Interface Name="Hik.Communication.Scs.Server.IScsServer"> + <Position X="0.5" Y="0.5" Width="3.75" /> + <TypeIdentifier> + <HashCode>AAAAAAAAACAAAAAAACAAAAAAAAAAAAAAJAAAIAAAACA=</HashCode> + <FileName>Communication\Scs\Server\IScsServer.cs</FileName> + </TypeIdentifier> + </Interface> + <Font Name="Segoe UI" Size="9" /> +</ClassDiagram>
\ No newline at end of file diff --git a/src/Scs/Diagrams/ScsServiceClientDiagram.cd b/src/Scs/Diagrams/ScsServiceClientDiagram.cd new file mode 100644 index 0000000..5cb9470 --- /dev/null +++ b/src/Scs/Diagrams/ScsServiceClientDiagram.cd @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<ClassDiagram MajorVersion="1" MinorVersion="1" MembersFormat="FullSignature"> + <Class Name="Hik.Communication.ScsServices.Client.ScsServiceClient<T>" Collapsed="true"> + <Position X="4.25" Y="2.25" Width="2" /> + <TypeIdentifier> + <HashCode>QAQABAIAECEAQEgAAAgAAIAAAAAAABIAAAAAAgAAAAA=</HashCode> + <FileName>Communication\ScsServices\Client\ScsServiceClient.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Interface Name="Hik.Communication.Scs.Client.IConnectableClient"> + <Position X="0.5" Y="0.5" Width="3.25" /> + <TypeIdentifier> + <HashCode>AAQAAAAAAAAAQAgAAAAAAIAAAAAAAAAAAAAAAgAAAAA=</HashCode> + <FileName>Communication\Scs\Client\IConnectableClient.cs</FileName> + </TypeIdentifier> + </Interface> + <Interface Name="Hik.Communication.ScsServices.Client.IScsServiceClient<T>"> + <Position X="4.25" Y="0.5" Width="2" /> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAA=</HashCode> + <FileName>Communication\ScsServices\Client\IScsServiceClient.cs</FileName> + </TypeIdentifier> + </Interface> + <Font Name="Segoe UI" Size="9" /> +</ClassDiagram>
\ No newline at end of file diff --git a/src/Scs/Diagrams/ScsServiceDiagram.cd b/src/Scs/Diagrams/ScsServiceDiagram.cd new file mode 100644 index 0000000..6de8205 --- /dev/null +++ b/src/Scs/Diagrams/ScsServiceDiagram.cd @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<ClassDiagram MajorVersion="1" MinorVersion="1" MembersFormat="FullSignature"> + <Class Name="Hik.Communication.ScsServices.Service.ScsServiceApplication" Collapsed="true"> + <Position X="0.5" Y="3.25" Width="2.5" /> + <NestedTypes> + <Class Name="Hik.Communication.ScsServices.Service.ScsServiceApplication.ServiceObject" Collapsed="true"> + <TypeIdentifier> + <NewMemberFileName>Communication\ScsServices\Service\ScsServiceApplication.cs</NewMemberFileName> + </TypeIdentifier> + </Class> + </NestedTypes> + <TypeIdentifier> + <HashCode>AAAAAAAAAGAABCIAACAAAQAAAAAAAAKAJAAAIDAAAAQ=</HashCode> + <FileName>Communication\ScsServices\Service\ScsServiceApplication.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Interface Name="Hik.Communication.ScsServices.Service.IScsServiceApplication"> + <Position X="0.5" Y="0.5" Width="4.25" /> + <TypeIdentifier> + <HashCode>AAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAJAAAICAAAAQ=</HashCode> + <FileName>Communication\ScsServices\Service\IScsServiceApplication.cs</FileName> + </TypeIdentifier> + </Interface> + <Font Name="Segoe UI" Size="9" /> +</ClassDiagram>
\ No newline at end of file diff --git a/src/Scs/Diagrams/ServiceSideClientDiagram.cd b/src/Scs/Diagrams/ServiceSideClientDiagram.cd new file mode 100644 index 0000000..db73465 --- /dev/null +++ b/src/Scs/Diagrams/ServiceSideClientDiagram.cd @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<ClassDiagram MajorVersion="1" MinorVersion="1" MembersFormat="FullSignature"> + <Class Name="Hik.Communication.ScsServices.Service.ScsServiceClient" Collapsed="true"> + <Position X="4" Y="0.75" Width="1.5" /> + <TypeIdentifier> + <HashCode>AAQABAIAAAEgAAgAgAAAAAAAAAAAABAAAAAAAgAAAAA=</HashCode> + <FileName>Communication\ScsServices\Service\ScsServiceClient.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Interface Name="Hik.Communication.ScsServices.Service.IScsServiceClient"> + <Position X="0.5" Y="0.5" Width="3.25" /> + <TypeIdentifier> + <HashCode>AAQAAAAAAAAAAAgAgAAAAAAAAAAAAAAAAAAAAgAAAAA=</HashCode> + <FileName>Communication\ScsServices\Service\IScsServiceClient.cs</FileName> + </TypeIdentifier> + </Interface> + <Font Name="Segoe UI" Size="9" /> +</ClassDiagram>
\ No newline at end of file diff --git a/src/Scs/Diagrams/WireProtocolsDiagram.cd b/src/Scs/Diagrams/WireProtocolsDiagram.cd new file mode 100644 index 0000000..ab569c4 --- /dev/null +++ b/src/Scs/Diagrams/WireProtocolsDiagram.cd @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<ClassDiagram MajorVersion="1" MinorVersion="1" MembersFormat="FullSignature"> + <Class Name="Hik.Communication.Scs.Communication.Protocols.BinarySerialization.BinarySerializationProtocol" Collapsed="true"> + <Position X="4.75" Y="0.5" Width="2.5" /> + <NestedTypes> + <Class Name="Hik.Communication.Scs.Communication.Protocols.BinarySerialization.BinarySerializationProtocol.DeserializationAppDomainBinder" Collapsed="true"> + <TypeIdentifier> + <NewMemberFileName>Communication\Scs\Communication\Protocols\BinarySerialization\BinarySerializationProtocol.cs</NewMemberFileName> + </TypeIdentifier> + </Class> + </NestedTypes> + <TypeIdentifier> + <HashCode>AACAAAACAAAABAABQQMAAIAAAAAACAAAAAAQAAAAAAA=</HashCode> + <FileName>Communication\Scs\Communication\Protocols\BinarySerialization\BinarySerializationProtocol.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Class Name="Hik.Communication.Scs.Communication.Protocols.BinarySerialization.BinarySerializationProtocolFactory" Collapsed="true"> + <Position X="4.75" Y="2.25" Width="2.5" /> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode> + <FileName>Communication\Scs\Communication\Protocols\BinarySerialization\BinarySerializationProtocolFactory.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Interface Name="Hik.Communication.Scs.Communication.Protocols.IScsWireProtocol"> + <Position X="0.5" Y="0.5" Width="4" /> + <TypeIdentifier> + <HashCode>AACAAAAAAAAABAAAAQAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode> + <FileName>Communication\Scs\Communication\Protocols\IScsWireProtocol.cs</FileName> + </TypeIdentifier> + </Interface> + <Interface Name="Hik.Communication.Scs.Communication.Protocols.IScsWireProtocolFactory"> + <Position X="0.5" Y="2.25" Width="4" /> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode> + <FileName>Communication\Scs\Communication\Protocols\IScsWireProtocolFactory.cs</FileName> + </TypeIdentifier> + </Interface> + <Font Name="Segoe UI" Size="9" /> +</ClassDiagram>
\ No newline at end of file diff --git a/src/Scs/Properties/AssemblyInfo.cs b/src/Scs/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..6601ece --- /dev/null +++ b/src/Scs/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Scs")] +[assembly: AssemblyDescription("Simple Client/Server Framework")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Halil ibrahim Kalkan")] +[assembly: AssemblyProduct("Scs")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("20dfc06b-5632-4956-beaf-a5e0bb126bb5")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.1.0.1")] +[assembly: AssemblyFileVersion("1.1.0.1")] diff --git a/src/Scs/Scs.csproj b/src/Scs/Scs.csproj new file mode 100644 index 0000000..66bfd66 --- /dev/null +++ b/src/Scs/Scs.csproj @@ -0,0 +1,135 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{0DC81B09-3ABF-4BB3-8C08-4E8EE4432BDC}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>Hik</RootNamespace> + <AssemblyName>Scs</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <DocumentationFile>bin\Debug\Scs.XML</DocumentationFile> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <DocumentationFile>bin\Release\Scs.XML</DocumentationFile> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Collections\ThreadSafeSortedList.cs" /> + <Compile Include="Communication\ScsServices\Client\IScsServiceClient.cs" /> + <Compile Include="Communication\ScsServices\Client\ScsServiceClient.cs" /> + <Compile Include="Communication\ScsServices\Client\ScsServiceClientBuilder.cs" /> + <Compile Include="Communication\ScsServices\Communication\AutoConnectRemoteInvokeProxy.cs" /> + <Compile Include="Communication\ScsServices\Communication\Messages\ScsRemoteException.cs" /> + <Compile Include="Communication\ScsServices\Communication\Messages\ScsRemoteInvokeMessage.cs" /> + <Compile Include="Communication\ScsServices\Communication\Messages\ScsRemoteInvokeReturnMessage.cs" /> + <Compile Include="Communication\ScsServices\Communication\RemoteInvokeProxy.cs" /> + <Compile Include="Communication\Scs\Communication\Messengers\RequestReplyMessenger.cs" /> + <Compile Include="Communication\ScsServices\Service\IScsServiceApplication.cs" /> + <Compile Include="Communication\ScsServices\Service\IScsServiceClient.cs" /> + <Compile Include="Communication\ScsServices\Service\ScsService.cs" /> + <Compile Include="Communication\ScsServices\Service\ScsServiceApplication.cs" /> + <Compile Include="Communication\ScsServices\Service\ScsServiceAttribute.cs" /> + <Compile Include="Communication\ScsServices\Service\ScsServiceBuilder.cs" /> + <Compile Include="Communication\ScsServices\Service\ScsServiceClient.cs" /> + <Compile Include="Communication\ScsServices\Service\ScsServiceClientFactory.cs" /> + <Compile Include="Communication\ScsServices\Service\ServiceClientEventArgs.cs" /> + <Compile Include="Communication\Scs\Client\ClientReConnecter.cs" /> + <Compile Include="Communication\Scs\Client\IConnectableClient.cs" /> + <Compile Include="Communication\Scs\Client\IScsClient.cs" /> + <Compile Include="Communication\Scs\Client\ScsClientBase.cs" /> + <Compile Include="Communication\Scs\Client\ScsClientFactory.cs" /> + <Compile Include="Communication\Scs\Client\Tcp\ScsTcpClient.cs" /> + <Compile Include="Communication\Scs\Client\Tcp\TcpHelper.cs" /> + <Compile Include="Communication\Scs\Communication\Channels\CommunicationChannelBase.cs" /> + <Compile Include="Communication\Scs\Communication\Channels\CommunicationChannelEventArgs.cs" /> + <Compile Include="Communication\Scs\Communication\Channels\ConnectionListenerBase.cs" /> + <Compile Include="Communication\Scs\Communication\Channels\ICommunicationChannel.cs" /> + <Compile Include="Communication\Scs\Communication\Channels\IConnectionListener.cs" /> + <Compile Include="Communication\Scs\Communication\Channels\Tcp\TcpCommunicationChannel.cs" /> + <Compile Include="Communication\Scs\Communication\Channels\Tcp\TcpConnectionListener.cs" /> + <Compile Include="Communication\Scs\Communication\CommunicationStateException.cs" /> + <Compile Include="Communication\Scs\Communication\CommunicationStates.cs" /> + <Compile Include="Communication\Scs\Communication\CommunicationException.cs" /> + <Compile Include="Communication\Scs\Communication\EndPoints\ScsEndPoint.cs" /> + <Compile Include="Communication\Scs\Communication\EndPoints\Tcp\ScsTcpEndPoint.cs" /> + <Compile Include="Communication\Scs\Communication\Messengers\IMessenger.cs" /> + <Compile Include="Communication\Scs\Communication\Messages\IScsMessage.cs" /> + <Compile Include="Communication\Scs\Communication\Messages\MessageEventArgs.cs" /> + <Compile Include="Communication\Scs\Communication\Messages\PingMessage.cs" /> + <Compile Include="Communication\Scs\Communication\Messages\ScsMessage.cs" /> + <Compile Include="Communication\Scs\Communication\Messages\ScsRawDataMessage.cs" /> + <Compile Include="Communication\Scs\Communication\Messages\ScsTextMessage.cs" /> + <Compile Include="Communication\Scs\Communication\Protocols\BinarySerialization\BinarySerializationProtocol.cs" /> + <Compile Include="Communication\Scs\Communication\Protocols\BinarySerialization\BinarySerializationProtocolFactory.cs" /> + <Compile Include="Communication\Scs\Communication\Protocols\IScsWireProtocol.cs" /> + <Compile Include="Communication\Scs\Communication\Protocols\IScsWireProtocolFactory.cs" /> + <Compile Include="Communication\Scs\Communication\Protocols\WireProtocolManager.cs" /> + <Compile Include="Communication\Scs\Communication\Messengers\SynchronizedMessenger.cs" /> + <Compile Include="Communication\Scs\Server\IScsServer.cs" /> + <Compile Include="Communication\Scs\Server\IScsServerClient.cs" /> + <Compile Include="Communication\Scs\Server\ScsServerBase.cs" /> + <Compile Include="Communication\Scs\Server\ScsServerClient.cs" /> + <Compile Include="Communication\Scs\Server\ScsServerFactory.cs" /> + <Compile Include="Communication\Scs\Server\ScsServerManager.cs" /> + <Compile Include="Communication\Scs\Server\ServerClientEventArgs.cs" /> + <Compile Include="Communication\Scs\Server\Tcp\ScsTcpServer.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="Threading\SequentialItemProcessor.cs" /> + <Compile Include="Threading\Timer.cs" /> + </ItemGroup> + <ItemGroup> + <None Include="Diagrams\ChannelsDiagram.cd" /> + <None Include="Diagrams\ConnListenerDiagram.cd" /> + <None Include="Diagrams\EndPointsDiagram.cd" /> + <None Include="Diagrams\MessageObjectsDiagram.cd" /> + <None Include="Diagrams\RequestReplyMessengerDiagram.cd" /> + <None Include="Diagrams\RmiMessagesDiagram.cd" /> + <None Include="Diagrams\ScsClientDiagram.cd" /> + <None Include="Diagrams\ScsServerClientDiagram.cd" /> + <None Include="Diagrams\ScsServerDiagram.cd" /> + <None Include="Diagrams\ScsServiceClientDiagram.cd" /> + <None Include="Diagrams\ScsServiceDiagram.cd" /> + <None Include="Diagrams\ServiceSideClientDiagram.cd" /> + <None Include="Diagrams\WireProtocolsDiagram.cd" /> + </ItemGroup> + <ItemGroup> + <Content Include="Changes.txt" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/src/Scs/Threading/SequentialItemProcessor.cs b/src/Scs/Threading/SequentialItemProcessor.cs new file mode 100644 index 0000000..185aae1 --- /dev/null +++ b/src/Scs/Threading/SequentialItemProcessor.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Hik.Threading +{ + /// <summary> + /// This class is used to process items sequentially in a multithreaded manner. + /// </summary> + /// <typeparam name="TItem">Type of item to process</typeparam> + public class SequentialItemProcessor<TItem> + { + #region Private fields + + /// <summary> + /// The method delegate that is called to actually process items. + /// </summary> + private readonly Action<TItem> _processMethod; + + /// <summary> + /// Item queue. Used to process items sequentially. + /// </summary> + private readonly Queue<TItem> _queue; + + /// <summary> + /// A reference to the current Task that is processing an item in + /// ProcessItem method. + /// </summary> + private Task _currentProcessTask; + + /// <summary> + /// Indicates state of the item processing. + /// </summary> + private bool _isProcessing; + + /// <summary> + /// A boolean value to control running of SequentialItemProcessor. + /// </summary> + private bool _isRunning; + + /// <summary> + /// An object to synchronize threads. + /// </summary> + private readonly object _syncObj = new object(); + + #endregion + + #region Constructor + + /// <summary> + /// Creates a new SequentialItemProcessor object. + /// </summary> + /// <param name="processMethod">The method delegate that is called to actually process items</param> + public SequentialItemProcessor(Action<TItem> processMethod) + { + _processMethod = processMethod; + _queue = new Queue<TItem>(); + } + + #endregion + + #region Public methods + + /// <summary> + /// Adds an item to queue to process the item. + /// </summary> + /// <param name="item">Item to add to the queue</param> + public void EnqueueMessage(TItem item) + { + //Add the item to the queue and start a new Task if needed + lock (_syncObj) + { + if (!_isRunning) + { + return; + } + + _queue.Enqueue(item); + + if (!_isProcessing) + { + _currentProcessTask = Task.Factory.StartNew(ProcessItem); + } + } + } + + /// <summary> + /// Starts processing of items. + /// </summary> + public void Start() + { + _isRunning = true; + } + + /// <summary> + /// Stops processing of items and waits stopping of current item. + /// </summary> + public void Stop() + { + _isRunning = false; + + //Clear all incoming messages + lock (_syncObj) + { + _queue.Clear(); + } + + //Check if is there a message that is being processed now + if (!_isProcessing) + { + return; + } + + //Wait current processing task to finish + try + { + _currentProcessTask.Wait(); + } + catch + { + + } + } + + #endregion + + #region Private methods + + /// <summary> + /// This method runs on a new seperated Task (thread) to process + /// items on the queue. + /// </summary> + private void ProcessItem() + { + //Try to get an item from queue to process it. + TItem itemToProcess; + lock (_syncObj) + { + if (!_isRunning || _isProcessing) + { + return; + } + + if (_queue.Count <= 0) + { + return; + } + + _isProcessing = true; + itemToProcess = _queue.Dequeue(); + } + + //Process the item (by calling the _processMethod delegate) + _processMethod(itemToProcess); + + //Process next item if available + lock (_syncObj) + { + _isProcessing = false; + if (!_isRunning || _queue.Count <= 0) + { + return; + } + + //Start a new task + _currentProcessTask = Task.Factory.StartNew(ProcessItem); + } + } + + #endregion + } +} diff --git a/src/Scs/Threading/Timer.cs b/src/Scs/Threading/Timer.cs new file mode 100644 index 0000000..331f6e7 --- /dev/null +++ b/src/Scs/Threading/Timer.cs @@ -0,0 +1,167 @@ +using System; +using System.Threading; + +namespace Hik.Threading +{ + /// <summary> + /// This class is a timer that performs some tasks periodically. + /// </summary> + public class Timer + { + #region Public events + + /// <summary> + /// This event is raised periodically according to Period of Timer. + /// </summary> + public event EventHandler Elapsed; + + #endregion + + #region Public fields + + /// <summary> + /// Task period of timer (as milliseconds). + /// </summary> + public int Period { get; set; } + + /// <summary> + /// Indicates whether timer raises Elapsed event on Start method of Timer for once. + /// Default: False. + /// </summary> + public bool RunOnStart { get; set; } + + #endregion + + #region Private fields + + /// <summary> + /// This timer is used to perfom the task at spesified intervals. + /// </summary> + private readonly System.Threading.Timer _taskTimer; + + /// <summary> + /// Indicates that whether timer is running or stopped. + /// </summary> + private volatile bool _running; + + /// <summary> + /// Indicates that whether performing the task or _taskTimer is in sleep mode. + /// This field is used to wait executing tasks when stopping Timer. + /// </summary> + private volatile bool _performingTasks; + + #endregion + + #region Constructors + + /// <summary> + /// Creates a new Timer. + /// </summary> + /// <param name="period">Task period of timer (as milliseconds)</param> + public Timer(int period) + : this(period, false) + { + + } + + /// <summary> + /// Creates a new Timer. + /// </summary> + /// <param name="period">Task period of timer (as milliseconds)</param> + /// <param name="runOnStart">Indicates whether timer raises Elapsed event on Start method of Timer for once</param> + public Timer(int period, bool runOnStart) + { + Period = period; + RunOnStart = runOnStart; + _taskTimer = new System.Threading.Timer(TimerCallBack, null, Timeout.Infinite, Timeout.Infinite); + } + + #endregion + + #region Public methods + + /// <summary> + /// Starts the timer. + /// </summary> + public void Start() + { + _running = true; + _taskTimer.Change(RunOnStart ? 0 : Period, Timeout.Infinite); + } + + /// <summary> + /// Stops the timer. + /// </summary> + public void Stop() + { + lock (_taskTimer) + { + _running = false; + _taskTimer.Change(Timeout.Infinite, Timeout.Infinite); + } + } + + /// <summary> + /// Waits the service to stop. + /// </summary> + public void WaitToStop() + { + lock (_taskTimer) + { + while (_performingTasks) + { + Monitor.Wait(_taskTimer); + } + } + } + + #endregion + + #region Private methods + + /// <summary> + /// This method is called by _taskTimer. + /// </summary> + /// <param name="state">Not used argument</param> + private void TimerCallBack(object state) + { + lock (_taskTimer) + { + if (!_running || _performingTasks) + { + return; + } + + _taskTimer.Change(Timeout.Infinite, Timeout.Infinite); + _performingTasks = true; + } + + try + { + if (Elapsed != null) + { + Elapsed(this, new EventArgs()); + } + } + catch + { + + } + finally + { + lock (_taskTimer) + { + _performingTasks = false; + if (_running) + { + _taskTimer.Change(Period, Timeout.Infinite); + } + + Monitor.Pulse(_taskTimer); + } + } + } + + #endregion + } +} |