public Task <bool> HandleAsync(MqttPublishInfo publishInfo) { try { var match = Regex.Match(publishInfo.Topic, RpcAckPattern); if (match.Success) { this.HandleRpcAck(match.Groups["guid"].Value); return(Task.FromResult(true)); } match = Regex.Match(publishInfo.Topic, TwinGetResponsePattern); if (match.Success) { this.HandleTwinResponse(this.GetIdFromMatch(match), match.Groups["res"].Value, match.Groups["rid"].Value, publishInfo.Payload); return(Task.FromResult(true)); } match = Regex.Match(publishInfo.Topic, TwinSubscriptionForPatchPattern); if (match.Success) { this.HandleDesiredProperyUpdate(this.GetIdFromMatch(match), match.Groups["version"].Value, publishInfo.Payload); return(Task.FromResult(true)); } match = Regex.Match(publishInfo.Topic, MethodCallPattern); if (match.Success) { this.HandleDirectMethodCall(this.GetIdFromMatch(match), match.Groups["mname"].Value, match.Groups["rid"].Value, publishInfo.Payload); return(Task.FromResult(true)); } if (ConnectivityTopic.Equals(publishInfo.Topic)) { this.HandleConnectivityEvent(publishInfo.Payload); return(Task.FromResult(true)); } } catch (Exception e) { Events.ErrorHandlingDownstreamMessage(publishInfo.Topic, e); } return(Task.FromResult(false)); }
Option <List <IIdentity> > GetIdentitiesFromUpdateMessage(MqttPublishInfo mqttPublishInfo) { var identityList = default(List <string>); try { var payloadAsString = Encoding.UTF8.GetString(mqttPublishInfo.Payload); identityList = JsonConvert.DeserializeObject <List <string> >(payloadAsString); } catch (Exception e) { Events.BadPayloadFormat(e); return(Option.None <List <IIdentity> >()); } var result = new List <IIdentity>(); foreach (var id in identityList) { if (this.systemComponentIdProvider.IsSystemComponent(id)) { continue; } var identityComponents = id.Split(identitySegmentSeparator, StringSplitOptions.RemoveEmptyEntries); switch (identityComponents.Length) { case 1: result.Add(this.identityProvider.Create(identityComponents[0])); break; case 2: result.Add(this.identityProvider.Create(identityComponents[0], identityComponents[1])); break; default: Events.BadIdentityFormat(id); continue; } } return(Option.Some(result)); }
async Task <bool> HandleTelemetry(Match match, MqttPublishInfo publishInfo) { var id1 = match.Groups["id1"]; var id2 = match.Groups["id2"]; var bag = match.Groups["bag"]; var isDirect = string.Equals(match.Groups["dialect"].Value, MqttBrokerAdapterConstants.DirectTopicPrefix); var identity = id2.Success ? this.identityProvider.Create(id1.Value, id2.Value) : this.identityProvider.Create(id1.Value); var maybeListener = await this.connectionRegistry.GetOrCreateDeviceListenerAsync(identity, isDirect); var listener = default(IDeviceListener); try { listener = maybeListener.Expect(() => new Exception($"No device listener found for {identity.Id}")); } catch (Exception) { Events.MissingListener(identity.Id); return(false); } var message = default(IMessage); try { message = ConvertToInternalMessage(publishInfo, id1.Value, id2.Success ? Option.Some(id2.Value) : Option.None <string>(), bag.Value); } catch (Exception e) { Events.UnexpectedMessageFormat(e, publishInfo.Topic); return(false); } await listener.ProcessDeviceMessageAsync(message); Events.TelemetryMessage(identity.Id, publishInfo.Payload.Length); return(true); }
public async Task <bool> HandleAsync(MqttPublishInfo publishInfo) { if (string.Equals(publishInfo.Topic, TopicDeviceConnected)) { try { await this.HandleDeviceConnectedAsync(publishInfo); return(true); } catch (Exception e) { Events.ErrorProcessingNotification(e); return(false); } } return(false); }
public async Task <bool> HandleAsync(MqttPublishInfo publishInfo) { if (publishInfo.Topic.Equals(MessageDelivered)) { try { var originalTopic = Encoding.UTF8.GetString(publishInfo.Payload); var match = Regex.Match(originalTopic, FeedbackMessagePattern); if (match.Success) { var id1 = match.Groups["id1"]; var id2 = match.Groups["id2"]; var lockToken = match.Groups["token"].Value; var identity = this.identityProvider.Create(id1.Value, id2.Value); if (this.pendingMessages.TryRemove(lockToken, out var _)) { await this.ConfirmMessageAsync(lockToken, identity); } else { Events.CannotFindMessageToConfirm(identity.Id); } } } catch (Exception ex) { Events.CannotDecodeConfirmation(ex); } return(true); } else { return(false); } }
public async Task <bool> HandleAsync(MqttPublishInfo publishInfo) { var match = Regex.Match(publishInfo.Topic, SubscriptionChangePattern); if (!match.Success) { return(false); } // After this point we know that this was a subscription change and will return 'true' // even in a case of error var subscriptionList = default(List <string>); try { var payloadAsString = Encoding.UTF8.GetString(publishInfo.Payload); subscriptionList = JsonConvert.DeserializeObject <List <string> >(payloadAsString); Events.HandlingSubscriptionChange(payloadAsString); } catch (Exception e) { Events.BadPayloadFormat(e); return(true); } if (subscriptionList == null) { // This case is valid and sent by the broker (as an empty string) when a client disconnects. // The meaning of the message is to remove subscriptions, but as the client is disconnecting // in a moment, we don't do anything. In fact, the disconnect message is supposed to arrive // first, and then this change notification gets ignored as it does not have related client. return(true); } var id1 = match.Groups["id1"]; var id2 = match.Groups["id2"]; var identity = id2.Success ? this.identityProvider.Create(id1.Value, id2.Value) : this.identityProvider.Create(id1.Value); var listener = default(IDeviceListener); var maybeListener = await this.connectionRegistry.GetDeviceListenerAsync(identity); if (!maybeListener.HasValue) { return(true); } else { listener = maybeListener.Expect(() => new Exception($"No device listener found for {identity.Id}")); } foreach (var subscriptionPattern in this.subscriptionPatterns) { var subscribes = false; foreach (var subscription in subscriptionList) { var subscriptionMatch = Regex.Match(subscription, subscriptionPattern.Pattern); if (IsMatchWithIds(subscriptionMatch, id1, id2)) { subscribes = true; break; } } try { await AddOrRemoveSubscription(listener, subscribes, subscriptionPattern.Subscrition); } catch (Exception e) { Events.FailedToChangeSubscriptionState(e, subscriptionPattern.Subscrition.ToString(), identity.Id); } } return(true); }
async Task HandleDeviceConnectedAsync(MqttPublishInfo mqttPublishInfo) { var updatedIdentities = this.GetIdentitiesFromUpdateMessage(mqttPublishInfo); await updatedIdentities.ForEachAsync(async i => await this.ReconcileConnectionsAsync(new HashSet <IIdentity>(i))); }
async Task <bool> HandleUpstreamRequest(Func <IDeviceListener, string, Task> action, Match match, MqttPublishInfo publishInfo) { var id1 = match.Groups["id1"]; var id2 = match.Groups["id2"]; var rid = match.Groups["rid"]; var identity = id2.Success ? this.identityProvider.Create(id1.Value, id2.Value) : this.identityProvider.Create(id1.Value); var maybeListener = await this.connectionRegistry.GetDeviceListenerAsync(identity); var listener = default(IDeviceListener); try { listener = maybeListener.Expect(() => new Exception($"No device listener found for {identity.Id}")); } catch (Exception) { Events.MissingListener(identity.Id); return(false); } var message = new EdgeMessage.Builder(publishInfo.Payload).Build(); _ = action(listener, rid.Value); return(true); }
public async Task <bool> HandleAsync(MqttPublishInfo publishInfo) { var match = Regex.Match(publishInfo.Topic, SubscriptionChangePattern); if (!match.Success) { return(false); } // After this point we know that this was a subscription change and will return 'true' // even in a case of error var subscriptionList = default(List <string>); try { var payloadAsString = Encoding.UTF8.GetString(publishInfo.Payload); subscriptionList = JsonConvert.DeserializeObject <List <string> >(payloadAsString); Events.HandlingSubscriptionChange(payloadAsString); } catch (Exception e) { Events.BadPayloadFormat(e); return(true); } if (subscriptionList == null) { // This case is valid and sent by the broker (as an empty string) when a client disconnects. // The meaning of the message is to remove subscriptions, but as the client is disconnecting // in a moment, we don't do anything. In fact, the disconnect message is supposed to arrive // first, and then this change notification gets ignored as it does not have related client. return(true); } // TODO: the following solution is to unblock the case when in a nested scenario a child edgehub // subscribes in the name of a device/module. However changes needed to support unsubscribe foreach (var subscriptionPattern in this.subscriptionPatterns) { foreach (var subscription in subscriptionList) { var subscriptionMatch = Regex.Match(subscription, subscriptionPattern.Pattern); if (subscriptionMatch.Success) { var id1 = subscriptionMatch.Groups["id1"]; var id2 = subscriptionMatch.Groups["id2"]; var isDirect = string.Equals(subscriptionMatch.Groups["dialect"].Value, DirectConnectionDialect); var identity = id2.Success ? this.identityProvider.Create(id1.Value, id2.Value) : this.identityProvider.Create(id1.Value); var maybeListener = await this.connectionRegistry.GetDeviceListenerAsync(identity, isDirect); if (maybeListener.HasValue) { try { var listener = maybeListener.Expect(() => new Exception($"No device listener found for {identity.Id}")); await AddOrRemoveSubscription(listener, true, subscriptionPattern.Subscrition); } catch (Exception e) { Events.FailedToChangeSubscriptionState(e, subscriptionPattern.Subscrition.ToString(), identity.Id); } } else { Events.CouldNotObtainListener(subscriptionPattern.Subscrition.ToString(), identity.Id); } } } } return(true); }