mirror of
https://github.com/PepperDash/PepperDashCore.git
synced 2026-01-11 19:44:44 +00:00
2
.gitignore
vendored
2
.gitignore
vendored
@@ -397,3 +397,5 @@ FodyWeavers.xsd
|
||||
# JetBrains Rider
|
||||
*.sln.iml
|
||||
*.projectinfo
|
||||
|
||||
output/
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,684 +0,0 @@
|
||||
/*PepperDash Technology Corp.
|
||||
JAG
|
||||
Copyright: 2017
|
||||
------------------------------------
|
||||
***Notice of Ownership and Copyright***
|
||||
The material in which this notice appears is the property of PepperDash Technology Corporation,
|
||||
which claims copyright under the laws of the United States of America in the entire body of material
|
||||
and in all parts thereof, regardless of the use to which it is being put. Any use, in whole or in part,
|
||||
of this material by another party without the express written permission of PepperDash Technology Corporation is prohibited.
|
||||
PepperDash Technology Corporation reserves all rights under applicable laws.
|
||||
------------------------------------ */
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.CrestronSockets;
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace DynamicTCP
|
||||
{
|
||||
public class DynamicTCPServer : Device
|
||||
{
|
||||
#region Events
|
||||
/// <summary>
|
||||
/// Event for Receiving text
|
||||
/// </summary>
|
||||
public event EventHandler<CopyCoreForSimplpGenericCommMethodReceiveTextArgs> TextReceived;
|
||||
|
||||
/// <summary>
|
||||
/// Event for client connection socket status change
|
||||
/// </summary>
|
||||
public event EventHandler<DynamicTCPSocketStatusChangeEventArgs> ClientConnectionChange;
|
||||
|
||||
/// <summary>
|
||||
/// Event for Server State Change
|
||||
/// </summary>
|
||||
public event EventHandler<DynamicTCPServerStateChangedEventArgs> ServerStateChange;
|
||||
#endregion
|
||||
|
||||
#region Properties/Variables
|
||||
/// <summary>
|
||||
/// Secure or unsecure TCP server. Defaults to Unsecure or standard TCP server without SSL
|
||||
/// </summary>
|
||||
public bool Secure { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// S+ Helper for Secure bool. Parameter in SIMPL+ so there is no get, one way set from simpl+ Param to property in func main of SIMPL+
|
||||
/// </summary>
|
||||
public ushort USecure
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value == 1)
|
||||
Secure = true;
|
||||
else if (value == 0)
|
||||
Secure = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Text representation of the Socket Status enum values for the server
|
||||
/// </summary>
|
||||
public string Status
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Secure ? SecureServer != null : UnsecureServer != null)
|
||||
return Secure ? SecureServer.State.ToString() : UnsecureServer.State.ToString();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bool showing if socket is connected
|
||||
/// </summary>
|
||||
public bool IsConnected
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Secure ? SecureServer != null : UnsecureServer != null) &&
|
||||
(Secure ? SecureServer.State == ServerState.SERVER_CONNECTED : UnsecureServer.State == ServerState.SERVER_CONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// S+ helper for IsConnected
|
||||
/// </summary>
|
||||
public ushort UIsConnected
|
||||
{
|
||||
get { return (ushort)(IsConnected ? 1 : 0); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bool showing if socket is connected
|
||||
/// </summary>
|
||||
public bool IsListening
|
||||
{
|
||||
get { return (Secure ? SecureServer != null : UnsecureServer != null) &&
|
||||
(Secure ? SecureServer.State == ServerState.SERVER_LISTENING : UnsecureServer.State == ServerState.SERVER_LISTENING); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// S+ helper for IsConnected
|
||||
/// </summary>
|
||||
public ushort UIsListening
|
||||
{
|
||||
get { return (ushort)(IsListening ? 1 : 0); }
|
||||
}
|
||||
|
||||
public ushort MaxClients { get; set; } // should be set by parameter in SIMPL+ in the MAIN method, Should not ever need to be configurable
|
||||
/// <summary>
|
||||
/// Number of clients currently connected.
|
||||
/// </summary>
|
||||
public ushort NumberOfClientsConnected
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Secure ? SecureServer != null : UnsecureServer != null)
|
||||
return Secure ? (ushort)SecureServer.NumberOfClientsConnected : (ushort)UnsecureServer.NumberOfClientsConnected;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Port Server should listen on
|
||||
/// </summary>
|
||||
public int Port { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// S+ helper for Port
|
||||
/// </summary>
|
||||
public ushort UPort
|
||||
{
|
||||
get { return Convert.ToUInt16(Port); }
|
||||
set { Port = Convert.ToInt32(value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
public bool SharedKeyRequired { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// S+ helper for requires shared key bool
|
||||
/// </summary>
|
||||
public ushort USharedKeyRequired
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value == 1)
|
||||
SharedKeyRequired = true;
|
||||
else
|
||||
SharedKeyRequired = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
public string SharedKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Heartbeat Required bool sets whether server disconnects client if heartbeat is not received
|
||||
/// </summary>
|
||||
public bool HeartbeatRequired { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// S+ Helper for Heartbeat Required
|
||||
/// </summary>
|
||||
public ushort UHeartbeatRequired
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value == 1)
|
||||
HeartbeatRequired = true;
|
||||
else
|
||||
HeartbeatRequired = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Milliseconds before server expects another heartbeat. Set by property HeartbeatRequiredIntervalInSeconds which is driven from S+
|
||||
/// </summary>
|
||||
public int HeartbeatRequiredIntervalMs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Simpl+ Heartbeat Analog value in seconds
|
||||
/// </summary>
|
||||
public ushort HeartbeatRequiredIntervalInSeconds { set { HeartbeatRequiredIntervalMs = (value * 1000); } }
|
||||
|
||||
/// <summary>
|
||||
/// String to Match for heartbeat. If null or empty any string will reset heartbeat timer
|
||||
/// </summary>
|
||||
public string HeartbeatStringToMatch { get; set; }
|
||||
|
||||
//private timers for Heartbeats per client
|
||||
Dictionary<uint, CTimer> HeartbeatTimerDictionary = new Dictionary<uint, CTimer>();
|
||||
|
||||
//flags to show the secure server is waiting for client at index to send the shared key
|
||||
List<uint> WaitingForSharedKey = new List<uint>();
|
||||
|
||||
//Store the connected client indexes
|
||||
List<uint> ConnectedClientsIndexes = new List<uint>();
|
||||
|
||||
/// <summary>
|
||||
/// Defaults to 2000
|
||||
/// </summary>
|
||||
public int BufferSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Private flag to note that the server has stopped intentionally
|
||||
/// </summary>
|
||||
private bool ServerStopped { get; set; }
|
||||
|
||||
//Servers
|
||||
SecureTCPServer SecureServer;
|
||||
TCPServer UnsecureServer;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// constructor
|
||||
/// </summary>
|
||||
public DynamicTCPServer()
|
||||
: base("Uninitialized Dynamic TCP Server")
|
||||
{
|
||||
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
|
||||
BufferSize = 2000;
|
||||
Secure = false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Methods - Server Actions
|
||||
/// <summary>
|
||||
/// Initialize Key for device using client name from SIMPL+. Called on Listen from SIMPL+
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
public void Initialize(string key)
|
||||
{
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start listening on the specified port
|
||||
/// </summary>
|
||||
public void Listen()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Port < 1 || Port > 65535)
|
||||
{
|
||||
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericSecureTcpClient '{0}': Invalid port", Key);
|
||||
ErrorLog.Warn(string.Format("GenericSecureTcpClient '{0}': Invalid port", Key));
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrEmpty(SharedKey) && SharedKeyRequired)
|
||||
{
|
||||
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericSecureTcpClient '{0}': No Shared Key set", Key);
|
||||
ErrorLog.Warn(string.Format("GenericSecureTcpClient '{0}': No Shared Key set", Key));
|
||||
return;
|
||||
}
|
||||
if (IsListening)
|
||||
return;
|
||||
if (Secure)
|
||||
{
|
||||
SecureServer = new SecureTCPServer(Port, MaxClients);
|
||||
SecureServer.SocketStatusChange += new SecureTCPServerSocketStatusChangeEventHandler(SecureServer_SocketStatusChange);
|
||||
ServerStopped = false;
|
||||
SecureServer.WaitForConnectionAsync(IPAddress.Any, SecureConnectCallback);
|
||||
onServerStateChange();
|
||||
Debug.Console(2, "Secure Server Status: {0}, Socket Status: {1}\r\n", SecureServer.State.ToString(), SecureServer.ServerSocketStatus);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnsecureServer = new TCPServer(Port, MaxClients);
|
||||
UnsecureServer.SocketStatusChange += new TCPServerSocketStatusChangeEventHandler(UnsecureServer_SocketStatusChange);
|
||||
ServerStopped = false;
|
||||
UnsecureServer.WaitForConnectionAsync(IPAddress.Any, UnsecureConnectCallback);
|
||||
onServerStateChange();
|
||||
Debug.Console(2, "Unsecure Server Status: {0}, Socket Status: {1}\r\n", UnsecureServer.State.ToString(), UnsecureServer.ServerSocketStatus);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorLog.Error("Error with Dynamic Server: {0}", ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop Listeneing
|
||||
/// </summary>
|
||||
public void StopListening()
|
||||
{
|
||||
Debug.Console(2, "Stopping Listener");
|
||||
if (SecureServer != null)
|
||||
SecureServer.Stop();
|
||||
if (UnsecureServer != null)
|
||||
UnsecureServer.Stop();
|
||||
ServerStopped = true;
|
||||
onServerStateChange();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect All Clients
|
||||
/// </summary>
|
||||
public void DisconnectAllClients()
|
||||
{
|
||||
Debug.Console(2, "Disconnecting All Clients");
|
||||
if (SecureServer != null)
|
||||
SecureServer.DisconnectAll();
|
||||
if (UnsecureServer != null)
|
||||
UnsecureServer.DisconnectAll();
|
||||
onConnectionChange();
|
||||
onServerStateChange(); //State shows both listening and connected
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Broadcast text from server to all connected clients
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
public void BroadcastText(string text)
|
||||
{
|
||||
if (ConnectedClientsIndexes.Count > 0)
|
||||
{
|
||||
byte[] b = Encoding.GetEncoding(28591).GetBytes(text);
|
||||
if (Secure)
|
||||
foreach (uint i in ConnectedClientsIndexes)
|
||||
SecureServer.SendDataAsync(i, b, b.Length, SecureSendDataAsyncCallback);
|
||||
else
|
||||
foreach (uint i in ConnectedClientsIndexes)
|
||||
UnsecureServer.SendDataAsync(i, b, b.Length, UnsecureSendDataAsyncCallback);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Not sure this is useful in library, maybe Pro??
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="clientIndex"></param>
|
||||
public void SendTextToClient(string text, uint clientIndex)
|
||||
{
|
||||
byte[] b = Encoding.GetEncoding(28591).GetBytes(text);
|
||||
if (Secure)
|
||||
SecureServer.SendDataAsync(clientIndex, b, b.Length, SecureSendDataAsyncCallback);
|
||||
else
|
||||
UnsecureServer.SendDataAsync(clientIndex, b, b.Length, UnsecureSendDataAsyncCallback);
|
||||
}
|
||||
|
||||
//private method to check heartbeat requirements and start or reset timer
|
||||
void checkHeartbeat(uint clientIndex, string received)
|
||||
{
|
||||
if (HeartbeatRequired)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(HeartbeatStringToMatch))
|
||||
{
|
||||
if (received == HeartbeatStringToMatch)
|
||||
{
|
||||
if (HeartbeatTimerDictionary.ContainsKey(clientIndex))
|
||||
HeartbeatTimerDictionary[clientIndex].Reset(HeartbeatRequiredIntervalMs);
|
||||
else
|
||||
{
|
||||
CTimer HeartbeatTimer = new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs);
|
||||
HeartbeatTimerDictionary.Add(clientIndex, HeartbeatTimer);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (HeartbeatTimerDictionary.ContainsKey(clientIndex))
|
||||
HeartbeatTimerDictionary[clientIndex].Reset(HeartbeatRequiredIntervalMs);
|
||||
else
|
||||
{
|
||||
CTimer HeartbeatTimer = new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs);
|
||||
HeartbeatTimerDictionary.Add(clientIndex, HeartbeatTimer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Methods - HeartbeatTimer Callback
|
||||
|
||||
void HeartbeatTimer_CallbackFunction(object o)
|
||||
{
|
||||
uint clientIndex = (uint)o;
|
||||
|
||||
string address = Secure ? SecureServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex) :
|
||||
UnsecureServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex);
|
||||
|
||||
ErrorLog.Error("Heartbeat not received for Client at IP: {0}, DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE", address);
|
||||
Debug.Console(2, "Heartbeat not received for Client at IP: {0}, DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE", address);
|
||||
|
||||
SendTextToClient("Heartbeat not received by server, closing connection", clientIndex);
|
||||
|
||||
if (Secure)
|
||||
SecureServer.Disconnect(clientIndex);
|
||||
else
|
||||
UnsecureServer.Disconnect(clientIndex);
|
||||
HeartbeatTimerDictionary.Remove(clientIndex);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods - Socket Status Changed Callbacks
|
||||
/// <summary>
|
||||
/// Secure Server Socket Status Changed Callback
|
||||
/// </summary>
|
||||
/// <param name="mySecureTCPServer"></param>
|
||||
/// <param name="clientIndex"></param>
|
||||
/// <param name="serverSocketStatus"></param>
|
||||
void SecureServer_SocketStatusChange(SecureTCPServer server, uint clientIndex, SocketStatus serverSocketStatus)
|
||||
{
|
||||
Debug.Console(2, "Client at {0} ServerSocketStatus {1}",
|
||||
server.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex), serverSocketStatus.ToString());
|
||||
if (server.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED)
|
||||
{
|
||||
if (SharedKeyRequired && !WaitingForSharedKey.Contains(clientIndex))
|
||||
WaitingForSharedKey.Add(clientIndex);
|
||||
if (!ConnectedClientsIndexes.Contains(clientIndex))
|
||||
ConnectedClientsIndexes.Add(clientIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ConnectedClientsIndexes.Contains(clientIndex))
|
||||
ConnectedClientsIndexes.Remove(clientIndex);
|
||||
if (HeartbeatRequired && HeartbeatTimerDictionary.ContainsKey(clientIndex))
|
||||
HeartbeatTimerDictionary.Remove(clientIndex);
|
||||
}
|
||||
if(SecureServer.ServerSocketStatus.ToString() != Status)
|
||||
onConnectionChange();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TCP Server (Unsecure) Socket Status Change Callback
|
||||
/// </summary>
|
||||
/// <param name="mySecureTCPServer"></param>
|
||||
/// <param name="clientIndex"></param>
|
||||
/// <param name="serverSocketStatus"></param>
|
||||
void UnsecureServer_SocketStatusChange(TCPServer server, uint clientIndex, SocketStatus serverSocketStatus)
|
||||
{
|
||||
Debug.Console(2, "Client at {0} ServerSocketStatus {1}",
|
||||
server.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex), serverSocketStatus.ToString());
|
||||
if (server.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED)
|
||||
{
|
||||
if (SharedKeyRequired && !WaitingForSharedKey.Contains(clientIndex))
|
||||
WaitingForSharedKey.Add(clientIndex);
|
||||
if (!ConnectedClientsIndexes.Contains(clientIndex))
|
||||
ConnectedClientsIndexes.Add(clientIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ConnectedClientsIndexes.Contains(clientIndex))
|
||||
ConnectedClientsIndexes.Remove(clientIndex);
|
||||
if (HeartbeatRequired && HeartbeatTimerDictionary.ContainsKey(clientIndex))
|
||||
HeartbeatTimerDictionary.Remove(clientIndex);
|
||||
}
|
||||
if (UnsecureServer.ServerSocketStatus.ToString() != Status)
|
||||
onConnectionChange();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Methods Connected Callbacks
|
||||
/// <summary>
|
||||
/// Secure TCP Client Connected to Secure Server Callback
|
||||
/// </summary>
|
||||
/// <param name="mySecureTCPServer"></param>
|
||||
/// <param name="clientIndex"></param>
|
||||
void SecureConnectCallback(SecureTCPServer mySecureTCPServer, uint clientIndex)
|
||||
{
|
||||
if (mySecureTCPServer.ClientConnected(clientIndex))
|
||||
{
|
||||
if (SharedKeyRequired)
|
||||
{
|
||||
byte[] b = Encoding.GetEncoding(28591).GetBytes(SharedKey + "\n");
|
||||
mySecureTCPServer.SendDataAsync(clientIndex, b, b.Length, SecureSendDataAsyncCallback);
|
||||
Debug.Console(2, "Sent Shared Key to client at {0}", mySecureTCPServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex));
|
||||
}
|
||||
if (HeartbeatRequired)
|
||||
{
|
||||
CTimer HeartbeatTimer = new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs);
|
||||
HeartbeatTimerDictionary.Add(clientIndex, HeartbeatTimer);
|
||||
}
|
||||
mySecureTCPServer.ReceiveDataAsync(clientIndex, SecureReceivedDataAsyncCallback);
|
||||
if (mySecureTCPServer.State != ServerState.SERVER_LISTENING && MaxClients > 1 && !ServerStopped)
|
||||
mySecureTCPServer.WaitForConnectionAsync(IPAddress.Any, SecureConnectCallback);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsecure TCP Client Connected to Unsecure Server Callback
|
||||
/// </summary>
|
||||
/// <param name="myTCPServer"></param>
|
||||
/// <param name="clientIndex"></param>
|
||||
void UnsecureConnectCallback(TCPServer myTCPServer, uint clientIndex)
|
||||
{
|
||||
if (myTCPServer.ClientConnected(clientIndex))
|
||||
{
|
||||
if (SharedKeyRequired)
|
||||
{
|
||||
byte[] b = Encoding.GetEncoding(28591).GetBytes(SharedKey + "\n");
|
||||
myTCPServer.SendDataAsync(clientIndex, b, b.Length, UnsecureSendDataAsyncCallback);
|
||||
Debug.Console(2, "Sent Shared Key to client at {0}", myTCPServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex));
|
||||
}
|
||||
if (HeartbeatRequired)
|
||||
{
|
||||
CTimer HeartbeatTimer = new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs);
|
||||
HeartbeatTimerDictionary.Add(clientIndex, HeartbeatTimer);
|
||||
}
|
||||
myTCPServer.ReceiveDataAsync(clientIndex, UnsecureReceivedDataAsyncCallback);
|
||||
if (myTCPServer.State != ServerState.SERVER_LISTENING && MaxClients > 1 && !ServerStopped)
|
||||
myTCPServer.WaitForConnectionAsync(IPAddress.Any, UnsecureConnectCallback);
|
||||
}
|
||||
if (myTCPServer.State != ServerState.SERVER_LISTENING && MaxClients > 1 && !ServerStopped)
|
||||
myTCPServer.WaitForConnectionAsync(IPAddress.Any, UnsecureConnectCallback);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Methods - Send/Receive Callbacks
|
||||
/// <summary>
|
||||
/// Secure Send Data Async Callback
|
||||
/// </summary>
|
||||
/// <param name="mySecureTCPServer"></param>
|
||||
/// <param name="clientIndex"></param>
|
||||
/// <param name="numberOfBytesSent"></param>
|
||||
void SecureSendDataAsyncCallback(SecureTCPServer mySecureTCPServer, uint clientIndex, int numberOfBytesSent)
|
||||
{
|
||||
//Seems there is nothing to do here
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsecure Send Data Asyc Callback
|
||||
/// </summary>
|
||||
/// <param name="myTCPServer"></param>
|
||||
/// <param name="clientIndex"></param>
|
||||
/// <param name="numberOfBytesSent"></param>
|
||||
void UnsecureSendDataAsyncCallback(TCPServer myTCPServer, uint clientIndex, int numberOfBytesSent)
|
||||
{
|
||||
//Seems there is nothing to do here
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Secure Received Data Async Callback
|
||||
/// </summary>
|
||||
/// <param name="mySecureTCPServer"></param>
|
||||
/// <param name="clientIndex"></param>
|
||||
/// <param name="numberOfBytesReceived"></param>
|
||||
void SecureReceivedDataAsyncCallback(SecureTCPServer mySecureTCPServer, uint clientIndex, int numberOfBytesReceived)
|
||||
{
|
||||
if (numberOfBytesReceived > 0)
|
||||
{
|
||||
string received = "Nothing";
|
||||
byte[] bytes = mySecureTCPServer.GetIncomingDataBufferForSpecificClient(clientIndex);
|
||||
received = System.Text.Encoding.GetEncoding(28591).GetString(bytes, 0, numberOfBytesReceived);
|
||||
if (WaitingForSharedKey.Contains(clientIndex))
|
||||
{
|
||||
received = received.Replace("\r", "");
|
||||
received = received.Replace("\n", "");
|
||||
if (received != SharedKey)
|
||||
{
|
||||
byte[] b = Encoding.GetEncoding(28591).GetBytes("Shared key did not match server. Disconnecting");
|
||||
Debug.Console(2, "Client at index {0} Shared key did not match the server, disconnecting client", clientIndex);
|
||||
ErrorLog.Error("Client at index {0} Shared key did not match the server, disconnecting client", clientIndex);
|
||||
mySecureTCPServer.SendDataAsync(clientIndex, b, b.Length, null);
|
||||
mySecureTCPServer.Disconnect(clientIndex);
|
||||
}
|
||||
if (mySecureTCPServer.NumberOfClientsConnected > 0)
|
||||
mySecureTCPServer.ReceiveDataAsync(SecureReceivedDataAsyncCallback);
|
||||
WaitingForSharedKey.Remove(clientIndex);
|
||||
byte[] skResponse = Encoding.GetEncoding(28591).GetBytes("Shared Key Match, Connected and ready for communication");
|
||||
mySecureTCPServer.SendDataAsync(clientIndex, skResponse, skResponse.Length, null);
|
||||
mySecureTCPServer.ReceiveDataAsync(SecureReceivedDataAsyncCallback);
|
||||
}
|
||||
else
|
||||
{
|
||||
mySecureTCPServer.ReceiveDataAsync(SecureReceivedDataAsyncCallback);
|
||||
Debug.Console(2, "Secure Server Listening on Port: {0}, client IP: {1}, NumberOfBytesReceived: {2}, Received: {3}\r\n",
|
||||
mySecureTCPServer.PortNumber, mySecureTCPServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex), numberOfBytesReceived, received);
|
||||
onTextReceived(received);
|
||||
}
|
||||
checkHeartbeat(clientIndex, received);
|
||||
}
|
||||
if (mySecureTCPServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED)
|
||||
mySecureTCPServer.ReceiveDataAsync(clientIndex, SecureReceivedDataAsyncCallback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsecure Received Data Async Callback
|
||||
/// </summary>
|
||||
/// <param name="myTCPServer"></param>
|
||||
/// <param name="clientIndex"></param>
|
||||
/// <param name="numberOfBytesReceived"></param>
|
||||
void UnsecureReceivedDataAsyncCallback(TCPServer myTCPServer, uint clientIndex, int numberOfBytesReceived)
|
||||
{
|
||||
if (numberOfBytesReceived > 0)
|
||||
{
|
||||
string received = "Nothing";
|
||||
byte[] bytes = myTCPServer.GetIncomingDataBufferForSpecificClient(clientIndex);
|
||||
received = System.Text.Encoding.GetEncoding(28591).GetString(bytes, 0, numberOfBytesReceived);
|
||||
if (WaitingForSharedKey.Contains(clientIndex))
|
||||
{
|
||||
received = received.Replace("\r", "");
|
||||
received = received.Replace("\n", "");
|
||||
if (received != SharedKey)
|
||||
{
|
||||
byte[] b = Encoding.GetEncoding(28591).GetBytes("Shared key did not match server. Disconnecting");
|
||||
Debug.Console(2, "Client at index {0} Shared key did not match the server, disconnecting client", clientIndex);
|
||||
ErrorLog.Error("Client at index {0} Shared key did not match the server, disconnecting client", clientIndex);
|
||||
myTCPServer.SendDataAsync(clientIndex, b, b.Length, null);
|
||||
myTCPServer.Disconnect(clientIndex);
|
||||
}
|
||||
if (myTCPServer.NumberOfClientsConnected > 0)
|
||||
myTCPServer.ReceiveDataAsync(UnsecureReceivedDataAsyncCallback);
|
||||
WaitingForSharedKey.Remove(clientIndex);
|
||||
byte[] skResponse = Encoding.GetEncoding(28591).GetBytes("Shared Key Match, Connected and ready for communication");
|
||||
myTCPServer.SendDataAsync(clientIndex, skResponse, skResponse.Length, null);
|
||||
myTCPServer.ReceiveDataAsync(UnsecureReceivedDataAsyncCallback);
|
||||
}
|
||||
else
|
||||
{
|
||||
myTCPServer.ReceiveDataAsync(UnsecureReceivedDataAsyncCallback);
|
||||
Debug.Console(2, "Secure Server Listening on Port: {0}, client IP: {1}, NumberOfBytesReceived: {2}, Received: {3}\r\n",
|
||||
myTCPServer.PortNumber, myTCPServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex), numberOfBytesReceived, received);
|
||||
onTextReceived(received);
|
||||
}
|
||||
checkHeartbeat(clientIndex, received);
|
||||
}
|
||||
if (myTCPServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED)
|
||||
myTCPServer.ReceiveDataAsync(clientIndex, UnsecureReceivedDataAsyncCallback);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Methods - EventHelpers/Callbacks
|
||||
//Private Helper method to call the Connection Change Event
|
||||
void onConnectionChange()
|
||||
{
|
||||
var handler = ClientConnectionChange;
|
||||
if (handler != null)
|
||||
{
|
||||
if (Secure)
|
||||
handler(this, new DynamicTCPSocketStatusChangeEventArgs(SecureServer, Secure));
|
||||
else
|
||||
handler(this, new DynamicTCPSocketStatusChangeEventArgs(UnsecureServer, Secure));
|
||||
}
|
||||
}
|
||||
|
||||
//Private Helper Method to call the Text Received Event
|
||||
void onTextReceived(string text)
|
||||
{
|
||||
var handler = TextReceived;
|
||||
if (handler != null)
|
||||
handler(this, new CopyCoreForSimplpGenericCommMethodReceiveTextArgs(text));
|
||||
}
|
||||
|
||||
//Private Helper Method to call the Server State Change Event
|
||||
void onServerStateChange()
|
||||
{
|
||||
var handler = ServerStateChange;
|
||||
if(handler != null)
|
||||
{
|
||||
if(Secure)
|
||||
handler(this, new DynamicTCPServerStateChangedEventArgs(SecureServer, Secure));
|
||||
else
|
||||
handler(this, new DynamicTCPServerStateChangedEventArgs(UnsecureServer, Secure));
|
||||
}
|
||||
}
|
||||
|
||||
//Private Event Handler method to handle the closing of connections when the program stops
|
||||
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
|
||||
{
|
||||
if (programEventType == eProgramStatusEventType.Stopping)
|
||||
{
|
||||
Debug.Console(1, this, "Program stopping. Closing server");
|
||||
DisconnectAllClients();
|
||||
StopListening();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
namespace PepperDash.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Background class that manages debug features for sockets
|
||||
/// </summary>
|
||||
public static class CommStatic
|
||||
{
|
||||
static List<ISocketStatus> Sockets = new List<ISocketStatus>();
|
||||
|
||||
/// <summary>
|
||||
/// Sets up the backing class. Adds console commands for S#Pro programs
|
||||
/// </summary>
|
||||
static CommStatic()
|
||||
{
|
||||
if (CrestronEnvironment.RuntimeEnvironment == eRuntimeEnvironment.SimplSharpPro)
|
||||
{
|
||||
CrestronConsole.AddNewConsoleCommand(SocketCommand, "socket", "socket commands: list, send, connect, disco",
|
||||
ConsoleAccessLevelEnum.AccessOperator);
|
||||
}
|
||||
}
|
||||
|
||||
static void SocketCommand(string s)
|
||||
{
|
||||
// 0 1 2
|
||||
//socket command number/key/all param
|
||||
//socket list
|
||||
//socket send 4 ver -v\n
|
||||
|
||||
if (string.IsNullOrEmpty(s))
|
||||
return;
|
||||
var tokens = s.Split(' ');
|
||||
if (tokens.Length == 0)
|
||||
return;
|
||||
var command = tokens[0].ToLower();
|
||||
if(command == "connect")
|
||||
{
|
||||
|
||||
}
|
||||
else if(command == "disco")
|
||||
{
|
||||
|
||||
}
|
||||
else if(command =="list")
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("{0} sockets", Sockets.Count);
|
||||
if(Sockets.Count == 0)
|
||||
return;
|
||||
// get the longest key name, for formatting
|
||||
var longestLength = Sockets.Aggregate("",
|
||||
(max, cur) => max.Length > cur.Key.Length ? max : cur.Key).Length;
|
||||
for(int i = 0; i < Sockets.Count; i++)
|
||||
{
|
||||
var sock = Sockets[i];
|
||||
CrestronConsole.ConsoleCommandResponse("{0} {1} {2} {3}",
|
||||
i, sock.Key, GetSocketType(sock), sock.ClientStatus);
|
||||
}
|
||||
}
|
||||
else if(command == "send")
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper for socket list, to show types
|
||||
/// </summary>
|
||||
static string GetSocketType(ISocketStatus sock)
|
||||
{
|
||||
if (sock is GenericSshClient)
|
||||
return "SSH";
|
||||
else if (sock is GenericTcpIpClient)
|
||||
return "TCP-IP";
|
||||
else
|
||||
return "?";
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="socket"></param>
|
||||
public static void AddSocket(ISocketStatus socket)
|
||||
{
|
||||
if(!Sockets.Contains(socket))
|
||||
Sockets.Add(socket);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="socket"></param>
|
||||
public static void RemoveSocket(ISocketStatus socket)
|
||||
{
|
||||
if (Sockets.Contains(socket))
|
||||
Sockets.Remove(socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,314 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.CrestronIO;
|
||||
using Crestron.SimplSharp.Net.Http;
|
||||
|
||||
namespace PepperDash.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Client for communicating with an HTTP Server Side Event pattern
|
||||
/// </summary>
|
||||
public class GenericHttpSseClient : ICommunicationReceiver
|
||||
{
|
||||
/// <summary>
|
||||
/// Notifies when bytes have been received
|
||||
/// </summary>
|
||||
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
|
||||
/// <summary>
|
||||
/// Notifies when text has been received
|
||||
/// </summary>
|
||||
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates connection status
|
||||
/// </summary>
|
||||
public bool IsConnected
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unique identifier for the instance
|
||||
/// </summary>
|
||||
public string Key
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name for the instance
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// URL of the server
|
||||
/// </summary>
|
||||
public string Url { get; set; }
|
||||
|
||||
HttpClient Client;
|
||||
HttpClientRequest Request;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="name"></param>
|
||||
public GenericHttpSseClient(string key, string name)
|
||||
{
|
||||
Key = key;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connects to the server. Requires Url to be set first.
|
||||
/// </summary>
|
||||
public void Connect()
|
||||
{
|
||||
InitiateConnection(Url);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnects from the server
|
||||
/// </summary>
|
||||
public void Disconnect()
|
||||
{
|
||||
CloseConnection(null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initiates connection to the server
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
public void InitiateConnection(string url)
|
||||
{
|
||||
CrestronInvoke.BeginInvoke(o =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if(string.IsNullOrEmpty(url))
|
||||
{
|
||||
Debug.Console(0, this, "Error connecting to Server. No URL specified");
|
||||
return;
|
||||
}
|
||||
|
||||
Client = new HttpClient();
|
||||
Request = new HttpClientRequest();
|
||||
Client.Verbose = true;
|
||||
Client.KeepAlive = true;
|
||||
Request.Url.Parse(url);
|
||||
Request.RequestType = RequestType.Get;
|
||||
Request.Header.SetHeaderValue("Accept", "text/event-stream");
|
||||
|
||||
// In order to get a handle on the response stream, we have to get
|
||||
// the request stream first. Boo
|
||||
Client.BeginGetRequestStream(GetRequestStreamCallback, Request, null);
|
||||
CrestronConsole.PrintLine("Request made!");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ErrorLog.Notice("Exception occured in AsyncWebPostHttps(): " + e.ToString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the connection to the server
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
public void CloseConnection(string s)
|
||||
{
|
||||
if (Client != null)
|
||||
{
|
||||
Client.Abort();
|
||||
IsConnected = false;
|
||||
|
||||
Debug.Console(1, this, "Client Disconnected");
|
||||
}
|
||||
}
|
||||
|
||||
private void GetRequestStreamCallback(HttpClientRequest request, HTTP_CALLBACK_ERROR error, object status)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
// End the the async request operation and return the data stream
|
||||
Stream requestStream = request.ThisClient.EndGetRequestStream(request, null);
|
||||
// If this were something other than a GET we could write to the stream here
|
||||
|
||||
// Closing makes the request happen
|
||||
requestStream.Close();
|
||||
|
||||
// Get a handle on the response stream.
|
||||
request.ThisClient.BeginGetResponseStream(GetResponseStreamCallback, request, status);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ErrorLog.Notice("Exception occured in GetSecureRequestStreamCallback(): " + e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="error"></param>
|
||||
/// <param name="status"></param>
|
||||
private void GetResponseStreamCallback(HttpClientRequest request, HTTP_CALLBACK_ERROR error, object status)
|
||||
{
|
||||
try
|
||||
{
|
||||
// This closes up the GetResponseStream async
|
||||
var response = request.ThisClient.EndGetResponseStream(request);
|
||||
|
||||
response.DataConnection.OnBytesReceived += new EventHandler(DataConnection_OnBytesReceived);
|
||||
|
||||
IsConnected = true;
|
||||
|
||||
Debug.Console(1, this, "Client Disconnected");
|
||||
|
||||
Stream streamResponse = response.ContentStream;
|
||||
// Object containing various states to be passed back to async callback below
|
||||
RequestState asyncState = new RequestState();
|
||||
asyncState.Request = request;
|
||||
asyncState.Response = response;
|
||||
asyncState.StreamResponse = streamResponse;
|
||||
asyncState.HttpClient = request.ThisClient;
|
||||
|
||||
// This processes the ongoing data stream
|
||||
Crestron.SimplSharp.CrestronIO.IAsyncResult asyncResult = null;
|
||||
do
|
||||
{
|
||||
asyncResult = streamResponse.BeginRead(asyncState.BufferRead, 0, RequestState.BUFFER_SIZE,
|
||||
new Crestron.SimplSharp.CrestronIO.AsyncCallback(ReadCallBack), asyncState);
|
||||
}
|
||||
while (asyncResult.CompletedSynchronously && !asyncState.Done);
|
||||
|
||||
//Console.WriteLine("\r\nExit Response Callback\r\n");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ErrorLog.Notice("Exception occured in GetSecureRequestStreamCallback(): " + e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
void DataConnection_OnBytesReceived(object sender, EventArgs e)
|
||||
{
|
||||
Debug.Console(1, this, "DataConnection OnBytesReceived Fired");
|
||||
}
|
||||
|
||||
private void ReadCallBack(Crestron.SimplSharp.CrestronIO.IAsyncResult asyncResult)
|
||||
{
|
||||
//we are getting back everything here, so cast the state from the call
|
||||
RequestState requestState = asyncResult.AsyncState as RequestState;
|
||||
Stream responseStream = requestState.StreamResponse;
|
||||
|
||||
int read = responseStream.EndRead(asyncResult);
|
||||
// Read the HTML page and then print it to the console.
|
||||
if (read > 0)
|
||||
{
|
||||
var bytes = requestState.BufferRead;
|
||||
|
||||
var bytesHandler = BytesReceived;
|
||||
if (bytesHandler != null)
|
||||
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
|
||||
var textHandler = TextReceived;
|
||||
if (textHandler != null)
|
||||
{
|
||||
var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length);
|
||||
textHandler(this, new GenericCommMethodReceiveTextArgs(str));
|
||||
}
|
||||
|
||||
//requestState.RequestData.Append(Encoding.ASCII.GetString(requestState.BufferRead, 0, read));
|
||||
//CrestronConsole.PrintLine(requestState.RequestData.ToString());
|
||||
|
||||
//clear the byte array buffer used.
|
||||
Array.Clear(requestState.BufferRead, 0, requestState.BufferRead.Length);
|
||||
|
||||
if (asyncResult.CompletedSynchronously)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Crestron.SimplSharp.CrestronIO.IAsyncResult asynchronousResult;
|
||||
do
|
||||
{
|
||||
asynchronousResult = responseStream.BeginRead(requestState.BufferRead, 0, RequestState.BUFFER_SIZE,
|
||||
new Crestron.SimplSharp.CrestronIO.AsyncCallback(ReadCallBack), requestState);
|
||||
}
|
||||
while (asynchronousResult.CompletedSynchronously && !requestState.Done);
|
||||
}
|
||||
else
|
||||
{
|
||||
requestState.Done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores the state of the request
|
||||
/// </summary>
|
||||
public class RequestState
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public const int BUFFER_SIZE = 10000;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public byte[] BufferRead;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public HttpClient HttpClient;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public HttpClientRequest Request;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public HttpClientResponse Response;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public Stream StreamResponse;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public bool Done;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public RequestState()
|
||||
{
|
||||
BufferRead = new byte[BUFFER_SIZE];
|
||||
HttpClient = null;
|
||||
Request = null;
|
||||
Response = null;
|
||||
StreamResponse = null;
|
||||
Done = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Waithandle for main thread.
|
||||
/// </summary>
|
||||
public class StreamAsyncTest
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public CEvent wait_for_response = new CEvent(true, false);
|
||||
}
|
||||
}
|
||||
@@ -14,125 +14,125 @@ namespace PepperDash.Core
|
||||
///
|
||||
/// </summary>
|
||||
public class GenericSshClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect
|
||||
{
|
||||
private const string SPlusKey = "Uninitialized SshClient";
|
||||
{
|
||||
private const string SPlusKey = "Uninitialized SshClient";
|
||||
/// <summary>
|
||||
/// Object to enable stream debugging
|
||||
/// </summary>
|
||||
public CommunicationStreamDebugging StreamDebugging { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Event that fires when data is received. Delivers args with byte array
|
||||
/// </summary>
|
||||
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
|
||||
/// <summary>
|
||||
/// Event that fires when data is received. Delivers args with byte array
|
||||
/// </summary>
|
||||
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
|
||||
|
||||
/// <summary>
|
||||
/// Event that fires when data is received. Delivered as text.
|
||||
/// </summary>
|
||||
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
|
||||
/// <summary>
|
||||
/// Event that fires when data is received. Delivered as text.
|
||||
/// </summary>
|
||||
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
|
||||
|
||||
/// <summary>
|
||||
/// Event when the connection status changes.
|
||||
/// </summary>
|
||||
public event EventHandler<GenericSocketStatusChageEventArgs> ConnectionChange;
|
||||
/// <summary>
|
||||
/// Event when the connection status changes.
|
||||
/// </summary>
|
||||
public event EventHandler<GenericSocketStatusChageEventArgs> ConnectionChange;
|
||||
|
||||
///// <summary>
|
||||
/////
|
||||
///// </summary>
|
||||
//public event GenericSocketStatusChangeEventDelegate SocketStatusChange;
|
||||
|
||||
/// <summary>
|
||||
/// Address of server
|
||||
/// </summary>
|
||||
public string Hostname { get; set; }
|
||||
/// <summary>
|
||||
/// Address of server
|
||||
/// </summary>
|
||||
public string Hostname { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Port on server
|
||||
/// </summary>
|
||||
public int Port { get; set; }
|
||||
/// <summary>
|
||||
/// Port on server
|
||||
/// </summary>
|
||||
public int Port { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Username for server
|
||||
/// </summary>
|
||||
public string Username { get; set; }
|
||||
/// <summary>
|
||||
/// Username for server
|
||||
/// </summary>
|
||||
public string Username { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// And... Password for server. That was worth documenting!
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
/// <summary>
|
||||
/// And... Password for server. That was worth documenting!
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True when the server is connected - when status == 2.
|
||||
/// </summary>
|
||||
public bool IsConnected
|
||||
{
|
||||
// returns false if no client or not connected
|
||||
/// <summary>
|
||||
/// True when the server is connected - when status == 2.
|
||||
/// </summary>
|
||||
public bool IsConnected
|
||||
{
|
||||
// returns false if no client or not connected
|
||||
get { return Client != null && ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// S+ helper for IsConnected
|
||||
/// </summary>
|
||||
public ushort UIsConnected
|
||||
{
|
||||
get { return (ushort)(IsConnected ? 1 : 0); }
|
||||
}
|
||||
/// <summary>
|
||||
/// S+ helper for IsConnected
|
||||
/// </summary>
|
||||
public ushort UIsConnected
|
||||
{
|
||||
get { return (ushort)(IsConnected ? 1 : 0); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public SocketStatus ClientStatus
|
||||
{
|
||||
get { return _ClientStatus; }
|
||||
private set
|
||||
{
|
||||
if (_ClientStatus == value)
|
||||
return;
|
||||
_ClientStatus = value;
|
||||
OnConnectionChange();
|
||||
}
|
||||
}
|
||||
SocketStatus _ClientStatus;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public SocketStatus ClientStatus
|
||||
{
|
||||
get { return _ClientStatus; }
|
||||
private set
|
||||
{
|
||||
if (_ClientStatus == value)
|
||||
return;
|
||||
_ClientStatus = value;
|
||||
OnConnectionChange();
|
||||
}
|
||||
}
|
||||
SocketStatus _ClientStatus;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the familiar Simpl analog status values. This drives the ConnectionChange event
|
||||
/// and IsConnected with be true when this == 2.
|
||||
/// </summary>
|
||||
public ushort UStatus
|
||||
{
|
||||
get { return (ushort)_ClientStatus; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Contains the familiar Simpl analog status values. This drives the ConnectionChange event
|
||||
/// and IsConnected with be true when this == 2.
|
||||
/// </summary>
|
||||
public ushort UStatus
|
||||
{
|
||||
get { return (ushort)_ClientStatus; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether client will attempt reconnection on failure. Default is true
|
||||
/// </summary>
|
||||
public bool AutoReconnect { get; set; }
|
||||
/// <summary>
|
||||
/// Determines whether client will attempt reconnection on failure. Default is true
|
||||
/// </summary>
|
||||
public bool AutoReconnect { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Will be set and unset by connect and disconnect only
|
||||
/// </summary>
|
||||
public bool ConnectEnabled { get; private set; }
|
||||
/// <summary>
|
||||
/// Will be set and unset by connect and disconnect only
|
||||
/// </summary>
|
||||
public bool ConnectEnabled { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// S+ helper for AutoReconnect
|
||||
/// </summary>
|
||||
public ushort UAutoReconnect
|
||||
{
|
||||
get { return (ushort)(AutoReconnect ? 1 : 0); }
|
||||
set { AutoReconnect = value == 1; }
|
||||
}
|
||||
/// <summary>
|
||||
/// S+ helper for AutoReconnect
|
||||
/// </summary>
|
||||
public ushort UAutoReconnect
|
||||
{
|
||||
get { return (ushort)(AutoReconnect ? 1 : 0); }
|
||||
set { AutoReconnect = value == 1; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Millisecond value, determines the timeout period in between reconnect attempts.
|
||||
/// Set to 5000 by default
|
||||
/// </summary>
|
||||
public int AutoReconnectIntervalMs { get; set; }
|
||||
/// <summary>
|
||||
/// Millisecond value, determines the timeout period in between reconnect attempts.
|
||||
/// Set to 5000 by default
|
||||
/// </summary>
|
||||
public int AutoReconnectIntervalMs { get; set; }
|
||||
|
||||
SshClient Client;
|
||||
SshClient Client;
|
||||
|
||||
ShellStream TheStream;
|
||||
ShellStream TheStream;
|
||||
|
||||
CTimer ReconnectTimer;
|
||||
CTimer ReconnectTimer;
|
||||
|
||||
//Lock object to prevent simulatneous connect/disconnect operations
|
||||
//private CCriticalSection connectLock = new CCriticalSection();
|
||||
@@ -140,12 +140,12 @@ namespace PepperDash.Core
|
||||
|
||||
private bool DisconnectLogged = false;
|
||||
|
||||
/// <summary>
|
||||
/// Typical constructor.
|
||||
/// </summary>
|
||||
public GenericSshClient(string key, string hostname, int port, string username, string password) :
|
||||
base(key)
|
||||
{
|
||||
/// <summary>
|
||||
/// Typical constructor.
|
||||
/// </summary>
|
||||
public GenericSshClient(string key, string hostname, int port, string username, string password) :
|
||||
base(key)
|
||||
{
|
||||
StreamDebugging = new CommunicationStreamDebugging(key);
|
||||
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
|
||||
Key = key;
|
||||
@@ -182,14 +182,6 @@ namespace PepperDash.Core
|
||||
}, System.Threading.Timeout.Infinite);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Just to help S+ set the key
|
||||
/// </summary>
|
||||
public void Initialize(string key)
|
||||
{
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles closing this up when the program shuts down
|
||||
/// </summary>
|
||||
@@ -201,14 +193,14 @@ namespace PepperDash.Core
|
||||
{
|
||||
this.LogDebug("Program stopping. Closing connection");
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connect to the server, using the provided properties.
|
||||
/// </summary>
|
||||
public void Connect()
|
||||
/// <summary>
|
||||
/// Connect to the server, using the provided properties.
|
||||
/// </summary>
|
||||
public void Connect()
|
||||
{
|
||||
// Don't go unless everything is here
|
||||
if (string.IsNullOrEmpty(Hostname) || Port < 1 || Port > 65535
|
||||
@@ -259,7 +251,7 @@ namespace PepperDash.Core
|
||||
try
|
||||
{
|
||||
Client.Connect();
|
||||
TheStream = Client.CreateShellStream("PDTShell", 100, 80, 100, 200, 65534);
|
||||
TheStream = Client.CreateShellStream("PDTShell", 0, 0, 0, 0, 65534);
|
||||
if (TheStream.DataAvailable)
|
||||
{
|
||||
// empty the buffer if there is data
|
||||
@@ -277,18 +269,17 @@ namespace PepperDash.Core
|
||||
|
||||
if (ie is SocketException)
|
||||
{
|
||||
this.LogException(ie, "CONNECTION failure: Cannot reach host, ({1})", Key, ie.Message);
|
||||
this.LogException(ie, "CONNECTION failure: Cannot reach host");
|
||||
}
|
||||
|
||||
if (ie is System.Net.Sockets.SocketException socketException)
|
||||
{
|
||||
this.LogException(ie, "'{0}' Connection failure: Cannot reach host '{1}' on port {2}, ({3})",
|
||||
Key, Hostname, Port, ie.GetType());
|
||||
this.LogException(ie, "Connection failure: Cannot reach {host} on {port}",
|
||||
Hostname, Port);
|
||||
}
|
||||
if (ie is SshAuthenticationException)
|
||||
{
|
||||
this.LogException(ie, "Authentication failure for username '{0}', ({1})", this,
|
||||
Username, ie.Message);
|
||||
this.LogException(ie, "Authentication failure for username {userName}", Username);
|
||||
}
|
||||
else
|
||||
this.LogException(ie, "Error on connect");
|
||||
@@ -297,7 +288,7 @@ namespace PepperDash.Core
|
||||
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
||||
if (AutoReconnect)
|
||||
{
|
||||
this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
||||
this.LogDebug("Checking autoreconnect: {autoReconnect}, {autoReconnectInterval}ms", AutoReconnect, AutoReconnectIntervalMs);
|
||||
ReconnectTimer.Reset(AutoReconnectIntervalMs);
|
||||
}
|
||||
}
|
||||
@@ -347,7 +338,7 @@ namespace PepperDash.Core
|
||||
}
|
||||
|
||||
KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Kills the stream, cleans up the client and sets it to null
|
||||
@@ -468,18 +459,18 @@ namespace PepperDash.Core
|
||||
ReconnectTimer.Reset(AutoReconnectIntervalMs);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper for ConnectionChange event
|
||||
/// </summary>
|
||||
void OnConnectionChange()
|
||||
{
|
||||
if (ConnectionChange != null)
|
||||
ConnectionChange(this, new GenericSocketStatusChageEventArgs(this));
|
||||
}
|
||||
/// <summary>
|
||||
/// Helper for ConnectionChange event
|
||||
/// </summary>
|
||||
void OnConnectionChange()
|
||||
{
|
||||
if (ConnectionChange != null)
|
||||
ConnectionChange(this, new GenericSocketStatusChageEventArgs(this));
|
||||
}
|
||||
|
||||
#region IBasicCommunication Members
|
||||
#region IBasicCommunication Members
|
||||
|
||||
/// <summary>
|
||||
/// Sends text to the server
|
||||
@@ -507,14 +498,14 @@ namespace PepperDash.Core
|
||||
}
|
||||
catch (ObjectDisposedException ex)
|
||||
{
|
||||
this.LogException(ex, "ObjectDisposedException sending {message}", text);
|
||||
this.LogError("ObjectDisposedException sending '{message}'. Restarting connection...", text.Trim());
|
||||
|
||||
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
||||
ReconnectTimer.Reset();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.LogException(ex, "Exception sending text: {message}", text);
|
||||
this.LogException(ex, "Exception sending text: '{message}'", text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -582,10 +573,10 @@ public class SshConnectionChangeEventArgs : EventArgs
|
||||
/// </summary>
|
||||
public ushort Status { get { return Client.UStatus; } }
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// S+ Constructor
|
||||
/// </summary>
|
||||
public SshConnectionChangeEventArgs() { }
|
||||
/// </summary>
|
||||
public SshConnectionChangeEventArgs() { }
|
||||
|
||||
/// <summary>
|
||||
/// EventArgs class
|
||||
@@ -593,9 +584,9 @@ public class SshConnectionChangeEventArgs : EventArgs
|
||||
/// <param name="isConnected">Connection State</param>
|
||||
/// <param name="client">The Client</param>
|
||||
public SshConnectionChangeEventArgs(bool isConnected, GenericSshClient client)
|
||||
{
|
||||
IsConnected = isConnected;
|
||||
Client = client;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
IsConnected = isConnected;
|
||||
Client = client;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,351 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
namespace PepperDash.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows for two simultaneous TCP clients to connect to a redundant pair of QSC Core DSPs and manages
|
||||
/// </summary>
|
||||
public class QscCoreDoubleTcpIpClient : IKeyed
|
||||
{
|
||||
/// <summary>
|
||||
/// Key to uniquely identify the instance of the class
|
||||
/// </summary>
|
||||
public string Key { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fires when a bool value changes to notify the S+ module
|
||||
/// </summary>
|
||||
public event EventHandler<BoolChangeEventArgs> BoolChange;
|
||||
/// <summary>
|
||||
/// Fires when a ushort value changes to notify the S+ module
|
||||
/// </summary>
|
||||
public event EventHandler<UshrtChangeEventArgs> UshortChange;
|
||||
/// <summary>
|
||||
/// Fires when a string value changes to notify the S+ module
|
||||
/// </summary>
|
||||
public event EventHandler<StringChangeEventArgs> StringChange;
|
||||
|
||||
/// <summary>
|
||||
/// The client for the master DSP unit
|
||||
/// </summary>
|
||||
public GenericTcpIpClient MasterClient { get; private set; }
|
||||
/// <summary>
|
||||
/// The client for the slave DSP unit
|
||||
/// </summary>
|
||||
public GenericTcpIpClient SlaveClient { get; private set; }
|
||||
|
||||
string Username;
|
||||
string Password;
|
||||
string LineEnding;
|
||||
|
||||
CommunicationGather MasterGather;
|
||||
CommunicationGather SlaveGather;
|
||||
|
||||
bool IsPolling;
|
||||
int PollingIntervalSeconds;
|
||||
CTimer PollTimer;
|
||||
|
||||
bool SlaveIsActive;
|
||||
|
||||
/// <summary>
|
||||
/// Default constuctor for S+
|
||||
/// </summary>
|
||||
public QscCoreDoubleTcpIpClient()
|
||||
{
|
||||
MasterClient = new GenericTcpIpClient("temp-master");
|
||||
MasterClient.AutoReconnect = true;
|
||||
MasterClient.AutoReconnectIntervalMs = 2000;
|
||||
SlaveClient = new GenericTcpIpClient("temp-slave");
|
||||
SlaveClient.AutoReconnect = true;
|
||||
SlaveClient.AutoReconnectIntervalMs = 2000;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connects to both DSP units
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="masterAddress"></param>
|
||||
/// <param name="masterPort"></param>
|
||||
/// <param name="slaveAddress"></param>
|
||||
/// <param name="slavePort"></param>
|
||||
/// <param name="username"></param>
|
||||
/// <param name="password"></param>
|
||||
/// <param name="pollingIntervalSeconds"></param>
|
||||
/// <param name="lineEnding"></param>
|
||||
public void Connect(string key, string masterAddress, int masterPort,
|
||||
string slaveAddress, int slavePort, string username, string password,
|
||||
int pollingIntervalSeconds, string lineEnding)
|
||||
{
|
||||
Key = key;
|
||||
|
||||
PollingIntervalSeconds = pollingIntervalSeconds;
|
||||
Username = username;
|
||||
Password = password;
|
||||
LineEnding = lineEnding;
|
||||
|
||||
MasterClient.Initialize(key + "-master");
|
||||
SlaveClient.Initialize(key + "-slave");
|
||||
|
||||
MasterClient.Hostname = masterAddress;
|
||||
MasterClient.Port = masterPort;
|
||||
|
||||
if (MasterClient != null)
|
||||
{
|
||||
MasterClient.Disconnect();
|
||||
}
|
||||
|
||||
if (SlaveClient != null)
|
||||
{
|
||||
SlaveClient.Disconnect();
|
||||
}
|
||||
|
||||
if (MasterGather == null)
|
||||
{
|
||||
MasterGather = new CommunicationGather(MasterClient, lineEnding);
|
||||
MasterGather.IncludeDelimiter = true;
|
||||
}
|
||||
|
||||
MasterGather.LineReceived -= MasterGather_LineReceived;
|
||||
MasterGather.LineReceived += new EventHandler<GenericCommMethodReceiveTextArgs>(MasterGather_LineReceived);
|
||||
|
||||
MasterClient.ConnectionChange -= MasterClient_SocketStatusChange;
|
||||
MasterClient.ConnectionChange += MasterClient_SocketStatusChange;
|
||||
|
||||
SlaveClient.Hostname = slaveAddress;
|
||||
SlaveClient.Port = slavePort;
|
||||
|
||||
if (SlaveGather == null)
|
||||
{
|
||||
SlaveGather = new CommunicationGather(SlaveClient, lineEnding);
|
||||
SlaveGather.IncludeDelimiter = true;
|
||||
}
|
||||
|
||||
SlaveGather.LineReceived -= MasterGather_LineReceived;
|
||||
SlaveGather.LineReceived += new EventHandler<GenericCommMethodReceiveTextArgs>(SlaveGather_LineReceived);
|
||||
|
||||
SlaveClient.ConnectionChange -= SlaveClient_SocketStatusChange;
|
||||
SlaveClient.ConnectionChange += SlaveClient_SocketStatusChange;
|
||||
|
||||
MasterClient.Connect();
|
||||
SlaveClient.Connect();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void Disconnect()
|
||||
{
|
||||
if (MasterClient != null)
|
||||
{
|
||||
MasterGather.LineReceived -= MasterGather_LineReceived;
|
||||
MasterClient.Disconnect();
|
||||
}
|
||||
if (SlaveClient != null)
|
||||
{
|
||||
SlaveGather.LineReceived -= SlaveGather_LineReceived;
|
||||
SlaveClient.Disconnect();
|
||||
}
|
||||
if (PollTimer != null)
|
||||
{
|
||||
IsPolling = false;
|
||||
|
||||
PollTimer.Stop();
|
||||
PollTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does not include line feed
|
||||
/// </summary>
|
||||
public void SendText(string s)
|
||||
{
|
||||
if (SlaveIsActive)
|
||||
{
|
||||
if (SlaveClient != null)
|
||||
{
|
||||
Debug.Console(2, this, "Sending to Slave: {0}", s);
|
||||
SlaveClient.SendText(s);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MasterClient != null)
|
||||
{
|
||||
Debug.Console(2, this, "Sending to Master: {0}", s);
|
||||
MasterClient.SendText(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MasterClient_SocketStatusChange(object sender, GenericSocketStatusChageEventArgs args)
|
||||
{
|
||||
OnUshortChange((ushort)args.Client.ClientStatus, MasterClientStatusId);
|
||||
|
||||
if (args.Client.IsConnected)
|
||||
{
|
||||
MasterGather.LineReceived += MasterGather_LineReceived;
|
||||
|
||||
StartPolling();
|
||||
}
|
||||
else
|
||||
MasterGather.LineReceived -= MasterGather_LineReceived;
|
||||
}
|
||||
|
||||
void SlaveClient_SocketStatusChange(object sender, GenericSocketStatusChageEventArgs args)
|
||||
{
|
||||
OnUshortChange((ushort)args.Client.ClientStatus, SlaveClientStatusId);
|
||||
|
||||
if (args.Client.IsConnected)
|
||||
{
|
||||
SlaveGather.LineReceived += SlaveGather_LineReceived;
|
||||
|
||||
StartPolling();
|
||||
}
|
||||
else
|
||||
SlaveGather.LineReceived -= SlaveGather_LineReceived;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void MasterGather_LineReceived(object sender, GenericCommMethodReceiveTextArgs e)
|
||||
{
|
||||
if (e.Text.Contains("login_required"))
|
||||
{
|
||||
MasterClient.SendText(string.Format("login {0} {1} \x0d\x0a", Username, Password));
|
||||
}
|
||||
else if (e.Text.Contains("login_success"))
|
||||
{
|
||||
// START THE POLLING, YO!
|
||||
}
|
||||
else if (e.Text.StartsWith("sr"))
|
||||
{
|
||||
// example response "sr "MyDesign" "NIEC2bxnVZ6a" 1 1"
|
||||
|
||||
var split = e.Text.Trim().Split(' ');
|
||||
if (split[split.Length - 1] == "1")
|
||||
{
|
||||
SlaveIsActive = false;
|
||||
OnBoolChange(false, SlaveIsActiveId);
|
||||
OnBoolChange(true, MasterIsActiveId);
|
||||
}
|
||||
}
|
||||
if (!SlaveIsActive)
|
||||
OnStringChange(e.Text, LineReceivedId);
|
||||
}
|
||||
|
||||
void SlaveGather_LineReceived(object sender, GenericCommMethodReceiveTextArgs e)
|
||||
{
|
||||
if (e.Text.Contains("login_required"))
|
||||
{
|
||||
SlaveClient.SendText(string.Format("login {0} {1} \x0d\x0a", Username, Password));
|
||||
}
|
||||
else if (e.Text.Contains("login_success"))
|
||||
{
|
||||
// START THE POLLING, YO!
|
||||
}
|
||||
else if (e.Text.StartsWith("sr"))
|
||||
{
|
||||
var split = e.Text.Trim().Split(' ');
|
||||
if (split[split.Length - 1] == "1")
|
||||
{
|
||||
SlaveIsActive = true;
|
||||
OnBoolChange(true, SlaveIsActiveId);
|
||||
OnBoolChange(false, MasterIsActiveId);
|
||||
}
|
||||
}
|
||||
if (SlaveIsActive)
|
||||
OnStringChange(e.Text, LineReceivedId);
|
||||
}
|
||||
|
||||
void StartPolling()
|
||||
{
|
||||
if (!IsPolling)
|
||||
{
|
||||
IsPolling = true;
|
||||
|
||||
Poll();
|
||||
if (PollTimer != null)
|
||||
PollTimer.Stop();
|
||||
|
||||
PollTimer = new CTimer(o => Poll(), null, PollingIntervalSeconds * 1000, PollingIntervalSeconds * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
void Poll()
|
||||
{
|
||||
if (MasterClient != null && MasterClient.IsConnected)
|
||||
{
|
||||
Debug.Console(2, this, "Polling Master.");
|
||||
MasterClient.SendText("sg\x0d\x0a");
|
||||
|
||||
}
|
||||
if (SlaveClient != null && SlaveClient.IsConnected)
|
||||
{
|
||||
Debug.Console(2, this, "Polling Slave.");
|
||||
SlaveClient.SendText("sg\x0d\x0a");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// login NAME PIN ---> login_success, login_failed
|
||||
|
||||
// status get
|
||||
// sg --> sr DESIGN_NAME DESIGN_ID IS_PRIMARY IS_ACTIVE
|
||||
|
||||
// CRLF
|
||||
|
||||
void OnBoolChange(bool state, ushort type)
|
||||
{
|
||||
var handler = BoolChange;
|
||||
if (handler != null)
|
||||
handler(this, new BoolChangeEventArgs(state, type));
|
||||
}
|
||||
|
||||
void OnUshortChange(ushort state, ushort type)
|
||||
{
|
||||
var handler = UshortChange;
|
||||
if (handler != null)
|
||||
handler(this, new UshrtChangeEventArgs(state, type));
|
||||
}
|
||||
|
||||
void OnStringChange(string value, ushort type)
|
||||
{
|
||||
var handler = StringChange;
|
||||
if (handler != null)
|
||||
handler(this, new StringChangeEventArgs(value, type));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public const ushort MasterIsActiveId = 3;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public const ushort SlaveIsActiveId = 4;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public const ushort MainModuleInitiailzeId = 5;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public const ushort MasterClientStatusId = 101;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public const ushort SlaveClientStatusId = 102;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public const ushort LineReceivedId = 201;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.CrestronSockets;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PepperDash.Core
|
||||
{
|
||||
@@ -25,6 +26,7 @@ namespace PepperDash.Core
|
||||
/// <summary>
|
||||
/// Indicates connection status
|
||||
/// </summary>
|
||||
[JsonProperty("isConnected")]
|
||||
bool IsConnected { get; }
|
||||
/// <summary>
|
||||
/// Connect to the device
|
||||
@@ -70,6 +72,7 @@ namespace PepperDash.Core
|
||||
/// <summary>
|
||||
/// Object to enable stream debugging
|
||||
/// </summary>
|
||||
[JsonProperty("streamDebugging")]
|
||||
CommunicationStreamDebugging StreamDebugging { get; }
|
||||
}
|
||||
|
||||
@@ -87,7 +90,9 @@ namespace PepperDash.Core
|
||||
/// <summary>
|
||||
/// The current socket status of the client
|
||||
/// </summary>
|
||||
SocketStatus ClientStatus { get; }
|
||||
[JsonProperty("clientStatus")]
|
||||
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
||||
SocketStatus ClientStatus { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -106,10 +111,12 @@ namespace PepperDash.Core
|
||||
/// <summary>
|
||||
/// Enable automatic recconnect
|
||||
/// </summary>
|
||||
[JsonProperty("autoReconnect")]
|
||||
bool AutoReconnect { get; set; }
|
||||
/// <summary>
|
||||
/// Interval in ms to attempt automatic recconnections
|
||||
/// </summary>
|
||||
[JsonProperty("autoReconnectIntervalMs")]
|
||||
int AutoReconnectIntervalMs { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@@ -98,9 +98,22 @@ namespace PepperDash.Core.Config
|
||||
merged.Add("destinationLists",
|
||||
Merge(template["destinationLists"], system["destinationLists"], "destinationLists"));
|
||||
|
||||
// Template tie lines take precedence. Config tool doesn't do them at system
|
||||
// level anyway...
|
||||
if (template["tieLines"] != null)
|
||||
|
||||
if (system["cameraLists"] == null)
|
||||
merged.Add("cameraLists", template["cameraLists"]);
|
||||
else
|
||||
merged.Add("cameraLists", Merge(template["cameraLists"], system["cameraLists"], "cameraLists"));
|
||||
|
||||
if (system["audioControlPointLists"] == null)
|
||||
merged.Add("audioControlPointLists", template["audioControlPointLists"]);
|
||||
else
|
||||
merged.Add("audioControlPointLists",
|
||||
Merge(template["audioControlPointLists"], system["audioControlPointLists"], "audioControlPointLists"));
|
||||
|
||||
|
||||
// Template tie lines take precedence. Config tool doesn't do them at system
|
||||
// level anyway...
|
||||
if (template["tieLines"] != null)
|
||||
merged.Add("tieLines", template["tieLines"]);
|
||||
else if (system["tieLines"] != null)
|
||||
merged.Add("tieLines", system["tieLines"]);
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
|
||||
namespace PepperDash.Core
|
||||
@@ -15,6 +16,7 @@ namespace PepperDash.Core
|
||||
/// <summary>
|
||||
/// Unique Key
|
||||
/// </summary>
|
||||
[JsonProperty("key")]
|
||||
string Key { get; }
|
||||
}
|
||||
|
||||
@@ -26,6 +28,7 @@ namespace PepperDash.Core
|
||||
/// <summary>
|
||||
/// Isn't it obvious :)
|
||||
/// </summary>
|
||||
[JsonProperty("name")]
|
||||
string Name { get; }
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,15 @@ namespace PepperDash.Core
|
||||
public void PreActivate()
|
||||
{
|
||||
if (_PreActivationActions != null)
|
||||
_PreActivationActions.ForEach(a => a.Invoke());
|
||||
_PreActivationActions.ForEach(a => {
|
||||
try
|
||||
{
|
||||
a.Invoke();
|
||||
} catch (Exception e)
|
||||
{
|
||||
Debug.LogMessage(e, "Error in PreActivationAction: " + e.Message, this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -123,7 +131,16 @@ namespace PepperDash.Core
|
||||
public void PostActivate()
|
||||
{
|
||||
if (_PostActivationActions != null)
|
||||
_PostActivationActions.ForEach(a => a.Invoke());
|
||||
_PostActivationActions.ForEach(a => {
|
||||
try
|
||||
{
|
||||
a.Invoke();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogMessage(e, "Error in PostActivationAction: " + e.Message, this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.CrestronIO;
|
||||
using Newtonsoft.Json;
|
||||
@@ -159,7 +160,11 @@ namespace PepperDash.Core.JsonToSimpl
|
||||
/// <returns></returns>
|
||||
public static JObject ParseObject(string json)
|
||||
{
|
||||
using (var reader = new JsonTextReader(new StringReader(json)))
|
||||
#if NET6_0
|
||||
using (var reader = new JsonTextReader(new System.IO.StringReader(json)))
|
||||
#else
|
||||
using (var reader = new JsonTextReader(new Crestron.SimplSharp.CrestronIO.StringReader(json)))
|
||||
#endif
|
||||
{
|
||||
var startDepth = reader.Depth;
|
||||
var obj = JObject.Load(reader);
|
||||
@@ -176,7 +181,11 @@ namespace PepperDash.Core.JsonToSimpl
|
||||
/// <returns></returns>
|
||||
public static JArray ParseArray(string json)
|
||||
{
|
||||
using (var reader = new JsonTextReader(new StringReader(json)))
|
||||
#if NET6_0
|
||||
using (var reader = new JsonTextReader(new System.IO.StringReader(json)))
|
||||
#else
|
||||
using (var reader = new JsonTextReader(new Crestron.SimplSharp.CrestronIO.StringReader(json)))
|
||||
#endif
|
||||
{
|
||||
var startDepth = reader.Depth;
|
||||
var obj = JArray.Load(reader);
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
namespace PepperDash.Core.PasswordManagement
|
||||
{
|
||||
// Example JSON password array configuration object
|
||||
//{
|
||||
// "global":{
|
||||
// "passwords":[
|
||||
// {
|
||||
// "key": "Password01",
|
||||
// "name": "Technician Password",
|
||||
// "enabled": true,
|
||||
// "password": "1988"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// JSON password array configuration object
|
||||
/// </summary>
|
||||
//public class PasswordConfig
|
||||
//{
|
||||
// /// <summary>
|
||||
// /// Key used to search for object in JSON array
|
||||
// /// </summary>
|
||||
// public string key { get; set; }
|
||||
// /// <summary>
|
||||
// /// Friendly name of password object
|
||||
// /// </summary>
|
||||
// public string name { get; set; }
|
||||
// /// <summary>
|
||||
// /// Password object enabled
|
||||
// /// </summary>
|
||||
// public bool enabled { get; set; }
|
||||
// /// <summary>
|
||||
// ///
|
||||
// /// </summary>
|
||||
// public ushort simplEnabled
|
||||
// {
|
||||
// get { return (ushort)(enabled ? 1 : 0); }
|
||||
// set { enabled = Convert.ToBoolean(value); }
|
||||
// }
|
||||
// /// <summary>
|
||||
// /// Password object configured password
|
||||
// /// </summary>
|
||||
// public string password { get; set; }
|
||||
// /// <summary>
|
||||
// /// Password type
|
||||
// /// </summary>
|
||||
// private int type { get; set; }
|
||||
// /// <summary>
|
||||
// /// Password Type for S+
|
||||
// /// </summary>
|
||||
// public ushort simplType
|
||||
// {
|
||||
// get { return Convert.ToUInt16(type); }
|
||||
// set { type = value; }
|
||||
// }
|
||||
// /// <summary>
|
||||
// /// Password path
|
||||
// /// **FUTURE** implementation of saving passwords recieved from Fusion or other external sources back to config
|
||||
// /// </summary>
|
||||
// public string path { get; set; }
|
||||
// /// <summary>
|
||||
// /// Constructor
|
||||
// /// </summary>
|
||||
// public PasswordConfig()
|
||||
// {
|
||||
// simplEnabled = 0;
|
||||
// simplType = 0;
|
||||
// }
|
||||
//}
|
||||
|
||||
// Example JSON password collections configuration object
|
||||
//{
|
||||
// "global": {
|
||||
// "passwords": {
|
||||
// "1": {
|
||||
// "name": "Technician Password",
|
||||
// "password": "2468"
|
||||
// },
|
||||
// "2": {
|
||||
// "name": "System Password",
|
||||
// "password": "123456"
|
||||
// },
|
||||
// "3": {
|
||||
// "name": "Master Password",
|
||||
// "password": "abc123"
|
||||
// },
|
||||
// "5": {
|
||||
// "name": "Backdoor Password",
|
||||
// "password": "1988"
|
||||
// },
|
||||
// "10": {
|
||||
// "name": "Backdoor Password",
|
||||
// "password": "1988"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// JSON password array configuration object
|
||||
/// </summary>
|
||||
public class PasswordConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Password object configured password
|
||||
/// </summary>
|
||||
public string password { get; set; }
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public PasswordConfig()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Global JSON object
|
||||
/// </summary>
|
||||
//public class GlobalConfig
|
||||
//{
|
||||
// //public List<PasswordConfig> passwords { get; set; }
|
||||
// public Dictionary<uint, PasswordConfig> passwords { get; set; }
|
||||
|
||||
// /// <summary>
|
||||
// /// Constructor
|
||||
// /// </summary>
|
||||
// public GlobalConfig()
|
||||
// {
|
||||
|
||||
// }
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Root JSON object
|
||||
/// </summary>
|
||||
//public class RootObject
|
||||
//{
|
||||
// public GlobalConfig global { get; set; }
|
||||
//}
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
namespace PepperDash.Core.PasswordManagement
|
||||
{
|
||||
public class PasswordClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Password Client
|
||||
/// </summary>
|
||||
public PasswordConfig Client { get; set; }
|
||||
/// <summary>
|
||||
/// Used to build the password entered by the user
|
||||
/// </summary>
|
||||
public string PasswordToValidate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Boolean event
|
||||
/// </summary>
|
||||
public event EventHandler<BoolChangeEventArgs> BoolChange;
|
||||
/// <summary>
|
||||
/// Ushort event
|
||||
/// </summary>
|
||||
public event EventHandler<UshrtChangeEventArgs> UshrtChange;
|
||||
/// <summary>
|
||||
/// String event
|
||||
/// </summary>
|
||||
public event EventHandler<StringChangeEventArgs> StringChange;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public PasswordClient()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize method
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
public void Initialize(string key)
|
||||
{
|
||||
OnBoolChange(false, 0, PasswordManagementConstants.BoolEvaluatedChange);
|
||||
|
||||
Client = new PasswordConfig();
|
||||
PasswordToValidate = "";
|
||||
|
||||
// there has to be a better way to get the index of the current index of password
|
||||
ushort i = 0;
|
||||
foreach (var password in PasswordManager.Passwords)
|
||||
{
|
||||
i++;
|
||||
OnUshrtChange((ushort)password.Key, (ushort)password.Key, PasswordManagementConstants.PasswordKey);
|
||||
}
|
||||
|
||||
OnBoolChange(true, 0, PasswordManagementConstants.BoolEvaluatedChange);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves password by key
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
//public void GetPasswordByKey(string key)
|
||||
//{
|
||||
// if (string.IsNullOrEmpty(key))
|
||||
// {
|
||||
// Debug.Console(1, "PassowrdClient.GetPasswordByKey failed:\rKey {0} is null or empty", key);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// PasswordConfig password = PasswordManager.Passwords.FirstOrDefault(p => p.key.Equals(key));
|
||||
// if (password == null)
|
||||
// {
|
||||
// OnUshrtChange(0, 0, PasswordManagementConstants.SelectedPasswordLength);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// Client = password;
|
||||
// OnUshrtChange((ushort)Client.password.Length, 0, PasswordManagementConstants.SelectedPasswordLength);
|
||||
// OnStringChange(Client.key, 0, PasswordManagementConstants.PasswordKeySelected);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve password by index
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
public void GetPasswordByIndex(ushort key)
|
||||
{
|
||||
PasswordConfig pw = PasswordManager.Passwords[key];
|
||||
if (pw == null)
|
||||
{
|
||||
OnUshrtChange(0, 0, PasswordManagementConstants.SelectedPasswordLength);
|
||||
return;
|
||||
}
|
||||
|
||||
Client = pw;
|
||||
OnUshrtChange((ushort)Client.password.Length, 0, PasswordManagementConstants.SelectedPasswordLength);
|
||||
OnUshrtChange(key, 0, PasswordManagementConstants.PasswordKeySelected);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Password validation method
|
||||
/// </summary>
|
||||
/// <param name="password"></param>
|
||||
public void ValidatePassword(string password)
|
||||
{
|
||||
if (string.IsNullOrEmpty(password))
|
||||
return;
|
||||
|
||||
if (string.Equals(Client.password, password))
|
||||
{
|
||||
OnBoolChange(true, 0, PasswordManagementConstants.PasswordIsValid);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnBoolChange(true, 0, PasswordManagementConstants.PasswordIsInvalid);
|
||||
}
|
||||
|
||||
|
||||
OnBoolChange(false, 0, PasswordManagementConstants.PasswordIsValid);
|
||||
OnBoolChange(false, 0, PasswordManagementConstants.PasswordIsInvalid);
|
||||
|
||||
ClearPassword();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the user entered passwrod string, will attempt to validate the user entered
|
||||
/// password against the selected password when the length of the 2 are equal
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
public void BuildPassword(string data)
|
||||
{
|
||||
PasswordToValidate = String.Concat(PasswordToValidate, data);
|
||||
OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedChange);
|
||||
|
||||
if (PasswordToValidate.Length == Client.password.Length)
|
||||
ValidatePassword(PasswordToValidate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the user entered password and resets the LEDs
|
||||
/// </summary>
|
||||
public void ClearPassword()
|
||||
{
|
||||
PasswordToValidate = "";
|
||||
OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedChange);
|
||||
|
||||
for(var i = 1; i <= Client.password.Length; i++)
|
||||
OnBoolChange(false, (ushort)i, PasswordManagementConstants.PasswordLedChange);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Protected boolean change event handler
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="type"></param>
|
||||
protected void OnBoolChange(bool state, ushort index, ushort type)
|
||||
{
|
||||
var handler = BoolChange;
|
||||
if (handler != null)
|
||||
{
|
||||
var args = new BoolChangeEventArgs(state, type);
|
||||
args.Index = index;
|
||||
BoolChange(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Protected ushort change event handler
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="type"></param>
|
||||
protected void OnUshrtChange(ushort value, ushort index, ushort type)
|
||||
{
|
||||
var handler = UshrtChange;
|
||||
if (handler != null)
|
||||
{
|
||||
var args = new UshrtChangeEventArgs(value, type);
|
||||
args.Index = index;
|
||||
UshrtChange(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Protected string change event handler
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="type"></param>
|
||||
protected void OnStringChange(string value, ushort index, ushort type)
|
||||
{
|
||||
var handler = StringChange;
|
||||
if (handler != null)
|
||||
{
|
||||
var args = new StringChangeEventArgs(value, type);
|
||||
args.Index = index;
|
||||
StringChange(this, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,233 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Crestron.SimplSharp;
|
||||
using PepperDash.Core.JsonToSimpl;
|
||||
using PepperDash.Core.JsonStandardObjects;
|
||||
|
||||
namespace PepperDash.Core.PasswordManagement
|
||||
{
|
||||
public class PasswordManager
|
||||
{
|
||||
/// <summary>
|
||||
/// List of passwords configured
|
||||
/// </summary>
|
||||
public static Dictionary<uint, PasswordConfig> Passwords = new Dictionary<uint, PasswordConfig>();
|
||||
private Dictionary<uint, PasswordConfig> TempPasswords = new Dictionary<uint, PasswordConfig>();
|
||||
|
||||
CTimer UpdateTimer;
|
||||
public long UpdateTimerElapsedMs = 5000;
|
||||
|
||||
/// <summary>
|
||||
/// Boolean event
|
||||
/// </summary>
|
||||
public event EventHandler<BoolChangeEventArgs> BoolChange;
|
||||
/// <summary>
|
||||
/// Ushort event
|
||||
/// </summary>
|
||||
public event EventHandler<UshrtChangeEventArgs> UshrtChange;
|
||||
/// <summary>
|
||||
/// String event
|
||||
/// </summary>
|
||||
public event EventHandler<StringChangeEventArgs> StringChange;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public PasswordManager()
|
||||
{
|
||||
Passwords.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize method
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="uniqueId"></param>
|
||||
//public void Initialize(string uniqueId, string key)
|
||||
//{
|
||||
// OnBoolChange(false, 0, PasswordManagementConstants.BoolEvaluatedChange);
|
||||
|
||||
// try
|
||||
// {
|
||||
// if(string.IsNullOrEmpty(uniqueId) || string.IsNullOrEmpty(key))
|
||||
// {
|
||||
// Debug.Console(1, "PasswordManager.Initialize({0}, {1}) null or empty parameters", uniqueId, key);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// JsonToSimplMaster master = J2SGlobal.GetMasterByFile(uniqueId);
|
||||
// if(master == null)
|
||||
// {
|
||||
// Debug.Console(1, "PassowrdManager.Initialize failed:\rCould not find JSON file with uniqueID {0}", uniqueId);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// var global = master.JsonObject.ToObject<RootObject>().global;
|
||||
// var passwords = global.passwords;
|
||||
// if(passwords == null)
|
||||
// {
|
||||
// Debug.Console(1, "PasswordManager.Initialize failed:\rCould not find password object");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// foreach(var password in passwords)
|
||||
// {
|
||||
// if (password != null)
|
||||
// {
|
||||
// var index = passwords.IndexOf(password);
|
||||
|
||||
// password.path = string.Format("global.passwords[{0}]", index);
|
||||
// Debug.Console(1, "PasswordManager.Initialize: {0}, {1}, {2}, {3}, {4}, {5}", password.key, password.name, password.simplEnabled, password.simplType, password.password, password.path);
|
||||
// //AddPassword(password);
|
||||
|
||||
// OnStringChange(password.path, (ushort)index, PasswordManagementConstants.FullPathToPassword);
|
||||
// OnStringChange(password.key, (ushort)index, PasswordManagementConstants.PasswordKey);
|
||||
// }
|
||||
// }
|
||||
|
||||
// OnUshrtChange(Convert.ToUInt16(Passwords.Count), 0, PasswordManagementConstants.PasswordListCount);
|
||||
// }
|
||||
// catch(Exception e)
|
||||
// {
|
||||
// var msg = string.Format("PasswordManager.Initialize({0}, {1}) failed:\r{2}", uniqueId, key, e.Message);
|
||||
// CrestronConsole.PrintLine(msg);
|
||||
// ErrorLog.Error(msg);
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// OnBoolChange(true, 0, PasswordManagementConstants.BoolEvaluatedChange);
|
||||
// }
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Adds password to the list
|
||||
/// </summary>
|
||||
/// <param name="password"></param>
|
||||
//private void AddPassword(PasswordConfig password)
|
||||
//{
|
||||
// if (password == null)
|
||||
// return;
|
||||
|
||||
// var item = Passwords.FirstOrDefault(i => i.key.Equals(password.key));
|
||||
// if (item != null)
|
||||
// Passwords.Remove(item);
|
||||
// Passwords.Add(password);
|
||||
|
||||
// Passwords.Sort((x, y) => string.Compare(x.key, y.key));
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Removes password from the list
|
||||
/// </summary>
|
||||
/// <param name="password"></param>
|
||||
//private void RemovePassword(PasswordConfig password)
|
||||
//{
|
||||
// if (password == null)
|
||||
// return;
|
||||
|
||||
// var item = Passwords.FirstOrDefault(i => i.key.Equals(password.key));
|
||||
// if (item != null)
|
||||
// Passwords.Remove(item);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Updates password stored in the dictonary
|
||||
/// </summary>
|
||||
/// <param name="uniqueId"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="password"></param>
|
||||
public void UpdatePassword(ushort key, string password)
|
||||
{
|
||||
if (string.IsNullOrEmpty(password))
|
||||
return;
|
||||
|
||||
var pw = TempPasswords[key];
|
||||
if (pw == null)
|
||||
{
|
||||
pw = new PasswordConfig();
|
||||
}
|
||||
pw.password = password;
|
||||
|
||||
if (UpdateTimer == null)
|
||||
{
|
||||
// (o) => SavePasswords removes the need to create a callback method that takes in an object
|
||||
UpdateTimer = new CTimer((o) => StorePassword(), UpdateTimerElapsedMs);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateTimer.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores the updated passwords in TempPassword in the Passwords dictionary
|
||||
/// </summary>
|
||||
private void StorePassword()
|
||||
{
|
||||
UpdateTimer.Stop();
|
||||
|
||||
foreach (var tempPw in TempPasswords)
|
||||
{
|
||||
Passwords[tempPw.Key] = tempPw.Value;
|
||||
}
|
||||
|
||||
TempPasswords.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Protected boolean change event handler
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="type"></param>
|
||||
protected void OnBoolChange(bool state, ushort index, ushort type)
|
||||
{
|
||||
var handler = BoolChange;
|
||||
if (handler != null)
|
||||
{
|
||||
var args = new BoolChangeEventArgs(state, type);
|
||||
args.Index = index;
|
||||
BoolChange(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Protected ushort change event handler
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="type"></param>
|
||||
protected void OnUshrtChange(ushort value, ushort index, ushort type)
|
||||
{
|
||||
var handler = UshrtChange;
|
||||
if (handler != null)
|
||||
{
|
||||
var args = new UshrtChangeEventArgs(value, type);
|
||||
args.Index = index;
|
||||
UshrtChange(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Protected string change event handler
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="type"></param>
|
||||
protected void OnStringChange(string value, ushort index, ushort type)
|
||||
{
|
||||
var handler = StringChange;
|
||||
if (handler != null)
|
||||
{
|
||||
var args = new StringChangeEventArgs(value, type);
|
||||
args.Index = index;
|
||||
StringChange(this, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
namespace PepperDash.Core.PasswordManagement
|
||||
{
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
<Company>PepperDash Technologies</Company>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<RepositoryUrl>https://github.com/PepperDash/PepperDashCore</RepositoryUrl>
|
||||
<PackageTags>crestron;4series;</PackageTags>
|
||||
<PackageTags>crestron;4series;</PackageTags>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<InformationalVersion>$(Version)</InformationalVersion>
|
||||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
@@ -24,6 +25,14 @@
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<DocumentationFile>bin\4Series\$(Configuration)\PepperDashCore.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="lib\**" />
|
||||
<Compile Remove="Properties\**" />
|
||||
<EmbeddedResource Remove="lib\**" />
|
||||
<EmbeddedResource Remove="Properties\**" />
|
||||
<None Remove="lib\**" />
|
||||
<None Remove="Properties\**" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
@@ -31,7 +40,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />
|
||||
<PackageReference Include="Crestron.SimplSharp.SDK.Library" Version="2.20.66" />
|
||||
<PackageReference Include="Crestron.SimplSharp.SDK.Library" Version="2.21.90" />
|
||||
<PackageReference Include="Serilog" Version="3.1.1" />
|
||||
<PackageReference Include="Serilog.Expressions" Version="4.0.0" />
|
||||
<PackageReference Include="Serilog.Formatting.Compact" Version="2.0.0" />
|
||||
@@ -40,6 +49,9 @@
|
||||
<PackageReference Include="SSH.NET" Version="2024.2.0" />
|
||||
<PackageReference Include="WebSocketSharp" Version="1.0.3-rc11" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net6'">
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="Comm\._GenericSshClient.cs" />
|
||||
<Compile Remove="Comm\._GenericTcpIpClient.cs" />
|
||||
|
||||
Reference in New Issue
Block a user