mirror of
https://github.com/PepperDash/PepperDashCore.git
synced 2026-02-15 20:54:46 +00:00
fix: remove WebSocketSharp reference in favor of System.Net.WebSockets
This commit is contained in:
BIN
src/.DS_Store
vendored
BIN
src/.DS_Store
vendored
Binary file not shown.
BIN
src/Pepperdash Core/.DS_Store
vendored
BIN
src/Pepperdash Core/.DS_Store
vendored
Binary file not shown.
@@ -7,198 +7,104 @@ using Serilog;
|
|||||||
using Serilog.Core;
|
using Serilog.Core;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
using Serilog.Configuration;
|
using Serilog.Configuration;
|
||||||
using WebSocketSharp.Server;
|
using System.Net.WebSockets;
|
||||||
using Crestron.SimplSharp;
|
using System.Threading;
|
||||||
using WebSocketSharp;
|
|
||||||
using System.Security.Authentication;
|
|
||||||
using WebSocketSharp.Net;
|
|
||||||
using X509Certificate2 = System.Security.Cryptography.X509Certificates.X509Certificate2;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Org.BouncyCastle.Asn1.X509;
|
|
||||||
using Serilog.Formatting;
|
using Serilog.Formatting;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Serilog.Formatting.Json;
|
using Serilog.Formatting.Json;
|
||||||
|
|
||||||
namespace PepperDash.Core
|
namespace PepperDash.Core
|
||||||
{
|
{
|
||||||
public class DebugWebsocketSink : ILogEventSink
|
public class DebugWebsocketSink : ILogEventSink, IDisposable
|
||||||
{
|
{
|
||||||
private HttpServer _httpsServer;
|
private readonly ITextFormatter _formatter;
|
||||||
|
private readonly List<WebSocket> _clients;
|
||||||
|
private readonly object _lock = new object();
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
private string _path = "/debug/join/";
|
public DebugWebsocketSink(ITextFormatter formatter)
|
||||||
private const string _certificateName = "selfCres";
|
{
|
||||||
private const string _certificatePassword = "cres12345";
|
_formatter = formatter ?? new JsonFormatter();
|
||||||
|
_clients = new List<WebSocket>();
|
||||||
|
}
|
||||||
|
|
||||||
public int Port
|
public void AddClient(WebSocket socket)
|
||||||
{ get
|
{
|
||||||
|
lock (_lock)
|
||||||
{
|
{
|
||||||
|
_clients.Add(socket);
|
||||||
if(_httpsServer == null) return 0;
|
|
||||||
return _httpsServer.Port;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Url
|
public void RemoveClient(WebSocket socket)
|
||||||
{
|
{
|
||||||
get
|
lock (_lock)
|
||||||
{
|
{
|
||||||
if (_httpsServer == null) return "";
|
_clients.Remove(socket);
|
||||||
return $"wss://{CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)}:{_httpsServer.Port}{_httpsServer.WebSocketServices[_path].Path}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsRunning { get => _httpsServer?.IsListening ?? false; }
|
|
||||||
|
|
||||||
|
|
||||||
private readonly ITextFormatter _textFormatter;
|
|
||||||
|
|
||||||
public DebugWebsocketSink(ITextFormatter formatProvider)
|
|
||||||
{
|
|
||||||
|
|
||||||
_textFormatter = formatProvider ?? new JsonFormatter();
|
|
||||||
|
|
||||||
if (!File.Exists($"\\user\\{_certificateName}.pfx"))
|
|
||||||
CreateCert(null);
|
|
||||||
|
|
||||||
CrestronEnvironment.ProgramStatusEventHandler += type =>
|
|
||||||
{
|
|
||||||
if (type == eProgramStatusEventType.Stopping)
|
|
||||||
{
|
|
||||||
StopServer();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CreateCert(string[] args)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//Debug.Console(0,"CreateCert Creating Utility");
|
|
||||||
CrestronConsole.PrintLine("CreateCert Creating Utility");
|
|
||||||
//var utility = new CertificateUtility();
|
|
||||||
var utility = new BouncyCertificate();
|
|
||||||
//Debug.Console(0, "CreateCert Calling CreateCert");
|
|
||||||
CrestronConsole.PrintLine("CreateCert Calling CreateCert");
|
|
||||||
//utility.CreateCert();
|
|
||||||
var ipAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0);
|
|
||||||
var hostName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0);
|
|
||||||
var domainName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, 0);
|
|
||||||
|
|
||||||
//Debug.Console(0, "DomainName: {0} | HostName: {1} | {1}.{0}@{2}", domainName, hostName, ipAddress);
|
|
||||||
CrestronConsole.PrintLine(string.Format("DomainName: {0} | HostName: {1} | {1}.{0}@{2}", domainName, hostName, ipAddress));
|
|
||||||
|
|
||||||
var certificate = utility.CreateSelfSignedCertificate(string.Format("CN={0}.{1}", hostName, domainName), new[] { string.Format("{0}.{1}", hostName, domainName), ipAddress }, new[] { KeyPurposeID.IdKPServerAuth, KeyPurposeID.IdKPClientAuth });
|
|
||||||
//Crestron fails to let us do this...perhaps it should be done through their Dll's but haven't tested
|
|
||||||
//Debug.Print($"CreateCert Storing Certificate To My.LocalMachine");
|
|
||||||
//utility.AddCertToStore(certificate, StoreName.My, StoreLocation.LocalMachine);
|
|
||||||
//Debug.Console(0, "CreateCert Saving Cert to \\user\\");
|
|
||||||
CrestronConsole.PrintLine("CreateCert Saving Cert to \\user\\");
|
|
||||||
utility.CertificatePassword = _certificatePassword;
|
|
||||||
utility.WriteCertificate(certificate, @"\user\", _certificateName);
|
|
||||||
//Debug.Console(0, "CreateCert Ending CreateCert");
|
|
||||||
CrestronConsole.PrintLine("CreateCert Ending CreateCert");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
//Debug.Console(0, "WSS CreateCert Failed\r\n{0}\r\n{1}", ex.Message, ex.StackTrace);
|
|
||||||
CrestronConsole.PrintLine(string.Format("WSS CreateCert Failed\r\n{0}\r\n{1}", ex.Message, ex.StackTrace));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Emit(LogEvent logEvent)
|
public void Emit(LogEvent logEvent)
|
||||||
{
|
{
|
||||||
if (_httpsServer == null || !_httpsServer.IsListening) return;
|
if (logEvent == null || _disposed) return;
|
||||||
|
|
||||||
var sw = new StringWriter();
|
var writer = new StringWriter();
|
||||||
_textFormatter.Format(logEvent, sw);
|
_formatter.Format(logEvent, writer);
|
||||||
|
var json = writer.ToString();
|
||||||
|
var buffer = Encoding.UTF8.GetBytes(json);
|
||||||
|
|
||||||
_httpsServer.WebSocketServices.Broadcast(sw.ToString());
|
lock (_lock)
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StartServerAndSetPort(int port)
|
|
||||||
{
|
|
||||||
Debug.Console(0, "Starting Websocket Server on port: {0}", port);
|
|
||||||
|
|
||||||
|
|
||||||
Start(port, $"\\user\\{_certificateName}.pfx", _certificatePassword);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Start(int port, string certPath = "", string certPassword = "")
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
_httpsServer = new HttpServer(port, true);
|
foreach (var client in _clients.ToArray())
|
||||||
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(certPath))
|
|
||||||
{
|
{
|
||||||
Debug.Console(0, "Assigning SSL Configuration");
|
try
|
||||||
_httpsServer.SslConfiguration = new ServerSslConfiguration(new X509Certificate2(certPath, certPassword))
|
|
||||||
{
|
{
|
||||||
ClientCertificateRequired = false,
|
if (client.State == WebSocketState.Open)
|
||||||
CheckCertificateRevocation = false,
|
|
||||||
EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls,
|
|
||||||
//this is just to test, you might want to actually validate
|
|
||||||
ClientCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
|
|
||||||
{
|
{
|
||||||
Debug.Console(0, "HTTPS ClientCerticateValidation Callback triggered");
|
Task.Run(async () =>
|
||||||
return true;
|
{
|
||||||
|
await client.SendAsync(
|
||||||
|
new ArraySegment<byte>(buffer),
|
||||||
|
WebSocketMessageType.Text,
|
||||||
|
true,
|
||||||
|
CancellationToken.None);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RemoveClient(client);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
Debug.Console(0, "Adding Debug Client Service");
|
|
||||||
_httpsServer.AddWebSocketService<DebugClient>(_path);
|
|
||||||
Debug.Console(0, "Assigning Log Info");
|
|
||||||
_httpsServer.Log.Level = LogLevel.Trace;
|
|
||||||
_httpsServer.Log.Output = (d, s) =>
|
|
||||||
{
|
|
||||||
uint level;
|
|
||||||
|
|
||||||
switch(d.Level)
|
|
||||||
{
|
|
||||||
case WebSocketSharp.LogLevel.Fatal:
|
|
||||||
level = 3;
|
|
||||||
break;
|
|
||||||
case WebSocketSharp.LogLevel.Error:
|
|
||||||
level = 2;
|
|
||||||
break;
|
|
||||||
case WebSocketSharp.LogLevel.Warn:
|
|
||||||
level = 1;
|
|
||||||
break;
|
|
||||||
case WebSocketSharp.LogLevel.Info:
|
|
||||||
level = 0;
|
|
||||||
break;
|
|
||||||
case WebSocketSharp.LogLevel.Debug:
|
|
||||||
level = 4;
|
|
||||||
break;
|
|
||||||
case WebSocketSharp.LogLevel.Trace:
|
|
||||||
level = 5;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
level = 4;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
catch (Exception)
|
||||||
Debug.Console(level, "{1} {0}\rCaller:{2}\rMessage:{3}\rs:{4}", d.Level.ToString(), d.Date.ToString(), d.Caller.ToString(), d.Message, s);
|
{
|
||||||
};
|
RemoveClient(client);
|
||||||
Debug.Console(0, "Starting");
|
}
|
||||||
|
}
|
||||||
_httpsServer.Start();
|
|
||||||
Debug.Console(0, "Ready");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Debug.Console(0, "WebSocket Failed to start {0}", ex.Message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopServer()
|
public void StopServer()
|
||||||
{
|
{
|
||||||
Debug.Console(0, "Stopping Websocket Server");
|
if (_disposed) return;
|
||||||
_httpsServer?.Stop();
|
lock (_lock)
|
||||||
|
{
|
||||||
|
foreach (var client in _clients)
|
||||||
|
{
|
||||||
|
if (client.State == WebSocketState.Open)
|
||||||
|
{
|
||||||
|
client.Abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_clients.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_httpsServer = null;
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_disposed) return;
|
||||||
|
_disposed = true;
|
||||||
|
StopServer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,61 +117,4 @@ namespace PepperDash.Core
|
|||||||
return loggerConfiguration.Sink(new DebugWebsocketSink(formatProvider));
|
return loggerConfiguration.Sink(new DebugWebsocketSink(formatProvider));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DebugClient : WebSocketBehavior
|
|
||||||
{
|
|
||||||
private DateTime _connectionTime;
|
|
||||||
|
|
||||||
public TimeSpan ConnectedDuration
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (Context.WebSocket.IsAlive)
|
|
||||||
{
|
|
||||||
return DateTime.Now - _connectionTime;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new TimeSpan(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public DebugClient()
|
|
||||||
{
|
|
||||||
Debug.Console(0, "DebugClient Created");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnOpen()
|
|
||||||
{
|
|
||||||
base.OnOpen();
|
|
||||||
|
|
||||||
var url = Context.WebSocket.Url;
|
|
||||||
Debug.Console(0, Debug.ErrorLogLevel.Notice, "New WebSocket Connection from: {0}", url);
|
|
||||||
|
|
||||||
_connectionTime = DateTime.Now;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnMessage(MessageEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnMessage(e);
|
|
||||||
|
|
||||||
Debug.Console(0, "WebSocket UiClient Message: {0}", e.Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnClose(CloseEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnClose(e);
|
|
||||||
|
|
||||||
Debug.Console(0, Debug.ErrorLogLevel.Notice, "WebSocket UiClient Closing: {0} reason: {1}", e.Code, e.Reason);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnError(WebSocketSharp.ErrorEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnError(e);
|
|
||||||
|
|
||||||
Debug.Console(2, Debug.ErrorLogLevel.Notice, "WebSocket UiClient Error: {0} message: {1}", e.Exception, e.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,8 @@
|
|||||||
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||||
<PackageReference Include="SSH.NET" Version="2024.2.0" />
|
<PackageReference Include="SSH.NET" Version="2024.2.0" />
|
||||||
<PackageReference Include="WebSocketSharp" Version="1.0.3-rc11" />
|
<!-- WebSocketSharp reference removed -->
|
||||||
|
<!-- System.Net.WebSockets is part of .NET Core -->
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Remove="Comm\._GenericSshClient.cs" />
|
<Compile Remove="Comm\._GenericSshClient.cs" />
|
||||||
|
|||||||
Reference in New Issue
Block a user