- New "カードを配る" switch on the create-table screen (default off); the lobby shows "カードあり" for tables that use it - Card mode (server/cards.js restored): crypto-shuffled deck kept server-side, hole cards sent only to their owner until showdown/all-in reveal, board dealt per street with burns, all-in runout on a timer (frozen while paused) - Showdown is evaluated and every pot (incl. side pots, split pots) is paid out automatically; host winner selection is only used when card mode is off - Play UI: board, hole cards, own cards in the action bar, hand names, winning cards highlighted; layout tuned for 7+ seats and short screens - Playing-card styles use .pcard so they don't clash with the existing .card panel - Tests for hand evaluation, card privacy, runout, side pots, ties and random play Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
85 lines
3.4 KiB
JavaScript
85 lines
3.4 KiB
JavaScript
'use strict';
|
||
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
|
||
// プロジェクト直下の .env を読み込む(既存の環境変数は上書きしない)。
|
||
// 秘密情報はソースコードに書かず .env(git 管理外)か環境変数で渡す。
|
||
function loadDotEnv(file) {
|
||
let text;
|
||
try {
|
||
text = fs.readFileSync(file, 'utf8');
|
||
} catch {
|
||
return;
|
||
}
|
||
if (process.platform !== 'win32' && (fs.statSync(file).mode & 0o077) !== 0) {
|
||
console.warn(`[config] ${file} が他ユーザーから読める状態です。chmod 600 してください。`);
|
||
}
|
||
for (const line of text.split(/\r?\n/)) {
|
||
const m = line.match(/^\s*([A-Z_][A-Z0-9_]*)\s*=\s*(.*?)\s*$/);
|
||
if (!m || line.trim().startsWith('#')) continue;
|
||
const value = m[2].replace(/^(['"])(.*)\1$/, '$2');
|
||
if (process.env[m[1]] === undefined) process.env[m[1]] = value;
|
||
}
|
||
}
|
||
loadDotEnv(path.join(__dirname, '..', '.env'));
|
||
|
||
const ACCESS_KEY = process.env.ACCESS_KEY;
|
||
if (!ACCESS_KEY || !/^\d{6}$/.test(ACCESS_KEY)) {
|
||
console.error('[config] ACCESS_KEY(6桁の数字)が未設定です。.env か環境変数で指定してください。');
|
||
process.exit(1);
|
||
}
|
||
|
||
// 管理者キー(任意)。入力すると管理者として入室でき、ハンドレンジ学習ページが見える
|
||
const ADMIN_KEY = process.env.ADMIN_KEY || null;
|
||
if (ADMIN_KEY && (!/^\d{6}$/.test(ADMIN_KEY) || ADMIN_KEY === ACCESS_KEY)) {
|
||
console.error('[config] ADMIN_KEY は ACCESS_KEY と異なる6桁の数字にしてください。');
|
||
process.exit(1);
|
||
}
|
||
|
||
module.exports = {
|
||
PORT: Number(process.env.PORT) || 4671,
|
||
|
||
// 既定では自分自身(127.0.0.1)でのみ待ち受け、外部には nginx 等の HTTPS 経由で公開する。
|
||
// どうしても直接公開する場合のみ HOST=0.0.0.0 にする(通信が平文になるので非推奨)。
|
||
HOST: process.env.HOST || '127.0.0.1',
|
||
|
||
// 公開URL(例: https://poker.kanawo.net)。設定するとこのドメイン以外からのアクセスを拒否する。
|
||
// ローカル開発時は未設定のままにする。
|
||
PUBLIC_ORIGIN: process.env.PUBLIC_ORIGIN ? new URL(process.env.PUBLIC_ORIGIN).origin : null,
|
||
|
||
// 参加キー(6桁の数字)。.env の ACCESS_KEY
|
||
ACCESS_KEY,
|
||
ADMIN_KEY,
|
||
|
||
// 1テーブルの最大着席数
|
||
MAX_SEATS: 9,
|
||
|
||
// 同時に存在できるテーブル数の上限
|
||
MAX_TABLES: 30,
|
||
|
||
// 誰も接続していないテーブルを削除するまでの時間
|
||
EMPTY_TABLE_TTL_MS: 30 * 60 * 1000,
|
||
|
||
// オールインで残りの場札をめくる間隔(カード機能あり)
|
||
RUNOUT_STEP_MS: 1500,
|
||
// ハンド終了後、次のハンドまで結果を表示する時間(カードありは手札を見比べられるよう長め)
|
||
SHOWDOWN_MS: 4000,
|
||
CARD_SHOWDOWN_MS: 6000,
|
||
FOLD_WIN_MS: 2500,
|
||
// 参加者が2人揃ってから次のハンドを始めるまで
|
||
NEXT_HAND_DELAY_MS: 2000,
|
||
|
||
// 鍵入力のブルートフォース対策
|
||
// IP(IPv6 は /64 単位)ごと: WINDOW 内で MAX_FAILURES 回まで
|
||
AUTH_MAX_FAILURES: 5,
|
||
AUTH_FAILURE_WINDOW_MS: 30 * 60 * 1000,
|
||
// サーバ全体: 1時間に GLOBAL_MAX_FAILURES 回失敗したら新規の鍵入力を一時停止
|
||
// (入室済みの人は Cookie があるので影響なし)
|
||
AUTH_GLOBAL_MAX_FAILURES: 30,
|
||
AUTH_GLOBAL_WINDOW_MS: 60 * 60 * 1000,
|
||
|
||
// Socket.IO のイベント数上限(1接続あたり / 秒)
|
||
SOCKET_EVENTS_PER_SEC: 10,
|
||
};
|