| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748 |
- using Application.Abstractions.Data;
- using Application.Abstractions.Messaging;
- using Microsoft.EntityFrameworkCore;
- using System.Security.Cryptography;
- namespace Application.Features.Admin.Store.Game.GenerateCode;
- 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.Game.AnyAsync(c => c.Code == 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);
- }
- }
|