- JavaScript 90.4%
- HTML 9.6%
| src | ||
| .gitignore | ||
| diag-probe.js | ||
| final-multifeature-test.js | ||
| itg-peer.js | ||
| itg-server.js | ||
| LICENSE | ||
| online-deploy-test.js | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
MAINER4IK XMCL-compatible P2P
Проект повторяет сетевую модель XMCL без прямого runtime-зависимого использования @xmcl/nat-api и @xmcl/stun-client.
Уже реализовано
- STUN Binding Request/Response, transaction IDs, IPv4/IPv6 XOR-MAPPED-ADDRESS;
- NAT probe с повторными измерениями;
- UPnP SSDP discovery + SOAP Add/DeletePortMapping;
- NAT-PMP public address и UDP/TCP mapping;
lodash.debounceостаётся обычной npm-зависимостью;node-datachannelPeerConnection;metadataheartbeat;minecraftDataChannel;- guest local TCP proxy → DataChannel → host LAN TCP;
- signaling rooms и Electron IPC;
- Electron UI.
- Named rooms with optional password protection; passwords are stored as
scrypthashes by the signaling server. - Регистрация и авторизация по логину/паролю:
auth:register/auth:login/auth:token/auth:logout/auth:me;- пароли хранятся как
scrypt-хэши в SQLite-БД (src/signaling/xmcl.db,DB_FILE— переопределить путь); - после входа клиент получает сессионный токен и сохраняет его в
localStorage; - комнаты (
room:create/room:join) доступны только авторизованным — иначеerror auth_required; - логин: 3–32 символа
[a-z0-9_.-], пароль: 4–128 символов.
- Мультирумы: один клиент может состоять сразу в нескольких комнатах (вкладки в UI), пользователи и их комнаты
хранятся в SQLite. Структура БД:
users,rooms,room_members,chat_messages,chat_attachments. - Чат в комнате через signaling WebSocket:
chat:send/chat:message/chat:history(последниеCHAT_HISTORY, по умолчанию 100); вложения отправляются как base64 и хранятся в БД (BLOB), лимитMAX_ATTACHMENT(по умолчанию 5 МБ на файл). - Управление комнатой: мастер (хост) может передать роль другому участнику (
transfer-master, требует статусconnected) и удалить участника (remove-member, без разрыва его соединения — он остаётся в других комнатах). - Dynamic TURN credentials from
https://test2.xneon.org/turn-credentialswith 10-minute expiry. - Порт P2P-слоя XMCL (
@xmcl/wrtc-multiplayer) вsrc/wrtc:ice-servers.js— пул ICE-серверов с живым тестированием/ротацией (createIceServersProvider), нормализация TURN-credentials сtest2.xneon.org,toNativeIceServer()(только native-формат);peer-context.js— ротация серверов на пир, target/shared TURN, heartbeat;peer-session.js— PeerConnection lifecycle (offer/answer, кандидаты с debounce, ICE-состояния), metadata heartbeat,minecraft/downloadканалы, TCP-прокси;peer-group.js—Peers/PeerGroup: создать/принять пир, retry offer до 6 попыток, shared TURN broadcast,rtc-state, реконнект с backoff;nat.js— определение типа NAT (symmetric/blocked) через собственный@stun-client;lan-discover.js,map-port-candidate.js,tcp-bridge.js,messages.js,ssdp-client.js.
Проверка P2P без Electron
Интеграционный тест поднимает локальный signaling-сервер и два PeerGroup в РАЗНЫХ процессах
(обязательно: два PeerGroup в одном процессе вызывают fast-fail в libdatachannel на Windows 26200):
Start-Process node -ArgumentList "itg-server.js" -NoNewWindow
Start-Sleep -Seconds 2
Start-Process node -ArgumentList "itg-peer.js master" -NoNewWindow
Start-Sleep -Seconds 1
Start-Process node -ArgumentList "itg-peer.js member" -NoNewWindow
В логах обеих сторон должны появиться RTC STATE connected и обмен IDENTITY
(хост и гость видят друг друга по metadata-каналу через реальный signaling).
ВАЖНО про эту dev-машину (Windows build 26200, за симметричным NAT): если оба пира сидят за одним NAT, ICE может номинировать srflx-пару через общий публичный IP (hairpin NAT), DTLS/SCTP не завершится и канал не откроется — это не баг порта, а ограничение среды. На двух устройствах с разными публичными IP такой петли нет (это и была первопричина симптома «второй друг не может подключиться»).
Технические ограничения libdatachannel (Windows, build 26200)
- В одном Node-процессе нельзя держать одновременно два
PeerConnectionодной пары — libdatachannel fast-fail (0xC0000409) в момент открытия DataChannel. Реальная игра всегда запускается отдельным процессом на каждом устройстве, поэтому для продакшена это ограничение некритично. - Ответчик должен отвечать на offer не в том же тике:
setRemoteDescription→ пауза (~500ms, см.PeerSession.setRemoteDescription) →setLocalDescription('answer'). - Колбэки
PeerConnection(onLocalDescriptionи др.) нужно регистрировать ДО вызоваcreateDataChannelна этом жеPeerConnection.
Запуск
npm install --cache .npm-cache
npm run signal
npm start
Для native dependency рекомендуется Node 22.16 LTS. В текущем окружении Electron installer блокируется политикой записи в %LocalAppData%, поэтому production .exe ещё не собран.
NAT/TURN
STUN не гарантирует direct connection при symmetric NAT. Для production добавляется coturn и ICE config:
[
'stun:turn.example.com:3478',
'turn:user:password@turn.example.com:3478?transport=udp',
'turn:user:password@turn.example.com:3478?transport=tcp',
'turns:user:password@turn.example.com:5349?transport=tcp'
]
Сервер coturn будет настраиваться отдельно на Ubuntu: 3478/udp, 3478/tcp, 5349/tcp, relay range и временные credentials.
Авторизация и БД (сервер)
Всё хранится в SQLite (src/signaling/xmcl.db, создаётся автоматически; DB_FILE — переопределить путь), использован
встроенный модуль node:sqlite (без внешних зависимостей).
Таблицы:
users— аккаунты (login, display_name,scrypt-хэш пароля, токен сессии);rooms— комнаты (name, пароль-хэш, текущий владелецmaster_id,epoch);room_members— членство: комнаты, в которых состоит юзер (переживает отключение; удаляется при явном выходе или кике);chat_messages/chat_attachments— история чата и вложений (BLOB).
Регистрация и вход в UI лаунчера — кнопки Войти / Регистрация. После входа токен лежит в localStorage,
при переподключении шлётся auth:token, открытые комнаты автоматически восстанавливаются. Выход — кнопка Выйти.
Полезные команды протокола:
auth:register/auth:login/auth:token/auth:logout/auth:me/auth:rooms(список своих комнат);room:create/room:join/room:leave/room:ping;chat:send/chat:history;transfer-master(передать корону),remove-member(кикнуть),close-room.
Проверка мультирумов/чата/кика без Electron:
Start-Process node -ArgumentList "itg-server.js" -NoNewWindow
Start-Sleep -Seconds 2
node final-multifeature-test.js
Ожидается ALL PASS (регистрация двух юзеров, две комнаты у одного клиента, передача мастера, кик без разрыва ws,
чат с вложением, история из БД, восстановление членства после реконнекта).
Attribution
Интеграция и модификации: MAINER4IK. Поведение и API сверяются с XMCL и публичной документацией @xmcl/wrtc-multiplayer.