aliyun-net-sdk-dybaseapi/Dybaseapi/MNS/Util/AliyunSDKUtils.cs (239 lines of code) (raw):

using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Net; using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Threading; namespace Aliyun.Acs.Dybaseapi.MNS.Util { /// <summary> /// This class defines utilities and constants that can be used by MNS clients. /// </summary> public static partial class AliyunSDKUtils { #region Internal Constants internal const string SDKVersionNumber = "1.0.0.0"; internal static string _userAgentBaseName = "aliyun-sdk-dotnet"; private const int DefaultConnectionLimit = 50; private const int DefaultMaxIdleTime = 50 * 1000; // 50 seconds internal static readonly DateTime EPOCH_START = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); internal const int DefaultBufferSize = 8192; internal static Dictionary<int, string> RFCEncodingSchemes = new Dictionary<int, string> { { 3986, ValidUrlCharacters }, { 1738, ValidUrlCharactersRFC1738 } }; #endregion #region Public Constants /// <summary> /// The Set of accepted and valid queueUrl characters per RFC3986. /// Characters outside of this set will be encoded. /// </summary> public const string ValidUrlCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~"; /// <summary> /// The Set of accepted and valid queueUrl characters per RFC1738. /// Characters outside of this set will be encoded. /// </summary> public const string ValidUrlCharactersRFC1738 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_."; /// <summary> /// The set of accepted and valid queueUrl path characters per RFC3986. /// </summary> private static string ValidPathCharacters = DetermineValidPathCharacters(); // Checks which path characters should not be encoded private static string DetermineValidPathCharacters() { const string basePathCharacters = "/:'()!*[]"; var sb = new StringBuilder(); foreach (var c in basePathCharacters) { var escaped = Uri.EscapeUriString(c.ToString()); if (escaped.Length == 1 && escaped[0] == c) sb.Append(c); } return sb.ToString(); } /// <summary> /// The ISO8601Date Format string. Used when parsing date objects /// </summary> public const string ISO8601DateFormat = "yyyy-MM-dd\\THH:mm:ss.fff\\Z"; /// <summary> /// The RFC822Date Format string. Used when parsing date objects /// </summary> public const string RFC822DateFormat = "ddd, dd MMM yyyy HH:mm:ss \\G\\M\\T"; #endregion #region UserAgent static string _versionNumber; static string _sdkUserAgent; /// <summary> /// The MNS SDK User Agent /// </summary> public static string SDKUserAgent { get { return _sdkUserAgent; } } static AliyunSDKUtils() { BuildUserAgentString(); } static void BuildUserAgentString() { if (_versionNumber == null) { _versionNumber = SDKVersionNumber; } _sdkUserAgent = string.Format(CultureInfo.InvariantCulture, "{0}/{1} .NET Runtime/{2} .NET Framework/{3} OS/{4}", _userAgentBaseName, _versionNumber, DetermineRuntime(), DetermineFramework(), DetermineOSVersion()); } static string DetermineRuntime() { return string.Format(CultureInfo.InvariantCulture, "{0}.{1}", Environment.Version.Major, Environment.Version.MajorRevision); } static string DetermineFramework() { try { return Environment.Version.Major.ToString(); // compatible fix //if (Environment.Version.Major >= 4 && Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Net Framework Setup\\NDP\\v4") != null) // return "4.0"; //if (Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Net Framework Setup\\NDP\\v3.5") != null) // return "3.5"; //if (Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Net Framework Setup\\NDP\\v3.0") != null) // return "3.0"; //if (Registry.LocalMachine.OpenSubKey(@"Software\\Microsoft\\Net Framework Setup\\NDP\\v2.0.50727") != null) //return "2.0"; } catch (Exception) { } return "Unknown"; } static string DetermineOSVersion() { return Environment.OSVersion.Version.ToString(); } #endregion #region HTTP Connection Configurations private const int _defaultConnectionLimit = 2; internal static int GetConnectionLimit(int? clientConfigValue) { // Connection limit has been explicitly set on the client. if (clientConfigValue.HasValue) return clientConfigValue.Value; // If default has been left at the system default return the SDK default. if (ServicePointManager.DefaultConnectionLimit == _defaultConnectionLimit) return DefaultConnectionLimit; // The system default has been explicitly changed so we will honor that value. return ServicePointManager.DefaultConnectionLimit; } private const int _defaultMaxIdleTime = 100 * 1000; internal static int GetMaxIdleTime(int? clientConfigValue) { // MaxIdleTime has been explicitly set on the client. if (clientConfigValue.HasValue) return clientConfigValue.Value; // If default has been left at the system default return the SDK default. if (ServicePointManager.MaxServicePointIdleTime == _defaultMaxIdleTime) return DefaultMaxIdleTime; // The system default has been explicitly changed so we will honor that value. return ServicePointManager.MaxServicePointIdleTime; } #endregion #region Internal Methods /** * Convert Dictionary of paremeters to queueUrl encoded query string */ internal static string GetParametersAsString(IDictionary<string, string> parameters) { string[] keys = new string[parameters.Keys.Count]; parameters.Keys.CopyTo(keys, 0); Array.Sort<string>(keys); StringBuilder data = new StringBuilder(512); foreach (string key in keys) { string value = parameters[key]; if (value != null) { data.Append(key); data.Append('='); data.Append(value); data.Append('&'); } } string result = data.ToString(); if (result.Length == 0) return string.Empty; return result.Remove(result.Length - 1); } public static void CopyTo(this Stream input, Stream output) { byte[] buffer = new byte[16 * 1024]; int bytesRead; while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0) { output.Write(buffer, 0, bytesRead); } } /// <summary> /// Utility method for converting Unix epoch seconds to DateTime structure. /// </summary> /// <param name="milliSeconds">The number of milliSeconds since January 1, 1970.</param> /// <returns>Converted DateTime structure</returns> public static DateTime ConvertFromUnixEpochSeconds(long milliSeconds) { return new DateTime(milliSeconds * 10000L + EPOCH_START.Ticks, DateTimeKind.Utc).ToLocalTime(); } #endregion #region Public Methods and Properties /// <summary> /// Formats the current date as ISO 8601 timestamp /// </summary> /// <returns>An ISO 8601 formatted string representation /// of the current date and time /// </returns> public static string FormattedCurrentTimestampRFC822 { get { return GetFormattedTimestampRFC822(0); } } /// <summary> /// Gets the RFC822 formatted timestamp that is minutesFromNow /// in the future. /// </summary> /// <param name="minutesFromNow">The number of minutes from the current instant /// for which the timestamp is needed.</param> /// <returns>The ISO8601 formatted future timestamp.</returns> public static string GetFormattedTimestampRFC822(int minutesFromNow) { DateTime dateTime = DateTime.UtcNow.AddMinutes(minutesFromNow); DateTime formatted = new DateTime( dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond, DateTimeKind.Local ); return formatted.ToString( RFC822DateFormat, CultureInfo.InvariantCulture ); } /// <summary> /// URL encodes a string per RFC3986. If the path property is specified, /// the accepted path characters {/+:} are not encoded. /// </summary> /// <param name="data">The string to encode</param> /// <param name="path">Whether the string is a URL path or not</param> /// <returns>The encoded string</returns> public static string UrlEncode(string data, bool path) { return UrlEncode(3986, data, path); } /// <summary> /// URL encodes a string per the specified RFC. If the path property is specified, /// the accepted path characters {/+:} are not encoded. /// </summary> /// <param name="rfcNumber">RFC number determing safe characters</param> /// <param name="data">The string to encode</param> /// <param name="path">Whether the string is a URL path or not</param> /// <returns>The encoded string</returns> /// <remarks> /// Currently recognised RFC versions are 1738 (Dec '94) and 3986 (Jan '05). /// If the specified RFC is not recognised, 3986 is used by default. /// </remarks> internal static string UrlEncode(int rfcNumber, string data, bool path) { StringBuilder encoded = new StringBuilder(data.Length * 2); string validUrlCharacters; if (!RFCEncodingSchemes.TryGetValue(rfcNumber, out validUrlCharacters)) validUrlCharacters = ValidUrlCharacters; string unreservedChars = String.Concat(validUrlCharacters, (path ? ValidPathCharacters : "")); foreach (char symbol in Encoding.UTF8.GetBytes(data)) { if (unreservedChars.IndexOf(symbol) != -1) { encoded.Append(symbol); } else { encoded.Append("%").Append(string.Format(CultureInfo.InvariantCulture, "{0:X2}", (int)symbol)); } } return encoded.ToString(); } public static void Sleep(int ms) { Thread.Sleep(ms); } internal static string ExtractQueueName(string queueUrl, string endpoint) { if (!queueUrl.StartsWith(endpoint)) throw new ArgumentException(String.Format("Invalid Queue URL {0}", queueUrl)); string queueName = queueUrl.Substring(endpoint.Length); queueName = Regex.Replace(queueName.Trim(), "/", ""); if (string.IsNullOrEmpty(queueName)) throw new ArgumentException(String.Format("Invalid Queue Name {0}", queueName)); return queueName; } static readonly object _preserveStackTraceLookupLock = new object(); static bool _preserveStackTraceLookup = false; static MethodInfo _preserveStackTrace; /// <summary> /// This method is used preserve the stacktrace used from clients that support async calls. This /// make sure that exceptions thrown during EndXXX methods has the orignal stacktrace that happen /// in the background thread. /// </summary> /// <param name="exception"></param> internal static void PreserveStackTrace(Exception exception) { if (!_preserveStackTraceLookup) { lock (_preserveStackTraceLookupLock) { _preserveStackTraceLookup = true; try { _preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace", BindingFlags.Instance | BindingFlags.NonPublic); } catch { } } } if (_preserveStackTrace != null) { _preserveStackTrace.Invoke(exception, null); } } #endregion } }