♻️ Replace normal streams with JetStream
🐛 Fix pass order didn't handled successfully
This commit is contained in:
@@ -13,6 +13,8 @@ using EFCore.BulkExtensions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using NATS.Client.Core;
|
||||
using NATS.Client.JetStream;
|
||||
using NATS.Net;
|
||||
using NodaTime;
|
||||
using OtpNet;
|
||||
using AuthService = DysonNetwork.Pass.Auth.AuthService;
|
||||
@@ -189,7 +191,8 @@ public class AccountService(
|
||||
);
|
||||
}
|
||||
|
||||
public async Task<Account> CreateBotAccount(Account account, Guid automatedId, string? pictureId, string? backgroundId)
|
||||
public async Task<Account> CreateBotAccount(Account account, Guid automatedId, string? pictureId,
|
||||
string? backgroundId)
|
||||
{
|
||||
var dupeAutomateCount = await db.Accounts.Where(a => a.AutomatedId == automatedId).CountAsync();
|
||||
if (dupeAutomateCount > 0)
|
||||
@@ -230,7 +233,7 @@ public class AccountService(
|
||||
);
|
||||
account.Profile.Background = CloudFileReferenceObject.FromProtoValue(file);
|
||||
}
|
||||
|
||||
|
||||
db.Accounts.Add(account);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
@@ -442,7 +445,7 @@ public class AccountService(
|
||||
if (contact is null)
|
||||
{
|
||||
logger.LogWarning(
|
||||
"Unable to send factor code to #{FactorId} with, due to no contact method was found...",
|
||||
"Unable to send factor code to #{FactorId} with, due to no contact method was found...",
|
||||
factor.Id
|
||||
);
|
||||
return;
|
||||
@@ -740,10 +743,14 @@ public class AccountService(
|
||||
db.Accounts.Remove(account);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
await nats.PublishAsync(AccountDeletedEvent.Type, JsonSerializer.SerializeToUtf8Bytes(new AccountDeletedEvent
|
||||
{
|
||||
AccountId = account.Id,
|
||||
DeletedAt = SystemClock.Instance.GetCurrentInstant()
|
||||
}));
|
||||
var js = nats.CreateJetStreamContext();
|
||||
await js.PublishAsync(
|
||||
AccountDeletedEvent.Type,
|
||||
GrpcTypeHelper.ConvertObjectToByteString(new AccountDeletedEvent
|
||||
{
|
||||
AccountId = account.Id,
|
||||
DeletedAt = SystemClock.Instance.GetCurrentInstant()
|
||||
}).ToByteArray()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,6 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Nager.Holiday" Version="1.0.1" />
|
||||
<PackageReference Include="NATS.Client.Core" Version="2.6.8" />
|
||||
<PackageReference Include="NATS.Client.JetStream" Version="2.6.8" />
|
||||
<PackageReference Include="Nerdbank.GitVersioning" Version="3.7.115">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Pass.Wallet;
|
||||
using DysonNetwork.Shared.Proto;
|
||||
using DysonNetwork.Shared.Stream;
|
||||
using NATS.Client.Core;
|
||||
using NATS.Client.JetStream.Models;
|
||||
using NATS.Net;
|
||||
|
||||
namespace DysonNetwork.Pass.Startup;
|
||||
|
||||
@@ -13,18 +16,30 @@ public class BroadcastEventHandler(
|
||||
{
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
await foreach (var msg in nats.SubscribeAsync<byte[]>(PaymentOrderEventBase.Type, cancellationToken: stoppingToken))
|
||||
var js = nats.CreateJetStreamContext();
|
||||
|
||||
await js.EnsureStreamCreated("payment_events", [PaymentOrderEventBase.Type]);
|
||||
|
||||
var consumer = await js.CreateOrUpdateConsumerAsync("payment_events",
|
||||
new ConsumerConfig("pass_payment_handler"),
|
||||
cancellationToken: stoppingToken);
|
||||
|
||||
await foreach (var msg in consumer.ConsumeAsync<byte[]>(cancellationToken: stoppingToken))
|
||||
{
|
||||
PaymentOrderEvent? evt = null;
|
||||
try
|
||||
{
|
||||
evt = JsonSerializer.Deserialize<PaymentOrderEvent>(msg.Data);
|
||||
evt = JsonSerializer.Deserialize<PaymentOrderEvent>(msg.Data, GrpcTypeHelper.SerializerOptions);
|
||||
|
||||
logger.LogInformation(
|
||||
"Received order event: {ProductIdentifier} {OrderId}",
|
||||
evt?.ProductIdentifier,
|
||||
evt?.OrderId
|
||||
);
|
||||
|
||||
if (evt?.ProductIdentifier is null ||
|
||||
!evt.ProductIdentifier.StartsWith(SubscriptionType.StellarProgram))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
logger.LogInformation("Handling stellar program order: {OrderId}", evt.OrderId);
|
||||
|
||||
@@ -38,19 +53,20 @@ public class BroadcastEventHandler(
|
||||
);
|
||||
if (order is null)
|
||||
{
|
||||
logger.LogWarning("Order with ID {OrderId} not found.", evt.OrderId);
|
||||
await nats.PublishAsync(PaymentOrderEventBase.Type, msg.Data, cancellationToken: stoppingToken);
|
||||
logger.LogWarning("Order with ID {OrderId} not found. Redelivering.", evt.OrderId);
|
||||
await msg.NakAsync(cancellationToken: stoppingToken);
|
||||
continue;
|
||||
}
|
||||
|
||||
await subscriptions.HandleSubscriptionOrder(order);
|
||||
|
||||
logger.LogInformation("Subscription for order {OrderId} handled successfully.", evt.OrderId);
|
||||
await msg.AckAsync(cancellationToken: stoppingToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error processing payment order event for order {OrderId}", evt?.OrderId);
|
||||
await nats.PublishAsync(PaymentOrderEventBase.Type, msg.Data, cancellationToken: stoppingToken);
|
||||
logger.LogError(ex, "Error processing payment order event for order {OrderId}. Redelivering.", evt?.OrderId);
|
||||
await msg.NakAsync(cancellationToken: stoppingToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,9 +207,11 @@ public static class ServiceCollectionExtensions
|
||||
services.AddScoped<SafetyService>();
|
||||
services.AddScoped<SocialCreditService>();
|
||||
services.AddScoped<ExperienceService>();
|
||||
|
||||
|
||||
services.Configure<OidcProviderOptions>(configuration.GetSection("OidcProvider"));
|
||||
services.AddScoped<OidcProviderService>();
|
||||
|
||||
services.AddHostedService<BroadcastEventHandler>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using NATS.Client.Core;
|
||||
using NATS.Client.JetStream;
|
||||
using NATS.Net;
|
||||
using NodaTime;
|
||||
using AccountService = DysonNetwork.Pass.Account.AccountService;
|
||||
|
||||
@@ -253,6 +255,27 @@ public class PaymentService(
|
||||
throw new InvalidOperationException("Order not found");
|
||||
}
|
||||
|
||||
var js = nats.CreateJetStreamContext();
|
||||
|
||||
if (order.Status == OrderStatus.Paid)
|
||||
{
|
||||
await js.PublishAsync(
|
||||
PaymentOrderEventBase.Type,
|
||||
GrpcTypeHelper.ConvertObjectToByteString(new PaymentOrderEvent
|
||||
{
|
||||
OrderId = order.Id,
|
||||
WalletId = payerWallet.Id,
|
||||
AccountId = payerWallet.AccountId,
|
||||
AppIdentifier = order.AppIdentifier,
|
||||
ProductIdentifier = order.ProductIdentifier,
|
||||
Meta = order.Meta ?? [],
|
||||
Status = (int)order.Status,
|
||||
}).ToByteArray()
|
||||
);
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
if (order.Status != OrderStatus.Unpaid)
|
||||
{
|
||||
throw new InvalidOperationException($"Order is in invalid status: {order.Status}");
|
||||
@@ -282,16 +305,19 @@ public class PaymentService(
|
||||
|
||||
await NotifyOrderPaid(order, payerWallet, order.PayeeWallet);
|
||||
|
||||
await nats.PublishAsync(PaymentOrderEventBase.Type, JsonSerializer.SerializeToUtf8Bytes(new PaymentOrderEvent
|
||||
{
|
||||
OrderId = order.Id,
|
||||
WalletId = payerWallet.Id,
|
||||
AccountId = payerWallet.AccountId,
|
||||
AppIdentifier = order.AppIdentifier,
|
||||
ProductIdentifier = order.ProductIdentifier,
|
||||
Meta = order.Meta ?? [],
|
||||
Status = (int)order.Status,
|
||||
}));
|
||||
await js.PublishAsync(
|
||||
PaymentOrderEventBase.Type,
|
||||
GrpcTypeHelper.ConvertObjectToByteString(new PaymentOrderEvent
|
||||
{
|
||||
OrderId = order.Id,
|
||||
WalletId = payerWallet.Id,
|
||||
AccountId = payerWallet.AccountId,
|
||||
AppIdentifier = order.AppIdentifier,
|
||||
ProductIdentifier = order.ProductIdentifier,
|
||||
Meta = order.Meta ?? [],
|
||||
Status = (int)order.Status,
|
||||
}).ToByteArray()
|
||||
);
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user