From e3b348b55c054303d34987247b505aa7699e9142 Mon Sep 17 00:00:00 2001 From: Dennis Reimann Date: Sat, 16 May 2020 23:57:49 +0200 Subject: [PATCH 1/3] GreenField: Add Server Info API basics --- .../BTCPayServerClient.ServerInfo.cs | 16 +++ BTCPayServer.Client/Models/ServerInfoData.cs | 47 +++++++++ BTCPayServer.Tests/GreenfieldAPITests.cs | 22 +++++ BTCPayServer/BTCPayServer.csproj | 4 + .../GreenField/ServerInfoController.cs | 73 ++++++++++++++ .../v1/swagger.template.serverinfo.json | 99 +++++++++++++++++++ 6 files changed, 261 insertions(+) create mode 100644 BTCPayServer.Client/BTCPayServerClient.ServerInfo.cs create mode 100644 BTCPayServer.Client/Models/ServerInfoData.cs create mode 100644 BTCPayServer/Controllers/GreenField/ServerInfoController.cs create mode 100644 BTCPayServer/wwwroot/swagger/v1/swagger.template.serverinfo.json diff --git a/BTCPayServer.Client/BTCPayServerClient.ServerInfo.cs b/BTCPayServer.Client/BTCPayServerClient.ServerInfo.cs new file mode 100644 index 000000000..eab3f4b8f --- /dev/null +++ b/BTCPayServer.Client/BTCPayServerClient.ServerInfo.cs @@ -0,0 +1,16 @@ +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using BTCPayServer.Client.Models; + +namespace BTCPayServer.Client +{ + public partial class BTCPayServerClient + { + public virtual async Task GetServerInfo(CancellationToken token = default) + { + var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/server/info"), token); + return await HandleResponse(response); + } + } +} diff --git a/BTCPayServer.Client/Models/ServerInfoData.cs b/BTCPayServer.Client/Models/ServerInfoData.cs new file mode 100644 index 000000000..edd301ca3 --- /dev/null +++ b/BTCPayServer.Client/Models/ServerInfoData.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; + +namespace BTCPayServer.Client.Models +{ + public class ServerInfoData + { + /// + /// detailed status information + /// + public ServerInfoStatusData Status { get; set; } + + /// + /// the BTCPay Server version + /// + public string Version { get; set; } + + /// + /// the Tor hostname + /// + public string Onion { get; set; } + + /// + /// the payment methods this server supports + /// + public IEnumerable SupportedPaymentMethods { get; set; } + } + + public class ServerInfoStatusData + { + /// + /// are all chains fully synched + /// + public bool FullySynched { get; set; } + + /// + /// detailed sync information per chain + /// + public IEnumerable SyncStatus { get; set; } + } + + public class ServerInfoSyncStatusData + { + public string CryptoCode { get; set; } + public int BlockHeaders { get; set; } + public double Progress { get; set; } + } +} diff --git a/BTCPayServer.Tests/GreenfieldAPITests.cs b/BTCPayServer.Tests/GreenfieldAPITests.cs index faf0b7729..4b58513e9 100644 --- a/BTCPayServer.Tests/GreenfieldAPITests.cs +++ b/BTCPayServer.Tests/GreenfieldAPITests.cs @@ -291,5 +291,27 @@ namespace BTCPayServer.Tests Assert.True(apiHealthData.Synchronized); } } + + [Fact(Timeout = TestTimeout)] + [Trait("Integration", "Integration")] + public async Task ServerInfoControllerTests() + { + using (var tester = ServerTester.Create()) + { + await tester.StartAsync(); + var unauthClient = new BTCPayServerClient(tester.PayTester.ServerUri); + await AssertHttpError(401, async () => await unauthClient.GetServerInfo()); + + var user = tester.NewAccount(); + user.GrantAccess(); + var clientBasic = await user.CreateClient(); + var serverInfoData = await clientBasic.GetServerInfo(); + Assert.NotNull(serverInfoData); + Assert.NotNull(serverInfoData.Status); + Assert.True(serverInfoData.Status.FullySynched); + Assert.Contains("BTC", serverInfoData.SupportedPaymentMethods); + Assert.Contains("BTC_LightningLike", serverInfoData.SupportedPaymentMethods); + } + } } } diff --git a/BTCPayServer/BTCPayServer.csproj b/BTCPayServer/BTCPayServer.csproj index c37a38ca5..e23f17bcc 100644 --- a/BTCPayServer/BTCPayServer.csproj +++ b/BTCPayServer/BTCPayServer.csproj @@ -21,6 +21,10 @@ + + true + PreserveNewest + diff --git a/BTCPayServer/Controllers/GreenField/ServerInfoController.cs b/BTCPayServer/Controllers/GreenField/ServerInfoController.cs new file mode 100644 index 000000000..255c7a480 --- /dev/null +++ b/BTCPayServer/Controllers/GreenField/ServerInfoController.cs @@ -0,0 +1,73 @@ +using System.Linq; +using System.Threading.Tasks; +using BTCPayServer.Client.Models; +using BTCPayServer.Data; +using BTCPayServer.HostedServices; +using BTCPayServer.Security; +using BTCPayServer.Services; +using BTCPayServer.Services.Invoices; +using BTCPayServer.Services.Stores; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; + +namespace BTCPayServer.Controllers.GreenField +{ + [ApiController] + public class GreenFieldServerInfoController : Controller + { + private readonly BTCPayServerEnvironment _env; + private readonly NBXplorerDashboard _dashBoard; + private readonly StoreRepository _storeRepository; + private readonly UserManager _userManager; + private readonly BTCPayNetworkProvider _networkProvider; + private readonly PaymentMethodHandlerDictionary _paymentMethodHandlerDictionary; + + public GreenFieldServerInfoController( + BTCPayServerEnvironment env, + NBXplorerDashboard dashBoard, + StoreRepository storeRepository, + UserManager userManager, + BTCPayNetworkProvider networkProvider, + PaymentMethodHandlerDictionary paymentMethodHandlerDictionary) + { + _env = env; + _dashBoard = dashBoard; + _storeRepository = storeRepository; + _userManager = userManager; + _networkProvider = networkProvider; + _paymentMethodHandlerDictionary = paymentMethodHandlerDictionary; + } + + [Authorize(AuthenticationSchemes = AuthenticationSchemes.Greenfield)] + [HttpGet("~/api/v1/server/info")] + public async Task ServerInfo() + { + var stores = await _storeRepository.GetStoresByUserId(_userManager.GetUserId(User)); + var supportedPaymentMethods = _paymentMethodHandlerDictionary + .SelectMany(handler => handler.GetSupportedPaymentMethods().Select(id => id.ToString())) + .Distinct(); + var syncStatus = _dashBoard.GetAll() + .Select(summary => new ServerInfoSyncStatusData + { + CryptoCode = summary.Network.CryptoCode, + // TODO: Implement these fields + BlockHeaders = 0, + Progress = 0 + }); + ServerInfoStatusData status = new ServerInfoStatusData + { + FullySynched = _dashBoard.IsFullySynched(), + SyncStatus = syncStatus + }; + ServerInfoData model = new ServerInfoData + { + Status = status, + Onion = _env.OnionUrl, + Version = _env.Version, + SupportedPaymentMethods = supportedPaymentMethods + }; + return Ok(model); + } + } +} diff --git a/BTCPayServer/wwwroot/swagger/v1/swagger.template.serverinfo.json b/BTCPayServer/wwwroot/swagger/v1/swagger.template.serverinfo.json new file mode 100644 index 000000000..c1ef20713 --- /dev/null +++ b/BTCPayServer/wwwroot/swagger/v1/swagger.template.serverinfo.json @@ -0,0 +1,99 @@ +{ + "paths": { + "/api/v1/server/info": { + "get": { + "tags": [ + "ServerInfo" + ], + "summary": "Get server info", + "description": "Information about the server, chains and sync states", + "operationId": "ServerInfo_GetServerInfo", + "responses": { + "200": { + "description": "Server information", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationServerInfoData" + } + } + } + } + }, + "security": [ + { + "API Key": [], + "Basic": [] + } + ] + } + } + }, + "components": { + "schemas": { + "ApplicationServerInfoData": { + "type": "object", + "properties": { + "status": { + "$ref": "#/components/schemas/ApplicationServerInfoStatusData" + }, + "version": { + "type": "string", + "description": "BTCPay Server version" + }, + "onion": { + "type": "string", + "description": "The Tor hostname" + }, + "supportedPaymentMethods": { + "type": "array", + "description": "The payment methods this server supports", + "items": { + "type": "string" + } + } + } + }, + "ApplicationServerInfoStatusData": { + "type": "object", + "description": "Detailed sync status", + "properties": { + "fullySynched": { + "type": "boolean", + "description": "True if the instance is fully synchronized, according to NBXplorer" + }, + "syncStatus": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApplicationServerInfoSyncStatusData" + } + } + } + }, + "ApplicationServerInfoSyncStatusData": { + "type": "object", + "description": "Detailed sync status", + "properties": { + "cryptoCode": { + "type": "string", + "description": "True if the instance is fully synchronized, according to NBXplorer" + }, + "blockHeaders": { + "type": "integer", + "description": "True if the instance is fully synchronized, according to NBXplorer" + }, + "progress": { + "type": "number", + "format": "double", + "description": "True if the instance is fully synchronized, according to NBXplorer" + } + } + } + } + }, + "tags": [ + { + "name": "ServerInfo" + } + ] +} From 3b6dbe76c562442f55fb57b92ef3870369b2b14c Mon Sep 17 00:00:00 2001 From: Dennis Reimann Date: Mon, 18 May 2020 16:02:15 +0200 Subject: [PATCH 2/3] Add sync state --- BTCPayServer.Client/Models/ServerInfoData.cs | 2 +- BTCPayServer.Tests/GreenfieldAPITests.cs | 10 +++++++--- .../Controllers/GreenField/ServerInfoController.cs | 5 ++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/BTCPayServer.Client/Models/ServerInfoData.cs b/BTCPayServer.Client/Models/ServerInfoData.cs index edd301ca3..382456efd 100644 --- a/BTCPayServer.Client/Models/ServerInfoData.cs +++ b/BTCPayServer.Client/Models/ServerInfoData.cs @@ -42,6 +42,6 @@ namespace BTCPayServer.Client.Models { public string CryptoCode { get; set; } public int BlockHeaders { get; set; } - public double Progress { get; set; } + public float Progress { get; set; } } } diff --git a/BTCPayServer.Tests/GreenfieldAPITests.cs b/BTCPayServer.Tests/GreenfieldAPITests.cs index 4b58513e9..511cbafd1 100644 --- a/BTCPayServer.Tests/GreenfieldAPITests.cs +++ b/BTCPayServer.Tests/GreenfieldAPITests.cs @@ -4,11 +4,8 @@ using System.Net.Http; using System.Threading.Tasks; using BTCPayServer.Client; using BTCPayServer.Client.Models; -using BTCPayServer.Controllers; using BTCPayServer.Services; using BTCPayServer.Tests.Logging; -using Microsoft.AspNet.SignalR.Client; -using Microsoft.AspNetCore.Mvc; using Xunit; using Xunit.Abstractions; using CreateApplicationUserRequest = BTCPayServer.Client.Models.CreateApplicationUserRequest; @@ -306,11 +303,18 @@ namespace BTCPayServer.Tests user.GrantAccess(); var clientBasic = await user.CreateClient(); var serverInfoData = await clientBasic.GetServerInfo(); + Assert.NotNull(serverInfoData); + Assert.NotNull(serverInfoData.Version); + Assert.NotNull(serverInfoData.Onion); Assert.NotNull(serverInfoData.Status); + Assert.True(serverInfoData.Status.FullySynched); Assert.Contains("BTC", serverInfoData.SupportedPaymentMethods); Assert.Contains("BTC_LightningLike", serverInfoData.SupportedPaymentMethods); + + Assert.NotNull(serverInfoData.Status.SyncStatus); + Assert.Single(serverInfoData.Status.SyncStatus.Select(s => s.CryptoCode == "BTC")); } } } diff --git a/BTCPayServer/Controllers/GreenField/ServerInfoController.cs b/BTCPayServer/Controllers/GreenField/ServerInfoController.cs index 255c7a480..b8de96b6d 100644 --- a/BTCPayServer/Controllers/GreenField/ServerInfoController.cs +++ b/BTCPayServer/Controllers/GreenField/ServerInfoController.cs @@ -51,9 +51,8 @@ namespace BTCPayServer.Controllers.GreenField .Select(summary => new ServerInfoSyncStatusData { CryptoCode = summary.Network.CryptoCode, - // TODO: Implement these fields - BlockHeaders = 0, - Progress = 0 + BlockHeaders = summary.Status.ChainHeight, + Progress = summary.Status.SyncHeight.GetValueOrDefault(0) / (float)summary.Status.ChainHeight }); ServerInfoStatusData status = new ServerInfoStatusData { From 78d191f7d8070d89db57aeec7ecdf6c1680cd774 Mon Sep 17 00:00:00 2001 From: Dennis Reimann Date: Mon, 18 May 2020 16:51:21 +0200 Subject: [PATCH 3/3] Incorporate code review feedback --- BTCPayServer/BTCPayServer.csproj | 4 ---- BTCPayServer/Controllers/GreenField/ServerInfoController.cs | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/BTCPayServer/BTCPayServer.csproj b/BTCPayServer/BTCPayServer.csproj index e23f17bcc..c37a38ca5 100644 --- a/BTCPayServer/BTCPayServer.csproj +++ b/BTCPayServer/BTCPayServer.csproj @@ -21,10 +21,6 @@ - - true - PreserveNewest - diff --git a/BTCPayServer/Controllers/GreenField/ServerInfoController.cs b/BTCPayServer/Controllers/GreenField/ServerInfoController.cs index b8de96b6d..4b8f0a820 100644 --- a/BTCPayServer/Controllers/GreenField/ServerInfoController.cs +++ b/BTCPayServer/Controllers/GreenField/ServerInfoController.cs @@ -48,6 +48,7 @@ namespace BTCPayServer.Controllers.GreenField .SelectMany(handler => handler.GetSupportedPaymentMethods().Select(id => id.ToString())) .Distinct(); var syncStatus = _dashBoard.GetAll() + .Where(summary => summary.Network.ShowSyncSummary) .Select(summary => new ServerInfoSyncStatusData { CryptoCode = summary.Network.CryptoCode,