| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647 |
- using System.Security.Cryptography;
- using Application.Abstractions.Data;
- using Application.Abstractions.Messaging;
- using Microsoft.EntityFrameworkCore;
- namespace Application.Features.Admin.Channel.List.GenerateDonationCode;
- internal sealed class Handler(IAppDbContext db) : IQueryHandler<Query, string>
- {
- // 혼동되는 문자(0/O, 1/I/L) 제외 31자. 6자리 조합 31^6 ≈ 8.8억.
- private const string Alphabet = "23456789ABCDEFGHJKMNPQRSTUVWXYZ";
- private const int CodeLength = 6;
- private const int MaxAttempts = 10;
- public async Task<string> Handle(Query request, CancellationToken ct)
- {
- for (var attempt = 0; attempt < MaxAttempts; attempt++)
- {
- var candidate = Generate();
- var exists = await db.Channel.AnyAsync(c => c.DonationCode == candidate, ct);
- if (!exists)
- {
- return candidate;
- }
- }
- // 31^6 ≈ 8.8억 중 10회 모두 충돌은 극히 낮은 확률. 호출자 측 유효성 검증으로 한 번 더 안전망.
- return Generate();
- }
- private static string Generate()
- {
- var chars = new char[CodeLength];
- var bytes = new byte[CodeLength];
- RandomNumberGenerator.Fill(bytes);
- for (var i = 0; i < CodeLength; i++)
- {
- chars[i] = Alphabet[bytes[i] % Alphabet.Length];
- }
- return new string(chars);
- }
- }
|