From f8738a9053a060ee3f4c3f44398b468041682f06 Mon Sep 17 00:00:00 2001 From: Jonathan Arndt Date: Wed, 19 Aug 2026 12:38:53 -0700 Subject: [PATCH] feat(messenger): implement client-specific event messaging for tech password validation --- .../Messengers/ITechPasswordMessenger.cs | 24 +++++++++++++++++-- .../Messengers/MessengerBase.cs | 23 ++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITechPasswordMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITechPasswordMessenger.cs index 283ef0c8..45453bc1 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITechPasswordMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITechPasswordMessenger.cs @@ -11,6 +11,15 @@ namespace PepperDash.Essentials.AppServer.Messengers { private readonly ITechPassword _room; + // Captures the id of the client whose /validateTechPassword request is in flight, so the + // TechPasswordValidateResult handler below can reply to only that client instead of + // broadcasting to every connected panel. Relies on ValidateTechPassword firing the event + // synchronously (true for all known ITechPassword implementations); if a future + // implementation validates asynchronously, _pendingClientId will already be null when the + // handler runs and this degrades to the previous broadcast behavior. + private readonly object _pendingLock = new object(); + private string _pendingClientId; + public ITechPasswordMessenger(string key, string messagePath, ITechPassword room) : base(key, messagePath, room as IKeyName) { @@ -28,7 +37,12 @@ namespace PepperDash.Essentials.AppServer.Messengers { var password = content.Value("password"); - _room.ValidateTechPassword(password); + lock (_pendingLock) + { + _pendingClientId = id; + _room.ValidateTechPassword(password); + _pendingClientId = null; + } }); AddAction("/setTechPassword", (id, content) => @@ -45,12 +59,18 @@ namespace PepperDash.Essentials.AppServer.Messengers _room.TechPasswordValidateResult += (sender, args) => { + string clientId; + lock (_pendingLock) + { + clientId = _pendingClientId; + } + var evt = new ITechPasswordEventMessage { IsValid = args.IsValid }; - PostEventMessage(evt, "passwordValidationResult"); + PostEventMessage(evt, "passwordValidationResult", clientId); }; } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/MessengerBase.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/MessengerBase.cs index eb3afec3..cd59db6e 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/MessengerBase.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/MessengerBase.cs @@ -405,5 +405,28 @@ namespace PepperDash.Essentials.AppServer.Messengers }); } + /// + /// Helper for posting an event message to a single client. A null/empty clientId falls back + /// to the existing broadcast behavior of the other PostEventMessage overloads. + /// + /// + /// + /// Client id that will direct the message back to only that client + protected void PostEventMessage(DeviceEventMessageBase message, string eventType, string clientId) + { + message.Key = _device.Key; + + message.Name = _device.Name; + + message.EventType = eventType; + + AppServerController?.SendMessageObject(new MobileControlMessage + { + Type = $"/event{MessagePath}/{eventType}", + ClientId = clientId, + Content = JToken.FromObject(message), + }); + } + } }