🎉 Initial commit for the Zone project

This commit is contained in:
2025-11-19 21:04:44 +08:00
parent 18d50346a9
commit 382579a20e
20 changed files with 505 additions and 10 deletions

View File

@@ -0,0 +1,26 @@
using DysonNetwork.Shared.Auth;
using DysonNetwork.Shared.Http;
namespace DysonNetwork.Zone.Startup;
public static class ApplicationConfiguration
{
public static WebApplication ConfigureAppMiddleware(this WebApplication app, IConfiguration configuration)
{
app.UseRequestLocalization();
app.ConfigureForwardedHeaders(configuration);
app.UseWebSockets();
app.UseAuthentication();
app.UseAuthorization();
app.UseMiddleware<PermissionMiddleware>();
app.MapControllers();
// Map gRPC services
app.MapGrpcReflectionService();
return app;
}
}

View File

@@ -0,0 +1,61 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using DysonNetwork.Shared.Proto;
using DysonNetwork.Shared.Stream;
using NATS.Client.Core;
using NATS.Client.JetStream.Models;
using NATS.Net;
namespace DysonNetwork.Zone.Startup;
public class BroadcastEventHandler(
IServiceProvider serviceProvider,
ILogger<BroadcastEventHandler> logger,
INatsConnection nats,
RingService.RingServiceClient pusher
) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var accountTask = HandleAccountDeletions(stoppingToken);
await Task.WhenAll(accountTask);
}
private async Task HandleAccountDeletions(CancellationToken stoppingToken)
{
var js = nats.CreateJetStreamContext();
await js.EnsureStreamCreated("account_events", [AccountDeletedEvent.Type]);
var consumer = await js.CreateOrUpdateConsumerAsync("account_events",
new ConsumerConfig("sphere_account_deleted_handler"), cancellationToken: stoppingToken);
await foreach (var msg in consumer.ConsumeAsync<byte[]>(cancellationToken: stoppingToken))
{
try
{
var evt = JsonSerializer.Deserialize<AccountDeletedEvent>(msg.Data, GrpcTypeHelper.SerializerOptions);
if (evt == null)
{
await msg.AckAsync(cancellationToken: stoppingToken);
continue;
}
logger.LogInformation("Account deleted: {AccountId}", evt.AccountId);
using var scope = serviceProvider.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<AppDatabase>();
// TODO clean up data
await msg.AckAsync(cancellationToken: stoppingToken);
}
catch (Exception ex)
{
logger.LogError(ex, "Error processing AccountDeleted");
await msg.NakAsync(cancellationToken: stoppingToken);
}
}
}
}

View File

@@ -0,0 +1,17 @@
using Quartz;
namespace DysonNetwork.Zone.Startup;
public static class ScheduledJobsConfiguration
{
public static IServiceCollection AddAppScheduledJobs(this IServiceCollection services)
{
services.AddQuartz(q =>
{
});
services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);
return services;
}
}

View File

@@ -0,0 +1,79 @@
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
using DysonNetwork.Shared.Cache;
using DysonNetwork.Shared.GeoIp;
using NodaTime;
using NodaTime.Serialization.SystemTextJson;
namespace DysonNetwork.Zone.Startup;
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddAppServices(this IServiceCollection services)
{
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddDbContext<AppDatabase>();
services.AddSingleton<IClock>(SystemClock.Instance);
services.AddHttpContextAccessor();
services.AddSingleton<ICacheService, CacheServiceRedis>();
services.AddHttpClient();
services
.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.NumberHandling =
JsonNumberHandling.AllowNamedFloatingPointLiterals;
options.JsonSerializerOptions.PropertyNamingPolicy =
JsonNamingPolicy.SnakeCaseLower;
options.JsonSerializerOptions.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
});
services.AddRazorPages();
services.AddGrpc(options =>
{
options.EnableDetailedErrors = true;
});
services.AddGrpcReflection();
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[] { new CultureInfo("en-US"), new CultureInfo("zh-Hans") };
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
});
services.AddHostedService<BroadcastEventHandler>();
return services;
}
public static IServiceCollection AddAppAuthentication(this IServiceCollection services)
{
services.AddAuthorization();
return services;
}
public static IServiceCollection AddAppFlushHandlers(this IServiceCollection services)
{
services.AddSingleton<FlushBufferService>();
return services;
}
public static IServiceCollection AddAppBusinessServices(
this IServiceCollection services,
IConfiguration configuration
)
{
services.Configure<GeoIpOptions>(configuration.GetSection("GeoIP"));
services.AddScoped<GeoIpService>();
return services;
}
}