diff --git a/CLZ Builds/PepperDash_Core.clz b/CLZ Builds/PepperDash_Core.clz deleted file mode 100644 index 57de2cc..0000000 Binary files a/CLZ Builds/PepperDash_Core.clz and /dev/null differ diff --git a/CLZ Builds/PepperDash_Core.dll b/CLZ Builds/PepperDash_Core.dll deleted file mode 100644 index 14b07ee..0000000 Binary files a/CLZ Builds/PepperDash_Core.dll and /dev/null differ diff --git a/CLZ Builds/PepperDash_Core.xml b/CLZ Builds/PepperDash_Core.xml deleted file mode 100644 index 44e8d98..0000000 --- a/CLZ Builds/PepperDash_Core.xml +++ /dev/null @@ -1,2137 +0,0 @@ - - - - PepperDash_Core - - - - - An embedded JsonToSimpl master object. - - - - - SIMPL+ can only execute the default constructor. If you have variables that require initialization, please - use an Initialize method - - - - - - - - - - - - - - - - - - - After save operation on JSON master happens, send it to server - - - - - - The core event and status-bearing class that most if not all device and connectors can derive from. - - - - - Base constructor for all Devices. - - - - - - Gets this device ready to be used in the system. Runs any added pre-activation items, and - all post-activation at end. Classes needing additional logic to - run should override CustomActivate() - - - - - Called in between Pre and PostActivationActions when Activate() is called. - Override to provide addtitional setup when calling activation. Overriding classes - do not need to call base.CustomActivate() - - true if device activated successfully. - - - - Call to deactivate device - unlink events, etc. Overriding classes do not - need to call base.Deactivate() - - - - - - Helper method to check object for bool value false and fire an Action method - - Should be of type bool, others will be ignored - Action to be run when o is false - - - - - - - - - A bandaid client that monitors whether the server is reachable - - - - - Timer to operate the bandaid monitor client in a loop. - - - - - - - - - - - - - - - constructor S+ Does not accept a key. Use initialze with key to set the debug key on this device. If using with + make sure to set all properties manually. - - - - - constructor with debug key set at instantiation. Make sure to set all properties before listening. - - - - - - Contstructor that sets all properties by calling the initialize method with a config object. - - - - - - Disconnects all clients and stops the server - - - - - Initialize Key for device using client name from SIMPL+. Called on Listen from SIMPL+ - - - - - - Start listening on the specified port - - - - - Stop Listeneing - - - - - Disconnects Client - - - - - - Disconnect All Clients - - - - - Broadcast text from server to all connected clients - - - - - - Not sure this is useful in library, maybe Pro?? - - - - - - - Secure Server Socket Status Changed Callback - - - - - - - - Secure TCP Client Connected to Secure Server Callback - - - - - - - Secure Received Data Async Callback - - - - - - - - Private Event Handler method to handle the closing of connections when the program stops - - - - - - Starts the monitor client cycle. Timed wait, then call RunMonitorClient - - - - - - - - - - - - - - - On monitor connect, restart the operation - - - - - If the client hangs, add to counter and maybe fire the choke event - - - - - Event for Receiving text - - - - - Event for client connection socket status change - - - - - Event for Server State Change - - - - - For a server with a pre shared key, this will fire after the communication is established and the key exchange is complete. If no shared key, this will fire - after connection is successful. Use this event to know when the client is ready for communication to avoid stepping on shared key. - - - - - A band aid event to notify user that the server has choked. - - - - - 3 by default - - - - - Text representation of the Socket Status enum values for the server - - - - - Bool showing if socket is connected - - - - - S+ helper for IsConnected - - - - - Bool showing if socket is connected - - - - - S+ helper for IsConnected - - - - - Number of clients currently connected. - - - - - Port Server should listen on - - - - - S+ helper for Port - - - - - Bool to show whether the server requires a preshared key. Must be set the same in the client, and if true shared keys must be identical on server/client - - - - - S+ helper for requires shared key bool - - - - - SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module. - If SharedKey changes while server is listening or clients are connected, disconnect and stop listening will be called - - - - - Heartbeat Required bool sets whether server disconnects client if heartbeat is not received - - - - - S+ Helper for Heartbeat Required - - - - - Milliseconds before server expects another heartbeat. Set by property HeartbeatRequiredIntervalInSeconds which is driven from S+ - - - - - Simpl+ Heartbeat Analog value in seconds - - - - - String to Match for heartbeat. If null or empty any string will reset heartbeat timer - - - - - Defaults to 2000 - - - - - Private flag to note that the server has stopped intentionally - - - - Privates * - - - - SIMPL+ default constructor. - - - - - Sets up class - overriding methods should always call this. - - - - - - Adds a child "module" to this master - - - - - - Called from the child to add changed or new values for saving - - - - Events * - - - - Mirrors the Unique ID for now. - - - - - Merely for use in debug messages - - - - - This will be prepended to all paths to allow path swapping or for more organized - sub-paths - - - - - This is added to the end of all paths - - - - - Enables debugging output to the console. Certain error messages will be logged to the - system's error log regardless of this setting - - - - - Ushort helper for Debug property - - - - Privates * - - - - SIMPL+ default constructor. - - - - - Read, evaluate and udpate status - - - - - Sets the filepath as well as registers this with the Global.Masters list - - - - - Call this before doing anything else - - - - - - - - - Set the JPath to evaluate for a given bool out index. - - - - - Set the JPath for a ushort out index. - - - - - Set the JPath for a string output index. - - - - - Evalutates all outputs with defined paths. called by S+ when paths are ready to process - and by Master when file is read. - - - - - Processes a bool property, converting to bool, firing off a BoolChange event - - - - - Processes the given path. - - JPath formatted path to the desired property - The string value of the property, or a default value if it - doesn't exist - This will return false in the case that EvaulateAllOnJsonChange - is false and the path does not evaluate to a property in the incoming JSON. - - - - Called from Master to read inputs and update their values in master JObject - Callback should hit one of the following four methods - - - - - Called during Process(...) to get the path to a given property. By default, - returns PathPrefix+path+PathSuffix. Override to change the way path is built. - - - - - Use a callback to reduce task switch/threading - - - - - This will be prepended to all paths to allow path swapping or for more organized - sub-paths - - - - - This is added to the end of all paths - - - - - - - - - - Defaults to Environment.NewLine; - - - - - This is something of a band-aid callback. If the client times out during the connection process, because the server - is stuck, this will fire. It is intended to be used by the Server class monitor client, to help - keep a watch on the server and reset it if necessary. - - - - - Semaphore on connect method - - - - - Flag Set only when the disconnect method is called. - - - - - private Timer for auto reconnect - - - - - Used to force disconnection on a dead connect attempt - - - - - Internal secure client - - - - - Just to help S+ set the key - - - - - Handles closing this up when the program shuts down - - - - - Connect Method. Will return if already connected. Will write errors if missing address, port, or unique key/name. - - - - - - - - - - Internal call to close up client. ALWAYS use this when disconnecting. - - - - ff - Called from Connect failure or Socket Status change if - auto reconnect and socket disconnected (Not disconnected by user) - - - - - Receive callback - - - - - - - - - - - - General send method - - - - - - - - - - SocketStatusChange Callback - - - - - - - Helper for ConnectionChange event - - - - - Helper to fire ClientReadyForCommunications event - - - - - For a client with a pre shared key, this will fire after the communication is established and the key exchange is complete. If you require - a key and subscribe to the socket change event and try to send data on a connection the data sent will interfere with the key exchange and disconnect. - - - - - Address of server - - - - - Port on server - - - - - S+ helper - - - - - Bool to show whether the server requires a preshared key. This is used in the DynamicTCPServer class - - - - - S+ helper for requires shared key bool - - - - - SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module - - - - - flag to show the client is waiting for the server to send the shared key - - - - - Defaults to 2000 - - - - - Bool showing if socket is connected - - - - - S+ helper for IsConnected - - - - - Bool showing if socket is ready for communication after shared key exchange - - - - - S+ helper for IsReadyForCommunication - - - - - Client socket status Read only - - - - - Contains the familiar Simpl analog status values. This drives the ConnectionChange event - and IsConnected would be true when this == 2. - - - - - Status text shows the message associated with socket status - - - - - bool to track if auto reconnect should be set on the socket - - - - - S+ helper for AutoReconnect - - - - - Milliseconds to wait before attempting to reconnect. Defaults to 5000 - - - - - Band aid delegate for choked server - - - - - An incoming communication stream - - - - - Represents a device that uses basic connection - - - - - For IBasicCommunication classes that have SocketStatus. GenericSshClient, - GenericTcpIpClient - - - - - - - - - - This delegate defines handler for IBasicCommunication status changes - - Device firing the status change - - - - - - - - - - Stupid S+ Constructor - - - - - - - - - - Stupid S+ Constructor - - - - - - - - - - - Gets a level or creates it if not existing - - - - - - - Adds a file master. If the master's key or filename is equivalent to any existing - master, this will fail - - New master to add - - - - - Gets a master by its key. Case-insensitive - - - - Privates * - - - - SIMPL+ default constructor. - - - - - Loads in JSON and triggers evaluation on all children - - - - - - Loads JSON into JsonObject, but does not trigger evaluation by children - - - - - - - - - - - This is something of a band-aid callback. If the client times out during the connection process, because the server - is stuck, this will fire. It is intended to be used by the Server class monitor client, to help - keep a watch on the server and reset it if necessary. - - - - - Semaphore on connect method - - - - - Flag Set only when the disconnect method is called. - - - - - private Timer for auto reconnect - - - - - Used to force disconnection on a dead connect attempt - - - - - Internal secure client - - - - - Just to help S+ set the key - - - - - Handles closing this up when the program shuts down - - - - - Connect Method. Will return if already connected. Will write errors if missing address, port, or unique key/name. - - - - - - - - - - Internal call to close up client. ALWAYS use this when disconnecting. - - - - ff - Called from Connect failure or Socket Status change if - auto reconnect and socket disconnected (Not disconnected by user) - - - - - Receive callback - - - - - - - - - - - - General send method - - - - - - - - - - SocketStatusChange Callback - - - - - - - Helper for ConnectionChange event - - - - - Helper to fire ClientReadyForCommunications event - - - - - For a client with a pre shared key, this will fire after the communication is established and the key exchange is complete. If you require - a key and subscribe to the socket change event and try to send data on a connection the data sent will interfere with the key exchange and disconnect. - - - - - Address of server - - - - - Port on server - - - - - S+ helper - - - - - Bool to show whether the server requires a preshared key. This is used in the DynamicTCPServer class - - - - - S+ helper for requires shared key bool - - - - - SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module - - - - - flag to show the client is waiting for the server to send the shared key - - - - - Defaults to 2000 - - - - - Bool showing if socket is connected - - - - - S+ helper for IsConnected - - - - - Bool showing if socket is ready for communication after shared key exchange - - - - - S+ helper for IsReadyForCommunication - - - - - Client socket status Read only - - - - - Contains the familiar Simpl analog status values. This drives the ConnectionChange event - and IsConnected would be true when this == 2. - - - - - Status text shows the message associated with socket status - - - - - bool to track if auto reconnect should be set on the socket - - - - - S+ helper for AutoReconnect - - - - - Milliseconds to wait before attempting to reconnect. Defaults to 5000 - - - - - Band aid delegate for choked server - - - - - - - - - - - - - - - For Simpl+ - - - - - True when user is found - - - - - For stupid S+ - - - - - - - - - - - For newer >=2.4.1 array lookups. - - - - - - - - - - - - - - - - - - - Provides the path append for GetFullPath - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Stores the state of the request - - - - - Waithandle for main thread. - - - - - - - - - - For Simpl+ - - - - - True when the preset is found - - - - - S+ helper for stupid S+ - - - - - Set only when the disconnect method is called. - - - - - Just to help S+ set the key - - - - - Handles closing this up when the program shuts down - - - - - General send method - - - - - This is useful from console and...? - - - - - - - - - - - - - - - - - - - - Address of server - - - - - Port on server - - - - - Another damn S+ helper because S+ seems to treat large port nums as signed ints - which screws up things - - - - - Defaults to 2000 - - - - - - - - - - - - - - - S+ helper for IsConnected - - - - - - - - - - Contains the familiar Simpl analog status values. This drives the ConnectionChange event - and IsConnected with be true when this == 2. - - - - - - - - - - - - - - - - - - - - S+ helper for AutoReconnect - - - - - Milliseconds to wait before attempting to reconnect. Defaults to 5000 - - - - - - - - - - Defaults to 32768 - - - - - Defaults to true - - - - - Defaults to 5000ms - - - - - Creates or gets a debug context - - - - - - - Do not use. For S+ access. - - - - - Used to save memory when shutting down - - - - - - Callback for console command - - - - - - Sets the debug level - - Valid values 0 (no debug), 1 (critical), 2 (all messages) - - - - Prints message to console if current debug level is equal to or higher than the level of this message. - Uses CrestronConsole.PrintLine. - - - Console format string - Object parameters - - - - Appends a device Key to the beginning of a message - - - - - Writes the memory object after timeout - - - - - Writes the memory - use SaveMemoryOnTimeout - - - - - - - - - - Helper to get the file path for this app's debug memory - - - - - Describes the folder location where a given program stores it's debug level memory. By default, the - file written will be named appNdebug where N is 1-10. - - - - - Defines the string event handler for line events on the gather - - - - - - Attaches to IBasicCommunication as a text gather - - - - - For receive buffer - - - - - Delimiter, like it says! - - - - - Fires up a gather, given a IBasicCommunicaion port and char for de - - - - - - - - - - - - - - Disconnects this gather from the Port's TextReceived event. This will not fire LineReceived - after the this call. - - - - - Handler for raw data coming from port - - - - - - - - - - - - Deconstructor. Disconnects from port TextReceived events. - - - - - Event that fires when a line is received from the IBasicCommunication source. - The event merely contains the text, not an EventArgs type class. - - - - - The communication port that this gathers on - - - - - Default false. If true, the delimiter will be included in the line output - events - - - - Privates * - - - - SIMPL+ default constructor. - - - - - Read, evaluate and udpate status - - - - - Returns the FileInfo object for a given path, with possible wildcards - - - - - - - - - - - - - - - - - - Sets the filepath as well as registers this with the Global.Masters list - - - - - - - - - - A bandaid client that monitors whether the server is reachable - - - - - Timer to operate the bandaid monitor client in a loop. - - - - - - - - - - - - - - - constructor S+ Does not accept a key. Use initialze with key to set the debug key on this device. If using with + make sure to set all properties manually. - - - - - constructor with debug key set at instantiation. Make sure to set all properties before listening. - - - - - - Contstructor that sets all properties by calling the initialize method with a config object. - - - - - - Disconnects all clients and stops the server - - - - - Initialize Key for device using client name from SIMPL+. Called on Listen from SIMPL+ - - - - - - Start listening on the specified port - - - - - Stop Listeneing - - - - - Disconnects Client - - - - - - Disconnect All Clients - - - - - Broadcast text from server to all connected clients - - - - - - Not sure this is useful in library, maybe Pro?? - - - - - - - Secure Server Socket Status Changed Callback - - - - - - - - Secure TCP Client Connected to Secure Server Callback - - - - - - - Secure Received Data Async Callback - - - - - - - - Private Event Handler method to handle the closing of connections when the program stops - - - - - - Starts the monitor client cycle. Timed wait, then call RunMonitorClient - - - - - - - - - - - - - - - On monitor connect, restart the operation - - - - - If the client hangs, add to counter and maybe fire the choke event - - - - - Event for Receiving text - - - - - Event for client connection socket status change - - - - - Event for Server State Change - - - - - For a server with a pre shared key, this will fire after the communication is established and the key exchange is complete. If no shared key, this will fire - after connection is successful. Use this event to know when the client is ready for communication to avoid stepping on shared key. - - - - - A band aid event to notify user that the server has choked. - - - - - 3 by default - - - - - Text representation of the Socket Status enum values for the server - - - - - Bool showing if socket is connected - - - - - S+ helper for IsConnected - - - - - Bool showing if socket is connected - - - - - S+ helper for IsConnected - - - - - Number of clients currently connected. - - - - - Port Server should listen on - - - - - S+ helper for Port - - - - - Bool to show whether the server requires a preshared key. Must be set the same in the client, and if true shared keys must be identical on server/client - - - - - S+ helper for requires shared key bool - - - - - SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module. - If SharedKey changes while server is listening or clients are connected, disconnect and stop listening will be called - - - - - Heartbeat Required bool sets whether server disconnects client if heartbeat is not received - - - - - S+ Helper for Heartbeat Required - - - - - Milliseconds before server expects another heartbeat. Set by property HeartbeatRequiredIntervalInSeconds which is driven from S+ - - - - - Simpl+ Heartbeat Analog value in seconds - - - - - String to Match for heartbeat. If null or empty any string will reset heartbeat timer - - - - - Defaults to 2000 - - - - - Private flag to note that the server has stopped intentionally - - - - - Describes the folder location where a given program stores it's debug level memory. By default, the - file written will be named appNdebug where N is 1-10. - - - - - The name of the file containing the current debug settings. - - - - - When true, the IncludedExcludedKeys dict will contain keys to include. - When false (default), IncludedExcludedKeys will contain keys to exclude. - - - - - Used to save memory when shutting down - - - - - - Callback for console command - - - - - - Sets the debug level - - Valid values 0 (no debug), 1 (critical), 2 (all messages) - - - - - - - - - Prints message to console if current debug level is equal to or higher than the level of this message. - Uses CrestronConsole.PrintLine. - - - Console format string - Object parameters - - - - Logs to Console when at-level, and all messages to error log, including device key - - - - - Logs to Console when at-level, and all messages to error log - - - - - Logs to both console and the custom user log (not the built-in error log). If appdebug level is set at - or above the level provided, then the output will be written to both console and the log. Otherwise - it will only be written to the log. - - - - - - - - Logs to both console and the custom user log (not the built-in error log). If appdebug level is set at - or above the level provided, then the output will be written to both console and the log. Otherwise - it will only be written to the log. - - - - String.format string - Parameters for substitution in the format string. - - - - Prints to log and error log - - - - - - - Writes the memory object after timeout - - - - - Writes the memory - use SaveMemoryOnTimeout - - - - - - - - - - Helper to get the file path for this app's debug memory - - - - - Reads the config file, checks if it needs a merge, merges and saves, then returns the merged Object. - - JObject of config file - - - - - - - - - - - Merges the contents of a base and a delta array, matching the entries on a top-level property - given by propertyName. Returns a merge of them. Items in the delta array that do not have - a matched item in base array will not be merged. Non keyed system items will replace the template items. - - - - - Helper for using with JTokens. Converts to JObject - - - - - Merge o2 onto o1 - - - - - - - Queue to temporarily store received messages with the source IP and Port info - - - - - Enables the UDP Server - - - - - Disabled the UDP Server - - - - - Recursive method to receive data - - - - - - - This method gets spooled up in its own thread an protected by a CCriticalSection to prevent multiple threads from running concurrently. - It will dequeue items as they are enqueued automatically. - - - - - General send method - - - - - - - - - - - - - - - - This event will fire when a message is dequeued that includes the source IP and Port info if needed to determine the source of the received data. - - - - - - - - - - Address of server - - - - - Port on server - - - - - Another damn S+ helper because S+ seems to treat large port nums as signed ints - which screws up things - - - - - Indicates that the UDP Server is enabled - - - - - Defaults to 2000 - - - - - Stupid S+ Constructor - - - - - Defaults to 32768 - - - - - - - - - - Typical constructor. - - - - - S+ Constructor - Must set all properties before calling Connect - - - - - Just to help S+ set the key - - - - - Handles closing this up when the program shuts down - - - - - Connect to the server, using the provided properties. - - - - - Disconnect the clients and put away it's resources. - - - - - Anything to do with reestablishing connection on failures - - - - - Handles the keyboard interactive authentication, should it be required. - - - - - Handler for data receive on ShellStream. Passes data across to queue for line parsing. - - - - - Error event handler for client events - disconnect, etc. Will forward those events via ConnectionChange - event - - - - - Helper for ConnectionChange event - - - - - - - - - - - Event that fires when data is received. Delivers args with byte array - - - - - Event that fires when data is received. Delivered as text. - - - - - Event when the connection status changes. - - - - - Address of server - - - - - Port on server - - - - - Username for server - - - - - And... Password for server. That was worth documenting! - - - - - True when the server is connected - when status == 2. - - - - - S+ helper for IsConnected - - - - - - - - - - Contains the familiar Simpl analog status values. This drives the ConnectionChange event - and IsConnected with be true when this == 2. - - - - - Determines whether client will attempt reconnection on failure. Default is true - - - - - Will be set and unset by connect and disconnect only - - - - - S+ helper for AutoReconnect - - - - - Millisecond value, determines the timeout period in between reconnect attempts. - Set to 5000 by default - - - - - Fired when connection changes - - - - - Background class that manages debug features for sockets - - - - - Sets up the backing class. Adds console commands for S#Pro programs - - - - - Helper for socket list, to show types - - - - - - - - - - - - - - - - diff --git a/Pepperdash Core/Pepperdash Core/Comm/EventArgs.cs b/Pepperdash Core/Pepperdash Core/Comm/EventArgs.cs index ed43c62..52ee207 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/EventArgs.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/EventArgs.cs @@ -93,6 +93,24 @@ namespace PepperDash.Core } } + public class GenericUdpConnectedEventArgs : EventArgs + { + public ushort UConnected; + public bool Connected; + + public GenericUdpConnectedEventArgs() { } + + public GenericUdpConnectedEventArgs(ushort uconnected) + { + UConnected = uconnected; + } + + public GenericUdpConnectedEventArgs(bool connected) + { + Connected = connected; + } + } + } \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericSecureTcpIpClient_ForServer.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericSecureTcpIpClient_ForServer.cs index df61965..c3882ca 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/GenericSecureTcpIpClient_ForServer.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/GenericSecureTcpIpClient_ForServer.cs @@ -33,6 +33,15 @@ namespace PepperDash.Core public event EventHandler TextReceived; + public event EventHandler AutoReconnectTriggered; + + /// + /// Event for Receiving text. Once subscribed to this event the receive callback will start a thread that dequeues the messages and invokes the event on a new thread. + /// It is not recommended to use both the TextReceived event and the TextReceivedQueueInvoke event. + /// + public event EventHandler TextReceivedQueueInvoke; + + public event EventHandler ConnectionChange; @@ -209,8 +218,20 @@ namespace PepperDash.Core get { return (ushort)(HeartbeatEnabled ? 1 : 0); } set { HeartbeatEnabled = value == 1; } } - public string HeartbeatString = "heartbeat"; - public int HeartbeatInterval = 50000; + + public string HeartbeatString { get; set; } + //public int HeartbeatInterval = 50000; + + /// + /// Milliseconds before server expects another heartbeat. Set by property HeartbeatRequiredIntervalInSeconds which is driven from S+ + /// + public int HeartbeatInterval { get; set; } + + /// + /// Simpl+ Heartbeat Analog value in seconds + /// + public ushort HeartbeatRequiredIntervalInSeconds { set { HeartbeatInterval = (value * 1000); } } + CTimer HeartbeatSendTimer; CTimer HeartbeatAckTimer; /// @@ -226,6 +247,24 @@ namespace PepperDash.Core bool ProgramIsStopping; + /// + /// Queue lock + /// + CCriticalSection DequeueLock = new CCriticalSection(); + + /// + /// Receive Queue size. Defaults to 20. Will set to 20 if QueueSize property is less than 20. Use constructor or set queue size property before + /// calling initialize. + /// + public int ReceiveQueueSize { get; set; } + + /// + /// Queue to temporarily store received messages with the source IP and Port info. Defaults to size 20. Use constructor or set queue size property before + /// calling initialize. + /// + private CrestronQueue MessageQueue; + + #endregion #region Constructors @@ -244,12 +283,24 @@ namespace PepperDash.Core //base class constructor public GenericSecureTcpIpClient_ForServer() - : base("Uninitialized DynamicTcpClient") + : base("Uninitialized Secure Tcp Client For Server") { CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); AutoReconnectIntervalMs = 5000; BufferSize = 2000; } + + /// + /// Contstructor that sets all properties by calling the initialize method with a config object. + /// + /// + public GenericSecureTcpIpClient_ForServer(string key, TcpClientConfigObject clientConfigObject) + : base(key) + { + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + Initialize(clientConfigObject); + } + #endregion #region Methods @@ -262,6 +313,43 @@ namespace PepperDash.Core Key = key; } + /// + /// Initialize called by the constructor that accepts a client config object. Can be called later to reset properties of client. + /// + /// + public void Initialize(TcpClientConfigObject clientConfigObject) + { + try + { + if (clientConfigObject != null) + { + var TcpSshProperties = clientConfigObject.Control.TcpSshProperties; + Hostname = TcpSshProperties.Address; + AutoReconnect = TcpSshProperties.AutoReconnect; + AutoReconnectIntervalMs = TcpSshProperties.AutoReconnectIntervalMs > 1000 ? + TcpSshProperties.AutoReconnectIntervalMs : 5000; + SharedKey = clientConfigObject.SharedKey; + SharedKeyRequired = clientConfigObject.SharedKeyRequired; + HeartbeatEnabled = clientConfigObject.HeartbeatRequired; + HeartbeatRequiredIntervalInSeconds = clientConfigObject.HeartbeatRequiredIntervalInSeconds > 0 ? + clientConfigObject.HeartbeatRequiredIntervalInSeconds : (ushort)15; + HeartbeatString = string.IsNullOrEmpty(clientConfigObject.HeartbeatStringToMatch) ? "heartbeat" : clientConfigObject.HeartbeatStringToMatch; + Port = TcpSshProperties.Port; + BufferSize = TcpSshProperties.BufferSize > 2000 ? TcpSshProperties.BufferSize : 2000; + ReceiveQueueSize = clientConfigObject.ReceiveQueueSize > 20 ? clientConfigObject.ReceiveQueueSize : 20; + MessageQueue = new CrestronQueue(ReceiveQueueSize); + } + else + { + ErrorLog.Error("Could not initialize client with key: {0}", Key); + } + } + catch + { + ErrorLog.Error("Could not initialize client with key: {0}", Key); + } + } + /// /// Handles closing this up when the program shuts down /// @@ -328,7 +416,7 @@ namespace PepperDash.Core Client = new SecureTCPClient(Hostname, Port, BufferSize); Client.SocketStatusChange += Client_SocketStatusChange; - if(HeartbeatEnabled) + if (HeartbeatEnabled) Client.SocketSendOrReceiveTimeOutInMs = (HeartbeatInterval * 5); Client.AddressClientConnectedTo = Hostname; Client.PortNumber = Port; @@ -473,6 +561,8 @@ namespace PepperDash.Core RetryTimer.Stop(); RetryTimer = null; } + if(AutoReconnectTriggered != null) + AutoReconnectTriggered(this, new EventArgs()); RetryTimer = new CTimer(o => Connect(), rndTime); } } @@ -487,7 +577,7 @@ namespace PepperDash.Core if (numBytes > 0) { string str = string.Empty; - + var handler = TextReceivedQueueInvoke; try { var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); @@ -517,6 +607,10 @@ namespace PepperDash.Core var textHandler = TextReceived; if (textHandler != null) textHandler(this, new GenericTcpServerCommMethodReceiveTextArgs(str)); + if (handler != null) + { + MessageQueue.TryToEnqueue(new GenericTcpServerCommMethodReceiveTextArgs(str)); + } } } } @@ -524,9 +618,51 @@ namespace PepperDash.Core { Debug.Console(1, this, "Error receiving data: {1}. Error: {0}", ex.Message, str); } + if (client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) + client.ReceiveDataAsync(Receive); + + //Check to see if there is a subscription to the TextReceivedQueueInvoke event. If there is start the dequeue thread. + if (handler != null) + { + var gotLock = DequeueLock.TryEnter(); + if (gotLock) + CrestronInvoke.BeginInvoke((o) => DequeueEvent()); + } + } + else //JAG added this as I believe the error return is 0 bytes like the server. See help when hover on ReceiveAsync + { + client.DisconnectFromServer(); + } + } + + /// + /// This method gets spooled up in its own thread an protected by a CCriticalSection to prevent multiple threads from running concurrently. + /// It will dequeue items as they are enqueued automatically. + /// + void DequeueEvent() + { + try + { + while (true) + { + // Pull from Queue and fire an event. Block indefinitely until an item can be removed, similar to a Gather. + var message = MessageQueue.Dequeue(); + var handler = TextReceivedQueueInvoke; + if (handler != null) + { + handler(this, message); + } + } + } + catch (Exception e) + { + Debug.Console(0, "DequeueEvent error: {0}\r", e); + } + // Make sure to leave the CCritical section in case an exception above stops this thread, or we won't be able to restart it. + if (DequeueLock != null) + { + DequeueLock.Leave(); } - if (client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) - client.ReceiveDataAsync(Receive); } void HeartbeatStart() diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericSecureTcpIpServer.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericSecureTcpIpServer.cs index 5554764..ea9c606 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/GenericSecureTcpIpServer.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/GenericSecureTcpIpServer.cs @@ -28,6 +28,12 @@ namespace PepperDash.Core /// public event EventHandler TextReceived; + /// + /// Event for Receiving text. Once subscribed to this event the receive callback will start a thread that dequeues the messages and invokes the event on a new thread. + /// It is not recommended to use both the TextReceived event and the TextReceivedQueueInvoke event. + /// + public event EventHandler TextReceivedQueueInvoke; + /// /// Event for client connection socket status change /// @@ -56,10 +62,26 @@ namespace PepperDash.Core #region Properties/Variables /// - /// + /// Server listen lock /// CCriticalSection ServerCCSection = new CCriticalSection(); + /// + /// Queue lock + /// + CCriticalSection DequeueLock = new CCriticalSection(); + + /// + /// Receive Queue size. Defaults to 20. Will set to 20 if QueueSize property is less than 20. Use constructor or set queue size property before + /// calling initialize. + /// + public int ReceiveQueueSize { get; set; } + + /// + /// Queue to temporarily store received messages with the source IP and Port info. Defaults to size 20. Use constructor or set queue size property before + /// calling initialize. + /// + private CrestronQueue MessageQueue; /// /// A bandaid client that monitors whether the server is reachable @@ -145,7 +167,9 @@ namespace PepperDash.Core { get { return (ushort)(IsListening ? 1 : 0); } } - + /// + /// Max number of clients this server will allow for connection. Crestron max is 64. This number should be less than 65 + /// public ushort MaxClients { get; set; } // should be set by parameter in SIMPL+ in the MAIN method, Should not ever need to be configurable /// /// Number of clients currently connected. @@ -269,7 +293,7 @@ namespace PepperDash.Core /// constructor S+ Does not accept a key. Use initialze with key to set the debug key on this device. If using with + make sure to set all properties manually. /// public GenericSecureTcpIpServer() - : base("Uninitialized Dynamic TCP Server") + : base("Uninitialized Secure TCP Server") { HeartbeatRequiredIntervalInSeconds = 15; CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); @@ -282,7 +306,7 @@ namespace PepperDash.Core /// /// public GenericSecureTcpIpServer(string key) - : base("Uninitialized Dynamic TCP Server") + : base("Uninitialized Secure TCP Server") { HeartbeatRequiredIntervalInSeconds = 15; CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); @@ -292,11 +316,11 @@ namespace PepperDash.Core } /// - /// Contstructor that sets all properties by calling the initialize method with a config object. + /// Contstructor that sets all properties by calling the initialize method with a config object. This does set Queue size. /// /// public GenericSecureTcpIpServer(TcpServerConfigObject serverConfigObject) - : base("Uninitialized Dynamic TCP Server") + : base("Uninitialized Secure TCP Server") { HeartbeatRequiredIntervalInSeconds = 15; CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); @@ -345,7 +369,8 @@ namespace PepperDash.Core HeartbeatRequiredIntervalInSeconds = serverConfigObject.HeartbeatRequiredIntervalInSeconds; HeartbeatStringToMatch = serverConfigObject.HeartbeatStringToMatch; BufferSize = serverConfigObject.BufferSize; - + ReceiveQueueSize = serverConfigObject.ReceiveQueueSize > 20 ? serverConfigObject.ReceiveQueueSize : 20; + MessageQueue = new CrestronQueue(ReceiveQueueSize); } else { @@ -391,7 +416,7 @@ namespace PepperDash.Core } else { - KillServer(); + //KillServer(); Remove this to be able to reactivate listener if it stops itself due to max clients without disconnecting connected clients. SecureServer.PortNumber = Port; } ServerStopped = false; @@ -678,7 +703,10 @@ namespace PepperDash.Core { Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Error in Socket Status Change Callback. Error: {0}", ex); } - onConnectionChange(clientIndex, server.GetServerSocketStatusForSpecificClient(clientIndex)); + //Use a thread for this event so that the server state updates to listening while this event is processed. Listening must be added to the server state + //after every client connection so that the server can check and see if it is at max clients. Due to this the event fires and server listening enum bit flag + //is not set. Putting in a thread allows the state to update before this event processes so that the subscribers to this event get accurate isListening in the event. + CrestronInvoke.BeginInvoke(o => onConnectionChange(clientIndex, server.GetServerSocketStatusForSpecificClient(clientIndex)), null); } #endregion @@ -770,6 +798,7 @@ namespace PepperDash.Core if (numberOfBytesReceived > 0) { string received = "Nothing"; + var handler = TextReceivedQueueInvoke; try { byte[] bytes = mySecureTCPServer.GetIncomingDataBufferForSpecificClient(clientIndex); @@ -792,11 +821,16 @@ namespace PepperDash.Core byte[] success = Encoding.GetEncoding(28591).GetBytes("Shared Key Match"); mySecureTCPServer.SendDataAsync(clientIndex, success, success.Length, null); OnServerClientReadyForCommunications(clientIndex); - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Client with index {0} provided the shared key and successfully connected to the server", clientIndex); - + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Client with index {0} provided the shared key and successfully connected to the server", clientIndex); + } + else if (!string.IsNullOrEmpty(checkHeartbeat(clientIndex, received))) + { + onTextReceived(received, clientIndex); + if (handler != null) + { + MessageQueue.TryToEnqueue(new GenericTcpServerCommMethodReceiveTextArgs(received, clientIndex)); + } } - else if (!string.IsNullOrEmpty(checkHeartbeat(clientIndex, received))) - onTextReceived(received, clientIndex); } catch (Exception ex) { @@ -804,13 +838,49 @@ namespace PepperDash.Core } if (mySecureTCPServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) mySecureTCPServer.ReceiveDataAsync(clientIndex, SecureReceivedDataAsyncCallback); + + //Check to see if there is a subscription to the TextReceivedQueueInvoke event. If there is start the dequeue thread. + if (handler != null) + { + var gotLock = DequeueLock.TryEnter(); + if (gotLock) + CrestronInvoke.BeginInvoke((o) => DequeueEvent()); + } } else { - // If numberOfBytesReceived <= 0 mySecureTCPServer.Disconnect(clientIndex); - } + } + } + /// + /// This method gets spooled up in its own thread an protected by a CCriticalSection to prevent multiple threads from running concurrently. + /// It will dequeue items as they are enqueued automatically. + /// + void DequeueEvent() + { + try + { + while (true) + { + // Pull from Queue and fire an event. Block indefinitely until an item can be removed, similar to a Gather. + var message = MessageQueue.Dequeue(); + var handler = TextReceivedQueueInvoke; + if (handler != null) + { + handler(this, message); + } + } + } + catch (Exception e) + { + Debug.Console(0, "DequeueEvent error: {0}\r", e); + } + // Make sure to leave the CCritical section in case an exception above stops this thread, or we won't be able to restart it. + if (DequeueLock != null) + { + DequeueLock.Leave(); + } } #endregion diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs index 65c428f..525f32b 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs @@ -29,10 +29,27 @@ namespace PepperDash.Core //public event GenericSocketStatusChangeEventDelegate SocketStatusChange; public event EventHandler ConnectionChange; + + private string _Hostname { get; set;} /// /// Address of server /// - public string Hostname { get; set; } + public string Hostname { + get + { + return _Hostname; + } + + set + { + _Hostname = value; + if (Client != null) + { + + Client.AddressClientConnectedTo = _Hostname; + } + } + } /// /// Port on server @@ -233,10 +250,13 @@ namespace PepperDash.Core if (Client == null) { + + Client = new TCPClient(Hostname, Port, BufferSize); Client.SocketStatusChange += Client_SocketStatusChange; } DisconnectCalledByUser = false; + Client.ConnectToServerAsync(ConnectToServerCallback); // (null); } @@ -352,7 +372,6 @@ namespace PepperDash.Core } } - public class TcpSshPropertiesConfig { [JsonProperty(Required = Required.Always)] diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericUdpServer.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericUdpServer.cs index f819c17..011c17c 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/GenericUdpServer.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/GenericUdpServer.cs @@ -43,6 +43,8 @@ namespace PepperDash.Core //public event GenericSocketStatusChangeEventDelegate SocketStatusChange; public event EventHandler ConnectionChange; + public event EventHandler UpdateConnectionStatus; + public SocketStatus ClientStatus { get @@ -51,6 +53,11 @@ namespace PepperDash.Core } } + public ushort UStatus + { + get { return (ushort)Server.ServerStatus; } + } + CCriticalSection DequeueLock; /// @@ -87,6 +94,11 @@ namespace PepperDash.Core private set; } + public ushort UIsConnected + { + get { return IsConnected ? (ushort)1 : (ushort)0; } + } + /// /// Defaults to 2000 /// @@ -94,6 +106,20 @@ namespace PepperDash.Core public UDPServer Server { get; private set; } + /// + /// Constructor for S+. Make sure to set key, address, port, and buffersize using init method + /// + public GenericUdpServer() + : base("Uninitialized Udp Server") + { + BufferSize = 5000; + DequeueLock = new CCriticalSection(); + MessageQueue = new CrestronQueue(); + + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); + } + public GenericUdpServer(string key, string address, int port, int buffefSize) : base(key) { @@ -108,6 +134,13 @@ namespace PepperDash.Core CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); } + public void Initialize(string key, string address, ushort port) + { + Key = key; + Hostname = address; + UPort = port; + } + void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) { // Re-enable the server if the link comes back up and the status should be connected @@ -135,7 +168,6 @@ namespace PepperDash.Core if (Server == null) { Server = new UDPServer(); - } if (string.IsNullOrEmpty(Hostname)) @@ -157,6 +189,10 @@ namespace PepperDash.Core if (status == SocketErrorCodes.SOCKET_OK) IsConnected = true; + var handler = UpdateConnectionStatus; + if (handler != null) + handler(this, new GenericUdpConnectedEventArgs(UIsConnected)); + // Start receiving data Server.ReceiveDataAsync(Receive); } @@ -170,6 +206,10 @@ namespace PepperDash.Core Server.DisableUDPServer(); IsConnected = false; + + var handler = UpdateConnectionStatus; + if (handler != null) + handler(this, new GenericUdpConnectedEventArgs(UIsConnected)); } diff --git a/Pepperdash Core/Pepperdash Core/Comm/TcpClientConfigObject.cs b/Pepperdash Core/Pepperdash Core/Comm/TcpClientConfigObject.cs new file mode 100644 index 0000000..a4fe8b2 --- /dev/null +++ b/Pepperdash Core/Pepperdash Core/Comm/TcpClientConfigObject.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using PepperDash.Core; +using Newtonsoft.Json; + +namespace PepperDash.Core +{ + /// + /// Client config object for TCP client with server that inherits from TcpSshPropertiesConfig and adds properties for shared key and heartbeat + /// + public class TcpClientConfigObject + { + /// + /// TcpSsh Properties + /// + public ControlPropertiesConfig Control { get; set; } + /// + /// Bool value for secure. Currently not implemented in TCP sockets as they are not dynamic + /// + public bool Secure { get; set; } + /// + /// Require a shared key that both server and client negotiate. If negotiation fails server disconnects the client + /// + public bool SharedKeyRequired { get; set; } + + /// + /// The shared key that must match on the server and client + /// + public string SharedKey { get; set; } + /// + /// Require a heartbeat on the client/server connection that will cause the server/client to disconnect if the heartbeat is not received. + /// heartbeats do not raise received events. + /// + public bool HeartbeatRequired { get; set; } + /// + /// The interval in seconds for the heartbeat from the client. If not received client is disconnected + /// + public ushort HeartbeatRequiredIntervalInSeconds { get; set; } + /// + /// HeartbeatString that will be checked against the message received. defaults to heartbeat if no string is provided. + /// + public string HeartbeatStringToMatch { get; set; } + /// + /// Receive Queue size must be greater than 20 or defaults to 20 + /// + public int ReceiveQueueSize { get; set; } + } +} \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/Comm/TcpServerConfigObject.cs b/Pepperdash Core/Pepperdash Core/Comm/TcpServerConfigObject.cs index c7c1998..785851b 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/TcpServerConfigObject.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/TcpServerConfigObject.cs @@ -6,17 +6,55 @@ using Crestron.SimplSharp; namespace PepperDash.Core { + /// + /// Tcp Server Config object with properties for a tcp server with shared key and heartbeat capabilities + /// public class TcpServerConfigObject { + /// + /// Uique key + /// public string Key { get; set; } - public bool Secure { get; set; } + /// + /// Max Clients that the server will allow to connect. + /// public ushort MaxClients { get; set; } + /// + /// Bool value for secure. Currently not implemented in TCP sockets as they are not dynamic + /// + public bool Secure { get; set; } + /// + /// Port for the server to listen on + /// public int Port { get; set; } + /// + /// Require a shared key that both server and client negotiate. If negotiation fails server disconnects the client + /// public bool SharedKeyRequired { get; set; } + /// + /// The shared key that must match on the server and client + /// public string SharedKey { get; set; } + /// + /// Require a heartbeat on the client/server connection that will cause the server/client to disconnect if the heartbeat is not received. + /// heartbeats do not raise received events. + /// public bool HeartbeatRequired { get; set; } + /// + /// The interval in seconds for the heartbeat from the client. If not received client is disconnected + /// public ushort HeartbeatRequiredIntervalInSeconds { get; set; } + /// + /// HeartbeatString that will be checked against the message received. defaults to heartbeat if no string is provided. + /// public string HeartbeatStringToMatch { get; set; } + /// + /// Client buffer size. See Crestron help. defaults to 2000 if not greater than 2000 + /// public int BufferSize { get; set; } + /// + /// Receive Queue size must be greater than 20 or defaults to 20 + /// + public int ReceiveQueueSize { get; set; } } } \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/Comm/eControlMethods.cs b/Pepperdash Core/Pepperdash Core/Comm/eControlMethods.cs index d4a2028..5a7a6ea 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/eControlMethods.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/eControlMethods.cs @@ -6,6 +6,9 @@ using Crestron.SimplSharp; namespace PepperDash.Core { + /// + /// Crestron Control Methods for a comm object + /// public enum eControlMethod { None = 0, Com, IpId, IpidTcp, IR, Ssh, Tcpip, Telnet, Cresnet, Cec, Udp diff --git a/Pepperdash Core/Pepperdash Core/CoreInterfaces.cs b/Pepperdash Core/Pepperdash Core/CoreInterfaces.cs index 195d6e2..3a5df42 100644 --- a/Pepperdash Core/Pepperdash Core/CoreInterfaces.cs +++ b/Pepperdash Core/Pepperdash Core/CoreInterfaces.cs @@ -6,13 +6,25 @@ using Crestron.SimplSharp; namespace PepperDash.Core { + /// + /// Unique key interface to require a unique key for the class + /// public interface IKeyed { + /// + /// Unique Key + /// string Key { get; } } + /// + /// Named Keyed device interface. Forces the devie to have a Unique Key and a name. + /// public interface IKeyName : IKeyed { + /// + /// Isn't it obvious :) + /// string Name { get; } } } \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/Device.cs b/Pepperdash Core/Pepperdash Core/Device.cs index 7132f94..62dc6b1 100644 --- a/Pepperdash Core/Pepperdash Core/Device.cs +++ b/Pepperdash Core/Pepperdash Core/Device.cs @@ -10,8 +10,17 @@ namespace PepperDash.Core /// public class Device : IKeyName { + /// + /// Unique Key + /// public string Key { get; protected set; } - public string Name { get; protected set; } + /// + /// Name of the devie + /// + public string Name { get; protected set; } + /// + /// + /// public bool Enabled { get; protected set; } ///// diff --git a/Pepperdash Core/Pepperdash Core/JsonToSimpl/EventArgs and Constants.cs b/Pepperdash Core/Pepperdash Core/JsonToSimpl/EventArgs and Constants.cs index b8259b9..a94eac1 100644 --- a/Pepperdash Core/Pepperdash Core/JsonToSimpl/EventArgs and Constants.cs +++ b/Pepperdash Core/Pepperdash Core/JsonToSimpl/EventArgs and Constants.cs @@ -6,6 +6,9 @@ using Crestron.SimplSharp; namespace PepperDash.Core.JsonToSimpl { + /// + /// Constants for Simpl modules + /// public class JsonToSimplConstants { public const ushort JsonIsValidBoolChange = 2; diff --git a/Pepperdash Core/Pepperdash Core/Network/DiscoveryThings.cs b/Pepperdash Core/Pepperdash Core/Network/DiscoveryThings.cs index 72f2285..973c03a 100644 --- a/Pepperdash Core/Pepperdash Core/Network/DiscoveryThings.cs +++ b/Pepperdash Core/Pepperdash Core/Network/DiscoveryThings.cs @@ -6,10 +6,14 @@ using Crestron.SimplSharp; namespace PepperDash.Core { - + /// + /// Not in use + /// public static class NetworkComm { - + /// + /// Not in use + /// static NetworkComm() { } diff --git a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj index 548590e..6c7960d 100644 --- a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj +++ b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj @@ -31,6 +31,7 @@ 512 true true + bin\PepperDash_Core.xml .allowedReferenceRelatedFileExtensions @@ -81,6 +82,7 @@ + diff --git a/Pepperdash Core/Pepperdash Core/Properties/UpdateAssemblyVersion.ps1 b/Pepperdash Core/Pepperdash Core/Properties/UpdateAssemblyVersion.ps1 new file mode 100644 index 0000000..46392b3 --- /dev/null +++ b/Pepperdash Core/Pepperdash Core/Properties/UpdateAssemblyVersion.ps1 @@ -0,0 +1,35 @@ +function Update-SourceVersion +{ + Param ([string]$Version) + $NewVersion = ‘AssemblyVersion("‘ + $Version + ‘.*")’; + foreach ($o in $input) + { + Write-output $o.FullName + $TmpFile = $o.FullName + “.tmp” + get-content $o.FullName | + %{$_ -replace ‘AssemblyVersion\("(\d+\.\d+\.\d+)\.\*"\)’, $NewVersion } > $TmpFile + move-item $TmpFile $o.FullName -force + } +} + +function Update-AllAssemblyInfoFiles ( $version ) +{ + foreach ($file in “AssemblyInfo.cs”, “AssemblyInfo.vb” ) + { + get-childitem -recurse |? {$_.Name -eq $file} | Update-SourceVersion $version ; + } +} + +# validate arguments +$r= [System.Text.RegularExpressions.Regex]::Match($args[0], "^\d+\.\d+\.\d+$"); +if ($r.Success) +{ + Update-AllAssemblyInfoFiles $args[0]; +} +else +{ + echo ” “; + echo “Error: Input version does not match x.y.z format!” + echo ” “; + echo "Unable to apply version to AssemblyInfo.cs files"; +}