Beispiel #1
0
        public static async Task <ClientTokenCloudConnection> Create(
            ITokenCredentials tokenCredentials,
            Action <string, CloudConnectionStatus> connectionStatusChangedHandler,
            ITransportSettings[] transportSettings,
            IMessageConverterProvider messageConverterProvider,
            IClientProvider clientProvider,
            ICloudListener cloudListener,
            TimeSpan idleTimeout,
            bool closeOnIdleTimeout,
            TimeSpan operationTimeout)
        {
            Preconditions.CheckNotNull(tokenCredentials, nameof(tokenCredentials));
            var cloudConnection = new ClientTokenCloudConnection(
                tokenCredentials.Identity,
                connectionStatusChangedHandler,
                transportSettings,
                messageConverterProvider,
                clientProvider,
                cloudListener,
                idleTimeout,
                closeOnIdleTimeout,
                operationTimeout);
            ITokenProvider tokenProvider = new ClientTokenBasedTokenProvider(tokenCredentials, cloudConnection);
            ICloudProxy    cloudProxy    = await cloudConnection.CreateNewCloudProxyAsync(tokenProvider);

            cloudConnection.cloudProxy = Option.Some(cloudProxy);
            return(cloudConnection);
        }
Beispiel #2
0
        /// <summary>
        /// This method does the following -
        ///     1. Updates the Identity to be used for the cloud connection
        ///     2. Updates the cloud proxy -
        ///         i. If there is an existing device client and
        ///             a. If is waiting for an updated token, and the Identity has a token,
        ///                then it uses that to give it to the waiting client authentication method.
        ///             b. If not, then it creates a new cloud proxy (and device client) and closes the existing one
        ///         ii. Else, if there is no cloud proxy, then opens a device client and creates a cloud proxy.
        /// </summary>
        public async Task <ICloudProxy> UpdateTokenAsync(ITokenCredentials newTokenCredentials)
        {
            Preconditions.CheckNotNull(newTokenCredentials, nameof(newTokenCredentials));

            using (await this.identityUpdateLock.LockAsync())
            {
                // Disable callbacks while we update the cloud proxy.
                // TODO - instead of this, make convert Option<ICloudProxy> CloudProxy to Task<Option<ICloudProxy>> GetCloudProxy
                // which can be awaited when an update is in progress.
                this.callbacksEnabled = false;
                try
                {
                    ITokenProvider tokenProvider = new ClientTokenBasedTokenProvider(newTokenCredentials, this);
                    // First check if there is an existing cloud proxy
                    ICloudProxy proxy = await this.CloudProxy.Map(
                        async cp =>
                    {
                        // If the Identity has a token, and we have a tokenGetter, that means
                        // the connection is waiting for a new token. So give it the token and
                        // complete the tokenGetter
                        if (this.tokenGetter.HasValue)
                        {
                            if (TokenHelper.IsTokenExpired(this.Identity.IotHubHostName, newTokenCredentials.Token))
                            {
                                throw new InvalidOperationException($"Token for client {this.Identity.Id} is expired");
                            }

                            this.tokenGetter.ForEach(
                                tg =>
                            {
                                // First reset the token getter and then set the result.
                                this.tokenGetter = Option.None <TaskCompletionSource <string> >();
                                tg.SetResult(newTokenCredentials.Token);
                            });
                            return(cp);
                        }
                        // Else this is a new connection for the same device Id. So open a new connection,
                        // and if that is successful, close the existing one.
                        else
                        {
                            ICloudProxy newCloudProxy = await this.CreateNewCloudProxyAsync(tokenProvider);
                            await cp.CloseAsync();
                            return(newCloudProxy);
                        }
                    })
                                        // No existing cloud proxy, so just create a new one.
                                        .GetOrElse(() => this.CreateNewCloudProxyAsync(tokenProvider));

                    // Set Identity only after successfully opening cloud proxy
                    // That way, if a we have one existing connection for a deviceA,
                    // and a new connection for deviceA comes in with an invalid key/token,
                    // the existing connection is not affected.
                    this.cloudProxy = Option.Some(proxy);
                    Events.UpdatedCloudConnection(this.Identity);
                    return(proxy);
                }
                catch (Exception ex)
                {
                    Events.CreateException(ex, this.Identity);
                    throw;
                }
                finally
                {
                    this.callbacksEnabled = true;
                }
            }
        }