mirror of
https://github.com/aljazceru/BTCPayServerPlugins.git
synced 2025-12-17 07:34:24 +01:00
upd prism
This commit is contained in:
@@ -11,7 +11,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Product>LN Prism</Product>
|
<Product>LN Prism</Product>
|
||||||
<Description>Automated value splits for lightning.</Description>
|
<Description>Automated value splits for lightning.</Description>
|
||||||
<Version>1.1.4</Version>
|
<Version>1.1.5</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<!-- Plugin development properties -->
|
<!-- Plugin development properties -->
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@@ -7,12 +7,27 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>Destination</th>
|
<th>Destination</th>
|
||||||
<th>Sats</th>
|
<th>Sats</th>
|
||||||
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
@foreach (var (dest, balance) in DestinationBalance)
|
@foreach (var (dest, balance) in DestinationBalance)
|
||||||
{
|
{
|
||||||
<tr>
|
<tr>
|
||||||
<td>@dest</td>
|
<td>@dest</td>
|
||||||
<td>@(balance / 1000m)</td>
|
<td>@(balance / 1000m)</td>
|
||||||
|
<td>
|
||||||
|
@if (UpdatingDestination == dest)
|
||||||
|
{
|
||||||
|
<input type="number" @bind="UpdatingValue" min="0" />
|
||||||
|
|
||||||
|
<button type="button" class="btn btn-sm btn-link" @onclick="() => UpdatingDestination = null">Cancel</button>
|
||||||
|
<button type="button" class="btn btn-sm btn-link" @onclick="Update">Update</button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
<button type="button" class="btn btn-sm btn-link" @onclick="StartUpdate(dest,balance)">Update</button>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
</table>
|
</table>
|
||||||
@@ -44,10 +59,33 @@
|
|||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
|
||||||
|
private string? UpdatingDestination { get; set; }
|
||||||
|
private long? UpdatingValue { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Dictionary<string, long> DestinationBalance { get; set; }
|
public Dictionary<string, long> DestinationBalance { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Dictionary<string, PendingPayout> PendingPayouts { get; set; }
|
public Dictionary<string, PendingPayout> PendingPayouts { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public EventCallback<(string destination, long newBalance)> OnUpdate { get; set; }
|
||||||
|
|
||||||
|
private EventCallback StartUpdate(string dest, long balance)
|
||||||
|
{
|
||||||
|
UpdatingDestination = dest;
|
||||||
|
UpdatingValue = Convert.ToInt32(balance/1000m);
|
||||||
|
return EventCallback.Empty;
|
||||||
|
}
|
||||||
|
private async Task Update()
|
||||||
|
{
|
||||||
|
if (UpdatingDestination is null || UpdatingValue is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await OnUpdate.InvokeAsync((UpdatingDestination, Convert.ToInt64(UpdatingValue.Value * 1000m)));
|
||||||
|
UpdatingDestination = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
@using Newtonsoft.Json.Linq
|
||||||
|
<div class=" border-light ">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">Destination Id</label>
|
||||||
|
<input type="text" @bind="WorkingId" class="form-control"/>
|
||||||
|
@if (InvalidId)
|
||||||
|
{
|
||||||
|
<span class="text-danger">Invalid</span>
|
||||||
|
}
|
||||||
|
<span class="form-text">An alias to reference in destinations of prisms.</span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">Destination</label>
|
||||||
|
<input type="text" @bind="WorkingCopy.Destination" class="form-control"/>
|
||||||
|
@if (Invalid)
|
||||||
|
{
|
||||||
|
<span class="text-danger">Invalid</span>
|
||||||
|
}
|
||||||
|
<span class="form-text">Can be a lightning address, LNURL, or a custom value that another plugin supports</span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">Sat Threshold</label>
|
||||||
|
<input type="number" @bind="WorkingCopy.SatThreshold" min="1" class="form-control"/>
|
||||||
|
<span class="form-text">How many sats do you want to accumulate before sending? Leave blank to use default setting.</span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">Reserve fee</label>
|
||||||
|
<input type="number" @bind="WorkingCopy.Reserve" min="0" max="100" class="form-control"/>
|
||||||
|
<span class="form-text">When a payout is being generated, how much of its amount in percentage should be excluded to cover the fee? Once the payment is settled, if the lightning node provides the exact fee, the balance is adjusted accordingly. Leave blank to use default setting.</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button type="button" class="btn btn-primary" @onclick="Update">Update</button>
|
||||||
|
<button type="button" class="btn btn-outline-danger" @onclick="() => SettingsChanged.InvokeAsync(null)">Remove</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
|
||||||
|
public bool Invalid { get; set; } = false;
|
||||||
|
|
||||||
|
private PrismDestination WorkingCopy { get; set; }
|
||||||
|
private string WorkingId { get; set; }
|
||||||
|
private string OriginalWorkingId { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public Func<string, bool> ValidateDestination { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public Func<string, bool> ValidateId { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public PrismDestination Settings
|
||||||
|
{
|
||||||
|
get => WorkingCopy;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
WorkingCopy = JObject.FromObject(value ?? new PrismDestination()).ToObject<PrismDestination>();
|
||||||
|
Invalid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string Id
|
||||||
|
{
|
||||||
|
get => WorkingId;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (OriginalWorkingId != value)
|
||||||
|
{
|
||||||
|
WorkingId = value;
|
||||||
|
OriginalWorkingId = value;
|
||||||
|
InvalidId = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool InvalidId { get; set; }
|
||||||
|
|
||||||
|
public async Task Update()
|
||||||
|
{
|
||||||
|
if (ValidateDestination.Invoke(WorkingCopy.Destination))
|
||||||
|
{
|
||||||
|
await SettingsChanged.InvokeAsync(WorkingCopy);
|
||||||
|
|
||||||
|
Invalid = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Invalid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ValidateId.Invoke(WorkingId))
|
||||||
|
{
|
||||||
|
await IdChanged.InvokeAsync(WorkingId);
|
||||||
|
InvalidId = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
InvalidId = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public EventCallback<PrismDestination?> SettingsChanged { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public EventCallback<string> IdChanged { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
@using Microsoft.AspNetCore.Http
|
@using Microsoft.AspNetCore.Http
|
||||||
@using Microsoft.AspNetCore.Routing
|
@using Microsoft.AspNetCore.Routing
|
||||||
@using Microsoft.Extensions.Logging
|
@using Microsoft.Extensions.Logging
|
||||||
@using Newtonsoft.Json.Linq
|
@using NBitcoin
|
||||||
@using LightningAddressData = BTCPayServer.Data.LightningAddressData
|
@using LightningAddressData = BTCPayServer.Data.LightningAddressData
|
||||||
@inject IPluginHookService PluginHookService
|
@inject IPluginHookService PluginHookService
|
||||||
@inject LightningAddressService LightningAddressService
|
@inject LightningAddressService LightningAddressService
|
||||||
@@ -39,12 +39,20 @@ else
|
|||||||
}
|
}
|
||||||
|
|
||||||
<datalist id="users">
|
<datalist id="users">
|
||||||
<option value="*"></option>
|
<option value="*">Catch-all lightning payments made against invoices in your store (excluding when other prisms are configured that capture those payments.)</option>
|
||||||
|
|
||||||
@foreach (var user in Users)
|
@foreach (var user in Users)
|
||||||
{
|
{
|
||||||
<option value="@user.Username"></option>
|
<option value="@user.Username">A lightning address configured on your store</option>
|
||||||
}
|
}
|
||||||
</datalist>
|
</datalist>
|
||||||
|
<datalist id="destinations">
|
||||||
|
@foreach (var destination in Destinations)
|
||||||
|
{
|
||||||
|
<option value="@destination">@destination</option>
|
||||||
|
}
|
||||||
|
</datalist>
|
||||||
|
|
||||||
<h2 class="mb-4">
|
<h2 class="mb-4">
|
||||||
Prism
|
Prism
|
||||||
<a href="https://dergigi.com/2023/03/12/lightning-prisms/" class="ms-1" target="_blank" rel="noreferrer noopener">
|
<a href="https://dergigi.com/2023/03/12/lightning-prisms/" class="ms-1" target="_blank" rel="noreferrer noopener">
|
||||||
@@ -79,17 +87,41 @@ else
|
|||||||
<span class="text-muted">When a payout is being generated, how many of its amount in percentage should be excluded to cover the fee? Once the payment is settled, if the lightning node provides the exact fee, the balance is adjusted accordingly.</span>
|
<span class="text-muted">When a payout is being generated, how many of its amount in percentage should be excluded to cover the fee? Once the payment is settled, if the lightning node provides the exact fee, the balance is adjusted accordingly.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row" id="prism-holder">
|
<div class="row" id="prism-holder">
|
||||||
@foreach (var item in Settings.Splits)
|
|
||||||
{
|
<div class="prism col-sm-12 col-md-8 border border-light p-2">
|
||||||
<PrismSplit Split="@item" OnRequestRemove="@RemovePrism"/>
|
@foreach (var item in Settings.Splits)
|
||||||
}
|
{
|
||||||
|
<PrismSplit Split="@item" OnRequestRemove="@RemovePrism"/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="prism col-sm-12 col-md-4 border border-light p-2">
|
||||||
|
@if (Destinations.Any())
|
||||||
|
{
|
||||||
|
<div class="form-group">
|
||||||
|
<select class="form-select" @bind="SelectedDestinationId">
|
||||||
|
|
||||||
|
<option value="null">Select destination to configure</option>
|
||||||
|
@foreach (var destination in Destinations)
|
||||||
|
{
|
||||||
|
<option value="@destination">@destination</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (SelectedDestinationId is not null && SelectedDestinationId != "null")
|
||||||
|
{
|
||||||
|
<PrismDestinationEditor ValidateId="ValidateId" Id="@SelectedDestinationId" IdChanged="OnIdRenamed" ValidateDestination="s => ValidateDestination(s, false)" @bind-Settings="SelectedDestination"></PrismDestinationEditor>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<PrismBalances DestinationBalance="Settings.DestinationBalance" PendingPayouts="Settings.PendingPayouts"></PrismBalances>
|
<PrismBalances OnUpdate="OnUpdateBalance" DestinationBalance="Settings.DestinationBalance" PendingPayouts="Settings.PendingPayouts"></PrismBalances>
|
||||||
|
|
||||||
|
|
||||||
@if (StatusMessageModel != null)
|
@if (StatusMessageModel != null)
|
||||||
{
|
{
|
||||||
<div class="alert alert-@StatusMessageModel.ToString(StatusMessageModel.Severity)">
|
<div class="alert alert-@StatusMessageModel.ToString(StatusMessageModel.Severity)">
|
||||||
@@ -99,6 +131,7 @@ else
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<button type="button" class="btn btn-primary mx-2" id="add-prism" @onclick="CreateNewPrism">Add Prism</button>
|
<button type="button" class="btn btn-primary mx-2" id="add-prism" @onclick="CreateNewPrism">Add Prism</button>
|
||||||
|
<button type="button" class="btn btn-primary mx-2" id="add-destination" @onclick="AddDestination">Add Destination</button>
|
||||||
<button type="submit" class="btn btn-primary mx-2">Save</button>
|
<button type="submit" class="btn btn-primary mx-2">Save</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -106,6 +139,43 @@ else
|
|||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
|
||||||
|
|
||||||
|
private void AddDestination()
|
||||||
|
{
|
||||||
|
SelectedDestinationId = "";
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? SelectedDestinationId { get; set; }
|
||||||
|
|
||||||
|
public PrismDestination? SelectedDestination
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (SelectedDestinationId is null || SelectedDestinationId == "null")
|
||||||
|
return null;
|
||||||
|
Settings.Destinations.TryGetValue(SelectedDestinationId, out var res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SelectedDestinationId is null)
|
||||||
|
return;
|
||||||
|
if (value is null)
|
||||||
|
{
|
||||||
|
Settings.Destinations.Remove(SelectedDestinationId);
|
||||||
|
SelectedDestinationId = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Settings.Destinations.AddOrReplace(SelectedDestinationId, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] Destinations => Settings.Destinations.Keys.ToArray();
|
||||||
|
|
||||||
public bool Loading { get; set; } = true;
|
public bool Loading { get; set; } = true;
|
||||||
public List<LightningAddressData> Users { get; set; } = new();
|
public List<LightningAddressData> Users { get; set; } = new();
|
||||||
public PaymentMethodId pmi { get; set; } = new("BTC", LightningPaymentType.Instance);
|
public PaymentMethodId pmi { get; set; } = new("BTC", LightningPaymentType.Instance);
|
||||||
@@ -115,7 +185,6 @@ else
|
|||||||
{
|
{
|
||||||
if (firstRender)
|
if (firstRender)
|
||||||
{
|
{
|
||||||
|
|
||||||
PayoutProcessorLink = LinkGenerator.GetUriByAction(HttpContextAccessor.HttpContext, "ConfigureStorePayoutProcessors", "UIPayoutProcessors", new {StoreId});
|
PayoutProcessorLink = LinkGenerator.GetUriByAction(HttpContextAccessor.HttpContext, "ConfigureStorePayoutProcessors", "UIPayoutProcessors", new {StoreId});
|
||||||
LNAddressLink = LinkGenerator.GetUriByAction(HttpContextAccessor.HttpContext, "EditLightningAddress", "UILNURL", new {StoreId});
|
LNAddressLink = LinkGenerator.GetUriByAction(HttpContextAccessor.HttpContext, "EditLightningAddress", "UILNURL", new {StoreId});
|
||||||
PayoutsLink = LinkGenerator.GetUriByAction(HttpContextAccessor.HttpContext, "Payouts", "UIStorePullPayments", new {StoreId, payoutState = PayoutState.AwaitingPayment, paymentMethodId = pmi.ToString()});
|
PayoutsLink = LinkGenerator.GetUriByAction(HttpContextAccessor.HttpContext, "Payouts", "UIStorePullPayments", new {StoreId, payoutState = PayoutState.AwaitingPayment, paymentMethodId = pmi.ToString()});
|
||||||
@@ -148,7 +217,6 @@ else
|
|||||||
NoPayoutProcessors = PayoutProcessorFactories.Any(factory => factory.GetSupportedPaymentMethods().Contains(pmi)) && !(await fetchProcessors).Any();
|
NoPayoutProcessors = PayoutProcessorFactories.Any(factory => factory.GetSupportedPaymentMethods().Contains(pmi)) && !(await fetchProcessors).Any();
|
||||||
Loading = false;
|
Loading = false;
|
||||||
await InvokeAsync(StateHasChanged);
|
await InvokeAsync(StateHasChanged);
|
||||||
|
|
||||||
}
|
}
|
||||||
await base.OnAfterRenderAsync(firstRender);
|
await base.OnAfterRenderAsync(firstRender);
|
||||||
}
|
}
|
||||||
@@ -160,7 +228,7 @@ else
|
|||||||
|
|
||||||
private void SatBreakerOnPrismUpdated(object sender, PrismPaymentDetectedEventArgs e)
|
private void SatBreakerOnPrismUpdated(object sender, PrismPaymentDetectedEventArgs e)
|
||||||
{
|
{
|
||||||
if(e.StoreId != StoreId) return;
|
if (e.StoreId != StoreId) return;
|
||||||
if (e.Settings != Settings && e.Settings.Version != Settings.Version)
|
if (e.Settings != Settings && e.Settings.Version != Settings.Version)
|
||||||
{
|
{
|
||||||
Settings.DestinationBalance = e.Settings.DestinationBalance;
|
Settings.DestinationBalance = e.Settings.DestinationBalance;
|
||||||
@@ -200,14 +268,13 @@ else
|
|||||||
foreach (var destination in prism.Destinations)
|
foreach (var destination in prism.Destinations)
|
||||||
{
|
{
|
||||||
var dest = destination.Destination;
|
var dest = destination.Destination;
|
||||||
//check that the source is a valid internet identifier, which is username@domain(and optional port)
|
|
||||||
if (string.IsNullOrEmpty(dest))
|
if (string.IsNullOrEmpty(dest))
|
||||||
{
|
{
|
||||||
MessageStore.Add(() => destination.Destination, "Destination is required");
|
MessageStore.Add(() => destination.Destination, "Destination is required");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ValidateDestination(dest))
|
if (!ValidateDestination(dest, true))
|
||||||
{
|
{
|
||||||
MessageStore.Add(() => destination.Destination, "Destination is not valid");
|
MessageStore.Add(() => destination.Destination, "Destination is not valid");
|
||||||
}
|
}
|
||||||
@@ -217,8 +284,12 @@ else
|
|||||||
EditContext.NotifyValidationStateChanged();
|
EditContext.NotifyValidationStateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ValidateDestination(string dest)
|
private bool ValidateDestination(string dest, bool allowAlias)
|
||||||
{
|
{
|
||||||
|
if (allowAlias && Destinations.Contains(dest))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
LNURL.LNURL.ExtractUriFromInternetIdentifier(dest);
|
LNURL.LNURL.ExtractUriFromInternetIdentifier(dest);
|
||||||
@@ -243,7 +314,7 @@ else
|
|||||||
|
|
||||||
public ValidationMessageStore MessageStore { get; set; }
|
public ValidationMessageStore MessageStore { get; set; }
|
||||||
|
|
||||||
public EditContext EditContext { get; set; }
|
public EditContext? EditContext { get; set; }
|
||||||
public StatusMessageModel StatusMessageModel { get; set; }
|
public StatusMessageModel StatusMessageModel { get; set; }
|
||||||
|
|
||||||
public PrismSettings Settings { get; set; }
|
public PrismSettings Settings { get; set; }
|
||||||
@@ -301,9 +372,84 @@ else
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
EditContext.OnValidationRequested -= Validate;
|
if (EditContext is not null)
|
||||||
EditContext.OnFieldChanged -= FieldChanged;
|
{
|
||||||
|
EditContext.OnValidationRequested -= Validate;
|
||||||
|
EditContext.OnFieldChanged -= FieldChanged;
|
||||||
|
}
|
||||||
SatBreaker.PrismUpdated -= SatBreakerOnPrismUpdated;
|
SatBreaker.PrismUpdated -= SatBreakerOnPrismUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool ValidateId(string arg)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(arg))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (SelectedDestinationId == arg)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (Destinations.Contains(arg))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OnIdRenamed(string s)
|
||||||
|
{
|
||||||
|
if(SelectedDestinationId == s)
|
||||||
|
return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await SatBreaker._updateLock.WaitAsync();
|
||||||
|
|
||||||
|
if (SelectedDestinationId == s)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// find all prisms splits that use this id + all destination balances that use this id + all pending payouts that use this id and rename them
|
||||||
|
foreach (var destination in Settings.Splits.SelectMany(split => split.Destinations.Where(destination => destination.Destination == SelectedDestinationId)))
|
||||||
|
{
|
||||||
|
destination.Destination = s;
|
||||||
|
}
|
||||||
|
if (Settings.DestinationBalance.Remove(SelectedDestinationId, out var db))
|
||||||
|
{
|
||||||
|
Settings.DestinationBalance.Add(s, db);
|
||||||
|
}
|
||||||
|
if(Settings.Destinations.Remove(SelectedDestinationId, out var dest))
|
||||||
|
{
|
||||||
|
Settings.Destinations.Add(s, dest);
|
||||||
|
}
|
||||||
|
SelectedDestinationId = s;
|
||||||
|
|
||||||
|
await SatBreaker.UpdatePrismSettingsForStore(StoreId, Settings, true);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
SatBreaker._updateLock.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OnUpdateBalance((string destination, long newBalance) obj)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await SatBreaker._updateLock.WaitAsync();
|
||||||
|
if (obj.newBalance == 0)
|
||||||
|
{
|
||||||
|
Settings.DestinationBalance.Remove(obj.destination);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Settings.DestinationBalance.AddOrReplace(obj.destination, obj.newBalance);
|
||||||
|
}
|
||||||
|
await SatBreaker.UpdatePrismSettingsForStore(StoreId, Settings, true);
|
||||||
|
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
SatBreaker._updateLock.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="prism col-sm-12 col-xl-10 col-xxl-constrain border border-light p-2 m-1">
|
<div class="border border-light p-2 m-1">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label">Source</label>
|
<label class="form-label">Source</label>
|
||||||
<input type="text" @bind="Split.Source" list="users" class="form-control src"/>
|
<input type="text" @bind="Split.Source" list="users" class="form-control src"/>
|
||||||
@@ -15,11 +15,11 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach(var destination in Split.Destinations)
|
@foreach (var destination in Split.Destinations)
|
||||||
{
|
{
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" @bind="@destination.Destination" class="form-control dest"/>
|
<input type="text" @bind="@destination.Destination" list="destinations" class="form-control dest"/>
|
||||||
|
|
||||||
<ValidationMessage2 For="() => destination.Destination" class="text-danger"></ValidationMessage2>
|
<ValidationMessage2 For="() => destination.Destination" class="text-danger"></ValidationMessage2>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ namespace BTCPayServer.Plugins.Prism
|
|||||||
|
|
||||||
record CreditDestination(string StoreId, Dictionary<string, long> Destcredits, List<string> PayoutsToRemove);
|
record CreditDestination(string StoreId, Dictionary<string, long> Destcredits, List<string> PayoutsToRemove);
|
||||||
|
|
||||||
private readonly SemaphoreSlim _updateLock = new(1, 1);
|
public readonly SemaphoreSlim _updateLock = new(1, 1);
|
||||||
|
|
||||||
public async Task<PrismSettings> Get(string storeId)
|
public async Task<PrismSettings> Get(string storeId)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user