/// <summary> /// Convert twin to registration information. /// </summary> /// <param name="twin"></param> /// <param name="onlyServerState"></param> /// <returns></returns> public static BaseRegistration ToRegistration(DeviceTwinModel twin, bool onlyServerState = false) { if (twin == null) { return(null); } var type = twin.Tags.GetValueOrDefault <string>(nameof(DeviceType), null); if (string.IsNullOrEmpty(type) && twin.Properties.Reported != null) { type = twin.Properties.Reported.GetValueOrDefault <string>(TwinProperty.kType, null); } switch (type?.ToLowerInvariant() ?? "") { case "endpoint": return(EndpointRegistration.FromTwin(twin, onlyServerState)); case "application": return(ApplicationRegistration.FromTwin(twin)); case "supervisor": return(SupervisorRegistration.FromTwin(twin, onlyServerState)); } return(null); }
/// <summary> /// Returns true if this registration matches the server endpoint /// model provided. /// </summary> /// <param name="registration"></param> /// <param name="model"></param> /// <returns></returns> public static bool Matches(this EndpointRegistration registration, EndpointInfoModel model) { return(model != null && registration.Matches(model.Registration?.Endpoint) && registration.NotSeenSince == model.NotSeenSince && registration.ApplicationId == model.ApplicationId && (registration.ActivationState ?? EndpointActivationState.Deactivated) == (model.ActivationState ?? EndpointActivationState.Deactivated)); }
/// <summary> /// Returns true if this registration matches the endpoint /// model provided. /// </summary> /// <param name="registration"></param> /// <param name="endpoint"></param> /// <returns></returns> public static bool Matches(this EndpointRegistration registration, EndpointModel endpoint) { return(endpoint != null && registration.EndpointUrl == endpoint.Url && registration.AlternativeUrls.DecodeAsList().ToHashSetSafe().SetEqualsSafe( endpoint.AlternativeUrls) && registration.SecurityMode == (endpoint.SecurityMode ?? SecurityMode.Best) && registration.SecurityPolicy == endpoint.SecurityPolicy && endpoint.Certificate.SequenceEqualsSafe( registration.Certificate.DecodeAsByteArray())); }
public void TestEqualIsEqualWithDeviceModel() { var r1 = CreateRegistration(); var m = EndpointRegistration.Patch(null, r1); var r2 = BaseRegistration.ToRegistration(m); Assert.Equal(r1, r2); Assert.Equal(r1.GetHashCode(), r2.GetHashCode()); Assert.True(r1 == r2); Assert.False(r1 != r2); }
public void TestEqualIsNotEqualWithServiceModelConversionWhenDisabled() { var r1 = CreateRegistration(); var m = r1.ToServiceModel(); var r2 = EndpointRegistration.FromServiceModel(m, true); Assert.NotEqual(r1, r2); Assert.NotEqual(r1.GetHashCode(), r2.GetHashCode()); Assert.True(r1 != r2); Assert.False(r1 == r2); }
/// <summary> /// Flag endpoint as synchronized - i.e. it matches the other. /// </summary> /// <param name="registration"></param> /// <param name="other"></param> internal static bool IsInSyncWith(this EndpointRegistration registration, EndpointRegistration other) { return (other != null && registration.EndpointUrl == other.EndpointUrl && registration.AlternativeUrls.DecodeAsList().ToHashSetSafe().SetEqualsSafe( other.AlternativeUrls.DecodeAsList()) && registration.SecurityPolicy == other.SecurityPolicy && registration.SecurityMode == other.SecurityMode && registration.Certificate.DecodeAsByteArray().SequenceEqualsSafe( other.Certificate.DecodeAsByteArray())); }
public void TestEqualIsNotEqualWithDeviceModel() { var r1 = CreateRegistration(); var m = EndpointRegistration.Patch(null, r1); m.Properties.Desired["Credential"] = "password"; var r2 = BaseRegistration.ToRegistration(m); Assert.NotEqual(r1, r2); Assert.NotEqual(r1.GetHashCode(), r2.GetHashCode()); Assert.True(r1 != r2); Assert.False(r1 == r2); }
public void TestEqualIsNotEqualWithServiceModelConversion() { var r1 = CreateRegistration(); var m = r1.ToServiceModel(); m.Registration.Endpoint.SecurityPolicy = ""; var r2 = EndpointRegistration.FromServiceModel(m); Assert.NotEqual(r1, r2); Assert.NotEqual(r1.GetHashCode(), r2.GetHashCode()); Assert.True(r1 != r2); Assert.False(r1 == r2); }
/// <summary> /// Flag endpoint as synchronized - i.e. it matches the other. /// </summary> /// <param name="registration"></param> /// <param name="other"></param> internal static bool IsInSyncWith(this EndpointRegistration registration, EndpointRegistration other) { if (registration == null) { return(other == null); } return (other != null && registration.EndpointUrl == other.EndpointUrl && registration.AlternativeUrls.DecodeAsList().ToHashSetSafe().SetEqualsSafe( other.AlternativeUrls.DecodeAsList()) && registration.SecurityPolicy == other.SecurityPolicy && registration.SecurityMode == other.SecurityMode && registration.Thumbprint == other.Thumbprint); }
/// <summary> /// Flag endpoint as synchronized - i.e. it matches the other. /// </summary> /// <param name="other"></param> internal void MarkAsInSyncWith(EndpointRegistration other) { _isInSync = other != null && EndpointUrl == other.EndpointUrl && AlternativeUrls.DecodeAsList().ToHashSetSafe().SetEqualsSafe( other.AlternativeUrls.DecodeAsList()) && CredentialType == other.CredentialType && JToken.DeepEquals(Credential, other.Credential) && SecurityPolicy == other.SecurityPolicy && SecurityMode == other.SecurityMode && ClientCertificate.DecodeAsByteArray().SequenceEqualsSafe( other.ClientCertificate.DecodeAsByteArray()) && ServerThumbprint.DecodeAsByteArray().SequenceEqualsSafe( other.ServerThumbprint.DecodeAsByteArray()); }
public void TestEqualIsEqualWithDeviceModelWhenDisabled() { var fix = new Fixture(); var r1 = CreateRegistration(); var r2 = EndpointRegistration.FromServiceModel( r1.ToServiceModel(), true); var m1 = EndpointRegistration.Patch(r1, r2); var r3 = EndpointRegistration.FromServiceModel( r2.ToServiceModel(), false); var m2 = EndpointRegistration.Patch(r2, r3); Assert.True((bool?)m1.Tags[nameof(BaseRegistration.IsDisabled)] ?? false); Assert.NotNull((DateTime?)m1.Tags[nameof(BaseRegistration.NotSeenSince)]); Assert.Null((bool?)m2.Tags[nameof(BaseRegistration.IsDisabled)]); Assert.Null((DateTime?)m2.Tags[nameof(BaseRegistration.NotSeenSince)]); }
/// <summary> /// Get site or gateway id from registration /// </summary> /// <param name="registration"></param> /// <returns></returns> public static string GetSiteOrGatewayId(this EndpointRegistration registration) { if (registration == null) { return(null); } var siteOrGatewayId = registration?.SiteId; if (siteOrGatewayId == null) { var id = registration?.DiscovererId ?? registration?.SupervisorId; if (id != null) { siteOrGatewayId = DiscovererModelEx.ParseDeviceId(id, out _); } } return(siteOrGatewayId); }
/// <summary> /// Convert to service model /// </summary> /// <param name="registration"></param> /// <returns></returns> public static EndpointInfoModel ToServiceModel(this EndpointRegistration registration) { if (registration == null) { return(null); } return(new EndpointInfoModel { ApplicationId = registration.ApplicationId, Registration = new EndpointRegistrationModel { Id = registration.DeviceId, SiteId = string.IsNullOrEmpty(registration.SiteId) ? null : registration.SiteId, SupervisorId = string.IsNullOrEmpty(registration.SupervisorId) ? null : registration.SupervisorId, DiscovererId = string.IsNullOrEmpty(registration.DiscovererId) ? null : registration.DiscovererId, AuthenticationMethods = registration.AuthenticationMethods?.DecodeAsList(j => j.ToObject <AuthenticationMethodModel>()), SecurityLevel = registration.SecurityLevel, EndpointUrl = string.IsNullOrEmpty(registration.EndpointRegistrationUrl) ? (string.IsNullOrEmpty(registration.EndpointUrl) ? registration.EndpointUrlLC : registration.EndpointUrl) : registration.EndpointRegistrationUrl, Endpoint = new EndpointModel { Url = string.IsNullOrEmpty(registration.EndpointUrl) ? registration.EndpointUrlLC : registration.EndpointUrl, AlternativeUrls = registration.AlternativeUrls?.DecodeAsList().ToHashSetSafe(), SecurityMode = registration.SecurityMode == SecurityMode.Best ? null : registration.SecurityMode, SecurityPolicy = string.IsNullOrEmpty(registration.SecurityPolicy) ? null : registration.SecurityPolicy, Certificate = registration.Certificate.DecodeAsByteArray() } }, ActivationState = registration.ActivationState, NotSeenSince = registration.NotSeenSince, EndpointState = registration.ActivationState == EndpointActivationState.ActivatedAndConnected ? (registration.State == EndpointConnectivityState.Disconnected ? EndpointConnectivityState.Connecting : registration.State) : EndpointConnectivityState.Disconnected, OutOfSync = registration.Connected && !registration._isInSync ? true : (bool?)null }); }
/// <summary> /// Create patch twin model to upload /// </summary> /// <param name="existing"></param> /// <param name="update"></param> public static DeviceTwinModel Patch(this EndpointRegistration existing, EndpointRegistration update) { var twin = BaseRegistrationEx.PatchBase(existing, update); // Tags if (update?.EndpointRegistrationUrl != null && update.EndpointRegistrationUrl != existing?.EndpointRegistrationUrl) { twin.Tags.Add(nameof(EndpointRegistration.EndpointUrlLC), update.EndpointUrlLC); twin.Tags.Add(nameof(EndpointRegistration.EndpointRegistrationUrl), update.EndpointRegistrationUrl); } if (update?.SecurityLevel != existing?.SecurityLevel) { twin.Tags.Add(nameof(EndpointRegistration.SecurityLevel), update?.SecurityLevel == null ? null : JToken.FromObject(update?.SecurityLevel)); } if (update?.Activated != null && update.Activated != existing?.Activated) { twin.Tags.Add(nameof(EndpointRegistration.Activated), update?.Activated); } var methodEqual = update?.AuthenticationMethods.DecodeAsList().SetEqualsSafe( existing?.AuthenticationMethods?.DecodeAsList(), JToken.DeepEquals); if (!(methodEqual ?? true)) { twin.Tags.Add(nameof(EndpointRegistration.AuthenticationMethods), update?.AuthenticationMethods == null ? null : JToken.FromObject(update.AuthenticationMethods, new JsonSerializer { NullValueHandling = NullValueHandling.Ignore })); } // Endpoint Property if (update?.EndpointUrl != null && update.EndpointUrl != existing?.EndpointUrl) { twin.Properties.Desired.Add(nameof(EndpointRegistration.EndpointUrl), update.EndpointUrl); } var urlsEqual = update?.AlternativeUrls.DecodeAsList().ToHashSetSafe().SetEqualsSafe( existing?.AlternativeUrls?.DecodeAsList()); if (!(urlsEqual ?? true)) { twin.Properties.Desired.Add(nameof(EndpointRegistration.AlternativeUrls), update?.AlternativeUrls == null ? null : JToken.FromObject(update.AlternativeUrls)); } if (update?.SecurityMode != null && update.SecurityMode != existing?.SecurityMode) { twin.Properties.Desired.Add(nameof(EndpointRegistration.SecurityMode), JToken.FromObject(update.SecurityMode)); } if (update?.SecurityPolicy != null && update?.SecurityPolicy != existing?.SecurityPolicy) { twin.Properties.Desired.Add(nameof(EndpointRegistration.SecurityPolicy), update.SecurityPolicy); } if (update?.CredentialType != existing?.CredentialType) { twin.Properties.Desired.Add(nameof(EndpointRegistration.CredentialType), update?.CredentialType == null ? null : JToken.FromObject(update?.CredentialType)); } if (!JToken.DeepEquals(update?.Credential, existing?.Credential)) { twin.Properties.Desired.Add(nameof(EndpointRegistration.Credential), update?.Credential); } var certEqual = update?.Certificate.DecodeAsByteArray().SequenceEqualsSafe( existing?.Certificate.DecodeAsByteArray()); if (update?.Certificate != null && !(certEqual ?? true)) { twin.Properties.Desired.Add(nameof(EndpointRegistration.Certificate), update?.Certificate == null ? null : JToken.FromObject(update.Certificate)); } // Recalculate identity var reportedEndpointUrl = existing?.EndpointRegistrationUrl; if (update?.EndpointRegistrationUrl != null) { reportedEndpointUrl = update.EndpointRegistrationUrl; } if (reportedEndpointUrl == null) { throw new ArgumentException(nameof(EndpointRegistration.EndpointUrl)); } var applicationId = existing?.ApplicationId; if (update?.ApplicationId != null) { applicationId = update.ApplicationId; } if (applicationId == null) { throw new ArgumentException(nameof(EndpointRegistration.ApplicationId)); } var securityMode = existing?.SecurityMode; if (update?.SecurityMode != null) { securityMode = update.SecurityMode; } var securityPolicy = existing?.SecurityPolicy; if (update?.SecurityPolicy != null) { securityPolicy = update.SecurityPolicy; } twin.Id = EndpointInfoModelEx.CreateEndpointId( applicationId, reportedEndpointUrl, securityMode, securityPolicy); if (existing?.DeviceId != twin.Id) { twin.Etag = null; // Force creation of new identity } return(twin); }
/// <summary> /// Create patch twin model to upload /// </summary> /// <param name="existing"></param> /// <param name="update"></param> public static DeviceTwinModel Patch(this EndpointRegistration existing, EndpointRegistration update) { var twin = new DeviceTwinModel { Etag = existing?.Etag, Tags = new Dictionary <string, JToken>(), Properties = new TwinPropertiesModel { Desired = new Dictionary <string, JToken>() } }; // Tags if (update?.ApplicationId != null && update.ApplicationId != existing?.ApplicationId) { twin.Tags.Add(nameof(ApplicationId), update.ApplicationId); } if (update?.IsDisabled != null && update.IsDisabled != existing?.IsDisabled) { twin.Tags.Add(nameof(EntityRegistration.IsDisabled), (update?.IsDisabled ?? false) ? true : (bool?)null); twin.Tags.Add(nameof(EntityRegistration.NotSeenSince), (update?.IsDisabled ?? false) ? DateTime.UtcNow : (DateTime?)null); } if (update?.SiteOrGatewayId != existing?.SiteOrGatewayId) { twin.Tags.Add(nameof(EntityRegistration.SiteOrGatewayId), update?.SiteOrGatewayId); } if (update?.SupervisorId != existing?.SupervisorId) { twin.Tags.Add(nameof(EndpointRegistration.SupervisorId), update?.SupervisorId); } if (update?.DiscovererId != existing?.DiscovererId) { twin.Tags.Add(nameof(EndpointRegistration.DiscovererId), update?.DiscovererId); } if (update?.SiteId != existing?.SiteId) { twin.Tags.Add(nameof(EntityRegistration.SiteId), update?.SiteId); } var certUpdate = update?.Certificate.DecodeAsByteArray().SequenceEqualsSafe( existing?.Certificate.DecodeAsByteArray()); if (!(certUpdate ?? true)) { twin.Tags.Add(nameof(EntityRegistration.Certificate), update?.Certificate == null ? null : JToken.FromObject(update.Certificate)); twin.Tags.Add(nameof(EntityRegistration.Thumbprint), update?.Certificate?.DecodeAsByteArray()?.ToSha1Hash()); } twin.Tags.Add(nameof(EntityRegistration.DeviceType), update?.DeviceType); if (update?.EndpointRegistrationUrl != null && update.EndpointRegistrationUrl != existing?.EndpointRegistrationUrl) { twin.Tags.Add(nameof(EndpointRegistration.EndpointUrlLC), update.EndpointUrlLC); twin.Tags.Add(nameof(EndpointRegistration.EndpointRegistrationUrl), update.EndpointRegistrationUrl); } if (update?.SecurityLevel != existing?.SecurityLevel) { twin.Tags.Add(nameof(EndpointRegistration.SecurityLevel), update?.SecurityLevel == null ? null : JToken.FromObject(update?.SecurityLevel)); } if (update?.Activated != null && update.Activated != existing?.Activated) { twin.Tags.Add(nameof(EndpointRegistration.Activated), update?.Activated); } var methodEqual = update?.AuthenticationMethods.DecodeAsList().SetEqualsSafe( existing?.AuthenticationMethods?.DecodeAsList(), JToken.DeepEquals); if (!(methodEqual ?? true)) { twin.Tags.Add(nameof(EndpointRegistration.AuthenticationMethods), update?.AuthenticationMethods == null ? null : JToken.FromObject(update.AuthenticationMethods, new JsonSerializer { NullValueHandling = NullValueHandling.Ignore })); } // Endpoint Property if (update?.EndpointUrl != null && update.EndpointUrl != existing?.EndpointUrl) { twin.Properties.Desired.Add(nameof(EndpointRegistration.EndpointUrl), update.EndpointUrl); } var urlsEqual = update?.AlternativeUrls.DecodeAsList().ToHashSetSafe().SetEqualsSafe( existing?.AlternativeUrls?.DecodeAsList()); if (!(urlsEqual ?? true)) { twin.Properties.Desired.Add(nameof(EndpointRegistration.AlternativeUrls), update?.AlternativeUrls == null ? null : JToken.FromObject(update.AlternativeUrls)); } if (update?.SecurityMode != null && update.SecurityMode != existing?.SecurityMode) { twin.Properties.Desired.Add(nameof(EndpointRegistration.SecurityMode), JToken.FromObject(update.SecurityMode)); } if (update?.SecurityPolicy != null && update?.SecurityPolicy != existing?.SecurityPolicy) { twin.Properties.Desired.Add(nameof(EndpointRegistration.SecurityPolicy), update.SecurityPolicy); } var certEqual = update?.Certificate.DecodeAsByteArray().SequenceEqualsSafe( existing?.Certificate.DecodeAsByteArray()); if (update?.Certificate != null && !(certEqual ?? true)) { twin.Properties.Desired.Add(nameof(EndpointRegistration.Certificate), update?.Certificate == null ? null : JToken.FromObject(update.Certificate)); } // Recalculate identity var reportedEndpointUrl = existing?.EndpointRegistrationUrl; if (update?.EndpointRegistrationUrl != null) { reportedEndpointUrl = update.EndpointRegistrationUrl; } if (reportedEndpointUrl == null) { throw new ArgumentException(nameof(EndpointRegistration.EndpointUrl)); } var applicationId = existing?.ApplicationId; if (update?.ApplicationId != null) { applicationId = update.ApplicationId; } if (applicationId == null) { throw new ArgumentException(nameof(EndpointRegistration.ApplicationId)); } var securityMode = existing?.SecurityMode; if (update?.SecurityMode != null) { securityMode = update.SecurityMode; } var securityPolicy = existing?.SecurityPolicy; if (update?.SecurityPolicy != null) { securityPolicy = update.SecurityPolicy; } twin.Id = EndpointInfoModelEx.CreateEndpointId( applicationId, reportedEndpointUrl, securityMode, securityPolicy); if (existing?.DeviceId != twin.Id) { twin.Etag = null; // Force creation of new identity } return(twin); }
/// <summary> /// Create device twin /// </summary> /// <param name="registration"></param> /// <param name="serializer"></param> /// <returns></returns> public static DeviceTwinModel ToDeviceTwin(this EndpointRegistration registration, IJsonSerializer serializer) { return(Patch(null, registration, serializer)); }
/// <summary> /// Create device twin /// </summary> /// <param name="registration"></param> /// <returns></returns> public static DeviceTwinModel ToDeviceTwin(this EndpointRegistration registration) { return(Patch(null, registration)); }
/// <summary> /// Decode tags and property into registration object /// </summary> /// <param name="twin"></param> /// <param name="properties"></param> /// <returns></returns> public static EndpointRegistration ToEndpointRegistration(this DeviceTwinModel twin, Dictionary <string, JToken> properties) { if (twin == null) { return(null); } var tags = twin.Tags ?? new Dictionary <string, JToken>(); var connected = twin.IsConnected(); var registration = new EndpointRegistration { // Device DeviceId = twin.Id, Etag = twin.Etag, // Tags IsDisabled = tags.GetValueOrDefault(nameof(EndpointRegistration.IsDisabled), twin.IsDisabled()), NotSeenSince = tags.GetValueOrDefault <DateTime>(nameof(EndpointRegistration.NotSeenSince), null), Thumbprint = tags.GetValueOrDefault <string>(nameof(EndpointRegistration.Thumbprint), null), SupervisorId = tags.GetValueOrDefault <string>(nameof(EndpointRegistration.SupervisorId), null), DiscovererId = tags.GetValueOrDefault <string>(nameof(EndpointRegistration.DiscovererId), tags.GetValueOrDefault <string>(nameof(EndpointRegistration.SupervisorId), null)), Activated = tags.GetValueOrDefault <bool>(nameof(EndpointRegistration.Activated), null), ApplicationId = tags.GetValueOrDefault <string>(nameof(EndpointRegistration.ApplicationId), null), SecurityLevel = tags.GetValueOrDefault <int>(nameof(EndpointRegistration.SecurityLevel), null), AuthenticationMethods = tags.GetValueOrDefault <Dictionary <string, JToken> >(nameof(EndpointRegistration.AuthenticationMethods), null), EndpointRegistrationUrl = tags.GetValueOrDefault <string>(nameof(EndpointRegistration.EndpointRegistrationUrl), null), // Properties Connected = connected ?? properties.GetValueOrDefault(TwinProperty.Connected, false), Type = properties.GetValueOrDefault <string>(TwinProperty.Type, null), State = properties.GetValueOrDefault(nameof(EndpointRegistration.State), EndpointConnectivityState.Connecting), SiteId = properties.GetValueOrDefault(TwinProperty.SiteId, tags.GetValueOrDefault <string>(nameof(EndpointRegistration.SiteId), null)), EndpointUrl = properties.GetValueOrDefault <string>(nameof(EndpointRegistration.EndpointUrl), null), AlternativeUrls = properties.GetValueOrDefault <Dictionary <string, string> >(nameof(EndpointRegistration.AlternativeUrls), null), SecurityMode = properties.GetValueOrDefault <SecurityMode>(nameof(EndpointRegistration.SecurityMode), null), SecurityPolicy = properties.GetValueOrDefault <string>(nameof(EndpointRegistration.SecurityPolicy), null), Certificate = properties.GetValueOrDefault <Dictionary <string, string> >(nameof(EndpointRegistration.Certificate), null), }; return(registration); }