btcpayserver/BTCPayServer/Shitcoins/Monero/Services/MoneroRPCProvider.cs
2019-09-30 17:51:47 +09:00

118 lines
4.6 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Collections.Immutable;
using System.Net.Http;
using System.Threading.Tasks;
using BTCPayServer.Shitcoins.Monero.Configuration;
using BTCPayServer.Shitcoins.Monero.RPC;
using BTCPayServer.Shitcoins.Monero.RPC.Models;
using NBitcoin;
namespace BTCPayServer.Shitcoins.Monero.Services
{
public class MoneroRPCProvider
{
private readonly MoneroLikeConfiguration _moneroLikeConfiguration;
private readonly EventAggregator _eventAggregator;
public ImmutableDictionary<string, JsonRpcClient> DaemonRpcClients;
public ImmutableDictionary<string, JsonRpcClient> WalletRpcClients;
private ConcurrentDictionary<string, MoneroLikeSummary> _summaries =
new ConcurrentDictionary<string, MoneroLikeSummary>();
public ConcurrentDictionary<string, MoneroLikeSummary> Summaries => _summaries;
public MoneroRPCProvider(MoneroLikeConfiguration moneroLikeConfiguration, EventAggregator eventAggregator, IHttpClientFactory httpClientFactory)
{
_moneroLikeConfiguration = moneroLikeConfiguration;
_eventAggregator = eventAggregator;
DaemonRpcClients =
_moneroLikeConfiguration.MoneroLikeConfigurationItems.ToImmutableDictionary(pair => pair.Key,
pair => new JsonRpcClient(pair.Value.DaemonRpcUri, "", "", httpClientFactory.CreateClient()));
WalletRpcClients =
_moneroLikeConfiguration.MoneroLikeConfigurationItems.ToImmutableDictionary(pair => pair.Key,
pair => new JsonRpcClient(pair.Value.InternalWalletRpcUri, "", "", httpClientFactory.CreateClient()));
}
public bool IsAvailable(string cryptoCode)
{
cryptoCode = cryptoCode.ToUpperInvariant();
return _summaries.ContainsKey(cryptoCode) && IsAvailable(_summaries[cryptoCode]);
}
private bool IsAvailable(MoneroLikeSummary summary)
{
return summary.Synced &&
summary.WalletAvailable;
}
public async Task<MoneroLikeSummary> UpdateSummary(string cryptoCode)
{
if (!DaemonRpcClients.TryGetValue(cryptoCode.ToUpperInvariant(), out var daemonRpcClient) ||
!WalletRpcClients.TryGetValue(cryptoCode.ToUpperInvariant(), out var walletRpcClient))
{
return null;
}
var summary = new MoneroLikeSummary();
try
{
var daemonResult =
await daemonRpcClient.SendCommandAsync<JsonRpcClient.NoRequestModel, SyncInfoResponse>("sync_info",
JsonRpcClient.NoRequestModel.Instance);
summary.TargetHeight = daemonResult.TargetHeight ?? daemonResult.Height;
summary.Synced = !daemonResult.TargetHeight.HasValue ||
(daemonResult.Height >= daemonResult.TargetHeight && daemonResult.TargetHeight > 0);
summary.CurrentHeight = daemonResult.Height;
summary.UpdatedAt = DateTime.Now;
summary.DaemonAvailable = true;
}
catch
{
summary.DaemonAvailable = false;
}
try
{
var walletResult =
await walletRpcClient.SendCommandAsync<JsonRpcClient.NoRequestModel, GetHeightResponse>(
"get_height", JsonRpcClient.NoRequestModel.Instance);
summary.WalletHeight = walletResult.Height;
summary.WalletAvailable = true;
}
catch
{
summary.WalletAvailable = false;
}
var changed = !_summaries.ContainsKey(cryptoCode) || IsAvailable(cryptoCode) != IsAvailable(summary);
_summaries.AddOrReplace(cryptoCode, summary);
if (changed)
{
_eventAggregator.Publish(new MoneroDaemonStateChange() {Summary = summary, CryptoCode = cryptoCode});
}
return summary;
}
public class MoneroDaemonStateChange
{
public string CryptoCode { get; set; }
public MoneroLikeSummary Summary { get; set; }
}
public class MoneroLikeSummary
{
public bool Synced { get; set; }
public long CurrentHeight { get; set; }
public long WalletHeight { get; set; }
public long TargetHeight { get; set; }
public DateTime UpdatedAt { get; set; }
public bool DaemonAvailable { get; set; }
public bool WalletAvailable { get; set; }
}
}
}