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;
}