Kit.Core/LibExternal/Minio/MinioClientExtensions.cs

335 lines
14 KiB
C#

/*
* MinIO .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 MinIO, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Globalization;
using System.Net;
using System.Reflection;
using System.Runtime.InteropServices;
using Minio.Credentials;
using Minio.DataModel;
using Minio.DataModel.Result;
using Minio.Exceptions;
using Minio.Handlers;
using Minio.Helper;
namespace Minio;
public static class MinioClientExtensions
{
internal static string SystemUserAgent
{
get
{
var assembly = Assembly.GetExecutingAssembly();
var version = assembly.GetName().Version;
var release = $"minio-dotnet/{version}";
#if NET46
string arch = Environment.Is64BitOperatingSystem ? "x86_64" : "x86";
return $"MinIO ({Environment.OSVersion};{arch}) {release}";
#else
var arch = RuntimeInformation.OSArchitecture.ToString();
return $"MinIO ({RuntimeInformation.OSDescription};{arch}) {release}";
#endif
}
}
public static IMinioClient WithEndpoint(this IMinioClient minioClient, string endpoint)
{
if (minioClient is null) throw new ArgumentNullException(nameof(minioClient));
minioClient.Config.Endpoint = endpoint;
minioClient.SetBaseURL(GetBaseUrl(endpoint));
return minioClient;
}
public static IMinioClient WithEndpoint(this IMinioClient minioClient, string endpoint, int port)
{
if (minioClient is null) throw new ArgumentNullException(nameof(minioClient));
if (port < 1 || port > 65535)
throw new ArgumentException(
string.Format(CultureInfo.InvariantCulture, "Port {0} is not a number between 1 and 65535", port),
nameof(port));
endpoint = endpoint + ":" + port.ToString(CultureInfo.InvariantCulture);
minioClient.Config.Endpoint = endpoint;
minioClient.SetBaseURL(GetBaseUrl(endpoint));
return minioClient;
}
public static IMinioClient WithEndpoint(this IMinioClient minioClient, Uri url)
{
if (minioClient is null) throw new ArgumentNullException(nameof(minioClient));
if (url is null) throw new ArgumentNullException(nameof(url));
minioClient.SetBaseURL(url);
minioClient.Config.Endpoint = url.AbsoluteUri;
return minioClient;
}
public static IMinioClient WithRegion(this IMinioClient minioClient, string region)
{
if (minioClient is null) throw new ArgumentNullException(nameof(minioClient));
if (string.IsNullOrEmpty(region))
throw new ArgumentException(
string.Format(CultureInfo.InvariantCulture, "{0} the region value can't be null or empty.", region),
nameof(region));
minioClient.Config.Region = region;
return minioClient;
}
public static IMinioClient WithRegion(this IMinioClient minioClient)
{
if (minioClient is null) throw new ArgumentNullException(nameof(minioClient));
// Set region to its default value if empty or null
minioClient.Config.Region ??= "us-east-1";
return minioClient;
}
public static IMinioClient WithCredentials(this IMinioClient minioClient, string accessKey, string secretKey)
{
if (minioClient is null) throw new ArgumentNullException(nameof(minioClient));
minioClient.Config.AccessKey = accessKey;
minioClient.Config.SecretKey = secretKey;
return minioClient;
}
public static IMinioClient WithSessionToken(this IMinioClient minioClient, string st)
{
if (minioClient is null) throw new ArgumentNullException(nameof(minioClient));
minioClient.Config.SessionToken = st;
return minioClient;
}
/// <summary>
/// Connects to Cloud Storage with HTTPS if this method is invoked on client object
/// </summary>
/// <returns></returns>
public static IMinioClient WithSSL(this IMinioClient minioClient, bool secure = true)
{
if (minioClient is null) throw new ArgumentNullException(nameof(minioClient));
minioClient.Config.Secure = secure;
return minioClient;
}
/// <summary>
/// Uses webproxy for all requests if this method is invoked on client object.
/// </summary>
/// <param name="minioClient">The MinioClient instance used</param>
/// <param name="proxy">Information on the proxy server in the setup.</param>
/// <returns></returns>
public static IMinioClient WithProxy(this IMinioClient minioClient, IWebProxy proxy)
{
if (minioClient is null) throw new ArgumentNullException(nameof(minioClient));
minioClient.Config.Proxy = proxy;
return minioClient;
}
/// <summary>
/// Uses the set timeout for all requests if this method is invoked on client object
/// </summary>
/// <param name="minioClient">The MinioClient instance used</param>
/// <param name="timeout">Timeout in milliseconds.</param>
/// <returns></returns>
public static IMinioClient WithTimeout(this IMinioClient minioClient, int timeout)
{
if (minioClient is null) throw new ArgumentNullException(nameof(minioClient));
minioClient.Config.RequestTimeout = timeout;
return minioClient;
}
/// <summary>
/// Allows to add retry policy handler
/// </summary>
/// <param name="minioClient">The MinioClient instance used</param>
/// <param name="retryPolicyHandler">Delegate that will wrap execution of http client requests.</param>
/// <returns></returns>
public static IMinioClient WithRetryPolicy(this IMinioClient minioClient,
IRetryPolicyHandler retryPolicyHandler)
{
if (minioClient is null) throw new ArgumentNullException(nameof(minioClient));
minioClient.Config.RetryPolicyHandler = retryPolicyHandler;
return minioClient;
}
/// <summary>
/// Allows to add retry policy handler
/// </summary>
/// <param name="minioClient">The MinioClient instance used</param>
/// <param name="retryPolicyHandler">Delegate that will wrap execution of http client requests.</param>
/// <returns></returns>
public static IMinioClient WithRetryPolicy(this IMinioClient minioClient,
Func<Func<Task<ResponseResult>>, Task<ResponseResult>> retryPolicyHandler)
{
if (minioClient is null) throw new ArgumentNullException(nameof(minioClient));
_ = minioClient.WithRetryPolicy(new DefaultRetryPolicyHandler(retryPolicyHandler));
return minioClient;
}
/// <summary>
/// Allows end user to define the Http server and pass it as a parameter
/// </summary>
/// <param name="minioClient">The MinioClient instance used</param>
/// <param name="httpClient"> Instance of HttpClient</param>
/// <param name="disposeHttpClient"> Dispose the HttpClient when leaving</param>
/// <returns></returns>
public static IMinioClient WithHttpClient(this IMinioClient minioClient, HttpClient httpClient,
bool disposeHttpClient = false)
{
if (minioClient is null) throw new ArgumentNullException(nameof(minioClient));
if (httpClient is not null) minioClient.Config.HttpClient = httpClient;
minioClient.Config.DisposeHttpClient = disposeHttpClient;
return minioClient;
}
/// <summary>
/// With provider for credentials and session token if being used
/// </summary>
/// <returns></returns>
public static IMinioClient WithCredentialsProvider(this IMinioClient minioClient, IClientProvider provider)
{
if (minioClient is null) throw new ArgumentNullException(nameof(minioClient));
minioClient.Config.Provider = provider;
AccessCredentials credentials;
if (minioClient.Config.Provider is IAMAWSProvider)
// Empty object, we need the Minio client completely
credentials = new AccessCredentials();
else
credentials = minioClient.Config.Provider.GetCredentials();
if (credentials is null)
// Unable to fetch credentials.
return minioClient;
minioClient.Config.AccessKey = credentials.AccessKey;
minioClient.Config.SecretKey = credentials.SecretKey;
var isSessionTokenAvailable = !string.IsNullOrEmpty(credentials.SessionToken);
if ((minioClient.Config.Provider is AWSEnvironmentProvider ||
minioClient.Config.Provider is IAMAWSProvider ||
minioClient.Config.Provider is CertificateIdentityProvider ||
(minioClient.Config.Provider is ChainedProvider chainedProvider &&
chainedProvider.CurrentProvider is AWSEnvironmentProvider))
&& isSessionTokenAvailable)
minioClient.Config.SessionToken = credentials.SessionToken;
return minioClient;
}
public static IMinioClient Build(this IMinioClient minioClient)
{
if (minioClient is null) throw new ArgumentNullException(nameof(minioClient));
// Instantiate a region cache
minioClient.Config.RegionCache = BucketRegionCache.Instance;
if (string.IsNullOrEmpty(minioClient.Config.BaseUrl)) throw new MinioException("Endpoint not initialized.");
if (minioClient.Config.Provider is not null &&
minioClient.Config.Provider.GetType() != typeof(ChainedProvider) &&
minioClient.Config.SessionToken is null)
throw new MinioException("User Access Credentials Provider not initialized correctly.");
if (minioClient.Config.Provider is null &&
(string.IsNullOrEmpty(minioClient.Config.AccessKey) || string.IsNullOrEmpty(minioClient.Config.SecretKey)))
throw new MinioException("User Access Credentials not initialized.");
var host = minioClient.Config.BaseUrl;
var scheme = minioClient.Config.Secure ? Utils.UrlEncode("https") : Utils.UrlEncode("http");
if (!minioClient.Config.BaseUrl.StartsWith("http", StringComparison.OrdinalIgnoreCase))
minioClient.Config.Endpoint = string.Format(CultureInfo.InvariantCulture, "{0}://{1}", scheme, host);
else
minioClient.Config.Endpoint = host;
var httpClientHandler = new HttpClientHandler { Proxy = minioClient.Config.Proxy };
minioClient.Config.HttpClient ??= minioClient.Config.Proxy is null
? new HttpClient()
: new HttpClient(httpClientHandler);
_ = minioClient.Config.HttpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent",
minioClient.Config.FullUserAgent);
minioClient.Config.HttpClient.Timeout = TimeSpan.FromMinutes(30);
return minioClient;
}
/// <summary>
/// Sets app version and name. Used for constructing User-Agent header in all HTTP requests
/// </summary>
/// <param name="minioClient"></param>
/// <param name="appName"></param>
/// <param name="appVersion"></param>
public static IMinioClient SetAppInfo(this IMinioClient minioClient, string appName, string appVersion)
{
if (string.IsNullOrEmpty(appName))
throw new ArgumentException("Appname cannot be null or empty", nameof(appName));
if (string.IsNullOrEmpty(appVersion))
throw new ArgumentException("Appversion cannot be null or empty", nameof(appVersion));
minioClient.Config.CustomUserAgent = $"{appName}/{appVersion}";
return minioClient;
}
internal static Uri GetBaseUrl(string endpoint)
{
if (string.IsNullOrEmpty(endpoint))
throw new ArgumentException(
string.Format(CultureInfo.InvariantCulture,
"{0} is the value of the endpoint. It can't be null or empty.", endpoint),
nameof(endpoint));
if (endpoint.EndsWith("/", StringComparison.OrdinalIgnoreCase))
endpoint = endpoint[..^1];
if (!BuilderUtil.IsValidHostnameOrIPAddress(endpoint))
throw new InvalidEndpointException(
string.Format(CultureInfo.InvariantCulture, "{0} is invalid hostname.", endpoint), "endpoint");
string conn_url;
if (endpoint.StartsWith("http", StringComparison.OrdinalIgnoreCase))
throw new InvalidEndpointException(
string.Format(CultureInfo.InvariantCulture,
"{0} the value of the endpoint has the scheme (http/https) in it.", endpoint),
"endpoint");
var enable_https = Environment.GetEnvironmentVariable("ENABLE_HTTPS");
var scheme = enable_https?.Equals("1", StringComparison.OrdinalIgnoreCase) == true ? "https://" : "http://";
conn_url = scheme + endpoint;
var url = new Uri(conn_url);
var hostnameOfUri = url.Authority;
if (!string.IsNullOrEmpty(hostnameOfUri) && !BuilderUtil.IsValidHostnameOrIPAddress(hostnameOfUri))
throw new InvalidEndpointException(
string.Format(CultureInfo.InvariantCulture, "{0}, {1} is invalid hostname.", endpoint, hostnameOfUri),
"endpoint");
return url;
}
internal static void SetBaseURL(this IMinioClient minioClient, Uri url)
{
if (url.IsDefaultPort)
minioClient.Config.BaseUrl = url.Host;
else
minioClient.Config.BaseUrl = url.Host + ":" + url.Port;
}
}