Add RCON client + SendCurrency service (AtomCMS-faithful)

- rcon.ts: Node net.Socket transport speaking AtomCMS's exact protocol (raw
  JSON {"key","data"} over rcon_ip:rcon_port, fire-and-forget) with a bounded
  timeout + backoff retry; typed commands matching RconService EXACTLY
  (sendgift `itemid`, disconnect `username`, no-data => data:null, givepoints
  numeric `type`, forwarduser, setmotto/setrank/alertuser, give*). Injectable
  transport keeps command shapes unit-testable.
- send-currency.ts: mirrors the SendCurrency action — RCON deliver, else DB
  fallback (credits -> users.credits; duckets/diamonds/points -> users_currency
  by type 0/5/101).
- env: RCON_HOST/PORT/TIMEOUT/RETRIES. vitest: SKIP_ENV_VALIDATION for unit tests.

Verified: tsc exit 0, vitest 39/39, next build exit 0. Live TCP test deferred
(needs a running emulator).
This commit is contained in:
Simo committed 2026-06-27 16:37:42 +02:00
1 parent 443d908909
commit 8fca407f0f
6 files changed
+350

No files matched your search

+5
View File
@@ -9,6 +9,11 @@ const schema = z.object({
DATABASE_POOL_SIZE: z.coerce.number().int().positive().default(40),
DATABASE_IDLE_TIMEOUT_MS: z.coerce.number().int().positive().default(300_000),
HOTEL_NAME: z.string().default("Atom"),
// RCON link to the Arcturus emulator (raw-JSON TCP protocol).
RCON_HOST: z.string().default("127.0.0.1"),
RCON_PORT: z.coerce.number().int().positive().default(3001),
RCON_TIMEOUT_MS: z.coerce.number().int().positive().default(10_000),
RCON_MAX_RETRIES: z.coerce.number().int().positive().default(3),
// NextAuth v5 reads AUTH_SECRET itself; declared here for documentation/typing.
AUTH_SECRET: z.string().min(1).optional(),
// Mirrors Laravel config('habbo.site.convert_passwords') — enables md5->argon2id.