Google Api

This commit is contained in:
Paul Schneider 2017-06-20 02:47:52 +02:00
commit 83f9fc1bd8
123 changed files with 12961 additions and 60 deletions

View file

@ -0,0 +1,99 @@
/*
Copyright 2013 Google 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;
namespace Google.Apis.Util
{
/// <summary>
/// Implementation of <see cref="IBackOff"/> that increases the back-off period for each retry attempt using a
/// randomization function that grows exponentially. In addition, it also adds a randomize number of milliseconds
/// for each attempt.
/// </summary>
public class ExponentialBackOff : IBackOff
{
/// <summary>The maximum allowed number of retries.</summary>
private const int MaxAllowedNumRetries = 20;
private readonly TimeSpan deltaBackOff;
/// <summary>
/// Gets the delta time span used to generate a random milliseconds to add to the next back-off.
/// If the value is <see cref="System.TimeSpan.Zero"/> then the generated back-off will be exactly 1, 2, 4,
/// 8, 16, etc. seconds. A valid value is between zero and one second. The default value is 250ms, which means
/// that the generated back-off will be [0.75-1.25]sec, [1.75-2.25]sec, [3.75-4.25]sec, and so on.
/// </summary>
public TimeSpan DeltaBackOff
{
get { return deltaBackOff; }
}
private readonly int maxNumOfRetries;
/// <summary>Gets the maximum number of retries. Default value is <c>10</c>.</summary>
public int MaxNumOfRetries
{
get { return maxNumOfRetries; }
}
/// <summary>The random instance which generates a random number to add the to next back-off.</summary>
private Random random = new Random();
/// <summary>Constructs a new exponential back-off with default values.</summary>
public ExponentialBackOff()
: this(TimeSpan.FromMilliseconds(250))
{
}
/// <summary>Constructs a new exponential back-off with the given delta and maximum retries.</summary>
public ExponentialBackOff(TimeSpan deltaBackOff, int maximumNumOfRetries = 10)
{
if (deltaBackOff < TimeSpan.Zero || deltaBackOff > TimeSpan.FromSeconds(1))
{
throw new ArgumentOutOfRangeException("deltaBackOff");
}
if (maximumNumOfRetries < 0 || maximumNumOfRetries > MaxAllowedNumRetries)
{
throw new ArgumentOutOfRangeException("deltaBackOff");
}
this.deltaBackOff = deltaBackOff;
this.maxNumOfRetries = maximumNumOfRetries;
}
#region IBackOff Members
/// <inheritdoc/>
public TimeSpan GetNextBackOff(int currentRetry)
{
if (currentRetry <= 0)
{
throw new ArgumentOutOfRangeException("currentRetry");
}
if (currentRetry > MaxNumOfRetries)
{
return TimeSpan.MinValue;
}
// Generate a random number of milliseconds and add it to the current exponential number.
var randomMilli = (double)random.Next(
(int)(DeltaBackOff.TotalMilliseconds * -1),
(int)(DeltaBackOff.TotalMilliseconds * 1));
int backOffMilli = (int)(Math.Pow(2.0, (double)currentRetry - 1) * 1000 + randomMilli);
return TimeSpan.FromMilliseconds(backOffMilli);
}
#endregion
}
}

View file

@ -0,0 +1,33 @@
/*
Copyright 2013 Google 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;
namespace Google.Apis.Util
{
/// <summary>Strategy interface to control back-off between retry attempts.</summary>
public interface IBackOff
{
/// <summary>
/// Gets the a time span to wait before next retry. If the current retry reached the maximum number of retries,
/// the returned value is <see cref="TimeSpan.MinValue"/>.
/// </summary>
TimeSpan GetNextBackOff(int currentRetry);
/// <summary>Gets the maximum number of retries.</summary>
int MaxNumOfRetries { get; }
}
}

View file

@ -0,0 +1,56 @@
/*
Copyright 2013 Google 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;
namespace Google.Apis.Util
{
/// <summary>Clock wrapper for getting the current time.</summary>
public interface IClock
{
/// <summary>
/// Gets a <see cref="System.DateTime"/> object that is set to the current date and time on this computer,
/// expressed as the local time.
/// </summary>
[Obsolete("System local time is almost always inappropriate to use. If you really need this, call UtcNow and then call ToLocalTime on the result")]
DateTime Now { get; }
/// <summary>
/// Gets a <see cref="System.DateTime"/> object that is set to the current date and time on this computer,
/// expressed as UTC time.
/// </summary>
DateTime UtcNow { get; }
}
/// <summary>
/// A default clock implementation that wraps the <see cref="System.DateTime.UtcNow"/>
/// and <see cref="System.DateTime.Now"/> properties.
/// </summary>
public class SystemClock : IClock
{
/// <summary>Constructs a new system clock.</summary>
protected SystemClock() { }
/// <summary>The default instance.</summary>
public static readonly IClock Default = new SystemClock();
/// <inheritdoc/>
public DateTime Now => DateTime.Now;
/// <inheritdoc/>
public DateTime UtcNow => DateTime.UtcNow;
}
}

View file

@ -0,0 +1,75 @@
/*
Copyright 2011 Google 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.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Google.Apis.Util
{
/// <summary>
/// Repeatable class which allows you to both pass a single element, as well as an array, as a parameter value.
/// </summary>
public class Repeatable<T> : IEnumerable<T>
{
private readonly IList<T> values;
/// <summary>Creates a repeatable value.</summary>
public Repeatable(IEnumerable<T> enumeration)
{
values = new ReadOnlyCollection<T>(new List<T>(enumeration));
}
/// <inheritdoc/>
public IEnumerator<T> GetEnumerator()
{
return values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>Converts the single element into a repeatable.</summary>
public static implicit operator Repeatable<T>(T elem)
{
if (elem == null)
{
return null;
}
return new Repeatable<T>(new[] { elem });
}
/// <summary>Converts a number of elements into a repeatable.</summary>
public static implicit operator Repeatable<T>(T[] elem)
{
if (elem.Length == 0)
{
return null;
}
return new Repeatable<T>(elem);
}
/// <summary>Converts a number of elements into a repeatable.</summary>
public static implicit operator Repeatable<T>(List<T> elem)
{
return new Repeatable<T>(elem);
}
}
}

View file

@ -0,0 +1,82 @@
/*
Copyright 2011 Google 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;
namespace Google.Apis.Util
{
/// <summary>
/// An attribute which is used to specially mark a property for reflective purposes,
/// assign a name to the property and indicate it's location in the request as either
/// in the path or query portion of the request URL.
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class RequestParameterAttribute : Attribute
{
private readonly string name;
private readonly RequestParameterType type;
/// <summary>Gets the name of the parameter.</summary>
public string Name { get { return name; } }
/// <summary>Gets the type of the parameter, Path or Query.</summary>
public RequestParameterType Type { get { return type; } }
/// <summary>
/// Constructs a new property attribute to be a part of a REST URI.
/// This constructor uses <see cref="RequestParameterType.Query"/> as the parameter's type.
/// </summary>
/// <param name="name">
/// The name of the parameter. If the parameter is a path parameter this name will be used to substitute the
/// string value into the path, replacing {name}. If the parameter is a query parameter, this parameter will be
/// added to the query string, in the format "name=value".
/// </param>
public RequestParameterAttribute(string name)
: this(name, RequestParameterType.Query)
{
}
/// <summary>Constructs a new property attribute to be a part of a REST URI.</summary>
/// <param name="name">
/// The name of the parameter. If the parameter is a path parameter this name will be used to substitute the
/// string value into the path, replacing {name}. If the parameter is a query parameter, this parameter will be
/// added to the query string, in the format "name=value".
/// </param>
/// <param name="type">The type of the parameter, either Path, Query or UserDefinedQueries.</param>
public RequestParameterAttribute(string name, RequestParameterType type)
{
this.name = name;
this.type = type;
}
}
/// <summary>Describe the type of this parameter (Path, Query or UserDefinedQueries).</summary>
public enum RequestParameterType
{
/// <summary>A path parameter which is inserted into the path portion of the request URI.</summary>
Path,
/// <summary>A query parameter which is inserted into the query portion of the request URI.</summary>
Query,
/// <summary>
/// A group of user-defined parameters that will be added in to the query portion of the request URI. If this
/// type is being used, the name of the RequestParameterAttirbute is meaningless.
/// </summary>
UserDefinedQueries
}
}

View file

@ -0,0 +1,37 @@
/*
Copyright 2010 Google 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 Google.Apis.Requests;
using Newtonsoft.Json;
namespace Google.Apis.Util
{
/// <summary>
/// Calls to Google Api return StandardResponses as Json with
/// two properties Data, being the return type of the method called
/// and Error, being any errors that occure.
/// </summary>
public sealed class StandardResponse<InnerType>
{
/// <summary>May be null if call failed.</summary>
[JsonProperty("data")]
public InnerType Data { get; set; }
/// <summary>May be null if call succedded.</summary>
[JsonProperty("error")]
public RequestError Error { get; set; }
}
}

View file

@ -0,0 +1,52 @@
/*
Copyright 2013 Google 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.Threading.Tasks;
namespace Google.Apis.Util.Store
{
/// <summary>
/// Stores and manages data objects, where the key is a string and the value is an object.
/// <para>
/// <c>null</c> keys are not allowed.
/// </para>
/// </summary>
public interface IDataStore
{
/// <summary>Asynchronously stores the given value for the given key (replacing any existing value).</summary>
/// <typeparam name="T">The type to store in the data store.</typeparam>
/// <param name="key">The key.</param>
/// <param name="value">The value to store.</param>
Task StoreAsync<T>(string key, T value);
/// <summary>
/// Asynchronously deletes the given key. The type is provided here as well because the "real" saved key should
/// contain type information as well, so the data store will be able to store the same key for different types.
/// </summary>
/// <typeparam name="T">The type to delete from the data store.</typeparam>
/// <param name="key">The key to delete.</param>
Task DeleteAsync<T>(string key);
/// <summary>Asynchronously returns the stored value for the given key or <c>null</c> if not found.</summary>
/// <typeparam name="T">The type to retrieve from the data store.</typeparam>
/// <param name="key">The key to retrieve its value.</param>
/// <returns>The stored object.</returns>
Task<T> GetAsync<T>(string key);
/// <summary>Asynchronously clears all values in the data store.</summary>
Task ClearAsync();
}
}

View file

@ -0,0 +1,36 @@
/*
Copyright 2011 Google 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;
namespace Google.Apis.Util
{
/// <summary>Defines an attribute containing a string representation of the member.</summary>
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public class StringValueAttribute : Attribute
{
private readonly string text;
/// <summary>The text which belongs to this member.</summary>
public string Text { get { return text; } }
/// <summary>Creates a new string value attribute with the specified text.</summary>
public StringValueAttribute(string text)
{
text.ThrowIfNull("text");
this.text = text;
}
}
}

View file

@ -0,0 +1,122 @@
/*
Copyright 2016 Google 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;
using System.Reflection;
namespace Google.Apis.Util
{
/// <summary>
/// Workarounds for some unfortunate behaviors in the .NET Framework's
/// implementation of System.Uri
/// </summary>
/// <remarks>
/// UriPatcher lets us work around some unfortunate behaviors in the .NET Framework's
/// implementation of System.Uri.
///
/// == Problem 1: Slashes and dots
///
/// Prior to .NET 4.5, System.Uri would always unescape "%2f" ("/") and "%5c" ("\\").
/// Relative path components were also compressed.
///
/// As a result, this: "http://www.example.com/.%2f.%5c./"
/// ... turned into this: "http://www.example.com/"
///
/// This breaks API requests where slashes or dots appear in path parameters. Such requests
/// arise, for example, when these characters appear in the name of a GCS object.
///
/// == Problem 2: Fewer unreserved characters
///
/// Unless IDN/IRI parsing is enabled -- which it is not, by default, prior to .NET 4.5 --
/// Uri.EscapeDataString uses the set of "unreserved" characters from RFC 2396 instead of the
/// newer, *smaller* list from RFC 3986. We build requests using URI templating as described
/// by RFC 6570, which specifies that the latter definition (RFC 3986) should be used.
///
/// This breaks API requests with parameters including any of: !*'()
///
/// == Solutions
///
/// Though the default behaviors changed in .NET 4.5, these "quirks" remain for compatibility
/// unless the application explicitly targets the new runtime. Usually, that means adding a
/// TargetFrameworkAttribute to the entry assembly.
///
/// Applications running on .NET 4.0 or later can also set "DontUnescapePathDotsAndSlashes"
/// and enable IDN/IRI parsing using app.config or web.config.
///
/// As a class library, we can't control app.config or the entry assembly, so we can't take
/// either approach. Instead, we resort to reflection trickery to try to solve these problems
/// if we detect they exist. Sorry.
/// </remarks>
public static class UriPatcher
{
/// <summary>
/// Patch URI quirks in System.Uri. See class summary for details.
/// </summary>
public static void PatchUriQuirks()
{
var uriParser = typeof(System.Uri).GetTypeInfo().Assembly.GetType("System.UriParser");
if (uriParser == null) { return; }
// Is "%2f" unescaped for http: or https: URIs?
if (new Uri("http://example.com/%2f").AbsolutePath == "//" ||
new Uri("https://example.com/%2f").AbsolutePath == "//")
{
// Call System.UriParser.Http[s]Uri.SetUpdatableFlags(UriSyntaxFlags.None)
// https://github.com/Microsoft/referencesource/blob/d925d870f3cb3f6a/System/net/System/_UriSyntax.cs#L87
// https://github.com/Microsoft/referencesource/blob/d925d870f3cb3f6a/System/net/System/_UriSyntax.cs#L77
// https://github.com/Microsoft/referencesource/blob/d925d870f3cb3f6a/System/net/System/_UriSyntax.cs#L352
var setUpdatableFlagsMethod = uriParser.GetMethod("SetUpdatableFlags",
BindingFlags.Instance | BindingFlags.NonPublic);
if (setUpdatableFlagsMethod != null)
{
Action<string> setUriParserUpdatableFlags = (fieldName) =>
{
var parserField = uriParser.GetField(fieldName,
BindingFlags.Static | BindingFlags.NonPublic);
if (parserField == null) { return; }
var parserInstance = parserField.GetValue(null);
if (parserInstance == null) { return; }
setUpdatableFlagsMethod.Invoke(parserInstance, new object[] { 0 });
};
// Make the change for the http: and https: URI parsers.
setUriParserUpdatableFlags("HttpUri");
setUriParserUpdatableFlags("HttpsUri");
}
}
// Is "*" considered "unreserved"?
if (Uri.EscapeDataString("*") == "*")
{
// Set UriParser.s_QuirksVersion to at least UriQuirksVersion.V3
// https://github.com/Microsoft/referencesource/blob/d925d870f3cb3f6a/System/net/System/_UriSyntax.cs#L114
// https://github.com/Microsoft/referencesource/blob/d925d870f3cb3f6a/System/net/System/UriHelper.cs#L701
var quirksField = uriParser.GetField("s_QuirksVersion",
BindingFlags.Static | BindingFlags.NonPublic);
if (quirksField != null)
{
int quirksVersion = (int)quirksField.GetValue(null);
if (quirksVersion <= 2)
{
quirksField.SetValue(null, 3);
}
}
}
}
}
}

View file

@ -0,0 +1,175 @@
/*
Copyright 2010 Google 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 Google.Apis.Testing;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
namespace Google.Apis.Util
{
/// <summary>A utility class which contains helper methods and extension methods.</summary>
public static class Utilities
{
/// <summary>Returns the version of the core library.</summary>
[VisibleForTestOnly]
public static string GetLibraryVersion()
{
return Regex.Match(typeof(Utilities).GetTypeInfo().Assembly.FullName, "Version=([\\d\\.]+)").Groups[1].ToString();
}
/// <summary>
/// A Google.Apis utility method for throwing an <see cref="System.ArgumentNullException"/> if the object is
/// <c>null</c>.
/// </summary>
public static T ThrowIfNull<T>(this T obj, string paramName)
{
if (obj == null)
{
throw new ArgumentNullException(paramName);
}
return obj;
}
/// <summary>
/// A Google.Apis utility method for throwing an <see cref="System.ArgumentNullException"/> if the string is
/// <c>null</c> or empty.
/// </summary>
/// <returns>The original string.</returns>
public static string ThrowIfNullOrEmpty(this string str, string paramName)
{
if (string.IsNullOrEmpty(str))
{
throw new ArgumentException("Parameter was empty", paramName);
}
return str;
}
/// <summary>Returns <c>true</c> in case the enumerable is <c>null</c> or empty.</summary>
internal static bool IsNullOrEmpty<T>(this IEnumerable<T> coll)
{
return coll == null || coll.Count() == 0;
}
/// <summary>
/// A Google.Apis utility method for returning the first matching custom attribute (or <c>null</c>) of the specified member.
/// </summary>
public static T GetCustomAttribute<T>(this MemberInfo info) where T : Attribute
{
object[] results = info.GetCustomAttributes(typeof(T), false).ToArray();
return results.Length == 0 ? null : (T)results[0];
}
/// <summary>Returns the defined string value of an Enum.</summary>
internal static string GetStringValue(this Enum value)
{
FieldInfo entry = value.GetType().GetField(value.ToString());
entry.ThrowIfNull("value");
// If set, return the value.
var attribute = entry.GetCustomAttribute<StringValueAttribute>();
if (attribute != null)
{
return attribute.Text;
}
// Otherwise, throw an exception.
throw new ArgumentException(
string.Format("Enum value '{0}' does not contain a StringValue attribute", entry), "value");
}
/// <summary>
/// Returns the defined string value of an Enum. Use for test purposes or in other Google.Apis projects.
/// </summary>
public static string GetEnumStringValue(Enum value)
{
return value.GetStringValue();
}
/// <summary>
/// Tries to convert the specified object to a string. Uses custom type converters if available.
/// Returns null for a null object.
/// </summary>
[VisibleForTestOnly]
public static string ConvertToString(object o)
{
if (o == null)
{
return null;
}
if (o.GetType().GetTypeInfo().IsEnum)
{
// Try to convert the Enum value using the StringValue attribute.
var enumType = o.GetType();
FieldInfo field = enumType.GetField(o.ToString());
StringValueAttribute attribute = field.GetCustomAttribute<StringValueAttribute>();
return attribute != null ? attribute.Text : o.ToString();
}
if (o is DateTime)
{
// Honor RFC3339.
return ConvertToRFC3339((DateTime)o);
}
if (o is bool)
{
return o.ToString().ToLowerInvariant();
}
return o.ToString();
}
/// <summary>Converts the input date into a RFC3339 string (http://www.ietf.org/rfc/rfc3339.txt).</summary>
internal static string ConvertToRFC3339(DateTime date)
{
if (date.Kind == DateTimeKind.Unspecified)
{
date = date.ToUniversalTime();
}
return date.ToString("yyyy-MM-dd'T'HH:mm:ss.fffK", DateTimeFormatInfo.InvariantInfo);
}
/// <summary>
/// Parses the input string and returns <see cref="System.DateTime"/> if the input is a valid
/// representation of a date. Otherwise it returns <c>null</c>.
/// </summary>
public static DateTime? GetDateTimeFromString(string raw)
{
DateTime result;
if (!DateTime.TryParse(raw, out result))
{
return null;
}
return result;
}
/// <summary>Returns a string (by RFC3339) form the input <see cref="DateTime"/> instance.</summary>
public static string GetStringFromDateTime(DateTime? date)
{
if (!date.HasValue)
{
return null;
}
return ConvertToRFC3339(date.Value);
}
}
}