Adds IStreamDebugging and associated logic to implment on TCP, SSH and UDP methods

This commit is contained in:
Neil Dorin
2020-06-09 14:05:27 -06:00
parent e4712ebc53
commit 8f075fbed7
8 changed files with 263 additions and 15 deletions

View File

@@ -0,0 +1,127 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
namespace PepperDash.Core
{
/// <summary>
/// Controls the ability to disable/enable debugging of TX/RX data sent to/from a device with a built in timer to disable
/// </summary>
public class CommunicationStreamDebugging
{
public string ParentDeviceKey { get; private set; }
/// <summary>
/// Timer to disable automatically if not manually disabled
/// </summary>
private CTimer DebugExpiryPeriod;
public eStreamDebuggingSetting DebugSetting { get; private set; }
private uint _DebugTimeoutMin;
private const uint _DefaultDebugTimeoutMin = 30;
/// <summary>
/// Timeout in Minutes
/// </summary>
public uint DebugTimeoutMinutes
{
get
{
return _DebugTimeoutMin;
}
}
private long _DebugTimeoutInMs
{
get
{
return DebugTimeoutMinutes * 60000;
}
}
public bool RxStreamDebuggingIsEnabled{ get; private set; }
public bool TxStreamDebuggingIsEnabled { get; private set; }
public CommunicationStreamDebugging(string parentDeviceKey)
{
ParentDeviceKey = parentDeviceKey;
}
/// <summary>
/// Sets the debugging setting and if not setting to off, assumes the default of 30 mintues
/// </summary>
/// <param name="setting"></param>
public void SetDebuggingWithDefaultTimeout(eStreamDebuggingSetting setting)
{
if (setting == eStreamDebuggingSetting.Off)
{
DisableDebugging();
}
else
{
SetDebuggingWithSpecificTimeout(setting, _DefaultDebugTimeoutMin);
}
}
/// <summary>
/// Sets the debugging setting for the specified number of minutes
/// </summary>
/// <param name="setting"></param>
/// <param name="minutes"></param>
public void SetDebuggingWithSpecificTimeout(eStreamDebuggingSetting setting, uint minutes)
{
_DebugTimeoutMin = minutes;
if (DebugExpiryPeriod != null)
{
DisableDebugging();
}
DebugExpiryPeriod = new CTimer((o) => DisableDebugging(), _DebugTimeoutInMs);
if ((setting & eStreamDebuggingSetting.Rx) == eStreamDebuggingSetting.Rx)
RxStreamDebuggingIsEnabled = true;
if ((setting & eStreamDebuggingSetting.Tx) == eStreamDebuggingSetting.Tx)
TxStreamDebuggingIsEnabled = true;
Debug.SetDeviceDebugSettings(ParentDeviceKey, setting);
}
/// <summary>
/// Disabled debugging
/// </summary>
public void DisableDebugging()
{
DebugExpiryPeriod.Stop();
DebugExpiryPeriod.Dispose();
DebugExpiryPeriod = null;
RxStreamDebuggingIsEnabled = false;
TxStreamDebuggingIsEnabled = false;
Debug.SetDeviceDebugSettings(ParentDeviceKey, eStreamDebuggingSetting.Off);
}
}
/// <summary>
/// The available settings for stream debugging
/// </summary>
[Flags]
public enum eStreamDebuggingSetting
{
Off = 0,
Rx = 1,
Tx = 2,
Both = Rx | Tx
}
}

View File

