示例#1
0
        /// <summary>
        /// Uploads a file from the local workstation to S3.
        /// </summary>
        /// <param name="sourcePath">The source file path.</param>
        /// <param name="targetUri">
        /// The target S3 URI.  This may be either an <b>s3://BUCKET/KEY</b> or a
        /// <b>https://s3.REGION.amazonaws.com/BUCKET/KEY</b> URI referencing an S3
        /// bucket and key.
        /// </param>
        /// <param name="gzip">Optionally indicates that the target content encoding should be set to <b>gzip</b>.</param>
        /// <param name="metadata">
        /// <para>
        /// Optionally specifies HTTP metadata headers to be returned when the object
        /// is downloaded from S3.  This formatted as as comma separated a list of
        /// key/value pairs like:
        /// </para>
        /// <example>
        /// Content-Type=text,app-version=1.0.0
        /// </example>
        /// <note>
        /// <para>
        /// AWS supports <b>system</b> as well as <b>custom</b> headers.  System headers
        /// include standard HTTP headers such as <b>Content-Type</b> and <b>Content-Encoding</b>.
        /// Custom headers are required to include the <b>x-amz-meta-</b> prefix.
        /// </para>
        /// <para>
        /// You don't need to specify the <b>x-amz-meta-</b> prefix for setting custom
        /// headers; the AWS-CLI detects custom header names and adds the prefix automatically.
        /// This method will strip the prefix if present before calling the AWS-CLI to ensure
        /// the prefix doesn't end up being duplicated.
        /// </para>
        /// </note>
        /// </param>
        /// <param name="publicReadAccess">Optionally grant the upload public read access.</param>
        public static void S3Upload(string sourcePath, string targetUri, bool gzip = false, string metadata = null, bool publicReadAccess = false)
        {
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(sourcePath), nameof(sourcePath));
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(targetUri), nameof(targetUri));

            // $todo(jefflill):
            //
            // Hardcoding [max_concurrent_requests = 5] for now, down from the default value: 10.
            // I believe the higher setting is making uploads less reliable and may also consume
            // too much bandwidth.  We should probably make this a parameter.
            //
            // Note this changes this setting system side.

            ExecuteSafe("configure", "set", "default.s3.max_concurrent_requests", "5");

            // Perform the upload.

            var s3Uri = NetHelper.ToAwsS3Uri(targetUri);
            var args  = new List <string>()
            {
                "s3", "cp", sourcePath, s3Uri
            };

            if (gzip)
            {
                args.Add("--content-encoding");
                args.Add("gzip");
            }

            var sbMetadata = new StringBuilder();

            if (!string.IsNullOrEmpty(metadata) && metadata.Contains('='))
            {
                foreach (var item in metadata.Split(',', StringSplitOptions.RemoveEmptyEntries))
                {
                    // Strip off the [x-amz-meta-] prefix from the name, if present.
                    // Otherwise, the AWS-CLI will add the prefix again, duplicating it.

                    const string customPrefix = "x-amz-meta-";

                    var fields = item.Split('=', 2, StringSplitOptions.RemoveEmptyEntries);

                    if (fields.Length != 2)
                    {
                        throw new ArgumentException($"Invalid metadata [{metadata}].", nameof(metadata));
                    }

                    var name  = fields[0].Trim();
                    var value = fields[1].Trim();

                    if (value == string.Empty)
                    {
                        // Ignore metadata with empty values.

                        continue;
                    }

                    if (name.StartsWith(customPrefix))
                    {
                        name = name.Substring(customPrefix.Length);

                        metadata = $"{name}={value}";
                    }

                    // Some headers are considered to be "system defined" and need to be
                    // passed as command line options.  We'll separate those out, add the
                    // necessary options to the arguments and add any remaining headers
                    // to the metadata builder.

                    switch (name.ToLowerInvariant())
                    {
                    case "content-type":
                    case "cache-control":
                    case "content-disposition":
                    case "content-encoding":
                    case "content-language":
                    case "expires":

                        args.Add("--" + name.ToLowerInvariant());
                        args.Add(value);
                        break;

                    default:

                        sbMetadata.AppendWithSeparator($"{name}={value}", ",");
                        break;
                    }
                }
            }

            if (sbMetadata.Length > 0)
            {
                args.Add("--metadata");
                args.Add(sbMetadata.ToString());
            }

            AddDebugOption(args);

            s3Retry.Invoke(() => ExecuteSafe(args.ToArray()));

            if (publicReadAccess)
            {
                var uri    = new Uri(s3Uri, UriKind.Absolute);
                var bucket = uri.Host;
                var key    = uri.AbsolutePath.Substring(1);

                s3Retry.Invoke(() => ExecuteSafe("s3api", "put-object-acl", "--bucket", bucket, "--key", key, "--acl", "public-read"));
            }
        }
示例#2
0
 public void QueryAsyncSku(ReadOnlyCollection <ProductDefinition> products, Action <List <AndroidJavaObject> > onSkuDetailsResponse)
 {
     m_RetryPolicy.Invoke(retryAction => QueryAsyncSkuWithRetries(products, onSkuDetailsResponse, retryAction));
 }