public async Task <Try <ICloudConnection> > Connect(IClientCredentials clientCredentials, Action <string, CloudConnectionStatus> connectionStatusChangedHandler) { Preconditions.CheckNotNull(clientCredentials, nameof(clientCredentials)); try { Events.CreatingCloudConnectionUsingClientCredentials(clientCredentials); var cloudListener = new CloudListener(this.edgeHub.Expect(() => new InvalidOperationException("EdgeHub reference should not be null")), clientCredentials.Identity.Id); string productInfo = await this.productInfoStore.GetEdgeProductInfo(clientCredentials.Identity.Id); Option <string> modelId = await this.modelIdStore.GetModelId(clientCredentials.Identity.Id); if (this.edgeHubIdentity.Id.Equals(clientCredentials.Identity.Id)) { ICloudConnection cc = await CloudConnection.Create( clientCredentials.Identity, connectionStatusChangedHandler, this.transportSettings, this.messageConverterProvider, this.clientProvider, cloudListener, this.edgeHubTokenProvider, this.idleTimeout, this.closeOnIdleTimeout, this.operationTimeout, productInfo, modelId); Events.SuccessCreatingCloudConnection(clientCredentials.Identity); return(Try.Success(cc)); } else if (clientCredentials is ITokenCredentials clientTokenCredentails) { ICloudConnection cc = await ClientTokenCloudConnection.Create( clientTokenCredentails, connectionStatusChangedHandler, this.transportSettings, this.messageConverterProvider, this.clientProvider, cloudListener, this.idleTimeout, this.closeOnIdleTimeout, this.operationTimeout, productInfo, modelId); Events.SuccessCreatingCloudConnection(clientCredentials.Identity); return(Try.Success(cc)); } else { throw new InvalidOperationException($"Cannot connect using client credentials of type {clientCredentials.AuthenticationType} for identity {clientCredentials.Identity.Id}"); } } catch (Exception ex) { Events.ErrorCreatingCloudConnection(clientCredentials.Identity, ex); return(Try <ICloudConnection> .Failure(ex)); } }
public async Task <Try <ICloudConnection> > Connect(IClientCredentials identity, Action <string, CloudConnectionStatus> connectionStatusChangedHandler) { Preconditions.CheckNotNull(identity, nameof(identity)); try { var cloudListener = new CloudListener(this.edgeHub.Expect(() => new InvalidOperationException("EdgeHub reference should not be null")), identity.Identity.Id); var cloudConnection = new CloudConnection( connectionStatusChangedHandler, this.transportSettings, this.messageConverterProvider, this.clientProvider, cloudListener, this.edgeHubTokenProvider, this.deviceScopeIdentitiesCache, this.idleTimeout, this.closeOnIdleTimeout); await cloudConnection.CreateOrUpdateAsync(identity); Events.SuccessCreatingCloudConnection(identity.Identity); return(Try.Success <ICloudConnection>(cloudConnection)); } catch (Exception ex) { Events.ErrorCreatingCloudConnection(identity.Identity, ex); return(Try <ICloudConnection> .Failure(ex)); } }
public async Task CallMethodAsync_InvokesDeviceProxy() { var edgeHub = Mock.Of <IEdgeHub>(); var identity = Mock.Of <IIdentity>(i => i.Id == "device1"); string testMethod = "testMethod"; var testByteArray = new byte[] { 0x00, 0x01, 0x02 }; string id = "1"; var request = new DirectMethodRequest(id, testMethod, testByteArray, TimeSpan.FromSeconds(30)); var cloudListener = new CloudListener(edgeHub, identity.Id); await cloudListener.CallMethodAsync(request); Mock.Get(edgeHub).Verify(eh => eh.InvokeMethodAsync("upstream", request), Times.Once); }
public async Task <Try <ICloudConnection> > Connect(IIdentity identity, Action <string, CloudConnectionStatus> connectionStatusChangedHandler) { Preconditions.CheckNotNull(identity, nameof(identity)); try { var cloudListener = new CloudListener(this.edgeHub.Expect(() => new InvalidOperationException("EdgeHub reference should not be null")), identity.Id); Option <ServiceIdentity> serviceIdentity = (await this.deviceScopeIdentitiesCache.GetServiceIdentity(identity.Id)) .Filter(s => s.Status == ServiceIdentityStatus.Enabled); return(await serviceIdentity .Map( async si => { Events.CreatingCloudConnectionOnBehalfOf(identity); ConnectionMetadata connectionMetadata = await this.metadataStore.GetMetadata(identity.Id); string productInfo = connectionMetadata.EdgeProductInfo; Option <string> modelId = connectionMetadata.ModelId; ICloudConnection cc = await CloudConnection.Create( identity, connectionStatusChangedHandler, this.transportSettings, this.messageConverterProvider, this.clientProvider, cloudListener, this.edgeHubTokenProvider, this.idleTimeout, this.closeOnIdleTimeout, this.operationTimeout, productInfo, modelId); Events.SuccessCreatingCloudConnection(identity); return Try.Success(cc); }) .GetOrElse( async() => { Events.ServiceIdentityNotFound(identity); Option <IClientCredentials> clientCredentials = await this.credentialsCache.Get(identity); return await clientCredentials .Map(cc => this.Connect(cc, connectionStatusChangedHandler)) .GetOrElse(() => throw new InvalidOperationException($"Unable to find identity {identity.Id} in device scopes cache or credentials cache")); })); } catch (Exception ex) { Events.ErrorCreatingCloudConnection(identity, ex); return(Try <ICloudConnection> .Failure(ex)); } }
public async Task OnDesiredPropertyUpdatesForwardsToEdgeHub() { var edgeHub = new Mock <IEdgeHub>(); var identity = Mock.Of <IIdentity>(i => i.Id == "device1"); IMessage actual = null; edgeHub.Setup(r => r.UpdateDesiredPropertiesAsync(It.IsAny <string>(), It.IsAny <IMessage>())) .Callback <string, IMessage>((s, m) => actual = m) .Returns(Task.FromResult(true)); IMessage expected = new EdgeMessage.Builder(Encoding.UTF8.GetBytes("{\"abc\":\"xyz\"}")).Build(); var cloudListener = new CloudListener(edgeHub.Object, identity.Id); await cloudListener.OnDesiredPropertyUpdates(expected); Assert.Equal(expected, actual); }
public async Task TestProcessMessage() { var edgeHub = new Mock <IEdgeHub>(); var identity = Mock.Of <IIdentity>(i => i.Id == "device1"); IMessage sentMessage = null; edgeHub.Setup(r => r.SendC2DMessageAsync(It.IsAny <string>(), It.IsAny <IMessage>())) .Returns(Task.FromResult(true)) .Callback <string, IMessage>((id, m) => sentMessage = m); var cloudListener = new CloudListener(edgeHub.Object, identity.Id); var payload = new byte[] { 1, 2, 3 }; IMessage message = new EdgeMessage.Builder(payload).Build(); await cloudListener.ProcessMessageAsync(message); Assert.NotNull(sentMessage); }
async Task <Try <ICloudConnection> > ConnectInternalWithDeviceStateTracking(IIdentity identity, Action <string, CloudConnectionStatus> connectionStatusChangedHandler, bool refreshCachedIdentity) { Preconditions.CheckNotNull(identity, nameof(identity)); try { var cloudListener = new CloudListener(this.edgeHub.Expect(() => new InvalidOperationException("EdgeHub reference should not be null")), identity.Id); string authChain = await this.deviceScopeIdentitiesCache.VerifyServiceIdentityAuthChainState(identity.Id, this.nestedEdgeEnabled, refreshCachedIdentity); return(await this.TryCreateCloudConnectionFromServiceIdentity(identity, connectionStatusChangedHandler, refreshCachedIdentity, cloudListener, authChain)); } catch (DeviceInvalidStateException ex) { return(await this.TryRecoverCloudConnection(identity, connectionStatusChangedHandler, refreshCachedIdentity, ex)); } catch (Exception ex) { Events.ErrorCreatingCloudConnection(identity, ex); return(Try <ICloudConnection> .Failure(ex)); } }
public async Task <Try <ICloudConnection> > Connect(IClientCredentials clientCredentials, Action <string, CloudConnectionStatus> connectionStatusChangedHandler) { Preconditions.CheckNotNull(clientCredentials, nameof(clientCredentials)); try { Events.CreatingCloudConnectionUsingClientCredentials(clientCredentials); var cloudListener = new CloudListener(this.edgeHub.Expect(() => new InvalidOperationException("EdgeHub reference should not be null")), clientCredentials.Identity.Id); ConnectionMetadata connectionMetadata = await this.metadataStore.GetMetadata(clientCredentials.Identity.Id); string productInfo = connectionMetadata.EdgeProductInfo; Option <string> modelId = clientCredentials.ModelId.HasValue ? clientCredentials.ModelId : connectionMetadata.ModelId; string authChain = string.Empty; if (this.nestedEdgeEnabled) { Option <string> authChainMaybe = await this.deviceScopeIdentitiesCache.GetAuthChain(clientCredentials.Identity.Id); // It's possible to have no auth-chain for out-of-scope leaf devices connecting through // us as a gateway. In this case we let the upstream connection happen anyways, as any // unauthorized attempt here would be denied by IoTHub. authChain = authChainMaybe.OrDefault(); } // Get the transport settings ITransportSettings[] transportSettings = GetTransportSettings( this.upstreamProtocol, this.connectionPoolSize, this.proxy, this.useServerHeartbeat, authChain); if (this.edgeHubIdentity.Id.Equals(clientCredentials.Identity.Id)) { ICloudConnection cc = await CloudConnection.Create( clientCredentials.Identity, connectionStatusChangedHandler, transportSettings, this.messageConverterProvider, this.clientProvider, cloudListener, this.edgeHubTokenProvider, this.idleTimeout, this.closeOnIdleTimeout, this.operationTimeout, productInfo, modelId); Events.SuccessCreatingCloudConnection(clientCredentials.Identity); return(Try.Success(cc)); } else if (clientCredentials is ITokenCredentials clientTokenCredentails) { ICloudConnection cc = await ClientTokenCloudConnection.Create( clientTokenCredentails, connectionStatusChangedHandler, transportSettings, this.messageConverterProvider, this.clientProvider, cloudListener, this.idleTimeout, this.closeOnIdleTimeout, this.operationTimeout, productInfo, modelId); Events.SuccessCreatingCloudConnection(clientCredentials.Identity); return(Try.Success(cc)); } else { throw new InvalidOperationException($"Cannot connect using client credentials of type {clientCredentials.AuthenticationType} for identity {clientCredentials.Identity.Id}"); } } catch (Exception ex) { Events.ErrorCreatingCloudConnection(clientCredentials.Identity, ex); return(Try <ICloudConnection> .Failure(ex)); } }
async Task <Try <ICloudConnection> > TryCreateCloudConnectionFromServiceIdentity(IIdentity identity, Action <string, CloudConnectionStatus> connectionStatusChangedHandler, bool refreshOutOfDateCache, CloudListener cloudListener, string authChain) { Events.CreatingCloudConnectionOnBehalfOf(identity); ConnectionMetadata connectionMetadata = await this.metadataStore.GetMetadata(identity.Id); string productInfo = connectionMetadata.EdgeProductInfo; Option <string> modelId = connectionMetadata.ModelId; ITransportSettings[] transportSettings = GetTransportSettings( this.upstreamProtocol, this.connectionPoolSize, this.proxy, this.useServerHeartbeat, authChain); try { ICloudConnection cc = await CloudConnection.Create( identity, connectionStatusChangedHandler, transportSettings, this.messageConverterProvider, this.clientProvider, cloudListener, this.edgeHubTokenProvider, this.idleTimeout, this.closeOnIdleTimeout, this.operationTimeout, productInfo, modelId); Events.SuccessCreatingCloudConnection(identity); return(Try.Success(cc)); } catch (UnauthorizedException ex) when(this.trackDeviceState) { return(await this.TryRecoverCloudConnection(identity, connectionStatusChangedHandler, refreshOutOfDateCache, ex)); } }
async Task <Try <ICloudConnection> > ConnectInternal(IIdentity identity, Action <string, CloudConnectionStatus> connectionStatusChangedHandler) { Preconditions.CheckNotNull(identity, nameof(identity)); try { var cloudListener = new CloudListener(this.edgeHub.Expect(() => new InvalidOperationException("EdgeHub reference should not be null")), identity.Id); Option <ServiceIdentity> serviceIdentity = (await this.deviceScopeIdentitiesCache.GetServiceIdentity(identity.Id)) .Filter(s => s.Status == ServiceIdentityStatus.Enabled); string authChain = string.Empty; if (this.nestedEdgeEnabled) { Option <string> authChainMaybe = await this.deviceScopeIdentitiesCache.GetAuthChain(identity.Id); authChain = authChainMaybe.Expect(() => new InvalidOperationException($"No auth chain for the client identity: {identity.Id}")); } ITransportSettings[] transportSettings = GetTransportSettings( this.upstreamProtocol, this.connectionPoolSize, this.proxy, this.useServerHeartbeat, authChain); return(await serviceIdentity .Map( async si => { Events.CreatingCloudConnectionOnBehalfOf(identity); ConnectionMetadata connectionMetadata = await this.metadataStore.GetMetadata(identity.Id); string productInfo = connectionMetadata.EdgeProductInfo; Option <string> modelId = connectionMetadata.ModelId; ICloudConnection cc = await CloudConnection.Create( identity, connectionStatusChangedHandler, transportSettings, this.messageConverterProvider, this.clientProvider, cloudListener, this.edgeHubTokenProvider, this.idleTimeout, this.closeOnIdleTimeout, this.operationTimeout, productInfo, modelId); Events.SuccessCreatingCloudConnection(identity); return Try.Success(cc); }) .GetOrElse( async() => { // allow to use credential cache when auth mode is not Scope only (could be CloudAndScope or Cloud) or identity is for edgeHub if (!this.scopeAuthenticationOnly || this.edgeHubIdentity.Id.Equals(identity.Id)) { Events.ServiceIdentityNotFound(identity); Option <IClientCredentials> clientCredentials = await this.credentialsCache.Get(identity); var clientCredential = clientCredentials.Expect(() => new InvalidOperationException($"Unable to find identity {identity.Id} in device scopes cache or credentials cache")); return await this.Connect(clientCredential, connectionStatusChangedHandler); } else { throw new InvalidOperationException($"Unable to find identity {identity.Id} in device scopes cache"); } })); } catch (Exception ex) { Events.ErrorCreatingCloudConnection(identity, ex); return(Try <ICloudConnection> .Failure(ex)); } }