예제 #1
0
        async Task UpdateReportedPropertiesPatchAsync(string id, TwinInfo newTwinInfo, TwinCollection reportedProperties)
        {
            try
            {
                using (await this.twinLock.LockAsync())
                {
                    IEntityStore <string, TwinInfo> twinStore = this.TwinStore.Expect(() => new InvalidOperationException("Missing twin store"));

                    await twinStore.PutOrUpdate(
                        id,
                        newTwinInfo,
                        u =>
                    {
                        string mergedJson = JsonEx.Merge(u.ReportedPropertiesPatch, reportedProperties, /*treatNullAsDelete*/ false);
                        var mergedPatch   = new TwinCollection(mergedJson);
                        Events.UpdatingReportedPropertiesPatchCollection(id, mergedPatch.Version);
                        return(new TwinInfo(u.Twin, mergedPatch));
                    });
                }
            }
            catch (Exception e)
            {
                throw new InvalidOperationException($"Error updating twin patch for device {id}", e);
            }
        }
예제 #2
0
 public static void GetTwinFromStoreWhenOffline(string id, TwinInfo twinInfo, Exception e)
 {
     if (twinInfo.Twin != null)
     {
         Log.LogDebug((int)EventIds.GetTwinFromStoreWhenOffline, $"Getting twin for {id} at desired version " +
                      $"{twinInfo.Twin.Properties.Desired.Version} reported version {twinInfo.Twin.Properties.Reported.Version} from local store. Get from cloud threw {e.GetType()} {e.Message}");
     }
     else
     {
         Log.LogDebug((int)EventIds.GetTwinFromStoreWhenOffline, $"Getting twin info for {id}, but twin is null. Get from cloud threw {e.GetType()} {e.Message}");
     }
 }
예제 #3
0
 public async Task <IMessage> GetTwinAsync(string id)
 {
     return(await this.TwinStore.Match(
                async (store) =>
     {
         TwinInfo twinInfo = await this.GetTwinInfoWithStoreSupportAsync(id);
         return this.twinConverter.ToMessage(twinInfo.Twin);
     },
                async() =>
     {
         // pass through to cloud proxy
         Option <ICloudProxy> cloudProxy = await this.connectionManager.GetCloudConnection(id);
         return await cloudProxy.Match(async(cp) => await cp.GetTwinAsync(), () => throw new InvalidOperationException($"Cloud proxy unavailable for device {id}"));
     }));
예제 #4
0
        async Task <TwinInfo> GetTwinInfoWhenCloudOfflineAsync(string id, Exception e)
        {
            TwinInfo twinInfo = null;

            await this.ExecuteOnTwinStoreResultAsync(
                id,
                t =>
            {
                twinInfo = t;
                Events.GetTwinFromStoreWhenOffline(id, twinInfo, e);
                return(Task.CompletedTask);
            },
                () => throw new InvalidOperationException($"Error getting twin for device {id}", e));

            return(twinInfo);
        }
예제 #5
0
        internal async Task <TwinInfo> GetTwinInfoWhenCloudOnlineAsync(string id, ICloudProxy cp, bool sendDesiredPropertyUpdate)
        {
            TwinCollection diff = null;
            // Used for returning value to caller
            TwinInfo cached;

            using (await this.twinLock.LockAsync())
            {
                IMessage twinMessage = await cp.GetTwinAsync();

                Twin cloudTwin = this.twinConverter.FromMessage(twinMessage);
                Events.GotTwinFromCloudSuccess(id, cloudTwin.Properties.Desired.Version, cloudTwin.Properties.Reported.Version);
                var newTwin = new TwinInfo(cloudTwin, null);
                cached = newTwin;

                IEntityStore <string, TwinInfo> twinStore = this.TwinStore.Expect(() => new InvalidOperationException("Missing twin store"));

                await twinStore.PutOrUpdate(
                    id,
                    newTwin,
                    t =>
                {
                    // If the new twin is more recent than the cached twin, update the cached copy.
                    // If not, reject the cloud twin
                    if (t.Twin == null ||
                        cloudTwin.Properties.Desired.Version > t.Twin.Properties.Desired.Version ||
                        cloudTwin.Properties.Reported.Version > t.Twin.Properties.Reported.Version)
                    {
                        if (t.Twin != null)
                        {
                            Events.UpdateCachedTwin(
                                id,
                                t.Twin.Properties.Desired.Version,
                                cloudTwin.Properties.Desired.Version,
                                t.Twin.Properties.Reported.Version,
                                cloudTwin.Properties.Reported.Version);
                            cached = new TwinInfo(cloudTwin, t.ReportedPropertiesPatch);
                            // If the device is subscribed to desired property updates and we are refreshing twin as a result
                            // of a connection reset or desired property update, send a patch to the downstream device
                            if (sendDesiredPropertyUpdate)
                            {
                                Option <IReadOnlyDictionary <DeviceSubscription, bool> > subscriptions = this.connectionManager.GetSubscriptions(id);
                                subscriptions.ForEach(
                                    s =>
                                {
                                    if (s.TryGetValue(DeviceSubscription.DesiredPropertyUpdates, out bool hasDesiredPropertyUpdatesSubscription) &&
                                        hasDesiredPropertyUpdatesSubscription)
                                    {
                                        Events.SendDesiredPropertyUpdateToSubscriber(
                                            id,
                                            t.Twin.Properties.Desired.Version,
                                            cloudTwin.Properties.Desired.Version);
                                        diff = new TwinCollection(JsonEx.Diff(t.Twin.Properties.Desired, cloudTwin.Properties.Desired));
                                    }
                                });
                            }
                        }
                    }
                    else
                    {
                        Events.PreserveCachedTwin(id,
                                                  t.Twin.Properties.Desired.Version, cloudTwin.Properties.Desired.Version,
                                                  t.Twin.Properties.Reported.Version, cloudTwin.Properties.Reported.Version);
                        cached = t;
                    }
                    return(cached);
                });
            }
            if ((diff != null) && (diff.Count != 0))
            {
                Events.SendDiffToDeviceProxy(diff.ToString(), id);
                IMessage message = this.twinCollectionConverter.ToMessage(diff);
                await this.SendDesiredPropertiesToDeviceProxy(id, message);
            }
            return(cached);
        }