@@ -11,8 +11,10 @@ namespace PepperDash.Core
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public class GenericSshClient : Device, ISocketStatus, IAutoReconnect public class GenericSshClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect
{ {
public CommunicationStreamDebugging StreamDebugging { get; private set; }
/// <summary> /// <summary>
/// Event that fires when data is received. Delivers args with byte array /// Event that fires when data is received. Delivers args with byte array
/// </summary> /// </summary>
@@ -139,6 +141,7 @@ namespace PepperDash.Core
public GenericSshClient(string key, string hostname, int port, string username, string password) : public GenericSshClient(string key, string hostname, int port, string username, string password) :
base(key) base(key)
{ {
StreamDebugging = new CommunicationStreamDebugging(key);
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
Key = key; Key = key;
Hostname = hostname; Hostname = hostname;
@@ -240,7 +243,7 @@ namespace PepperDash.Core
try try
{ {
Client.Connect(); Client.Connect();
TheStream = Client.CreateShellStream("PDTShell", 100, 80, 100, 200, 65534); TheStream = Client.CreateShellStream("PDTShell", 100, 80, 100, 200, 100000);
TheStream.DataReceived += Stream_DataReceived; TheStream.DataReceived += Stream_DataReceived;
//TheStream.ErrorOccurred += TheStream_ErrorOccurred; //TheStream.ErrorOccurred += TheStream_ErrorOccurred;
Debug.Console(1, this, "Connected"); Debug.Console(1, this, "Connected");
@@ -381,6 +384,10 @@ namespace PepperDash.Core
{ {
var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length);
textHandler(this, new GenericCommMethodReceiveTextArgs(str)); textHandler(this, new GenericCommMethodReceiveTextArgs(str));
if (StreamDebugging.RxStreamDebuggingIsEnabled)
Debug.Console(0, this, "Recevied: '{0}'", str);
} }
} }
} }
@@ -422,8 +429,12 @@ namespace PepperDash.Core
{ {
if (Client != null) if (Client != null)
{ {
if (StreamDebugging.TxStreamDebuggingIsEnabled)
Debug.Console(0, this, "Sending {0} characters of text: '{1}'", text.Length, text);
TheStream.Write(text); TheStream.Write(text);
TheStream.Flush(); TheStream.Flush();
} }
} }
catch catch
@@ -444,6 +455,9 @@ namespace PepperDash.Core
{ {
if (Client != null) if (Client != null)
{ {
if (StreamDebugging.TxStreamDebuggingIsEnabled)
Debug.Console(0, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes));
TheStream.Write(bytes, 0, bytes.Length); TheStream.Write(bytes, 0, bytes.Length);
TheStream.Flush(); TheStream.Flush();
} }

View File

@@ -14,8 +14,10 @@ namespace PepperDash.Core
/// <summary> /// <summary>
/// A class to handle basic TCP/IP communications with a server /// A class to handle basic TCP/IP communications with a server
/// </summary> /// </summary>
public class GenericTcpIpClient : Device, ISocketStatus, IAutoReconnect public class GenericTcpIpClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect
{ {
public CommunicationStreamDebugging StreamDebugging { get; private set; }
/// <summary> /// <summary>
/// Fires when data is received from the server and returns it as a Byte array /// Fires when data is received from the server and returns it as a Byte array
/// </summary> /// </summary>
@@ -176,7 +178,7 @@ namespace PepperDash.Core
public GenericTcpIpClient(string key, string address, int port, int bufferSize) public GenericTcpIpClient(string key, string address, int port, int bufferSize)
: base(key) : base(key)
{ {
StreamDebugging = new CommunicationStreamDebugging(key);
Hostname = address; Hostname = address;
Port = port; Port = port;
BufferSize = bufferSize; BufferSize = bufferSize;
@@ -192,6 +194,7 @@ namespace PepperDash.Core
public GenericTcpIpClient(string key) public GenericTcpIpClient(string key)
: base(key) : base(key)
{ {
StreamDebugging = new CommunicationStreamDebugging(key);
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
AutoReconnectIntervalMs = 5000; AutoReconnectIntervalMs = 5000;
BufferSize = 2000; BufferSize = 2000;
@@ -348,8 +351,15 @@ namespace PepperDash.Core
if (textHandler != null) if (textHandler != null)
{ {
var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length);
if (StreamDebugging.RxStreamDebuggingIsEnabled)
Debug.Console(0, this, "Recevied: '{0}'", str);
textHandler(this, new GenericCommMethodReceiveTextArgs(str)); textHandler(this, new GenericCommMethodReceiveTextArgs(str));
} }
} }
client.ReceiveDataAsync(Receive); client.ReceiveDataAsync(Receive);
@@ -363,10 +373,12 @@ namespace PepperDash.Core
{ {
var bytes = Encoding.GetEncoding(28591).GetBytes(text); var bytes = Encoding.GetEncoding(28591).GetBytes(text);
// Check debug level before processing byte array // Check debug level before processing byte array
//if (Debug.Level == 2) if (StreamDebugging.TxStreamDebuggingIsEnabled)
// Debug.Console(2, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); Debug.Console(0, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes));
if(Client != null) if(Client != null)
Client.SendData(bytes, bytes.Length); Client.SendData(bytes, bytes.Length);
} }
/// <summary> /// <summary>
@@ -388,8 +400,8 @@ namespace PepperDash.Core
/// <param name="bytes"></param> /// <param name="bytes"></param>
public void SendBytes(byte[] bytes) public void SendBytes(byte[] bytes)
{ {
//if (Debug.Level == 2) if (StreamDebugging.TxStreamDebuggingIsEnabled)
// Debug.Console(2, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); Debug.Console(0, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes));
if(Client != null) if(Client != null)
Client.SendData(bytes, bytes.Length); Client.SendData(bytes, bytes.Length);
} }

View File

@@ -15,8 +15,9 @@ using Newtonsoft.Json.Linq;
namespace PepperDash.Core namespace PepperDash.Core
{ {
public class GenericUdpServer : Device, IBasicCommunication, ISocketStatus public class GenericUdpServer : Device, ISocketStatusWithStreamDebugging
{ {
public CommunicationStreamDebugging StreamDebugging { get; private set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@@ -138,6 +139,7 @@ namespace PepperDash.Core
public GenericUdpServer(string key, string address, int port, int buffefSize) public GenericUdpServer(string key, string address, int port, int buffefSize)
: base(key) : base(key)
{ {
StreamDebugging = new CommunicationStreamDebugging(key);
Hostname = address; Hostname = address;
Port = port; Port = port;
BufferSize = buffefSize; BufferSize = buffefSize;
@@ -268,8 +270,9 @@ namespace PepperDash.Core
var textHandler = TextReceived; var textHandler = TextReceived;
if (textHandler != null) if (textHandler != null)
{ {
if (StreamDebugging.RxStreamDebuggingIsEnabled)
Debug.Console(2, this, "RX: {0}", str); Debug.Console(0, this, "Recevied: '{0}'", str);
textHandler(this, new GenericCommMethodReceiveTextArgs(str)); textHandler(this, new GenericCommMethodReceiveTextArgs(str));
} }
else else
@@ -323,7 +326,9 @@ namespace PepperDash.Core
if (IsConnected && Server != null) if (IsConnected && Server != null)
{ {
Debug.Console(2, this, "TX: {0}", text); if (StreamDebugging.TxStreamDebuggingIsEnabled)
Debug.Console(0, this, "Sending {0} characters of text: '{1}'", text.Length, text);
Server.SendData(bytes, bytes.Length); Server.SendData(bytes, bytes.Length);
} }
} }
@@ -334,8 +339,9 @@ namespace PepperDash.Core
/// <param name="bytes"></param> /// <param name="bytes"></param>
public void SendBytes(byte[] bytes) public void SendBytes(byte[] bytes)
{ {
//if (Debug.Level == 2) if (StreamDebugging.TxStreamDebuggingIsEnabled)
// Debug.Console(2, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); Debug.Console(0, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes));
if (IsConnected && Server != null) if (IsConnected && Server != null)
Server.SendData(bytes, bytes.Length); Server.SendData(bytes, bytes.Length);
} }

View File

@@ -32,6 +32,22 @@ namespace PepperDash.Core
void SendBytes(byte[] bytes); void SendBytes(byte[] bytes);
} }
/// <summary>
/// Represents a device that implements IBasicCommunication and IStreamDebugging
/// </summary>
public interface IBasicCommunicationWithStreamDebugging : IBasicCommunication, IStreamDebugging
{
}
/// <summary>
/// Represents a device with stream debugging capablities
/// </summary>
public interface IStreamDebugging
{
CommunicationStreamDebugging StreamDebugging { get; }
}
/// <summary> /// <summary>
/// For IBasicCommunication classes that have SocketStatus. GenericSshClient, /// For IBasicCommunication classes that have SocketStatus. GenericSshClient,
/// GenericTcpIpClient /// GenericTcpIpClient
@@ -42,6 +58,13 @@ namespace PepperDash.Core
SocketStatus ClientStatus { get; } SocketStatus ClientStatus { get; }
} }
/// <summary>
/// Represents a device that implements ISocketStatus and IStreamDebugging
/// </summary>
public interface ISocketStatusWithStreamDebugging : ISocketStatus, IStreamDebugging
{
}
public interface IAutoReconnect public interface IAutoReconnect
{ {

View File

@@ -274,6 +274,28 @@ namespace PepperDash.Core
} }
} }
/// <summary>
/// sets the settings for a device or creates a new entry
/// </summary>
/// <param name="deviceKey"></param>
/// <param name="settings"></param>
/// <returns></returns>
public static void SetDeviceDebugSettings(string deviceKey, object settings)
{
Contexts.SetDebugSettingsForKey(deviceKey, settings);
SaveMemoryOnTimeout();
}
/// <summary>
/// Gets the device settings for a device by key or returns null
/// </summary>
/// <param name="deviceKey"></param>
/// <returns></returns>
public static object GetDeviceDebugSettingsForKey(string deviceKey)
{
return Contexts.GetDebugSettingsForKey(deviceKey);
}
/// <summary> /// <summary>
/// Sets the flag to prevent application starting on next boot /// Sets the flag to prevent application starting on next boot
/// </summary> /// </summary>

View File

@@ -5,16 +5,31 @@ using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace PepperDash.Core.DebugThings namespace PepperDash.Core.DebugThings
{ {
public class DebugContextCollection public class DebugContextCollection
{ {
/// <summary>
/// To prevent threading issues with the DeviceDebugSettings collection
/// </summary>
private CCriticalSection DeviceDebugSettingsLock;
[JsonProperty("items")] [JsonProperty("items")]
Dictionary<string, DebugContextItem> Items; Dictionary<string, DebugContextItem> Items;
/// <summary>
/// Collection of the debug settings for each device where the dictionary key is the device key
/// </summary>
[JsonProperty("deviceDebugSettings")]
private Dictionary<string, object> DeviceDebugSettings { get; set; }
public DebugContextCollection() public DebugContextCollection()
{ {
DeviceDebugSettingsLock = new CCriticalSection();
DeviceDebugSettings = new Dictionary<string, object>();
Items = new Dictionary<string, DebugContextItem>(); Items = new Dictionary<string, DebugContextItem>();
} }
@@ -43,6 +58,35 @@ namespace PepperDash.Core.DebugThings
Items[contextKey] = new DebugContextItem(this) { Level = 0 }; Items[contextKey] = new DebugContextItem(this) { Level = 0 };
return Items[contextKey]; return Items[contextKey];
} }
/// <summary>
/// sets the settings for a device or creates a new entry
/// </summary>
/// <param name="deviceKey"></param>
/// <param name="settings"></param>
/// <returns></returns>
public void SetDebugSettingsForKey(string deviceKey, object settings)
{
var existingSettings = DeviceDebugSettings[deviceKey];
if (existingSettings != null)
{
existingSettings = settings;
}
else
DeviceDebugSettings.Add(deviceKey, settings);
}
/// <summary>
/// Gets the device settings for a device by key or returns null
/// </summary>
/// <param name="deviceKey"></param>
/// <returns></returns>
public object GetDebugSettingsForKey(string deviceKey)
{
return DeviceDebugSettings[deviceKey];
}
} }
public class DebugContextItem public class DebugContextItem
@@ -59,7 +103,6 @@ namespace PepperDash.Core.DebugThings
[JsonProperty("doNotLoadOnNextBoot")] [JsonProperty("doNotLoadOnNextBoot")]
public bool DoNotLoadOnNextBoot { get; set; } public bool DoNotLoadOnNextBoot { get; set; }
public DebugContextItem(DebugContextCollection parent) public DebugContextItem(DebugContextCollection parent)
{ {

View File

@@ -69,6 +69,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="CommunicationExtras.cs" /> <Compile Include="CommunicationExtras.cs" />
<Compile Include="Comm\CommunicationStreamDebugging.cs" />
<Compile Include="Comm\ControlPropertiesConfig.cs" /> <Compile Include="Comm\ControlPropertiesConfig.cs" />
<Compile Include="Comm\GenericTcpIpClient_ForServer.cs" /> <Compile Include="Comm\GenericTcpIpClient_ForServer.cs" />
<Compile Include="Comm\GenericHttpSseClient.cs" /> <Compile Include="Comm\GenericHttpSseClient.cs" />