mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-02-14 20:24:57 +00:00
Compare commits
12 Commits
v2.17.0-mc
...
v2.17.0-mc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c90027578 | ||
|
|
bb694b4200 | ||
|
|
087d0a1149 | ||
|
|
4747c16b02 | ||
|
|
d33fd56529 | ||
|
|
8fc4d21f02 | ||
|
|
fd70377c7f | ||
|
|
06341b14f3 | ||
|
|
b0a090062f | ||
|
|
9c0cab8218 | ||
|
|
258699fbcd | ||
|
|
738504e9fc |
@@ -23,23 +23,32 @@
|
||||
<FileName>$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cpz</FileName>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="DeleteCLZ" BeforeTargets="PreBuildEvent" Condition="$(ProjectType) == 'Library' And $(TargetDir) != '' And Exists($(FileName))">
|
||||
<Delete Files="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).clz">
|
||||
<Target Name="DeleteCLZ" BeforeTargets="CoreBuild" Condition="$(ProjectType) == 'Library' And $(TargetDir) != ''">
|
||||
<ItemGroup>
|
||||
<OldCLZFiles Include="$(TargetDir)$(TargetName).*.$(TargetFramework).clz" />
|
||||
</ItemGroup>
|
||||
<Delete Files="@(OldCLZFiles)" Condition="@(OldCLZFiles) != ''">
|
||||
<Output TaskParameter="DeletedFiles" ItemName="DeletedList"/>
|
||||
</Delete>
|
||||
<Message Text="Deleted files: '@(DeletedList)'" />
|
||||
<Message Text="Deleted old CLZ files: '@(DeletedList)'" Condition="@(DeletedList) != ''" />
|
||||
</Target>
|
||||
<Target Name="DeleteCPZ" BeforeTargets="PreBuildEvent" Condition="$(ProjectType) == 'Program' And $(TargetDir) != '' And Exists($(FileName))">
|
||||
<Delete Files="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cpz">
|
||||
<Target Name="DeleteCPZ" BeforeTargets="CoreBuild" Condition="$(ProjectType) == 'Program' And $(TargetDir) != ''">
|
||||
<ItemGroup>
|
||||
<OldCPZFiles Include="$(TargetDir)$(TargetName).*.$(TargetFramework).cpz" />
|
||||
</ItemGroup>
|
||||
<Delete Files="@(OldCPZFiles)" Condition="@(OldCPZFiles) != ''">
|
||||
<Output TaskParameter="DeletedFiles" ItemName="DeletedList"/>
|
||||
</Delete>
|
||||
<Message Text="Deleted files: '@(DeletedList)'" />
|
||||
<Message Text="Deleted old CPZ files: '@(DeletedList)'" Condition="@(DeletedList) != ''" />
|
||||
</Target>
|
||||
<Target Name="DeleteCPLZ" BeforeTargets="PreBuildEvent" Condition="$(ProjectType) == 'ProgramLibrary' And $(TargetDir) != '' And Exists($(FileName))">
|
||||
<Delete Files="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cplz">
|
||||
<Target Name="DeleteCPLZ" BeforeTargets="CoreBuild" Condition="$(ProjectType) == 'ProgramLibrary' And $(TargetDir) != ''">
|
||||
<ItemGroup>
|
||||
<OldCPLZFiles Include="$(TargetDir)$(TargetName).*.$(TargetFramework).cplz" />
|
||||
</ItemGroup>
|
||||
<Delete Files="@(OldCPLZFiles)" Condition="@(OldCPLZFiles) != ''">
|
||||
<Output TaskParameter="DeletedFiles" ItemName="DeletedList"/>
|
||||
</Delete>
|
||||
<Message Text="Deleted files: '@(DeletedList)'" />
|
||||
<Message Text="Deleted old CPLZ files: '@(DeletedList)'" Condition="@(DeletedList) != ''" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CreateCPLZ" AfterTargets="Build" Condition="$(ProjectType) == 'ProgramLibrary' And $(TargetDir) != ''" DependsOnTargets="DeleteCPLZ">
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Use this interface on a device or room if it uses custom Mobile Control messengers
|
||||
/// </summary>
|
||||
public interface ICustomMobileControl : IKeyed
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,155 +1,72 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using Crestron.SimplSharpPro;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Use this interface on a device or room if it uses custom Mobile Control messengers
|
||||
/// </summary>
|
||||
public interface ICustomMobileControl : IKeyed
|
||||
{
|
||||
}
|
||||
|
||||
/*/// <summary>
|
||||
/// Describes a MobileControlSystemController
|
||||
/// </summary>
|
||||
public interface IMobileControl : IKeyed
|
||||
{
|
||||
void CreateMobileControlRoomBridge(IEssentialsRoom room, IMobileControl parent);
|
||||
|
||||
void LinkSystemMonitorToAppServer();
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
/// Defines the contract for IMobileControl
|
||||
/// </summary>
|
||||
public interface IMobileControl : IKeyed
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the Host
|
||||
/// </summary>
|
||||
string Host { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Client App URL
|
||||
/// </summary>
|
||||
string ClientAppUrl { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the System UUID
|
||||
/// </summary>
|
||||
string SystemUuid { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ApiOnlineAndAuthorized feedback
|
||||
/// </summary>
|
||||
BoolFeedback ApiOnlineAndAuthorized { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Sends the message object to the AppServer
|
||||
/// </summary>
|
||||
/// <param name="o">Message to send</param>
|
||||
void SendMessageObject(IMobileControlMessage o);
|
||||
|
||||
/// <summary>
|
||||
/// Adds an action for a messenger
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Messenger type. Must implement IMobileControlMessenger</typeparam>
|
||||
/// <param name="messenger">messenger to register</param>
|
||||
/// <param name="action">action to add</param>
|
||||
void AddAction<T>(T messenger, Action<string, string, JToken> action) where T : IMobileControlMessenger;
|
||||
|
||||
/// <summary>
|
||||
/// Removes an action for a messenger
|
||||
/// </summary>
|
||||
/// <param name="key">key for action</param>
|
||||
void RemoveAction(string key);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a device messenger
|
||||
/// </summary>
|
||||
/// <param name="messenger">Messenger to add</param>
|
||||
void AddDeviceMessenger(IMobileControlMessenger messenger);
|
||||
|
||||
/// <summary>
|
||||
/// Check if a device messenger exists
|
||||
/// </summary>
|
||||
/// <param name="key">Messenger key to find</param>
|
||||
bool CheckForDeviceMessenger(string key);
|
||||
|
||||
/// <summary>
|
||||
/// Get a Room Messenger by key
|
||||
/// </summary>
|
||||
/// <param name="key">messenger key to find</param>
|
||||
/// <returns>Messenger if found, null otherwise</returns>
|
||||
IMobileControlRoomMessenger GetRoomMessenger(string key);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the contract for IMobileControlMessenger
|
||||
/// </summary>
|
||||
public interface IMobileControlMessenger : IKeyed
|
||||
{
|
||||
IMobileControl AppServerController { get; }
|
||||
string MessagePath { get; }
|
||||
|
||||
string DeviceKey { get; }
|
||||
void RegisterWithAppServer(IMobileControl appServerController);
|
||||
}
|
||||
|
||||
public interface IMobileControlMessage
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
string Type { get; }
|
||||
|
||||
[JsonProperty("clientId", NullValueHandling = NullValueHandling.Ignore)]
|
||||
string ClientId { get; }
|
||||
|
||||
[JsonProperty("content", NullValueHandling = NullValueHandling.Ignore)]
|
||||
JToken Content { get; }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the contract for IMobileControlRoomMessenger
|
||||
/// </summary>
|
||||
public interface IMobileControlRoomMessenger : IKeyed
|
||||
{
|
||||
event EventHandler<EventArgs> UserCodeChanged;
|
||||
|
||||
event EventHandler<EventArgs> UserPromptedForCode;
|
||||
|
||||
event EventHandler<EventArgs> ClientJoined;
|
||||
|
||||
event EventHandler<EventArgs> AppUrlChanged;
|
||||
|
||||
string UserCode { get; }
|
||||
|
||||
string QrCodeUrl { get; }
|
||||
|
||||
string QrCodeChecksum { get; }
|
||||
|
||||
string McServerUrl { get; }
|
||||
|
||||
string RoomName { get; }
|
||||
|
||||
string AppUrl { get; }
|
||||
|
||||
void UpdateAppUrl(string url);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the contract for IMobileControlAction
|
||||
/// </summary>
|
||||
public interface IMobileControlAction
|
||||
{
|
||||
IMobileControlMessenger Messenger { get; }
|
||||
|
||||
Action<string, string, JToken> Action { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the contract for IMobileControlTouchpanelController
|
||||
/// </summary>
|
||||
public interface IMobileControlTouchpanelController : IKeyed
|
||||
{
|
||||
/// <summary>
|
||||
/// The default room key for the controller
|
||||
/// </summary>
|
||||
string DefaultRoomKey { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the application URL for the controller
|
||||
/// </summary>
|
||||
/// <param name="url">The application URL</param>
|
||||
void SetAppUrl(string url);
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the controller uses a direct server connection
|
||||
/// </summary>
|
||||
bool UseDirectServer { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the controller is a Zoom Room controller
|
||||
/// </summary>
|
||||
bool ZoomRoomController { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes a MobileControl Crestron Touchpanel Controller
|
||||
/// This interface extends the IMobileControlTouchpanelController to include connected IP information
|
||||
/// </summary>
|
||||
public interface IMobileControlCrestronTouchpanelController : IMobileControlTouchpanelController
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a collection of connected IP information for the touchpanel controller
|
||||
/// </summary>
|
||||
ReadOnlyCollection<ConnectedIpInformation> ConnectedIps { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for IMobileControlAction
|
||||
/// </summary>
|
||||
public interface IMobileControlAction
|
||||
{
|
||||
IMobileControlMessenger Messenger { get; }
|
||||
|
||||
Action<string, string, JToken> Action { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using Crestron.SimplSharpPro;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a MobileControl Crestron Touchpanel Controller
|
||||
/// This interface extends the IMobileControlTouchpanelController to include connected IP information
|
||||
/// </summary>
|
||||
public interface IMobileControlCrestronTouchpanelController : IMobileControlTouchpanelController
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a collection of connected IP information for the touchpanel controller
|
||||
/// </summary>
|
||||
ReadOnlyCollection<ConnectedIpInformation> ConnectedIps { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
public interface IMobileControlMessage
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
string Type { get; }
|
||||
|
||||
[JsonProperty("clientId", NullValueHandling = NullValueHandling.Ignore)]
|
||||
string ClientId { get; }
|
||||
|
||||
[JsonProperty("content", NullValueHandling = NullValueHandling.Ignore)]
|
||||
JToken Content { get; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for IMobileControlMessenger
|
||||
/// </summary>
|
||||
public interface IMobileControlMessenger : IKeyed
|
||||
{
|
||||
/// <summary>
|
||||
/// Parent controller for this messenger
|
||||
/// </summary>
|
||||
IMobileControl AppServerController { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Path to listen for messages
|
||||
/// </summary>
|
||||
string MessagePath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Key of the device this messenger is associated with
|
||||
/// </summary>
|
||||
string DeviceKey { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Register this messenger with the AppServerController
|
||||
/// </summary>
|
||||
/// <param name="appServerController"></param>
|
||||
void RegisterWithAppServer(IMobileControl appServerController);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for IMobileControlMessenger
|
||||
/// </summary>
|
||||
public interface IMobileControlMessengerWithSubscriptions : IMobileControlMessenger
|
||||
{
|
||||
/// <summary>
|
||||
/// Unsubscribe a client from this messenger
|
||||
/// </summary>
|
||||
/// <param name="clientId"></param>
|
||||
void UnsubscribeClient(string clientId);
|
||||
|
||||
/// <summary>
|
||||
/// Register this messenger with the AppServerController
|
||||
/// </summary>
|
||||
/// <param name="appServerController">parent for this messenger</param>
|
||||
/// <param name="enableMessengerSubscriptions">Enable messenger subscriptions</param>
|
||||
void RegisterWithAppServer(IMobileControl appServerController, bool enableMessengerSubscriptions);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for IMobileControlRoomMessenger
|
||||
/// </summary>
|
||||
public interface IMobileControlRoomMessenger : IKeyed
|
||||
{
|
||||
event EventHandler<EventArgs> UserCodeChanged;
|
||||
|
||||
event EventHandler<EventArgs> UserPromptedForCode;
|
||||
|
||||
event EventHandler<EventArgs> ClientJoined;
|
||||
|
||||
event EventHandler<EventArgs> AppUrlChanged;
|
||||
|
||||
string UserCode { get; }
|
||||
|
||||
string QrCodeUrl { get; }
|
||||
|
||||
string QrCodeChecksum { get; }
|
||||
|
||||
string McServerUrl { get; }
|
||||
|
||||
string RoomName { get; }
|
||||
|
||||
string AppUrl { get; }
|
||||
|
||||
void UpdateAppUrl(string url);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for IMobileControlTouchpanelController
|
||||
/// </summary>
|
||||
public interface IMobileControlTouchpanelController : IKeyed
|
||||
{
|
||||
/// <summary>
|
||||
/// The default room key for the controller
|
||||
/// </summary>
|
||||
string DefaultRoomKey { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the application URL for the controller
|
||||
/// </summary>
|
||||
/// <param name="url">The application URL</param>
|
||||
void SetAppUrl(string url);
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the controller uses a direct server connection
|
||||
/// </summary>
|
||||
bool UseDirectServer { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the controller is a Zoom Room controller
|
||||
/// </summary>
|
||||
bool ZoomRoomController { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PepperDash.Essentials.AppServer.Messengers
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for event messages that include the type of message and an event type
|
||||
/// </summary>
|
||||
public abstract class DeviceEventMessageBase : DeviceMessageBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The event type
|
||||
/// </summary>
|
||||
[JsonProperty("eventType")]
|
||||
public string EventType { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PepperDash.Essentials.AppServer.Messengers
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for device messages that include the type of message
|
||||
/// </summary>
|
||||
public abstract class DeviceMessageBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The device key
|
||||
/// </summary>
|
||||
[JsonProperty("key")]
|
||||
/// <summary>
|
||||
/// Gets or sets the Key
|
||||
/// </summary>
|
||||
public string Key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The device name
|
||||
/// </summary>
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of the message class
|
||||
/// </summary>
|
||||
[JsonProperty("messageType")]
|
||||
public string MessageType => GetType().Name;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the MessageBasePath
|
||||
/// </summary>
|
||||
[JsonProperty("messageBasePath")]
|
||||
|
||||
public string MessageBasePath { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PepperDash.Essentials.AppServer.Messengers
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a DeviceStateMessageBase
|
||||
/// </summary>
|
||||
public class DeviceStateMessageBase : DeviceMessageBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The interfaces implmented by the device sending the messsage
|
||||
/// </summary>
|
||||
[JsonProperty("interfaces")]
|
||||
public List<string> Interfaces { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the interfaces implemented by the device sending the message
|
||||
/// </summary>
|
||||
/// <param name="interfaces"></param>
|
||||
public void SetInterfaces(List<string> interfaces)
|
||||
{
|
||||
Interfaces = interfaces;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -53,8 +53,8 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
||||
{
|
||||
IsOnline = _communicationMonitor.CommunicationMonitor.IsOnline,
|
||||
Status = _communicationMonitor.CommunicationMonitor.Status
|
||||
}
|
||||
});
|
||||
},
|
||||
}, id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
||||
PowerState = _powerControl.PowerIsOnFeedback.BoolValue
|
||||
};
|
||||
|
||||
PostStatusMessage(messageObj);
|
||||
PostStatusMessage(messageObj, id);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -20,9 +20,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
||||
|
||||
protected override void RegisterActions()
|
||||
{
|
||||
AddAction("/status", (id, content) =>
|
||||
SendFullStatus(id)
|
||||
);
|
||||
AddAction("/status", (id, content) => SendFullStatus(id));
|
||||
|
||||
AddAction("/shutdownPromptStatus", (id, content) => SendFullStatus(id));
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Crestron.SimplSharp.Net;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Core.Logging;
|
||||
@@ -13,14 +13,33 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
||||
/// <summary>
|
||||
/// Provides a messaging bridge
|
||||
/// </summary>
|
||||
public abstract class MessengerBase : EssentialsDevice, IMobileControlMessenger
|
||||
public abstract class MessengerBase : EssentialsDevice, IMobileControlMessengerWithSubscriptions
|
||||
{
|
||||
/// <summary>
|
||||
/// The device this messenger is associated with
|
||||
/// </summary>
|
||||
protected IKeyName _device;
|
||||
|
||||
/// <summary>
|
||||
/// Enable subscriptions
|
||||
/// </summary>
|
||||
protected bool enableMessengerSubscriptions;
|
||||
|
||||
/// <summary>
|
||||
/// List of clients subscribed to this messenger
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Unsoliciited feedback from a device in a messenger will ONLY be sent to devices in this subscription list. When a client disconnects, it's ID will be removed from the collection.
|
||||
/// </remarks>
|
||||
protected HashSet<string> SubscriberIds = new HashSet<string>();
|
||||
|
||||
private readonly List<string> _deviceInterfaces;
|
||||
|
||||
private readonly Dictionary<string, Action<string, JToken>> _actions = new Dictionary<string, Action<string, JToken>>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the DeviceKey
|
||||
/// </summary>
|
||||
public string DeviceKey => _device?.Key ?? "";
|
||||
|
||||
|
||||
@@ -50,6 +69,12 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
||||
MessagePath = messagePath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for a messenger associated with a device
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="messagePath"></param>
|
||||
/// <param name="device"></param>
|
||||
protected MessengerBase(string key, string messagePath, IKeyName device)
|
||||
: this(key, messagePath)
|
||||
{
|
||||
@@ -81,6 +106,21 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
||||
RegisterActions();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register this messenger with appserver controller
|
||||
/// </summary>
|
||||
/// <param name="appServerController">Parent controller for this messenger</param>
|
||||
/// <param name="enableMessengerSubscriptions">Enable subscriptions</param>
|
||||
public void RegisterWithAppServer(IMobileControl appServerController, bool enableMessengerSubscriptions)
|
||||
{
|
||||
this.enableMessengerSubscriptions = enableMessengerSubscriptions;
|
||||
AppServerController = appServerController ?? throw new ArgumentNullException("appServerController");
|
||||
|
||||
AppServerController.AddAction(this, HandleMessage);
|
||||
|
||||
RegisterActions();
|
||||
}
|
||||
|
||||
private void HandleMessage(string path, string id, JToken content)
|
||||
{
|
||||
// replace base path with empty string. Should leave something like /fullStatus
|
||||
@@ -91,16 +131,20 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Executing action for path {path}", this, path);
|
||||
this.LogDebug("Executing action for path {path}", path);
|
||||
|
||||
action(id, content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an action for a given path
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="action"></param>
|
||||
protected void AddAction(string path, Action<string, JToken> action)
|
||||
{
|
||||
if (_actions.ContainsKey(path))
|
||||
{
|
||||
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Messenger {Key} already has action registered at {path}", this);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -115,6 +159,10 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
||||
return _actions.Keys.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes an action for a given path
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
protected void RemoveAction(string path)
|
||||
{
|
||||
if (!_actions.ContainsKey(path))
|
||||
@@ -128,17 +176,62 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
||||
/// <summary>
|
||||
/// Implemented in extending classes. Wire up API calls and feedback here
|
||||
/// </summary>
|
||||
/// <param name="appServerController"></param>
|
||||
protected virtual void RegisterActions()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add client to the susbscription list for unsolicited feedback
|
||||
/// </summary>
|
||||
/// <param name="clientId">Client ID to add</param>
|
||||
protected void SubscribeClient(string clientId)
|
||||
{
|
||||
if (!enableMessengerSubscriptions)
|
||||
{
|
||||
this.LogWarning("Messenger subscriptions not enabled");
|
||||
return;
|
||||
}
|
||||
|
||||
if (SubscriberIds.Any(id => id == clientId))
|
||||
{
|
||||
this.LogVerbose("Client {clientId} already subscribed", clientId);
|
||||
return;
|
||||
}
|
||||
|
||||
SubscriberIds.Add(clientId);
|
||||
|
||||
this.LogDebug("Client {clientId} subscribed", clientId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a client from the subscription list
|
||||
/// </summary>
|
||||
/// <param name="clientId">Client ID to remove</param>
|
||||
public void UnsubscribeClient(string clientId)
|
||||
{
|
||||
if (!enableMessengerSubscriptions)
|
||||
{
|
||||
this.LogWarning("Messenger subscriptions not enabled");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SubscriberIds.Any(i => i == clientId))
|
||||
{
|
||||
this.LogVerbose("Client with ID {clientId} is not subscribed", clientId);
|
||||
return;
|
||||
}
|
||||
|
||||
SubscriberIds.RemoveWhere((i) => i == clientId);
|
||||
|
||||
this.LogInformation("Client with ID {clientId} unsubscribed", clientId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper for posting status message
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="clientId">Optional client id that will direct the message back to only that client</param>
|
||||
protected void PostStatusMessage(DeviceStateMessageBase message, string clientId = null)
|
||||
{
|
||||
try
|
||||
@@ -169,6 +262,12 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper for posting status message
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="deviceState"></param>
|
||||
/// <param name="clientId">Optional client id that will direct the message back to only that client</param>
|
||||
protected void PostStatusMessage(string type, DeviceStateMessageBase deviceState, string clientId = null)
|
||||
{
|
||||
try
|
||||
@@ -192,18 +291,50 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper for posting status message
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="clientId">Optional client id that will direct the message back to only that client</param>
|
||||
protected void PostStatusMessage(JToken content, string type = "", string clientId = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Allow for legacy method to continue without subscriptions
|
||||
if (!enableMessengerSubscriptions)
|
||||
{
|
||||
AppServerController?.SendMessageObject(new MobileControlMessage { Type = !string.IsNullOrEmpty(type) ? type : MessagePath, ClientId = clientId, Content = content });
|
||||
return;
|
||||
}
|
||||
|
||||
// handle subscription feedback
|
||||
// If client is null or empty, this message is unsolicited feedback. Iterate through the subscriber list and send to all interested parties
|
||||
if (string.IsNullOrEmpty(clientId))
|
||||
{
|
||||
foreach (var client in SubscriberIds)
|
||||
{
|
||||
AppServerController?.SendMessageObject(new MobileControlMessage { Type = !string.IsNullOrEmpty(type) ? type : MessagePath, ClientId = client, Content = content });
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SubscribeClient(clientId);
|
||||
|
||||
AppServerController?.SendMessageObject(new MobileControlMessage { Type = !string.IsNullOrEmpty(type) ? type : MessagePath, ClientId = clientId, Content = content });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Exception posting status message", this);
|
||||
this.LogError("Exception posting status message: {message}", ex.Message);
|
||||
this.LogDebug(ex, "Stack Trace: ");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper for posting event message
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
protected void PostEventMessage(DeviceEventMessageBase message)
|
||||
{
|
||||
message.Key = _device.Key;
|
||||
@@ -217,6 +348,11 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper for posting event message
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="eventType"></param>
|
||||
protected void PostEventMessage(DeviceEventMessageBase message, string eventType)
|
||||
{
|
||||
message.Key = _device.Key;
|
||||
@@ -232,6 +368,10 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper for posting event message with no content
|
||||
/// </summary>
|
||||
/// <param name="eventType"></param>
|
||||
protected void PostEventMessage(string eventType)
|
||||
{
|
||||
AppServerController?.SendMessageObject(new MobileControlMessage
|
||||
@@ -242,64 +382,4 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract class DeviceMessageBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The device key
|
||||
/// </summary>
|
||||
[JsonProperty("key")]
|
||||
/// <summary>
|
||||
/// Gets or sets the Key
|
||||
/// </summary>
|
||||
public string Key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The device name
|
||||
/// </summary>
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of the message class
|
||||
/// </summary>
|
||||
[JsonProperty("messageType")]
|
||||
public string MessageType => GetType().Name;
|
||||
|
||||
[JsonProperty("messageBasePath")]
|
||||
/// <summary>
|
||||
/// Gets or sets the MessageBasePath
|
||||
/// </summary>
|
||||
public string MessageBasePath { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a DeviceStateMessageBase
|
||||
/// </summary>
|
||||
public class DeviceStateMessageBase : DeviceMessageBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The interfaces implmented by the device sending the messsage
|
||||
/// </summary>
|
||||
[JsonProperty("interfaces")]
|
||||
public List<string> Interfaces { get; private set; }
|
||||
|
||||
public void SetInterfaces(List<string> interfaces)
|
||||
{
|
||||
Interfaces = interfaces;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base class for event messages that include the type of message and an event type
|
||||
/// </summary>
|
||||
public abstract class DeviceEventMessageBase : DeviceMessageBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The event type
|
||||
/// </summary>
|
||||
[JsonProperty("eventType")]
|
||||
public string EventType { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
|
||||
namespace PepperDash.Essentials
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a ClientSpecificUpdateRequest
|
||||
/// </summary>
|
||||
public class ClientSpecificUpdateRequest
|
||||
{
|
||||
public ClientSpecificUpdateRequest(Action<string> action)
|
||||
{
|
||||
ResponseMethod = action;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ResponseMethod
|
||||
/// </summary>
|
||||
public Action<string> ResponseMethod { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,12 @@ namespace PepperDash.Essentials
|
||||
/// </summary>
|
||||
[JsonProperty("enableApiServer")]
|
||||
public bool EnableApiServer { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Enable subscriptions for Messengers
|
||||
/// </summary>
|
||||
[JsonProperty("enableMessengerSubscriptions")]
|
||||
public bool EnableMessengerSubscriptions { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -78,6 +84,15 @@ namespace PepperDash.Essentials
|
||||
[JsonProperty("csLanUiDeviceKeys")]
|
||||
public List<string> CSLanUiDeviceKeys { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get or set the Secure property
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Indicates whether the connection is secure (HTTPS).
|
||||
/// </remarks>
|
||||
[JsonProperty("Secure")]
|
||||
public bool Secure { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the MobileControlDirectServerPropertiesConfig class.
|
||||
/// </summary>
|
||||
|
||||
@@ -54,7 +54,10 @@ namespace PepperDash.Essentials
|
||||
StringComparer.InvariantCultureIgnoreCase
|
||||
);
|
||||
|
||||
public Dictionary<string, List<IMobileControlAction>> ActionDictionary => _actionDictionary;
|
||||
/// <summary>
|
||||
/// Actions
|
||||
/// </summary>
|
||||
public ReadOnlyDictionary<string, List<IMobileControlAction>> ActionDictionary => new ReadOnlyDictionary<string, List<IMobileControlAction>>(_actionDictionary);
|
||||
|
||||
private readonly GenericQueue _receiveQueue;
|
||||
private readonly List<MobileControlBridgeBase> _roomBridges =
|
||||
@@ -66,6 +69,16 @@ namespace PepperDash.Essentials
|
||||
private readonly Dictionary<string, IMobileControlMessenger> _defaultMessengers =
|
||||
new Dictionary<string, IMobileControlMessenger>();
|
||||
|
||||
/// <summary>
|
||||
/// Get the custom messengers with subscriptions
|
||||
/// </summary>
|
||||
public ReadOnlyDictionary<string, IMobileControlMessengerWithSubscriptions> Messengers => new ReadOnlyDictionary<string, IMobileControlMessengerWithSubscriptions>(_messengers.Values.OfType<IMobileControlMessengerWithSubscriptions>().ToDictionary(k => k.Key, v => v));
|
||||
|
||||
/// <summary>
|
||||
/// Get the default messengers
|
||||
/// </summary>
|
||||
public ReadOnlyDictionary<string, IMobileControlMessengerWithSubscriptions> DefaultMessengers => new ReadOnlyDictionary<string, IMobileControlMessengerWithSubscriptions>(_defaultMessengers.Values.OfType<IMobileControlMessengerWithSubscriptions>().ToDictionary(k => k.Key, v => v));
|
||||
|
||||
private readonly GenericQueue _transmitToServerQueue;
|
||||
|
||||
private readonly GenericQueue _transmitToClientsQueue;
|
||||
@@ -1199,8 +1212,7 @@ namespace PepperDash.Essentials
|
||||
|
||||
if (_initialized)
|
||||
{
|
||||
this.LogDebug("Registering messenger {messengerKey} AFTER initialization", messenger.Key);
|
||||
messenger.RegisterWithAppServer(this);
|
||||
RegisterMessengerWithServer(messenger);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1241,6 +1253,12 @@ namespace PepperDash.Essentials
|
||||
messenger.MessagePath
|
||||
);
|
||||
|
||||
if (messenger is IMobileControlMessengerWithSubscriptions subMessenger)
|
||||
{
|
||||
subMessenger.RegisterWithAppServer(this, Config.EnableMessengerSubscriptions);
|
||||
return;
|
||||
}
|
||||
|
||||
messenger.RegisterWithAppServer(this);
|
||||
}
|
||||
|
||||
@@ -1335,11 +1353,30 @@ namespace PepperDash.Essentials
|
||||
{
|
||||
Log =
|
||||
{
|
||||
Output = (data, s) =>
|
||||
this.LogDebug(
|
||||
"Message from websocket: {message}",
|
||||
data
|
||||
)
|
||||
Output = (data, message) =>
|
||||
{
|
||||
switch (data.Level)
|
||||
{
|
||||
case LogLevel.Trace:
|
||||
this.LogVerbose(data.Message);
|
||||
break;
|
||||
case LogLevel.Debug:
|
||||
this.LogDebug(data.Message);
|
||||
break;
|
||||
case LogLevel.Info:
|
||||
this.LogInformation(data.Message);
|
||||
break;
|
||||
case LogLevel.Warn:
|
||||
this.LogWarning(data.Message);
|
||||
break;
|
||||
case LogLevel.Error:
|
||||
this.LogError(data.Message);
|
||||
break;
|
||||
case LogLevel.Fatal:
|
||||
this.LogFatal(data.Message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1383,13 +1420,13 @@ namespace PepperDash.Essentials
|
||||
|
||||
private void SetWebsocketDebugLevel(string cmdparameters)
|
||||
{
|
||||
if (CrestronEnvironment.ProgramCompatibility == eCrestronSeries.Series4)
|
||||
{
|
||||
this.LogInformation(
|
||||
"Setting websocket log level not currently allowed on 4 series."
|
||||
);
|
||||
return; // Web socket log level not currently allowed in series4
|
||||
}
|
||||
// if (CrestronEnvironment.ProgramCompatibility == eCrestronSeries.Series4)
|
||||
// {
|
||||
// this.LogInformation(
|
||||
// "Setting websocket log level not currently allowed on 4 series."
|
||||
// );
|
||||
// return; // Web socket log level not currently allowed in series4
|
||||
// }
|
||||
|
||||
if (string.IsNullOrEmpty(cmdparameters))
|
||||
{
|
||||
@@ -1415,6 +1452,8 @@ namespace PepperDash.Essentials
|
||||
_wsClient2.Log.Level = _wsLogLevel;
|
||||
}
|
||||
|
||||
_directServer?.SetWebsocketLogLevel(_wsLogLevel);
|
||||
|
||||
CrestronConsole.ConsoleCommandResponse($"Websocket log level set to {debugLevel}");
|
||||
}
|
||||
catch
|
||||
@@ -2420,33 +2459,4 @@ namespace PepperDash.Essentials
|
||||
CrestronConsole.ConsoleCommandResponse("Usage: mobilehttprequest:N get/post url\r");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a ClientSpecificUpdateRequest
|
||||
/// </summary>
|
||||
public class ClientSpecificUpdateRequest
|
||||
{
|
||||
public ClientSpecificUpdateRequest(Action<string> action)
|
||||
{
|
||||
ResponseMethod = action;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ResponseMethod
|
||||
/// </summary>
|
||||
public Action<string> ResponseMethod { get; private set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a UserCodeChanged
|
||||
/// </summary>
|
||||
public class UserCodeChanged
|
||||
{
|
||||
public Action<string, string> UpdateUserCode { get; private set; }
|
||||
|
||||
public UserCodeChanged(Action<string, string> updateMethod)
|
||||
{
|
||||
UpdateUserCode = updateMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ using PepperDash.Essentials.Core.DeviceInfo;
|
||||
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
|
||||
using PepperDash.Essentials.Core.UI;
|
||||
using Feedback = PepperDash.Essentials.Core.Feedback;
|
||||
using IPAddress = System.Net.IPAddress;
|
||||
|
||||
namespace PepperDash.Essentials.Touchpanel
|
||||
{
|
||||
@@ -106,11 +107,14 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
/// </summary>
|
||||
public DeviceInfo DeviceInfo => new DeviceInfo();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of connected IPs for this IpId
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<ConnectedIpInformation> ConnectedIps => Panel.ConnectedIpList;
|
||||
|
||||
private System.Net.IPAddress csIpAddress;
|
||||
private readonly IPAddress csIpAddress;
|
||||
|
||||
private System.Net.IPAddress csSubnetMask;
|
||||
private readonly IPAddress csSubnetMask;
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -190,12 +194,19 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
|
||||
RegisterForExtenders();
|
||||
|
||||
var csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter);
|
||||
var csSubnetMask = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, csAdapterId);
|
||||
var csIpAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId);
|
||||
try
|
||||
{
|
||||
var csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter);
|
||||
var csSubnetMask = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, csAdapterId);
|
||||
var csIpAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId);
|
||||
|
||||
this.csSubnetMask = System.Net.IPAddress.Parse(csSubnetMask);
|
||||
this.csIpAddress = System.Net.IPAddress.Parse(csIpAddress);
|
||||
this.csSubnetMask = IPAddress.Parse(csSubnetMask);
|
||||
this.csIpAddress = IPAddress.Parse(csIpAddress);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Debug.LogInformation("This processor does not have a CS LAN", this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -226,7 +237,7 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
{
|
||||
x70Panel.ExtenderApplicationControlReservedSigs.DeviceExtenderSigChange += (e, a) =>
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"X70 App Control Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}");
|
||||
this.LogVerbose("X70 App Control Device Extender args: {event}:{sig}:{type}:{boolValue}:{ushortValue}:{stringValue}", a.Event, a.Sig, a.Sig.Type, a.Sig.BoolValue, a.Sig.UShortValue, a.Sig.StringValue);
|
||||
|
||||
UpdateZoomFeedbacks();
|
||||
|
||||
@@ -245,7 +256,7 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
|
||||
x70Panel.ExtenderZoomRoomAppReservedSigs.DeviceExtenderSigChange += (e, a) =>
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"X70 Zoom Room Ap Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}");
|
||||
this.LogVerbose("X70 Zoom Room App Device Extender args: {event}:{sig}:{type}:{boolValue}:{ushortValue}:{stringValue}", a.Event, a.Sig, a.Sig.Type, a.Sig.BoolValue, a.Sig.UShortValue, a.Sig.StringValue);
|
||||
|
||||
if (a.Sig.Number == x70Panel.ExtenderZoomRoomAppReservedSigs.ZoomRoomIncomingCallFeedback.Number)
|
||||
{
|
||||
@@ -263,7 +274,7 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
DeviceInfo.MacAddress = x70Panel.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue;
|
||||
DeviceInfo.IpAddress = x70Panel.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue;
|
||||
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, this, $"MAC: {DeviceInfo.MacAddress} IP: {DeviceInfo.IpAddress}");
|
||||
this.LogDebug("MAC: {macAddress} IP: {ipAddress}", DeviceInfo.MacAddress, DeviceInfo.IpAddress);
|
||||
|
||||
var handler = DeviceInfoChanged;
|
||||
|
||||
@@ -293,7 +304,7 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
{
|
||||
x60withZoomApp.ExtenderApplicationControlReservedSigs.DeviceExtenderSigChange += (e, a) =>
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"X60 App Control Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}");
|
||||
this.LogVerbose("X60 App Control Device Extender args: {event}:{sig}:{type}:{boolValue}:{ushortValue}:{stringValue}", a.Event, a.Sig, a.Sig.Type, a.Sig.BoolValue, a.Sig.UShortValue, a.Sig.StringValue);
|
||||
|
||||
if (a.Sig.Number == x60withZoomApp.ExtenderApplicationControlReservedSigs.HideOpenApplicationFeedback.Number)
|
||||
{
|
||||
@@ -302,7 +313,7 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
};
|
||||
x60withZoomApp.ExtenderZoomRoomAppReservedSigs.DeviceExtenderSigChange += (e, a) =>
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"X60 Zoom Room App Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}");
|
||||
this.LogVerbose("X60 Zoom Room App Device Extender args: {event}:{sig}:{type}:{boolValue}:{ushortValue}:{stringValue}", a.Event, a.Sig, a.Sig.Type, a.Sig.BoolValue, a.Sig.UShortValue, a.Sig.StringValue);
|
||||
|
||||
if (a.Sig.Number == x60withZoomApp.ExtenderZoomRoomAppReservedSigs.ZoomRoomIncomingCallFeedback.Number)
|
||||
{
|
||||
@@ -319,7 +330,7 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
DeviceInfo.MacAddress = x60withZoomApp.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue;
|
||||
DeviceInfo.IpAddress = x60withZoomApp.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue;
|
||||
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, this, $"MAC: {DeviceInfo.MacAddress} IP: {DeviceInfo.IpAddress}");
|
||||
this.LogDebug("MAC: {macAddress} IP: {ipAddress}", DeviceInfo.MacAddress, DeviceInfo.IpAddress);
|
||||
|
||||
var handler = DeviceInfoChanged;
|
||||
|
||||
@@ -381,7 +392,7 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
/// <param name="args">The signal event arguments containing the changed signal information.</param>
|
||||
protected override void ExtenderSystemReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"System Device Extender args: ${args.Event}:${args.Sig}");
|
||||
this.LogVerbose("System Device Extender args: {event}:{sig}", args.Event, args.Sig);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -436,7 +447,7 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
|
||||
var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, lanAdapterId);
|
||||
|
||||
if(csIpAddress == null || csSubnetMask == null || url == null)
|
||||
if (csIpAddress == null || csSubnetMask == null || url == null)
|
||||
{
|
||||
this.LogWarning("CS IP Address Subnet Mask or url is null, cannot determine correct IP for URL");
|
||||
return url;
|
||||
@@ -447,7 +458,7 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
|
||||
var ip = ConnectedIps.Any(ipInfo =>
|
||||
{
|
||||
if (System.Net.IPAddress.TryParse(ipInfo.DeviceIpAddress, out var parsedIp))
|
||||
if (IPAddress.TryParse(ipInfo.DeviceIpAddress, out var parsedIp))
|
||||
{
|
||||
return csIpAddress.IsInSameSubnet(parsedIp, csSubnetMask);
|
||||
}
|
||||
@@ -481,7 +492,7 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
|
||||
if (mcList.Count == 0)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, this, $"No Mobile Control controller found");
|
||||
this.LogError("No Mobile Control controller found");
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -493,7 +504,7 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
|
||||
if (bridge == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, this, $"No Mobile Control bridge for {_config.DefaultRoomKey} found ");
|
||||
this.LogInformation("No Mobile Control bridge for {roomKey} found", _config.DefaultRoomKey);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -502,7 +513,7 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
_bridge.UserCodeChanged += UpdateFeedbacks;
|
||||
_bridge.AppUrlChanged += (s, a) =>
|
||||
{
|
||||
this.LogInformation("AppURL changed");
|
||||
this.LogInformation("AppURL changed: {appURL}", _bridge.AppUrl);
|
||||
SetAppUrl(_bridge.AppUrl);
|
||||
UpdateFeedbacks(s, a);
|
||||
};
|
||||
@@ -538,7 +549,7 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
{
|
||||
foreach (var feedback in ZoomFeedbacks)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, this, $"Updating {feedback.Key}");
|
||||
this.LogDebug("Updating {feedbackKey}", feedback.Key);
|
||||
feedback.FireUpdate();
|
||||
}
|
||||
}
|
||||
@@ -574,7 +585,7 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
|
||||
if (Panel is TswX60WithZoomRoomAppReservedSigs)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, this, $"X60 panel does not support zoom app");
|
||||
this.LogInformation("X60 panel does not support zoom app");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -650,7 +661,16 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
handler(this, new DeviceInfoEventArgs(DeviceInfo));
|
||||
}
|
||||
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, this, $"MAC: {DeviceInfo.MacAddress} IP: {DeviceInfo.IpAddress}");
|
||||
this.LogDebug("MAC: {macAddress} IP: {ipAddress}", DeviceInfo.MacAddress, DeviceInfo.IpAddress);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Force a reload of the iframe on the panel connected to this IP ID
|
||||
/// </summary>
|
||||
public void ReloadIframe()
|
||||
{
|
||||
this.LogInformation("Pulsing join 1");
|
||||
Panel.PulseBool(1, 100);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -659,6 +679,8 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
/// </summary>
|
||||
public class MobileControlTouchpanelControllerFactory : EssentialsPluginDeviceFactory<MobileControlTouchpanelController>
|
||||
{
|
||||
private Dictionary<string, Func<uint, CrestronControlSystem, string, BasicTriListWithSmartObject>> factories;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the MobileControlTouchpanelControllerFactory class.
|
||||
/// Sets up supported device type names and minimum framework version requirements.
|
||||
@@ -667,6 +689,31 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
{
|
||||
TypeNames = new List<string>() { "mccrestronapp", "mctsw550", "mctsw750", "mctsw1050", "mctsw560", "mctsw760", "mctsw1060", "mctsw570", "mctsw770", "mcts770", "mctsw1070", "mcts1070", "mcxpanel", "mcdge1000" };
|
||||
MinimumEssentialsFrameworkVersion = "2.0.0";
|
||||
|
||||
factories = new Dictionary<string, Func<uint, CrestronControlSystem, string, BasicTriListWithSmartObject>>
|
||||
{
|
||||
{"crestronapp", (id, controlSystem, projectName) => {
|
||||
var app = new CrestronApp(id, Global.ControlSystem);
|
||||
app.ParameterProjectName.Value = projectName;
|
||||
return app;
|
||||
}},
|
||||
{"xpanel", (id, controlSystem, projectName) => new XpanelForHtml5(id, controlSystem)},
|
||||
{"tsw550", (id, controlSystem, projectName) => new Tsw550(id, controlSystem)},
|
||||
{"tsw552", (id, controlSystem, projectName) => new Tsw552(id, controlSystem)},
|
||||
{"tsw560", (id, controlSystem, projectName) => new Tsw560(id, controlSystem)},
|
||||
{"tsw750", (id, controlSystem, projectName) => new Tsw750(id, controlSystem)},
|
||||
{"tsw752", (id, controlSystem, projectName) => new Tsw752(id, controlSystem)},
|
||||
{"tsw760", (id, controlSystem, projectName) => new Tsw760(id, controlSystem)},
|
||||
{"tsw1050", (id, controlSystem, projectName) => new Tsw1050(id, controlSystem)},
|
||||
{"tsw1052", (id, controlSystem, projectName) => new Tsw1052(id, controlSystem)},
|
||||
{"tsw1060", (id, controlSystem, projectName) => new Tsw1060(id, controlSystem)},
|
||||
{"tsw570", (id, controlSystem, projectName) => new Tsw570(id, controlSystem)},
|
||||
{"tsw770", (id, controlSystem, projectName) => new Tsw770(id, controlSystem)},
|
||||
{"ts770", (id, controlSystem, projectName) => new Ts770(id, controlSystem)},
|
||||
{"tsw1070", (id, controlSystem, projectName) => new Tsw1070(id, controlSystem)},
|
||||
{"ts1070", (id, controlSystem, projectName) => new Ts1070(id, controlSystem)},
|
||||
{"dge1000", (id, controlSystem, projectName) => new Dge1000(id, controlSystem)}
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -686,10 +733,10 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
|
||||
if (panel == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Unable to create Touchpanel for type {0}. Touchpanel Controller WILL NOT function correctly", dc.Type);
|
||||
Debug.LogError("Unable to create Touchpanel for type {type}. Touchpanel Controller WILL NOT function correctly", dc.Type);
|
||||
}
|
||||
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Factory Attempting to create new MobileControlTouchpanelController");
|
||||
Debug.LogDebug("Factory Attempting to create new MobileControlTouchpanelController");
|
||||
|
||||
var panelController = new MobileControlTouchpanelController(dc.Key, dc.Name, panel, props);
|
||||
|
||||
@@ -699,56 +746,21 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
private BasicTriListWithSmartObject GetPanelForType(string type, uint id, string projectName)
|
||||
{
|
||||
type = type.ToLower().Replace("mc", "");
|
||||
|
||||
try
|
||||
{
|
||||
if (type == "crestronapp")
|
||||
if (!factories.TryGetValue(type, out var buildCrestronHardwareDevice))
|
||||
{
|
||||
var app = new CrestronApp(id, Global.ControlSystem);
|
||||
app.ParameterProjectName.Value = projectName;
|
||||
return app;
|
||||
}
|
||||
else if (type == "xpanel")
|
||||
return new XpanelForHtml5(id, Global.ControlSystem);
|
||||
else if (type == "tsw550")
|
||||
return new Tsw550(id, Global.ControlSystem);
|
||||
else if (type == "tsw552")
|
||||
return new Tsw552(id, Global.ControlSystem);
|
||||
else if (type == "tsw560")
|
||||
return new Tsw560(id, Global.ControlSystem);
|
||||
else if (type == "tsw750")
|
||||
return new Tsw750(id, Global.ControlSystem);
|
||||
else if (type == "tsw752")
|
||||
return new Tsw752(id, Global.ControlSystem);
|
||||
else if (type == "tsw760")
|
||||
return new Tsw760(id, Global.ControlSystem);
|
||||
else if (type == "tsw1050")
|
||||
return new Tsw1050(id, Global.ControlSystem);
|
||||
else if (type == "tsw1052")
|
||||
return new Tsw1052(id, Global.ControlSystem);
|
||||
else if (type == "tsw1060")
|
||||
return new Tsw1060(id, Global.ControlSystem);
|
||||
else if (type == "tsw570")
|
||||
return new Tsw570(id, Global.ControlSystem);
|
||||
else if (type == "tsw770")
|
||||
return new Tsw770(id, Global.ControlSystem);
|
||||
else if (type == "ts770")
|
||||
return new Ts770(id, Global.ControlSystem);
|
||||
else if (type == "tsw1070")
|
||||
return new Tsw1070(id, Global.ControlSystem);
|
||||
else if (type == "ts1070")
|
||||
return new Ts1070(id, Global.ControlSystem);
|
||||
else if (type == "dge1000")
|
||||
return new Dge1000(id, Global.ControlSystem);
|
||||
else
|
||||
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "WARNING: Cannot create TSW controller with type '{0}'", type);
|
||||
Debug.LogError("Cannot create TSW controller with type {type}", type);
|
||||
return null;
|
||||
}
|
||||
|
||||
return buildCrestronHardwareDevice(id, Global.ControlSystem, projectName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "WARNING: Cannot create TSW base class. Panel will not function: {0}", e.Message);
|
||||
Debug.LogError("Cannot create TSW base class. Panel will not function: {message}", e.Message);
|
||||
Debug.LogDebug(e, "Stack Trace: ");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
17
src/PepperDash.Essentials.MobileControl/UserCodeChanged.cs
Normal file
17
src/PepperDash.Essentials.MobileControl/UserCodeChanged.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
|
||||
namespace PepperDash.Essentials
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a UserCodeChanged
|
||||
/// </summary>
|
||||
public class UserCodeChanged
|
||||
{
|
||||
public Action<string, string> UpdateUserCode { get; private set; }
|
||||
|
||||
public UserCodeChanged(Action<string, string> updateMethod)
|
||||
{
|
||||
UpdateUserCode = updateMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Represents info about a device including supproted interfaces
|
||||
/// </summary>
|
||||
public class DeviceInterfaceInfo : IKeyName
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the Key
|
||||
/// </summary>
|
||||
[JsonProperty("key")]
|
||||
public string Key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Name
|
||||
/// </summary>
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Interfaces
|
||||
/// </summary>
|
||||
[JsonProperty("interfaces")]
|
||||
public List<string> Interfaces { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.WebSocketServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a JoinResponse
|
||||
/// </summary>
|
||||
public class JoinResponse
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ClientId
|
||||
/// </summary>
|
||||
[JsonProperty("clientId")]
|
||||
public string ClientId { get; set; }
|
||||
|
||||
[JsonProperty("roomKey")]
|
||||
public string RoomKey { get; set; }
|
||||
|
||||
[JsonProperty("systemUUid")]
|
||||
public string SystemUuid { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the RoomUuid
|
||||
/// </summary>
|
||||
[JsonProperty("roomUUid")]
|
||||
public string RoomUuid { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Config
|
||||
/// </summary>
|
||||
[JsonProperty("config")]
|
||||
public object Config { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the CodeExpires
|
||||
/// </summary>
|
||||
[JsonProperty("codeExpires")]
|
||||
public DateTime CodeExpires { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the UserCode
|
||||
/// </summary>
|
||||
[JsonProperty("userCode")]
|
||||
public string UserCode { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the UserAppUrl
|
||||
/// </summary>
|
||||
[JsonProperty("userAppUrl")]
|
||||
public string UserAppUrl { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the EnableDebug
|
||||
/// </summary>
|
||||
[JsonProperty("enableDebug")]
|
||||
public bool EnableDebug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the DeviceInterfaceSupport
|
||||
/// </summary>
|
||||
[JsonProperty("deviceInterfaceSupport")]
|
||||
public Dictionary<string, DeviceInterfaceInfo> DeviceInterfaceSupport { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace PepperDash.Essentials.WebSocketServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a JoinToken
|
||||
/// </summary>
|
||||
public class JoinToken
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the Code
|
||||
/// </summary>
|
||||
public string Code { get; set; }
|
||||
|
||||
public string RoomKey { get; set; }
|
||||
|
||||
public string Uuid { get; set; }
|
||||
|
||||
public string TouchpanelKey { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Token
|
||||
/// </summary>
|
||||
public string Token { get; set; } = null;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Security.Authentication;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.WebScripting;
|
||||
@@ -35,6 +37,10 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
private readonly string appConfigFileName = "_config.local.json";
|
||||
private readonly string appConfigCsFileName = "_config.cs.json";
|
||||
|
||||
private const string certificateName = "selfCres";
|
||||
|
||||
private const string certificatePassword = "cres12345";
|
||||
|
||||
/// <summary>
|
||||
/// Where the key is the join token and the value is the room key
|
||||
/// </summary>
|
||||
@@ -155,7 +161,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Automatically forwarding port {0} to CS LAN", Port);
|
||||
this.LogInformation("Automatically forwarding port {port} to CS LAN", Port);
|
||||
|
||||
var csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter);
|
||||
var csIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId);
|
||||
@@ -164,16 +170,17 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
|
||||
if (result != CrestronEthernetHelper.PortForwardingUserPatRetCodes.NoErr)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Error, "Error adding port forwarding: {0}", result);
|
||||
this.LogError("Error adding port forwarding: {error}", result);
|
||||
}
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "This processor does not have a CS LAN", this);
|
||||
this.LogInformation("This processor does not have a CS LAN", this);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Error automatically forwarding port to CS LAN");
|
||||
this.LogError("Error automatically forwarding port to CS LAN: {message}", ex.Message);
|
||||
this.LogDebug(ex, "Stack Trace");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +197,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
{
|
||||
if (parent.Config.DirectServer.AutomaticallyForwardPortToCSLAN == false)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "This processor does not have a CS LAN", this);
|
||||
this.LogInformation("This processor does not have a CS LAN");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,13 +266,49 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
_server.OnPost += Server_OnPost;
|
||||
}
|
||||
|
||||
if (_parent.Config.DirectServer.Secure)
|
||||
{
|
||||
this.LogInformation("Adding SSL Configuration to server");
|
||||
_server.SslConfiguration = new ServerSslConfiguration(new X509Certificate2($"\\user\\{certificateName}.pfx", certificatePassword))
|
||||
{
|
||||
ClientCertificateRequired = false,
|
||||
CheckCertificateRevocation = false,
|
||||
EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11
|
||||
};
|
||||
}
|
||||
|
||||
_server.Log.Output = (data, message) =>
|
||||
{
|
||||
switch (data.Level)
|
||||
{
|
||||
case LogLevel.Trace:
|
||||
this.LogVerbose(data.Message);
|
||||
break;
|
||||
case LogLevel.Debug:
|
||||
this.LogDebug(data.Message);
|
||||
break;
|
||||
case LogLevel.Info:
|
||||
this.LogInformation(data.Message);
|
||||
break;
|
||||
case LogLevel.Warn:
|
||||
this.LogWarning(data.Message);
|
||||
break;
|
||||
case LogLevel.Error:
|
||||
this.LogError(data.Message);
|
||||
break;
|
||||
case LogLevel.Fatal:
|
||||
this.LogFatal(data.Message);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler;
|
||||
|
||||
_server.Start();
|
||||
|
||||
if (_server.IsListening)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Mobile Control WebSocket Server listening on port {port}", this, _server.Port);
|
||||
this.LogInformation("Mobile Control WebSocket Server listening on port {port}", _server.Port);
|
||||
}
|
||||
|
||||
CrestronEnvironment.ProgramStatusEventHandler += OnProgramStop;
|
||||
@@ -278,10 +321,17 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Exception intializing websocket server", this);
|
||||
this.LogError("Exception initializing direct server: {message}", ex.Message);
|
||||
this.LogDebug(ex, "Stack Trace");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetWebsocketLogLevel(LogLevel level)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse($"Setting direct server debug level to {level}", level.ToString());
|
||||
_server.Log.Level = level;
|
||||
}
|
||||
|
||||
private void AddClientsForTouchpanels()
|
||||
{
|
||||
var touchpanels = DeviceManager.AllDevices
|
||||
@@ -347,22 +397,6 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
|
||||
string ip = processorIp;
|
||||
|
||||
// Moved to the MobileControlTouchpanelController class in the GetUrlWithCorrectIp method
|
||||
// triggered by the Panel.IpInformationChange event so that we know we have the necessary info
|
||||
// to make the determination of which IP to use.
|
||||
//if (touchpanel.Touchpanel is IMobileControlCrestronTouchpanelController crestronTouchpanel && csIpAddress != null)
|
||||
//{
|
||||
// ip = crestronTouchpanel.ConnectedIps.Any(ipInfo =>
|
||||
// {
|
||||
// if (System.Net.IPAddress.TryParse(ipInfo.DeviceIpAddress, out var parsedIp))
|
||||
// {
|
||||
// return csIpAddress.IsInSameSubnet(parsedIp, csSubnetMask);
|
||||
// }
|
||||
// this.LogWarning("Invalid IP address: {deviceIpAddress}", ipInfo.DeviceIpAddress);
|
||||
// return false;
|
||||
// }) ? csIpAddress.ToString() : processorIp;
|
||||
//}
|
||||
|
||||
if (_parent.Config.DirectServer.CSLanUiDeviceKeys != null && _parent.Config.DirectServer.CSLanUiDeviceKeys.Any(k => k.Equals(touchpanel.Touchpanel.Key, StringComparison.InvariantCultureIgnoreCase)) && csIpAddress != null)
|
||||
{
|
||||
ip = csIpAddress.ToString();
|
||||
@@ -477,7 +511,8 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.LogError(ex, "Error getting application configuration");
|
||||
this.LogError("Error getting application configuration: {message}", ex.Message);
|
||||
this.LogDebug(ex, "Stack Trace");
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -513,15 +548,14 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
{
|
||||
if (token.Value == null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Warning, "Token value is null", this);
|
||||
this.LogWarning("Token value is null");
|
||||
continue;
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, "Adding token: {0} for room: {1}", this, token.Key, token.Value.RoomKey);
|
||||
this.LogInformation("Adding token: {key} for room: {roomKey}", token.Key, token.Value.RoomKey);
|
||||
|
||||
if (UiClients == null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Warning, "UiClients is null", this);
|
||||
UiClients = new Dictionary<string, UiClientContext>();
|
||||
}
|
||||
|
||||
@@ -531,7 +565,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
|
||||
if (UiClients.Count > 0)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Restored {uiClientCount} UiClients from secrets data", this, UiClients.Count);
|
||||
this.LogInformation("Restored {uiClientCount} UiClients from secrets data", UiClients.Count);
|
||||
|
||||
foreach (var client in UiClients)
|
||||
{
|
||||
@@ -541,36 +575,28 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
|
||||
_server.AddWebSocketService(path, () =>
|
||||
{
|
||||
var c = new UiClient();
|
||||
Debug.LogMessage(LogEventLevel.Debug, "Constructing UiClient with id: {key}", this, key);
|
||||
var c = new UiClient($"uiclient-{key}-{roomKey}");
|
||||
this.LogDebug("Constructing UiClient with id: {key}", key);
|
||||
|
||||
c.Controller = _parent;
|
||||
c.RoomKey = roomKey;
|
||||
UiClients[key].SetClient(c);
|
||||
return c;
|
||||
});
|
||||
|
||||
|
||||
//_server.WebSocketServices.AddService<UiClient>(path, (c) =>
|
||||
//{
|
||||
// Debug.Console(2, this, "Constructing UiClient with id: {0}", key);
|
||||
// c.Controller = _parent;
|
||||
// c.RoomKey = roomKey;
|
||||
// UiClients[key].SetClient(c);
|
||||
//});
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Warning, "No secret found");
|
||||
this.LogWarning("No secret found");
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Debug, "{uiClientCount} UiClients restored from secrets data", this, UiClients.Count);
|
||||
this.LogDebug("{uiClientCount} UiClients restored from secrets data", UiClients.Count);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Exception retrieving secret", this);
|
||||
this.LogError("Exception retrieving secret: {message}", ex.Message);
|
||||
this.LogDebug(ex, "Stack Trace");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -583,7 +609,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
{
|
||||
if (_secret == null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Error, "Secret is null", this);
|
||||
this.LogError("Secret is null");
|
||||
|
||||
_secret = new ServerTokenSecrets(string.Empty);
|
||||
}
|
||||
@@ -601,7 +627,8 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Exception updating secret", this);
|
||||
this.LogError("Exception updating secret: {message}", ex.Message);
|
||||
this.LogDebug(ex, "Stack Trace");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -704,18 +731,18 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
|
||||
_server.AddWebSocketService(path, () =>
|
||||
{
|
||||
var c = new UiClient();
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "Constructing UiClient with id: {0}", this, key);
|
||||
var c = new UiClient($"uiclient-{key}-{bridge.RoomKey}");
|
||||
this.LogVerbose("Constructing UiClient with id: {key}", key);
|
||||
c.Controller = _parent;
|
||||
c.RoomKey = bridge.RoomKey;
|
||||
UiClients[key].SetClient(c);
|
||||
return c;
|
||||
});
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, "Added new WebSocket UiClient service at path: {path}", this, path);
|
||||
Debug.LogMessage(LogEventLevel.Information, "Token: {@token}", this, token);
|
||||
this.LogInformation("Added new WebSocket UiClient service at path: {path}", path);
|
||||
this.LogInformation("Token: {@token}", token);
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "{serviceCount} websocket services present", this, _server.WebSocketServices.Count);
|
||||
this.LogVerbose("{serviceCount} websocket services present", _server.WebSocketServices.Count);
|
||||
|
||||
UpdateSecret();
|
||||
|
||||
@@ -729,7 +756,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
{
|
||||
if (s == "?" || string.IsNullOrEmpty(s))
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse(@"Removes all clients from the server. To execute add 'confirm' to command");
|
||||
CrestronConsole.ConsoleCommandResponse(@"Remove all clients from the server. To execute add 'confirm' to command");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -883,7 +910,8 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Caught an exception in the OnGet handler", this);
|
||||
this.LogError("Exception in OnGet handler: {message}", ex.Message);
|
||||
this.LogDebug(ex, "Stack Trace");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -972,6 +1000,20 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
res.StatusCode = 200;
|
||||
res.ContentType = "application/json";
|
||||
|
||||
var devices = DeviceManager.GetDevices();
|
||||
Dictionary<string, DeviceInterfaceInfo> deviceInterfaces = new Dictionary<string, DeviceInterfaceInfo>();
|
||||
|
||||
foreach (var device in devices)
|
||||
{
|
||||
var interfaces = device?.GetType().GetInterfaces().Select((i) => i.Name).ToList() ?? new List<string>();
|
||||
deviceInterfaces.Add(device.Key, new DeviceInterfaceInfo
|
||||
{
|
||||
Key = device.Key,
|
||||
Name = device is IKeyName ? (device as IKeyName).Name : "",
|
||||
Interfaces = interfaces
|
||||
});
|
||||
}
|
||||
|
||||
// Construct the response object
|
||||
JoinResponse jRes = new JoinResponse
|
||||
{
|
||||
@@ -985,7 +1027,8 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
UserAppUrl = string.Format("http://{0}:{1}/mc/app",
|
||||
CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0),
|
||||
Port),
|
||||
EnableDebug = false
|
||||
EnableDebug = false,
|
||||
DeviceInterfaceSupport = deviceInterfaces
|
||||
};
|
||||
|
||||
// Serialize to JSON and convert to Byte[]
|
||||
@@ -1171,7 +1214,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
}
|
||||
else
|
||||
{
|
||||
this.LogVerbose("File not found: {filePath}", filePath);
|
||||
this.LogWarning("File not found: {filePath}", filePath);
|
||||
res.StatusCode = (int)HttpStatusCode.NotFound;
|
||||
res.Close();
|
||||
return;
|
||||
@@ -1241,152 +1284,4 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Version
|
||||
/// </summary>
|
||||
public class Version
|
||||
{
|
||||
[JsonProperty("serverVersion")]
|
||||
public string ServerVersion { get; set; }
|
||||
|
||||
[JsonProperty("serverIsRunningOnProcessorHardware")]
|
||||
public bool ServerIsRunningOnProcessorHardware { get; private set; }
|
||||
|
||||
public Version()
|
||||
{
|
||||
ServerIsRunningOnProcessorHardware = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a UiClientContext
|
||||
/// </summary>
|
||||
public class UiClientContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the Client
|
||||
/// </summary>
|
||||
public UiClient Client { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the Token
|
||||
/// </summary>
|
||||
public JoinToken Token { get; private set; }
|
||||
|
||||
public UiClientContext(JoinToken token)
|
||||
{
|
||||
Token = token;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SetClient method
|
||||
/// </summary>
|
||||
public void SetClient(UiClient client)
|
||||
{
|
||||
Client = client;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a ServerTokenSecrets
|
||||
/// </summary>
|
||||
public class ServerTokenSecrets
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the GrantCode
|
||||
/// </summary>
|
||||
public string GrantCode { get; set; }
|
||||
|
||||
public Dictionary<string, JoinToken> Tokens { get; set; }
|
||||
|
||||
public ServerTokenSecrets(string grantCode)
|
||||
{
|
||||
GrantCode = grantCode;
|
||||
Tokens = new Dictionary<string, JoinToken>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a JoinToken
|
||||
/// </summary>
|
||||
public class JoinToken
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the Code
|
||||
/// </summary>
|
||||
public string Code { get; set; }
|
||||
|
||||
public string RoomKey { get; set; }
|
||||
|
||||
public string Uuid { get; set; }
|
||||
|
||||
public string TouchpanelKey { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Token
|
||||
/// </summary>
|
||||
public string Token { get; set; } = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a JoinResponse
|
||||
/// </summary>
|
||||
public class JoinResponse
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ClientId
|
||||
/// </summary>
|
||||
[JsonProperty("clientId")]
|
||||
public string ClientId { get; set; }
|
||||
|
||||
[JsonProperty("roomKey")]
|
||||
public string RoomKey { get; set; }
|
||||
|
||||
[JsonProperty("systemUUid")]
|
||||
public string SystemUuid { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the RoomUuid
|
||||
/// </summary>
|
||||
[JsonProperty("roomUUid")]
|
||||
public string RoomUuid { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Config
|
||||
/// </summary>
|
||||
[JsonProperty("config")]
|
||||
public object Config { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the CodeExpires
|
||||
/// </summary>
|
||||
[JsonProperty("codeExpires")]
|
||||
public DateTime CodeExpires { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the UserCode
|
||||
/// </summary>
|
||||
[JsonProperty("userCode")]
|
||||
public string UserCode { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the UserAppUrl
|
||||
/// </summary>
|
||||
[JsonProperty("userAppUrl")]
|
||||
public string UserAppUrl { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the EnableDebug
|
||||
/// </summary>
|
||||
[JsonProperty("enableDebug")]
|
||||
public bool EnableDebug { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.WebSocketServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a ServerTokenSecrets
|
||||
/// </summary>
|
||||
public class ServerTokenSecrets
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the GrantCode
|
||||
/// </summary>
|
||||
public string GrantCode { get; set; }
|
||||
|
||||
public Dictionary<string, JoinToken> Tokens { get; set; }
|
||||
|
||||
public ServerTokenSecrets(string grantCode)
|
||||
{
|
||||
GrantCode = grantCode;
|
||||
Tokens = new Dictionary<string, JoinToken>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,50 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Core.Logging;
|
||||
using PepperDash.Essentials.AppServer.Messengers;
|
||||
using PepperDash.Essentials.RoomBridges;
|
||||
using Serilog.Events;
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using WebSocketSharp;
|
||||
using WebSocketSharp.Server;
|
||||
using ErrorEventArgs = WebSocketSharp.ErrorEventArgs;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.WebSocketServer
|
||||
{
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the behaviour to associate with a UiClient for WebSocket communication
|
||||
/// </summary>
|
||||
public class UiClient : WebSocketBehavior
|
||||
public class UiClient : WebSocketBehavior, IKeyed
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string Key { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the mobile control system controller that handles this client's messages
|
||||
/// </summary>
|
||||
public MobileControlSystemController Controller { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the room key that this client is associated with
|
||||
/// </summary>
|
||||
public string RoomKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The unique identifier for this client instance
|
||||
/// </summary>
|
||||
private string _clientId;
|
||||
|
||||
/// <summary>
|
||||
/// The timestamp when this client connection was established
|
||||
/// </summary>
|
||||
private DateTime _connectionTime;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the duration that this client has been connected. Returns zero if not currently connected.
|
||||
/// </summary>
|
||||
public TimeSpan ConnectedDuration
|
||||
{
|
||||
get
|
||||
@@ -41,17 +60,22 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
}
|
||||
}
|
||||
|
||||
public UiClient()
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the UiClient class with the specified key
|
||||
/// </summary>
|
||||
/// <param name="key">The unique key to identify this client</param>
|
||||
public UiClient(string key)
|
||||
{
|
||||
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnOpen()
|
||||
{
|
||||
base.OnOpen();
|
||||
|
||||
var url = Context.WebSocket.Url;
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "New WebSocket Connection from: {0}", null, url);
|
||||
this.LogInformation("New WebSocket Connection from: {url}", url);
|
||||
|
||||
var match = Regex.Match(url.AbsoluteUri, "(?:ws|wss):\\/\\/.*(?:\\/mc\\/api\\/ui\\/join\\/)(.*)");
|
||||
|
||||
@@ -94,11 +118,21 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
// TODO: Future: Check token to see if there's already an open session using that token and reject/close the session
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the UserCodeChanged event from a room bridge and sends the updated user code to the client
|
||||
/// </summary>
|
||||
/// <param name="sender">The room bridge that raised the event</param>
|
||||
/// <param name="e">Event arguments</param>
|
||||
private void Bridge_UserCodeChanged(object sender, EventArgs e)
|
||||
{
|
||||
SendUserCodeToClient((MobileControlEssentialsRoomBridge)sender, _clientId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends the current user code and QR code URL to the specified client
|
||||
/// </summary>
|
||||
/// <param name="bridge">The room bridge containing the user code information</param>
|
||||
/// <param name="clientId">The ID of the client to send the information to</param>
|
||||
private void SendUserCodeToClient(MobileControlBridgeBase bridge, string clientId)
|
||||
{
|
||||
var content = new
|
||||
@@ -117,6 +151,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
Controller.SendMessageObjectToDirectClient(message);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnMessage(MessageEventArgs e)
|
||||
{
|
||||
base.OnMessage(e);
|
||||
@@ -128,18 +163,31 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnClose(CloseEventArgs e)
|
||||
{
|
||||
base.OnClose(e);
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Closing: {0} reason: {1}", null, e.Code, e.Reason);
|
||||
this.LogInformation("WebSocket UiClient Closing: {code} reason: {reason}", e.Code, e.Reason);
|
||||
|
||||
foreach (var messenger in Controller.Messengers)
|
||||
{
|
||||
messenger.Value.UnsubscribeClient(_clientId);
|
||||
}
|
||||
|
||||
foreach (var messenger in Controller.DefaultMessengers)
|
||||
{
|
||||
messenger.Value.UnsubscribeClient(_clientId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnError(ErrorEventArgs e)
|
||||
{
|
||||
base.OnError(e);
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Error: {exception} message: {message}", e.Exception, e.Message);
|
||||
this.LogError("WebSocket UiClient Error: {message}", e.Message);
|
||||
this.LogDebug(e.Exception, "Stack Trace");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
namespace PepperDash.Essentials.WebSocketServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a UiClientContext
|
||||
/// </summary>
|
||||
public class UiClientContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the Client
|
||||
/// </summary>
|
||||
public UiClient Client { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the Token
|
||||
/// </summary>
|
||||
public JoinToken Token { get; private set; }
|
||||
|
||||
public UiClientContext(JoinToken token)
|
||||
{
|
||||
Token = token;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SetClient method
|
||||
/// </summary>
|
||||
public void SetClient(UiClient client)
|
||||
{
|
||||
Client = client;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.WebSocketServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a Version
|
||||
/// </summary>
|
||||
public class Version
|
||||
{
|
||||
[JsonProperty("serverVersion")]
|
||||
public string ServerVersion { get; set; }
|
||||
|
||||
[JsonProperty("serverIsRunningOnProcessorHardware")]
|
||||
public bool ServerIsRunningOnProcessorHardware { get; private set; }
|
||||
|
||||
public Version()
|
||||
{
|
||||
ServerIsRunningOnProcessorHardware = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user