private static int BrowseAndSubscribeAllSensors(TheThing provider, TheThing targetThing, int maxSubscriptions, int minimumBrowseTags, out TheThing.MsgBrowseSensorsResponse browseResponse, out TheThing.MsgSubscribeSensorsResponse sensorSubscriptionResponse, out List <TheThing.TheSensorSubscriptionStatus> successfullSubscriptions) { browseResponse = provider.ProviderBrowseSensorsAsync().Result; Assert.IsNotNull(browseResponse, $"Timeout or browse message not implemented by plug-in: {new TheThingReference(provider)}"); Assert.IsTrue(string.IsNullOrEmpty(browseResponse.Error), $"Browse error: {browseResponse.Error}"); Assert.GreaterOrEqual(browseResponse.Sensors.Count, minimumBrowseTags); var subscribeRequest = new TheThing.MsgSubscribeSensors { DefaultTargetThing = provider, ReplaceAll = true, SubscriptionRequests = browseResponse.Sensors.Take(maxSubscriptions).Select(s => new TheThing.TheSensorSubscription { TargetThing = targetThing, TargetProperty = TheCommonUtils.CListToString(s.DisplayNamePath, "."), SensorId = s.SensorId, SampleRate = 1000, // TODO make the test configurable for custom subscription parameters //CustomSubscriptionInfo = new Dictionary<string, object> //{ // { "QueueSize", 50 }, //}, ExtensionData = s.ExtensionData, } ).ToList(), }; int subscriptionCount = subscribeRequest.SubscriptionRequests.Count; sensorSubscriptionResponse = provider.SubscribeSensorsAsync(subscribeRequest).Result; Assert.IsNotNull(sensorSubscriptionResponse, "Timeout or subscribe message not implemented by plug-in"); Assert.IsTrue(string.IsNullOrEmpty(sensorSubscriptionResponse.Error), $"Error from SubscribeSensors: {sensorSubscriptionResponse.Error}. {new TheThingReference(provider)}"); Assert.AreEqual(sensorSubscriptionResponse.SubscriptionStatus.Count, subscriptionCount); foreach (var status in sensorSubscriptionResponse.SubscriptionStatus) { Assert.True(string.IsNullOrEmpty(status.Error) || status.Error.Contains("BadUserAccessDenied"), $"{status.Subscription.SensorId}: {status.Error}"); } successfullSubscriptions = sensorSubscriptionResponse.SubscriptionStatus.Where(s => string.IsNullOrEmpty(s.Error)).ToList(); return(subscriptionCount); }
/// <summary> /// Handles Messages sent from a host sub-engine to its clients /// </summary> /// <param name="Command"></param> /// <param name="pMessage"></param> public override void HandleMessage(ICDEThing sender, object pIncoming) { TheProcessMessage pMsg = pIncoming as TheProcessMessage; if (pMsg == null) { return; } string[] cmd = pMsg.Message.TXT.Split(':'); switch (cmd[0]) { case nameof(TheThing.MsgBrowseSensors): var browseRequest = TheCommRequestResponse.ParseRequestMessageJSON <TheThing.MsgBrowseSensors>(pMsg.Message); var browseResponse = new TheThing.MsgBrowseSensorsResponse { Error = "Internal error", Sensors = new List <TheThing.TheSensorSourceInfo>() }; foreach (FieldMapping fld in MyModFieldStore.TheValues) { browseResponse.Sensors.Add(new TheThing.TheSensorSourceInfo { SourceType = fld.SourceType, cdeType = ePropertyTypes.TNumber, SensorId = TheCommonUtils.CStr(fld.cdeMID), ExtensionData = new Dictionary <string, object> { { nameof(FieldMapping.SourceOffset), fld.SourceOffset }, { nameof(FieldMapping.SourceSize), fld.SourceSize }, { nameof(FieldMapping.AllowWrite), fld.AllowWrite } }, DisplayNamePath = new string[] { MyBaseEngine.GetEngineName(), MyBaseThing.FriendlyName, fld.PropertyName } }); } browseResponse.Error = null; TheCommRequestResponse.PublishResponseMessageJson(pMsg.Message, browseResponse); break; case nameof(TheThing.MsgSubscribeSensors): var subscribeRequest = TheCommRequestResponse.ParseRequestMessageJSON <TheThing.MsgSubscribeSensors>(pMsg.Message); var subscribeResponse = new TheThing.MsgSubscribeSensorsResponse { Error = "Internal error", SubscriptionStatus = new List <TheThing.TheSensorSubscriptionStatus>() }; if (subscribeRequest.ReplaceAll) { MyModFieldStore.RemoveAllItems(); } var subscriptionStatus = new List <TheThing.TheSensorSubscriptionStatus>(); foreach (TheThing.TheSensorSubscription sub in subscribeRequest.SubscriptionRequests) { FieldMapping fld = new FieldMapping() { PropertyName = sub.TargetProperty, cdeMID = TheCommonUtils.CGuid(sub.SensorId) }; if (fld.cdeMID == Guid.Empty) { fld.cdeMID = Guid.NewGuid(); } object sourceType; if (sub.ExtensionData != null) { if (sub.ExtensionData.TryGetValue(nameof(TheThing.TheSensorSourceInfo.SourceType), out sourceType)) { fld.SourceType = TheCommonUtils.CStr(sourceType); } object offset; if (sub.ExtensionData.TryGetValue("SourceOffset", out offset)) { fld.SourceOffset = TheCommonUtils.CInt(offset); } object size; if (sub.ExtensionData.TryGetValue("SourceSize", out size)) { fld.SourceSize = TheCommonUtils.CInt(size); } object allowWrite; if (sub.ExtensionData.TryGetValue("AllowWrite", out allowWrite)) { fld.AllowWrite = TheCommonUtils.CBool(allowWrite); } MyModFieldStore.AddAnItem(fld); subscriptionStatus.Add(CreateSubscriptionStatusFromFieldMapping(fld)); } else { subscriptionStatus.Add(new TheThing.TheSensorSubscriptionStatus { Error = "Missing source info", Subscription = sub, }); } } subscribeResponse.SubscriptionStatus = subscriptionStatus; subscribeResponse.Error = null; TheCommRequestResponse.PublishResponseMessageJson(pMsg.Message, subscribeResponse); break; case nameof(TheThing.MsgGetSensorSubscriptions): var getResponse = new TheThing.MsgGetSensorSubscriptionsResponse { Error = "Internal error" }; getResponse.Subscriptions = MyModFieldStore.TheValues.Select(fld => CreateSubscriptionStatusFromFieldMapping(fld).Subscription).ToList(); getResponse.Error = null; TheCommRequestResponse.PublishResponseMessageJson(pMsg.Message, getResponse); break; case nameof(TheThing.MsgUnsubscribeSensors): var unsubscribeRequest = TheCommRequestResponse.ParseRequestMessageJSON <TheThing.MsgUnsubscribeSensors>(pMsg.Message); var unsubscribeResponse = new TheThing.MsgUnsubscribeSensorsResponse { Error = "Internal error", Failed = new List <TheThing.TheSensorSubscriptionStatus>() }; if (unsubscribeRequest.UnsubscribeAll) { MyModFieldStore.RemoveAllItems(); if (MyModFieldStore.GetCount() > 0) { unsubscribeResponse.Failed = MyModFieldStore.TheValues.Select(fld => CreateSubscriptionStatusFromFieldMapping(fld)).ToList(); } } else { List <FieldMapping> toRemove = MyModFieldStore.TheValues.FindAll(fld => unsubscribeRequest.SubscriptionIds.Contains(fld.cdeMID)); MyModFieldStore.RemoveItems(toRemove, null); foreach (FieldMapping fld in MyModFieldStore.TheValues) { if (toRemove.Any(t => t.cdeMID == fld.cdeMID)) { unsubscribeResponse.Failed.Add(CreateSubscriptionStatusFromFieldMapping(fld)); } } } unsubscribeResponse.Error = null; TheCommRequestResponse.PublishResponseMessageJson(pMsg.Message, unsubscribeResponse); break; case nameof(TheThing.MsgExportConfig): var exportRequest = TheCommRequestResponse.ParseRequestMessageJSON <TheThing.MsgExportConfig>(pMsg.Message); var exportResponse = new TheThing.MsgExportConfigResponse { Error = "Internal error" }; // No custom config beyond config properties and subscriptions exportResponse.Error = null; TheCommRequestResponse.PublishResponseMessageJson(pMsg.Message, exportResponse); break; case nameof(TheThing.MsgApplyConfig): break; default: break; } TheThing.TheSensorSubscriptionStatus CreateSubscriptionStatusFromFieldMapping(FieldMapping fld) { return(new TheThing.TheSensorSubscriptionStatus { Subscription = new TheThing.TheSensorSubscription { TargetProperty = fld.PropertyName, SensorId = TheCommonUtils.CStr(fld.cdeMID), SubscriptionId = fld.cdeMID, ExtensionData = new Dictionary <string, object> { { nameof(FieldMapping.SourceType), fld.SourceType }, { nameof(FieldMapping.SourceOffset), fld.SourceOffset }, { nameof(FieldMapping.SourceSize), fld.SourceSize }, { nameof(FieldMapping.AllowWrite), fld.AllowWrite } }, TargetThing = new TheThingReference(MyBaseThing), SampleRate = (int?)this.Interval }, Error = null, }); } }