internal async Task GetTwinInfoWhenCloudOnlineAsync()

in edge-hub/core/src/Microsoft.Azure.Devices.Edge.Hub.Core/TwinManager.cs [174:254]


        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();
                Shared.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;
        }