From 6936b034cbb593ac756b156940296f1f43ea54c5 Mon Sep 17 00:00:00 2001 From: "nicolas.dorier" Date: Wed, 18 Apr 2018 18:23:39 +0900 Subject: [PATCH] Add Bitcoin average quota --- .../Controllers/InvoiceController.UI.cs | 13 +---- BTCPayServer/Controllers/ServerController.cs | 48 ++++++++++++++----- BTCPayServer/Extensions.cs | 11 +++++ .../Models/ServerViewModels/RatesViewModel.cs | 2 + .../Services/Rates/CoinAverageRateProvider.cs | 23 +++++++++ BTCPayServer/Views/Server/Rates.cshtml | 15 +++++- 6 files changed, 88 insertions(+), 24 deletions(-) diff --git a/BTCPayServer/Controllers/InvoiceController.UI.cs b/BTCPayServer/Controllers/InvoiceController.UI.cs index 91c39408d..dcc524849 100644 --- a/BTCPayServer/Controllers/InvoiceController.UI.cs +++ b/BTCPayServer/Controllers/InvoiceController.UI.cs @@ -253,7 +253,7 @@ namespace BTCPayServer.Controllers }; var expiration = TimeSpan.FromSeconds(model.ExpirationSeconds); - model.TimeLeft = PrettyPrint(expiration); + model.TimeLeft = expiration.PrettyPrint(); return model; } @@ -272,17 +272,6 @@ namespace BTCPayServer.Controllers return price.ToString("C", _CurrencyNameTable.GetCurrencyProvider(currency)) + $" ({currency})"; } - private string PrettyPrint(TimeSpan expiration) - { - StringBuilder builder = new StringBuilder(); - if (expiration.Days >= 1) - builder.Append(expiration.Days.ToString(CultureInfo.InvariantCulture)); - if (expiration.Hours >= 1) - builder.Append(expiration.Hours.ToString("00", CultureInfo.InvariantCulture)); - builder.Append($"{expiration.Minutes.ToString("00", CultureInfo.InvariantCulture)}:{expiration.Seconds.ToString("00", CultureInfo.InvariantCulture)}"); - return builder.ToString(); - } - [HttpGet] [Route("i/{invoiceId}/status")] [Route("i/{invoiceId}/{paymentMethodId}/status")] diff --git a/BTCPayServer/Controllers/ServerController.cs b/BTCPayServer/Controllers/ServerController.cs index a08f7f6b9..5e6977389 100644 --- a/BTCPayServer/Controllers/ServerController.cs +++ b/BTCPayServer/Controllers/ServerController.cs @@ -36,13 +36,28 @@ namespace BTCPayServer.Controllers public async Task Rates() { var rates = (await _SettingsRepository.GetSettingAsync()) ?? new RatesSetting(); - return View(new RatesViewModel() + + var vm = new RatesViewModel() { CacheMinutes = rates.CacheInMinutes, PrivateKey = rates.PrivateKey, PublicKey = rates.PublicKey - }); + }; + await FetchRateLimits(vm); + return View(vm); + } + private static async Task FetchRateLimits(RatesViewModel vm) + { + var coinAverage = GetCoinaverageService(vm, false); + if (coinAverage != null) + { + try + { + vm.RateLimits = await coinAverage.GetRateLimitsAsync(); + } + catch { } + } } [Route("server/rates")] @@ -55,27 +70,38 @@ namespace BTCPayServer.Controllers rates.CacheInMinutes = vm.CacheMinutes; try { - var settings = new CoinAverageSettings() - { - KeyPair = (vm.PublicKey, vm.PrivateKey) - }; - if (settings.GetCoinAverageSignature() != null) - { - await new CoinAverageRateProvider("BTC") - { Authenticator = settings }.TestAuthAsync(); - } + var service = GetCoinaverageService(vm, true); + if(service != null) + await service.TestAuthAsync(); } catch { ModelState.AddModelError(nameof(vm.PrivateKey), "Invalid API key pair"); } if (!ModelState.IsValid) + { + await FetchRateLimits(vm); return View(vm); + } await _SettingsRepository.UpdateSetting(rates); StatusMessage = "Rate settings successfully updated"; return RedirectToAction(nameof(Rates)); } + private static CoinAverageRateProvider GetCoinaverageService(RatesViewModel vm, bool withAuth) + { + var settings = new CoinAverageSettings() + { + KeyPair = (vm.PublicKey, vm.PrivateKey) + }; + if (!withAuth || settings.GetCoinAverageSignature() != null) + { + return new CoinAverageRateProvider("BTC") + { Authenticator = settings }; + } + return null; + } + [Route("server/users")] public IActionResult ListUsers() { diff --git a/BTCPayServer/Extensions.cs b/BTCPayServer/Extensions.cs index 5f9df05c9..40fe847e5 100644 --- a/BTCPayServer/Extensions.cs +++ b/BTCPayServer/Extensions.cs @@ -28,11 +28,22 @@ using BTCPayServer.Payments; using Microsoft.AspNetCore.Identity; using BTCPayServer.Models; using System.Security.Claims; +using System.Globalization; namespace BTCPayServer { public static class Extensions { + public static string PrettyPrint(this TimeSpan expiration) + { + StringBuilder builder = new StringBuilder(); + if (expiration.Days >= 1) + builder.Append(expiration.Days.ToString(CultureInfo.InvariantCulture)); + if (expiration.Hours >= 1) + builder.Append(expiration.Hours.ToString("00", CultureInfo.InvariantCulture)); + builder.Append($"{expiration.Minutes.ToString("00", CultureInfo.InvariantCulture)}:{expiration.Seconds.ToString("00", CultureInfo.InvariantCulture)}"); + return builder.ToString(); + } public static decimal RoundUp(decimal value, int precision) { for (int i = 0; i < precision; i++) diff --git a/BTCPayServer/Models/ServerViewModels/RatesViewModel.cs b/BTCPayServer/Models/ServerViewModels/RatesViewModel.cs index b0e1c3cba..b72f1ba49 100644 --- a/BTCPayServer/Models/ServerViewModels/RatesViewModel.cs +++ b/BTCPayServer/Models/ServerViewModels/RatesViewModel.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; +using BTCPayServer.Services.Rates; namespace BTCPayServer.Models.ServerViewModels { @@ -14,5 +15,6 @@ namespace BTCPayServer.Models.ServerViewModels [Display(Name = "Cache the rates for ... minutes")] [Range(0, 60)] public int CacheMinutes { get; set; } + public GetRateLimitsResponse RateLimits { get; internal set; } } } diff --git a/BTCPayServer/Services/Rates/CoinAverageRateProvider.cs b/BTCPayServer/Services/Rates/CoinAverageRateProvider.cs index 7cdbb29aa..ebaa5bde0 100644 --- a/BTCPayServer/Services/Rates/CoinAverageRateProvider.cs +++ b/BTCPayServer/Services/Rates/CoinAverageRateProvider.cs @@ -170,6 +170,23 @@ namespace BTCPayServer.Services.Rates resp.EnsureSuccessStatusCode(); } + public async Task GetRateLimitsAsync() + { + var request = new HttpRequestMessage(HttpMethod.Get, "https://apiv2.bitcoinaverage.com/info/ratelimits"); + var auth = Authenticator; + if (auth != null) + { + await auth.AddHeader(request); + } + var resp = await _Client.SendAsync(request); + resp.EnsureSuccessStatusCode(); + var jobj = JObject.Parse(await resp.Content.ReadAsStringAsync()); + var response = new GetRateLimitsResponse(); + response.CounterReset = TimeSpan.FromSeconds(jobj["counter_reset"].Value()); + response.RequestsLeft = jobj["requests_left"].Value(); + return response; + } + public async Task GetExchangeTickersAsync() { var request = new HttpRequestMessage(HttpMethod.Get, "https://apiv2.bitcoinaverage.com/symbols/exchanges/ticker"); @@ -191,4 +208,10 @@ namespace BTCPayServer.Services.Rates return response; } } + + public class GetRateLimitsResponse + { + public TimeSpan CounterReset { get; set; } + public int RequestsLeft { get; set; } + } } diff --git a/BTCPayServer/Views/Server/Rates.cshtml b/BTCPayServer/Views/Server/Rates.cshtml index a8dfc17f7..89e145778 100644 --- a/BTCPayServer/Views/Server/Rates.cshtml +++ b/BTCPayServer/Views/Server/Rates.cshtml @@ -28,7 +28,6 @@ -

You can find the information on bitcoinaverage api key page

@@ -36,6 +35,20 @@
+ @if(Model.RateLimits != null) + { +
Current Bitcoin Average Quotas:
+ + + + + + + + + +
Requests left@Model.RateLimits.RequestsLeft
Quota reset in@Model.RateLimits.CounterReset
+ }