mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-08-31 19:08:29 +00:00
feat(mobile-control): track and validate UI client app versions
Extend the /system/clientJoined handler to accept an optional `appVersion` field reported by connecting UI clients (e.g. the React app's build-time APP_VERSION), so Essentials can record and validate what's actually running against the configured versions.touchpanelWrapperApp version. - Add ConnectedClientVersionInfo to capture clientId, roomKey, touchpanelKey, reported/expected app version, and last-seen time. - Add MobileControlSystemController.TrackClientAppVersion(), storing results in a new thread-safe ConnectedClientVersions dictionary and logging a warning on version mismatch. - Expose ConnectedClientVersions as a public read-only property for diagnostics. - Surface reported vs. expected versions per client in the `mobileinfo` console command output. No wire protocol changes required; content is passed as-is over the existing clientJoined message.
This commit is contained in:
parent
c323c872fc
commit
02216372bc
2 changed files with 136 additions and 0 deletions
|
|
@ -0,0 +1,47 @@
|
||||||
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the version information reported by a connected Mobile Control UI client
|
||||||
|
/// </summary>
|
||||||
|
public class ConnectedClientVersionInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the client id
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("clientId")]
|
||||||
|
public string ClientId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the room key the client joined
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("roomKey")]
|
||||||
|
public string RoomKey { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the touchpanel key the client joined as, if any
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("touchpanelKey")]
|
||||||
|
public string TouchpanelKey { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the app version reported by the client (e.g. the React app's build-time APP_VERSION)
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("appVersion")]
|
||||||
|
public string AppVersion { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the expected app version from the system config's versions.touchpanelWrapperApp, if configured
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("expectedAppVersion")]
|
||||||
|
public string ExpectedAppVersion { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the UTC time the client last reported this version
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("lastSeen")]
|
||||||
|
public DateTime LastSeen { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -69,11 +69,32 @@ namespace PepperDash.Essentials
|
||||||
private readonly Dictionary<string, IMobileControlMessenger> _defaultMessengers =
|
private readonly Dictionary<string, IMobileControlMessenger> _defaultMessengers =
|
||||||
new Dictionary<string, IMobileControlMessenger>();
|
new Dictionary<string, IMobileControlMessenger>();
|
||||||
|
|
||||||
|
private readonly Dictionary<string, ConnectedClientVersionInfo> _connectedClientVersions =
|
||||||
|
new Dictionary<string, ConnectedClientVersionInfo>(StringComparer.InvariantCultureIgnoreCase);
|
||||||
|
|
||||||
|
private readonly object _connectedClientVersionsLock = new object();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the custom messengers with subscriptions
|
/// Get the custom messengers with subscriptions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ReadOnlyDictionary<string, IMobileControlMessengerWithSubscriptions> Messengers => new ReadOnlyDictionary<string, IMobileControlMessengerWithSubscriptions>(_messengers.Values.OfType<IMobileControlMessengerWithSubscriptions>().ToDictionary(k => k.Key, v => v));
|
public ReadOnlyDictionary<string, IMobileControlMessengerWithSubscriptions> Messengers => new ReadOnlyDictionary<string, IMobileControlMessengerWithSubscriptions>(_messengers.Values.OfType<IMobileControlMessengerWithSubscriptions>().ToDictionary(k => k.Key, v => v));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the most recently reported UI app version for each connected client, keyed by clientId
|
||||||
|
/// </summary>
|
||||||
|
public ReadOnlyDictionary<string, ConnectedClientVersionInfo> ConnectedClientVersions
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (_connectedClientVersionsLock)
|
||||||
|
{
|
||||||
|
return new ReadOnlyDictionary<string, ConnectedClientVersionInfo>(
|
||||||
|
new Dictionary<string, ConnectedClientVersionInfo>(_connectedClientVersions)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the default messengers
|
/// Get the default messengers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -1782,6 +1803,28 @@ namespace PepperDash.Essentials
|
||||||
" Not Enabled in Config.\r\n"
|
" Not Enabled in Config.\r\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var connectedClientVersions = ConnectedClientVersions;
|
||||||
|
|
||||||
|
if (connectedClientVersions.Count == 0)
|
||||||
|
{
|
||||||
|
CrestronConsole.ConsoleCommandResponse("\r\nUI Client App Versions: None reported yet\r\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CrestronConsole.ConsoleCommandResponse("\r\nUI Client App Versions:\r\n");
|
||||||
|
foreach (var kv in connectedClientVersions)
|
||||||
|
{
|
||||||
|
var v = kv.Value;
|
||||||
|
var match = string.IsNullOrEmpty(v.ExpectedAppVersion) || string.Equals(v.ExpectedAppVersion, v.AppVersion, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
CrestronConsole.ConsoleCommandResponse(
|
||||||
|
$" Client: {v.ClientId} Touchpanel: {v.TouchpanelKey} Room: {v.RoomKey}\r\n" +
|
||||||
|
$" Reported: {v.AppVersion} Expected: {v.ExpectedAppVersion ?? "(not configured)"} Match: {(match ? "Yes" : "NO - MISMATCH")}\r\n" +
|
||||||
|
$" Last Seen (UTC): {v.LastSeen:yyyy-MM-dd HH:mm:ss}\r\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -2181,6 +2224,8 @@ namespace PepperDash.Essentials
|
||||||
var roomKey = content["roomKey"].Value<string>();
|
var roomKey = content["roomKey"].Value<string>();
|
||||||
var touchpanelKey = content.SelectToken("touchpanelKey");
|
var touchpanelKey = content.SelectToken("touchpanelKey");
|
||||||
|
|
||||||
|
TrackClientAppVersion(clientId, roomKey, touchpanelKey?.Value<string>(), content.SelectToken("appVersion")?.Value<string>());
|
||||||
|
|
||||||
if (_roomCombiner == null)
|
if (_roomCombiner == null)
|
||||||
{
|
{
|
||||||
var message = new MobileControlMessage
|
var message = new MobileControlMessage
|
||||||
|
|
@ -2252,6 +2297,50 @@ namespace PepperDash.Essentials
|
||||||
SendTouchpanelKey(clientId, touchpanelKey);
|
SendTouchpanelKey(clientId, touchpanelKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Records the app version reported by a connecting UI client (e.g. the mobile control React app's
|
||||||
|
/// build-time APP_VERSION) and compares it against the configured versions.touchpanelWrapperApp version.
|
||||||
|
/// </summary>
|
||||||
|
private void TrackClientAppVersion(string clientId, string roomKey, string touchpanelKey, string appVersion)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(appVersion))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var expectedVersion = ConfigReader.ConfigObject?.Versions?.TouchpanelWrapperApp?.Version;
|
||||||
|
|
||||||
|
var info = new ConnectedClientVersionInfo
|
||||||
|
{
|
||||||
|
ClientId = clientId,
|
||||||
|
RoomKey = roomKey,
|
||||||
|
TouchpanelKey = touchpanelKey,
|
||||||
|
AppVersion = appVersion,
|
||||||
|
ExpectedAppVersion = expectedVersion,
|
||||||
|
LastSeen = DateTime.UtcNow
|
||||||
|
};
|
||||||
|
|
||||||
|
lock (_connectedClientVersionsLock)
|
||||||
|
{
|
||||||
|
_connectedClientVersions[clientId] = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(expectedVersion) && !string.Equals(expectedVersion, appVersion, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
this.LogWarning(
|
||||||
|
"Client {clientId} (touchpanel {touchpanelKey}) reported UI app version {appVersion}, which does not match configured versions.touchpanelWrapperApp version {expectedVersion}",
|
||||||
|
clientId, touchpanelKey, appVersion, expectedVersion
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.LogVerbose(
|
||||||
|
"Client {clientId} (touchpanel {touchpanelKey}) reported UI app version {appVersion}",
|
||||||
|
clientId, touchpanelKey, appVersion
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void SendTouchpanelKey(string clientId, JToken touchpanelKeyToken)
|
private void SendTouchpanelKey(string clientId, JToken touchpanelKeyToken)
|
||||||
{
|
{
|
||||||
if (touchpanelKeyToken == null)
|
if (touchpanelKeyToken == null)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue