mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-03-03 17:36:59 +01:00
Add Bitcoin average quota
This commit is contained in:
parent
73ed4003a3
commit
6936b034cb
6 changed files with 88 additions and 24 deletions
|
@ -253,7 +253,7 @@ namespace BTCPayServer.Controllers
|
||||||
};
|
};
|
||||||
|
|
||||||
var expiration = TimeSpan.FromSeconds(model.ExpirationSeconds);
|
var expiration = TimeSpan.FromSeconds(model.ExpirationSeconds);
|
||||||
model.TimeLeft = PrettyPrint(expiration);
|
model.TimeLeft = expiration.PrettyPrint();
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,17 +272,6 @@ namespace BTCPayServer.Controllers
|
||||||
return price.ToString("C", _CurrencyNameTable.GetCurrencyProvider(currency)) + $" ({currency})";
|
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]
|
[HttpGet]
|
||||||
[Route("i/{invoiceId}/status")]
|
[Route("i/{invoiceId}/status")]
|
||||||
[Route("i/{invoiceId}/{paymentMethodId}/status")]
|
[Route("i/{invoiceId}/{paymentMethodId}/status")]
|
||||||
|
|
|
@ -36,13 +36,28 @@ namespace BTCPayServer.Controllers
|
||||||
public async Task<IActionResult> Rates()
|
public async Task<IActionResult> Rates()
|
||||||
{
|
{
|
||||||
var rates = (await _SettingsRepository.GetSettingAsync<RatesSetting>()) ?? new RatesSetting();
|
var rates = (await _SettingsRepository.GetSettingAsync<RatesSetting>()) ?? new RatesSetting();
|
||||||
return View(new RatesViewModel()
|
|
||||||
|
var vm = new RatesViewModel()
|
||||||
{
|
{
|
||||||
CacheMinutes = rates.CacheInMinutes,
|
CacheMinutes = rates.CacheInMinutes,
|
||||||
PrivateKey = rates.PrivateKey,
|
PrivateKey = rates.PrivateKey,
|
||||||
PublicKey = rates.PublicKey
|
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")]
|
[Route("server/rates")]
|
||||||
|
@ -55,27 +70,38 @@ namespace BTCPayServer.Controllers
|
||||||
rates.CacheInMinutes = vm.CacheMinutes;
|
rates.CacheInMinutes = vm.CacheMinutes;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var settings = new CoinAverageSettings()
|
var service = GetCoinaverageService(vm, true);
|
||||||
{
|
if(service != null)
|
||||||
KeyPair = (vm.PublicKey, vm.PrivateKey)
|
await service.TestAuthAsync();
|
||||||
};
|
|
||||||
if (settings.GetCoinAverageSignature() != null)
|
|
||||||
{
|
|
||||||
await new CoinAverageRateProvider("BTC")
|
|
||||||
{ Authenticator = settings }.TestAuthAsync();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(vm.PrivateKey), "Invalid API key pair");
|
ModelState.AddModelError(nameof(vm.PrivateKey), "Invalid API key pair");
|
||||||
}
|
}
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
await FetchRateLimits(vm);
|
||||||
return View(vm);
|
return View(vm);
|
||||||
|
}
|
||||||
await _SettingsRepository.UpdateSetting(rates);
|
await _SettingsRepository.UpdateSetting(rates);
|
||||||
StatusMessage = "Rate settings successfully updated";
|
StatusMessage = "Rate settings successfully updated";
|
||||||
return RedirectToAction(nameof(Rates));
|
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")]
|
[Route("server/users")]
|
||||||
public IActionResult ListUsers()
|
public IActionResult ListUsers()
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,11 +28,22 @@ using BTCPayServer.Payments;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using BTCPayServer.Models;
|
using BTCPayServer.Models;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
namespace BTCPayServer
|
namespace BTCPayServer
|
||||||
{
|
{
|
||||||
public static class Extensions
|
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)
|
public static decimal RoundUp(decimal value, int precision)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < precision; i++)
|
for (int i = 0; i < precision; i++)
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using BTCPayServer.Services.Rates;
|
||||||
|
|
||||||
namespace BTCPayServer.Models.ServerViewModels
|
namespace BTCPayServer.Models.ServerViewModels
|
||||||
{
|
{
|
||||||
|
@ -14,5 +15,6 @@ namespace BTCPayServer.Models.ServerViewModels
|
||||||
[Display(Name = "Cache the rates for ... minutes")]
|
[Display(Name = "Cache the rates for ... minutes")]
|
||||||
[Range(0, 60)]
|
[Range(0, 60)]
|
||||||
public int CacheMinutes { get; set; }
|
public int CacheMinutes { get; set; }
|
||||||
|
public GetRateLimitsResponse RateLimits { get; internal set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,6 +170,23 @@ namespace BTCPayServer.Services.Rates
|
||||||
resp.EnsureSuccessStatusCode();
|
resp.EnsureSuccessStatusCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<GetRateLimitsResponse> 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<int>());
|
||||||
|
response.RequestsLeft = jobj["requests_left"].Value<int>();
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<GetExchangeTickersResponse> GetExchangeTickersAsync()
|
public async Task<GetExchangeTickersResponse> GetExchangeTickersAsync()
|
||||||
{
|
{
|
||||||
var request = new HttpRequestMessage(HttpMethod.Get, "https://apiv2.bitcoinaverage.com/symbols/exchanges/ticker");
|
var request = new HttpRequestMessage(HttpMethod.Get, "https://apiv2.bitcoinaverage.com/symbols/exchanges/ticker");
|
||||||
|
@ -191,4 +208,10 @@ namespace BTCPayServer.Services.Rates
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class GetRateLimitsResponse
|
||||||
|
{
|
||||||
|
public TimeSpan CounterReset { get; set; }
|
||||||
|
public int RequestsLeft { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
<input asp-for="PublicKey" style="width:50%;" class="form-control" placeholder="Public key" />
|
<input asp-for="PublicKey" style="width:50%;" class="form-control" placeholder="Public key" />
|
||||||
<label class="sr-only" asp-for="PrivateKey"></label>
|
<label class="sr-only" asp-for="PrivateKey"></label>
|
||||||
<input asp-for="PrivateKey" style="width:50%;" class="form-control" placeholder="Private key" />
|
<input asp-for="PrivateKey" style="width:50%;" class="form-control" placeholder="Private key" />
|
||||||
<span asp-validation-for="PrivateKey" class="text-danger"></span>
|
|
||||||
<p class="form-text text-muted">You can find the information on <a target="_blank" href="https://bitcoinaverage.com/en/apikeys">bitcoinaverage api key page</a></p>
|
<p class="form-text text-muted">You can find the information on <a target="_blank" href="https://bitcoinaverage.com/en/apikeys">bitcoinaverage api key page</a></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -36,6 +35,20 @@
|
||||||
<input asp-for="CacheMinutes" class="form-control" />
|
<input asp-for="CacheMinutes" class="form-control" />
|
||||||
<span asp-validation-for="CacheMinutes" class="text-danger"></span>
|
<span asp-validation-for="CacheMinutes" class="text-danger"></span>
|
||||||
</div>
|
</div>
|
||||||
|
@if(Model.RateLimits != null)
|
||||||
|
{
|
||||||
|
<h5>Current Bitcoin Average Quotas:</h5>
|
||||||
|
<table class="table table-sm">
|
||||||
|
<tr>
|
||||||
|
<th>Requests left</th>
|
||||||
|
<td>@Model.RateLimits.RequestsLeft</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Quota reset in</th>
|
||||||
|
<td>@Model.RateLimits.CounterReset</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
}
|
||||||
<button type="submit" class="btn btn-primary" name="command" value="Save">Save</button>
|
<button type="submit" class="btn btn-primary" name="command" value="Save">Save</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Reference in a new issue