public async Task <HashResponseContent> RequestHashesAsync(HashRequestContent request) { int retry = 3; do { try { return(await InternalRequestHashesAsync(request).ConfigureAwait(false)); } catch (HasherException hashEx) { throw hashEx; } catch (TimeoutException) { throw new HasherException("Pokefamer Hasher server might down - timeout out"); } catch (Exception ex) { APIConfiguration.Logger.LogDebug(ex.Message); } finally { retry--; } await Task.Delay(1000).ConfigureAwait(false); } while (retry > 0); throw new HasherException("Pokefamer Hash API server might be down"); }
private HashResponseContent InternalRequestHashes(HashRequestContent request) { using (var client = new System.Net.Http.HttpClient()) { client.BaseAddress = _baseAddress; client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); client.DefaultRequestHeaders.Add("X-AuthToken", this.apiKey); var content = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json"); content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); var response = client.PostAsync(_endpoint, content).Result; switch (response.StatusCode) { case HttpStatusCode.OK: //200 AuthTokenExpiration = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc).AddSeconds(Convert.ToUInt32(((String[])response.Headers.GetValues("X-AuthTokenExpiration"))[0])).ToLocalTime(); MaxRequestCount = Convert.ToUInt16(((string[])response.Headers.GetValues("X-MaxRequestCount"))[0]); RatePeriodEnd = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc).AddSeconds(Convert.ToUInt32(((String[])response.Headers.GetValues("X-RatePeriodEnd"))[0])).ToLocalTime(); RateRequestRemaining = Convert.ToUInt16(((string[])response.Headers.GetValues("X-RateRequestsRemaining"))[0]); RateLimitSeconds = Convert.ToUInt16(((string[])response.Headers.GetValues("X-RateLimitSeconds"))[0]); var remainingSeconds = (DateTime.Now - RatePeriodEnd).TotalSeconds * -1; Logger.Debug($"{RateRequestRemaining}/{MaxRequestCount} requests remaining for the next {remainingSeconds} seconds. Key expires on: {AuthTokenExpiration}"); if ((AuthTokenExpiration - DateTime.Now).TotalDays <= 3) { if (ExpirationCounter-- == 0) { ExpirationCounter = 1000; Logger.ColoredConsoleWrite(ConsoleColor.Red, $"Attention! Your key is expiring in {(AuthTokenExpiration - DateTime.Now).Days} days and {(AuthTokenExpiration - DateTime.Now).Hours} hours! Expiration date: {AuthTokenExpiration}", LogLevel.Warning); } } ; return(JsonConvert.DeserializeObject <HashResponseContent>(response.Content.ReadAsStringAsync().Result)); case HttpStatusCode.BadRequest: // 400 var responseText = response.Content.ReadAsStringAsync().Result; throw new HasherException($"[HashService] 400: Your key is probably expired! {responseText}"); case HttpStatusCode.Unauthorized: // 401 Shared.KeyCollection.removeKey(this.apiKey); throw new HasherException("[HashService] 401: Your PF-Hashkey you provided is incorrect (or not valid anymore). "); case (HttpStatusCode)429: // To many requests responseText = response.Content.ReadAsStringAsync().Result; throw new HasherException($"[HashService] 429: Your request has been limited (Message : {responseText})"); case HttpStatusCode.ServiceUnavailable: responseText = response.Content.ReadAsStringAsync().Result; throw new HasherException($"[HashService] 503: It seems PokeFarmer server {_baseAddress}{_endpoint} is unavailable (Message : {responseText}) "); default: RandomHelper.RandomSleep(10000, 11000); throw new HasherException($"[HashService] Unknown: Pokefamer Hash API ({_baseAddress}{_endpoint}) might down!"); } } }
public HashResponseContent RequestHashes(HashRequestContent request) { int retry = 3; int cyclingRetrys = 40; bool changeKey; do { changeKey = false; try { if (!NoValidKey) { return(InternalRequestHashes(request)); } } catch (HasherException hashEx) { changeKey = true; cyclingRetrys--; Logger.Write(hashEx.Message); if (cyclingRetrys < 0) { throw hashEx; } } catch (Exception ex) { Logger.ColoredConsoleWrite(ConsoleColor.Red, "Error: PokeHashHasher.cs - RequestHashes()"); Logger.ColoredConsoleWrite(ConsoleColor.Red, ex.Message); } if (changeKey) { var nextKey = Shared.KeyCollection.nextKey(); if (nextKey != "") { this.apiKey = nextKey; Logger.Debug("Changing KEY to: " + this.apiKey.Substring(0, 5)); } else { NoValidKey = true; Logger.ColoredConsoleWrite(ConsoleColor.Red, "Error: PokeHashHasher.cs - NO VALID KEY FOUND - STOPPING"); System.Console.ReadKey(); Environment.Exit(-1); } RandomHelper.RandomSleep(250, 300); } else { RandomHelper.RandomSleep(1000, 1100); retry--; } } while (retry > 0); throw new HasherException("[HasherExeption] Default: pokefamer Hash API server might down"); }
public async Task <HashResponseContent> RequestHashesAsync(HashRequestContent request) { var hashed = new HashResponseContent() { LocationAuthHash = Utils.GenerateLocation1(request.AuthTicket, request.Latitude, request.Longitude, request.Altitude), LocationHash = Utils.GenerateLocation2(request.Latitude, request.Longitude, request.Altitude), RequestHashes = new List <long>() }; foreach (var req in request.Requests) { hashed.RequestHashes.Add((long)Utils.GenerateRequestHash(request.AuthTicket, req)); } return(hashed); }
public static string[] GetInformation(string apiKey) { var result = new [] { "", "" }; var client = new System.Net.Http.HttpClient(); Resources.Api.SetAPIKeyHashServerURL(apiKey); _baseAddress = Resources.Api.HashServerInfo.URL; client.BaseAddress = _baseAddress; client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); client.DefaultRequestHeaders.Add("X-AuthToken", apiKey); var hashRequest = new HashRequestContent(); var content = new StringContent(JsonConvert.SerializeObject(hashRequest), Encoding.UTF8, "application/json"); content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); HttpResponseMessage response = null; try { response = client.PostAsync(Resources.Api.EndPoint, content).Result; } catch (Exception) { //client.BaseAddress = _baseAddress2; //response = client.PostAsync(Resources.Api.EndPoint, content).Result; } try { var AuthTokenExpiration = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc).AddSeconds(Convert.ToUInt32(((String[])response.Headers.GetValues("X-AuthTokenExpiration"))[0])).ToLocalTime(); var MaxRequestCount = Convert.ToUInt16(((string[])response.Headers.GetValues("X-MaxRequestCount"))[0]); var RatePeriodEnd = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc).AddSeconds(Convert.ToUInt32(((String[])response.Headers.GetValues("X-RatePeriodEnd"))[0])).ToLocalTime(); var RateRequestRemaining = Convert.ToUInt16(((string[])response.Headers.GetValues("X-RateRequestsRemaining"))[0]); var RateLimitSeconds = Convert.ToUInt16(((string[])response.Headers.GetValues("X-RateLimitSeconds"))[0]); var remainingSeconds = (DateTime.Now - RatePeriodEnd).TotalSeconds * -1; Logger.Info($"{apiKey} : {RateRequestRemaining}/{MaxRequestCount} requests remaining for the next {remainingSeconds} seconds. Key expires on: {AuthTokenExpiration}"); result[0] = MaxRequestCount.ToString(); result[1] = AuthTokenExpiration.ToString("dd/MM/yyyy HH:mm:ss"); } catch (Exception) { result[1] = response.StatusCode.ToString(); } return(result); }
private async Task <HashResponseContent> InternalRequestHashesAsync(HashRequestContent request) { string key = GetAPIKey(); var maskedKey = key.Substring(0, 4) + "".PadLeft(key.Length - 8, 'X') + key.Substring(key.Length - 4, 4); // NOTE: This is really bad. Don't create new HttpClient's all the time. // Use a single client per-thread if you need one. using (var client = new System.Net.Http.HttpClient()) { // The URL to the hashing server. // Do not include "api/v1/hash" unless you know why you're doing it, and want to modify this code. client.BaseAddress = new Uri(PokeHashURL); // By default, all requests (and this example) are in JSON. client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); // Set the X-AuthToken to the key you purchased from Bossland GmbH client.DefaultRequestHeaders.Add("X-AuthToken", key); var content = new StringContent(JsonConvert.SerializeObject(request), Encoding.ASCII, "application/json"); // An odd bug with HttpClient. You need to set the content type again. content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); Stopwatch watcher = new Stopwatch(); HttpResponseMessage response = null; watcher.Start(); Stat stat = new Stat() { Timestamp = DateTime.Now }; try { response = await client.PostAsync(apiEndPoint, content).ConfigureAwait(false); } catch (Exception) { try { client.BaseAddress = new Uri(PokeHashURL2); response = await client.PostAsync(apiEndPoint, content).ConfigureAwait(false); } catch (Exception ex) { throw ex; } } finally { watcher.Stop(); // Need to check for null response. if (response == null) { throw new HasherException($"Hash API server ({client.BaseAddress}{apiEndPoint}) might down!"); } fullStats.APICalles++; fullStats.TotalTimes += watcher.ElapsedMilliseconds; stat.ResponseTime = watcher.ElapsedMilliseconds; statistics.Add(stat); statistics.RemoveAll(x => x.Timestamp < DateTime.Now.AddMinutes(-1)); if (statistics.Count > 0) { lastPrintVerbose = DateTime.Now; double agv = statistics.Sum(x => x.ResponseTime) / statistics.Count; fullStats.Last60MinAPICalles = statistics.Count; fullStats.Last60MinAPIAvgTime = agv; fullStats.Fastest = fullStats.Fastest == 0 ? watcher.ElapsedMilliseconds : Math.Min(fullStats.Fastest, watcher.ElapsedMilliseconds); fullStats.Slowest = Math.Max(fullStats.Slowest, watcher.ElapsedMilliseconds); fullStats.MaskedAPIKey = maskedKey; } #pragma warning disable IDE0018 // Inline variable declaration - Build.Bat Error Happens if We Do int maxRequestCount = 0; IEnumerable <string> headers; IEnumerable <string> requestRemains; if (response.Headers.TryGetValues("X-MaxRequestCount", out headers)) { // Get the rate-limit period ends at timestamp in seconds. maxRequestCount = Convert.ToInt32(headers.First()); } if (response.Headers.TryGetValues("X-AuthTokenExpiration", out headers)) { uint secondsToExpiration = 0; secondsToExpiration = Convert.ToUInt32(headers.First()); fullStats.Expired = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) .AddSeconds(secondsToExpiration).ToLocalTime().ToString("yyyy/MM/dd HH:mm:ss"); } if (response.Headers.TryGetValues("X-RateRequestsRemaining", out requestRemains)) { // Get the rate-limit period ends at timestamp in seconds. int requestRemain = Convert.ToInt32(requestRemains.First()); fullStats.HealthyRate = (double)(requestRemain) / maxRequestCount; UpdateRate(key, requestRemain); } APIConfiguration.Logger.HashStatusUpdate(fullStats); #pragma warning restore IDE0018 // Inline variable declaration - Build.Bat Error Happens if We Do } // TODO: Fix this up with proper retry-after when we get rate limited. switch (response.StatusCode) { // All good. Return the hashes back to the caller. :D case HttpStatusCode.OK: return(JsonConvert.DeserializeObject <HashResponseContent>(await response.Content.ReadAsStringAsync().ConfigureAwait(false))); // Returned when something in your request is "invalid". Also when X-AuthToken is not set. // See the error message for why it is bad. case HttpStatusCode.BadRequest: string responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); if (responseText.Contains("Unauthorized")) { APIConfiguration.Logger.LogDebug($"Unauthorized : {key} "); if (apiKeys.Count() > 1) { apiKeys.RemoveAll(x => x.Key == key); return(await RequestHashesAsync(request).ConfigureAwait(false)); } throw new HasherException($"Your API Key: {maskedKey} is incorrect or expired, please check auth.json (Pokefamer Message : {responseText})"); } Console.WriteLine($"Bad request sent to the hashing server! {responseText}"); break; // This error code is returned when your "key" is not in a valid state. (Expired, invalid, etc) case HttpStatusCode.Unauthorized: APIConfiguration.Logger.LogDebug($"Unauthorized : {key} "); if (apiKeys.Count() > 1) { apiKeys.RemoveAll(x => x.Key == key); return(await RequestHashesAsync(request).ConfigureAwait(false)); } throw new HasherException($"You are not authorized to use this service. Please check that your API key {maskedKey} is correct."); // This error code is returned when you have exhausted your current "hashes per second" value // You should queue up your requests, and retry in a second. case (HttpStatusCode)429: APIConfiguration.Logger.LogInfo($"Your request has been limited. {await response.Content.ReadAsStringAsync().ConfigureAwait(false)}"); if (apiKeys.Count() > 1) { return(await RequestHashesAsync(request).ConfigureAwait(false)); } long ratePeriodEndsAtTimestamp; IEnumerable <string> ratePeriodEndHeaderValues; if (response.Headers.TryGetValues("X-RatePeriodEnd", out ratePeriodEndHeaderValues)) { // Get the rate-limit period ends at timestamp in seconds. ratePeriodEndsAtTimestamp = Convert.ToInt64(ratePeriodEndHeaderValues.First()); } else { // If for some reason we couldn't get the timestamp, just default to 2 second wait. ratePeriodEndsAtTimestamp = Utils.GetTime(false) + 2; } long timeToWaitInSeconds = ratePeriodEndsAtTimestamp - Utils.GetTime(false); if (timeToWaitInSeconds > 0) { await Task.Delay((int)(timeToWaitInSeconds * 1000)).ConfigureAwait(false); // Wait until next rate-limit period begins. } return(await RequestHashesAsync(request).ConfigureAwait(false)); default: throw new HasherException($"Hash API server ({client.BaseAddress}{apiEndPoint}) might down!"); } } return(null); }
public async Task <HashResponseContent> RequestHashesAsync(HashRequestContent request) { // This value will determine which version of hashing you receive. // Currently supported versions: // v119 -> Pogo iOS 1.19 // v121 -> Pogo iOS 1.21 const string endpoint = "api/v122/hash"; // NOTE: This is really bad. Don't create new HttpClient's all the time. // Use a single client per-thread if you need one. using (var client = new System.Net.Http.HttpClient()) { // The URL to the hashing server. // Do not include "api/v1/hash" unless you know why you're doing it, and want to modify this code. client.BaseAddress = new Uri("http://pokehash.buddyauth.com/"); // By default, all requests (and this example) are in JSON. client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); // Set the X-AuthToken to the key you purchased from Bossland GmbH client.DefaultRequestHeaders.Add("X-AuthToken", this.apiKey); var content = new StringContent(JsonConvert.SerializeObject(request), Encoding.ASCII, "application/json"); // An odd bug with HttpClient. You need to set the content type again. content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); var response = await client.PostAsync(endpoint, content); // TODO: Fix this up with proper retry-after when we get rate limited. switch (response.StatusCode) { // All good. Return the hashes back to the caller. :D case HttpStatusCode.OK: return(JsonConvert.DeserializeObject <HashResponseContent>(await response.Content.ReadAsStringAsync())); // Returned when something in your request is "invalid". Also when X-AuthToken is not set. // See the error message for why it is bad. case HttpStatusCode.BadRequest: Console.WriteLine($"Bad request sent to the hashing server! {await response.Content.ReadAsStringAsync()}"); break; // This error code is returned when your "key" is not in a valid state. (Expired, invalid, etc) case HttpStatusCode.Unauthorized: Console.WriteLine("You are not authorized to use this service. please check you api key correct"); Console.ReadKey(); Environment.Exit(0); //TODO need logic layer to handle this error , maybe validation when first start break; // This error code is returned when you have exhausted your current "hashes per second" value // You should queue up your requests, and retry in a second. case (HttpStatusCode)429: Console.WriteLine($"Your request has been limited. {await response.Content.ReadAsStringAsync()}"); await Task.Delay(2 * 1000); //stop for 2 sec return(await RequestHashesAsync(request)); break; } } return(null); }