using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using BTCPayServer.Controllers; using BTCPayServer.Data; using BTCPayServer.Lightning; using BTCPayServer.Models.StoreViewModels; using BTCPayServer.Payments; using BTCPayServer.Payments.Lightning; using BTCPayServer.Services; using BTCPayServer.Services.Apps; using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Stores; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.Extensions.Caching.Memory; using NBitcoin; using NBitcoin.Secp256k1; namespace BTCPayServer.Components.MainNav { public class MainNav : ViewComponent { private readonly AppService _appService; private readonly StoreRepository _storeRepo; private readonly UIStoresController _storesController; private readonly BTCPayNetworkProvider _networkProvider; private readonly UserManager _userManager; private readonly PaymentMethodHandlerDictionary _paymentMethodHandlerDictionary; private readonly SettingsRepository _settingsRepository; private readonly IMemoryCache _cache; public PoliciesSettings PoliciesSettings { get; } public MainNav( AppService appService, StoreRepository storeRepo, UIStoresController storesController, BTCPayNetworkProvider networkProvider, UserManager userManager, PaymentMethodHandlerDictionary paymentMethodHandlerDictionary, SettingsRepository settingsRepository, IMemoryCache cache, PoliciesSettings policiesSettings) { _storeRepo = storeRepo; _appService = appService; _userManager = userManager; _networkProvider = networkProvider; _storesController = storesController; _paymentMethodHandlerDictionary = paymentMethodHandlerDictionary; _settingsRepository = settingsRepository; _cache = cache; PoliciesSettings = policiesSettings; } public async Task InvokeAsync() { var store = ViewContext.HttpContext.GetStoreData(); var serverSettings = await _settingsRepository.GetSettingAsync() ?? new ServerSettings(); var vm = new MainNavViewModel { Store = store, ContactUrl = serverSettings.ContactUrl }; #if ALTCOINS vm.AltcoinsBuild = true; #endif if (store != null) { var storeBlob = store.GetStoreBlob(); // Wallets _storesController.AddPaymentMethods(store, storeBlob, out var derivationSchemes, out var lightningNodes); foreach (var lnNode in lightningNodes) { var pmi = PaymentTypes.LN.GetPaymentMethodId(lnNode.CryptoCode); if (_paymentMethodHandlerDictionary.TryGet(pmi) is not LightningLikePaymentHandler handler) continue; if (lnNode.CacheKey is not null) { using var cts = new CancellationTokenSource(5000); try { lnNode.Available = await _cache.GetOrCreateAsync(lnNode.CacheKey, async entry => { entry.SetAbsoluteExpiration(TimeSpan.FromMinutes(5)); try { var paymentMethodDetails = store.GetPaymentMethodConfig(pmi, _paymentMethodHandlerDictionary); await handler.GetNodeInfo(paymentMethodDetails, null, throws: true); // if we came here without exception, this means the node is available return true; } catch (Exception) { return false; } }).WithCancellation(cts.Token); } catch when (cts.IsCancellationRequested) { } } } vm.DerivationSchemes = derivationSchemes; vm.LightningNodes = lightningNodes; // Apps var apps = await _appService.GetAllApps(UserId, false, store.Id, true); vm.Apps = apps .Where(a => !a.Archived) .Select(a => new StoreApp { Id = a.Id, AppName = a.AppName, AppType = a.AppType }).ToList(); vm.ArchivedAppsCount = apps.Count(a => a.Archived); } return View(vm); } private string UserId => _userManager.GetUserId(HttpContext.User); } }