Example #1
0
        private Func <IConfigurableHttpClientInitializer> ValidateAndGetInitializer(GoogleDriveOptions config)
        {
            if (_config.CredentialParameters == null)
            {
                throw new ArgumentNullException(nameof(_config.CredentialParameters));
            }

            //config should have either svc account config(ClientEmail, PrivateKey) or user account config(ClientId, ClientSecret, RefreshToken)
            var hasSvcAccount  = !string.IsNullOrWhiteSpace(_config.CredentialParameters.ClientEmail) && !string.IsNullOrWhiteSpace(_config.CredentialParameters.PrivateKey);
            var hasUserAccount = !string.IsNullOrWhiteSpace(_config.CredentialParameters.ClientId) && !string.IsNullOrWhiteSpace(_config.CredentialParameters.ClientSecret) && !string.IsNullOrWhiteSpace(_config.CredentialParameters.RefreshToken);

            if (hasSvcAccount && hasUserAccount)
            {
                throw new ArgumentException("Ambiguous account configuration. Only Service(ClientEmail, PrivateKey) or User(ClientId, ClientSecret, RefreshToken) account data should be provided.");
            }
            if (!hasSvcAccount && !hasUserAccount)
            {
                throw new ArgumentException("No valid account configuration present.");
            }

            if (string.IsNullOrWhiteSpace(_config.ApplicationName))
            {
                throw new ArgumentNullException(nameof(_config.ApplicationName));
            }
            if (string.IsNullOrWhiteSpace(_config.StorageRoot))
            {
                throw new ArgumentNullException(nameof(_config.StorageRoot));
            }

            _config.RootFolderName = !string.IsNullOrWhiteSpace(_config.RootFolderName) ? _config.RootFolderName : _config.ApplicationName;

            if (hasSvcAccount)
            {
                return(ServiceAccountInitializer);
            }
            else if (hasUserAccount)
            {
                return(UserAccountInitializer);
            }
            else
            {
                throw new InvalidOperationException("Invalid configuration exception");
            }
        }
Example #2
0
        public GoogleDriveService(IOptions <GoogleDriveOptions> config, ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.CreateLogger <GoogleDriveService>();
            _config = config?.Value ?? throw new ArgumentNullException(nameof(config));

            var httpInitializer = ValidateAndGetInitializer(_config);

            var svcInit = new BaseClientService.Initializer()
            {
                HttpClientInitializer           = httpInitializer(),
                ApplicationName                 = _config.ApplicationName,
                DefaultExponentialBackOffPolicy = ExponentialBackOffPolicy.None
            };

            _driveService = new DriveService(svcInit)
            {
                HttpClient =
                {
                    Timeout        = _config.TimeOut,
                    MessageHandler = { NumTries = 20 }
                }
            };

            var retryStatusCodes = new[] { HttpStatusCode.InternalServerError, HttpStatusCode.BadGateway, HttpStatusCode.ServiceUnavailable };

            var backoffHandler = new BackOffHandler(new BackOffHandler.Initializer(new ExponentialBackOff(TimeSpan.FromMilliseconds(500), 20))
            {
                MaxTimeSpan         = TimeSpan.FromSeconds(65),
                HandleExceptionFunc = exception =>
                {
                    var willDoBackoff = BackOffHandler.Initializer.DefaultHandleExceptionFunc(exception);
                    _logger.LogInformation($"'Exception' request: {exception.Message}. Try backoff: {willDoBackoff}");
                    return(willDoBackoff);
                },
                HandleUnsuccessfulResponseFunc = response =>
                {
                    var msg           = $"'Unsuccessful' request: {response.StatusCode}. ";
                    var willDoBackoff = retryStatusCodes.Contains(response.StatusCode);

                    if (!willDoBackoff)
                    {
                        try
                        {
                            var e = _driveService.DeserializeError(response).Result;
                            msg  += $"Reason: {(e.Errors?.Any() == true ? e.Errors[0].Reason : "unknown")}";

                            willDoBackoff = response.StatusCode == HttpStatusCode.Forbidden && (e.Errors[0].Reason == "rateLimitExceeded" || e.Errors[0].Reason == "userRateLimitExceeded");
                        }
                        catch
                        {
                        }
                    }
                    ;
                    _logger.LogInformation($"{msg} Backoff: {willDoBackoff}");
                    return(willDoBackoff);
                }
            });

            _driveService.HttpClient.MessageHandler.AddUnsuccessfulResponseHandler(backoffHandler);
            _driveService.HttpClient.MessageHandler.AddExceptionHandler(backoffHandler);
        }