From 7d17325be6daad6abd54170ccf4c3bf0a595f165 Mon Sep 17 00:00:00 2001 From: jakciehan Date: Sat, 16 May 2026 09:59:54 +0800 Subject: [PATCH] fix: 3v3 team match wrong problems --- content-security-service/run-deploy.sh | 2 +- deploy/edge/nginx.conf | 17 +- deploy/k8s/scripts/run-deploy.sh | 9 +- js/base/GameGlobal.js | 2 + js/entities/Bullet.js | 14 +- js/entities/PlayerTank.js | 2 +- js/entities/Tank.js | 17 ++ js/managers/NetworkManager.js | 2 + js/managers/ShareManager.js | 2 +- js/scenes/GameScene.js | 9 +- js/scenes/TeamGameScene.js | 199 ++++++++++++++--- js/scenes/TeamRoomScene.js | 2 + server/.dockerignore | 1 - server/DEPLOYMENT_GUIDE.md | 9 +- server/Dockerfile | 12 +- server/index.js | 118 +++++++--- server/k8s-deployment.yaml | 4 +- server/node_modules/.package-lock.json | 201 ++++------------- server/node_modules/ws/index.js | 21 +- server/node_modules/ws/lib/constants.js | 1 - .../node_modules/ws/lib/permessage-deflate.js | 26 +-- server/node_modules/ws/lib/sender.js | 2 +- server/node_modules/ws/lib/stream.js | 2 - .../node_modules/ws/lib/websocket-server.js | 34 +-- server/node_modules/ws/lib/websocket.js | 35 ++- server/node_modules/ws/package.json | 9 +- server/node_modules/ws/wrapper.mjs | 15 +- server/package-lock.json | 203 ++++-------------- server/package.json | 2 +- server/run-deploy.sh | 4 +- 30 files changed, 441 insertions(+), 535 deletions(-) diff --git a/content-security-service/run-deploy.sh b/content-security-service/run-deploy.sh index 473f451..93327b6 100755 --- a/content-security-service/run-deploy.sh +++ b/content-security-service/run-deploy.sh @@ -14,7 +14,7 @@ exec > >(tee -a "$LOG") 2>&1 SERVICE_DIR="/Users/hanchengxi/workspace/tankwar_proj/content-security-service" DEPLOY_DIR="/Users/hanchengxi/workspace/tankwar_proj/deploy/content-security" MASTER="root@host_172.16.16.16" -WORKERS_IP=("172.16.16.17" "172.16.16.8") +WORKERS_IP=("10.1.0.6" "172.16.32.10" "172.16.32.16") REMOTE_BUILD_DIR="/tmp/content-security-build" IMAGE_NAME="content-security-service:latest" diff --git a/deploy/edge/nginx.conf b/deploy/edge/nginx.conf index 19e446f..a2029f1 100644 --- a/deploy/edge/nginx.conf +++ b/deploy/edge/nginx.conf @@ -4,8 +4,9 @@ # that run the warmcheck/nginx DaemonSet (hostNetwork hostPort 80/443). # # Worker public IPs (cross-VPC, so we must use public addresses): -# - 43.138.255.42 (cvm-42 / 172.16.16.17) -# - 159.75.104.221 (cvm-221 / 172.16.16.8) +# - vm-0-6-opencloudos / 10.1.0.6 +# - vm-32-10-tencentos / 172.16.32.10 +# - vm-32-16-tencentos / 172.16.32.16 # # Master (43.139.80.61 / 172.16.16.16) is excluded — DaemonSet nodeAffinity # skips control-plane nodes, so it does NOT listen on :80/:443. @@ -42,15 +43,17 @@ stream { # ---- HTTP upstream (80) ---- upstream k8s_http { - # 2 workers; passive health check via max_fails/fail_timeout. - server 43.138.255.42:80 max_fails=3 fail_timeout=30s; - server 159.75.104.221:80 max_fails=3 fail_timeout=30s; + # 3 workers; passive health check via max_fails/fail_timeout. + server 10.1.0.6:80 max_fails=3 fail_timeout=30s; + server 172.16.32.10:80 max_fails=3 fail_timeout=30s; + server 172.16.32.16:80 max_fails=3 fail_timeout=30s; } # ---- HTTPS upstream (443, SNI passthrough) ---- upstream k8s_https { - server 43.138.255.42:443 max_fails=3 fail_timeout=30s; - server 159.75.104.221:443 max_fails=3 fail_timeout=30s; + server 10.1.0.6:443 max_fails=3 fail_timeout=30s; + server 172.16.32.10:443 max_fails=3 fail_timeout=30s; + server 172.16.32.16:443 max_fails=3 fail_timeout=30s; } # ---- Listeners ---- diff --git a/deploy/k8s/scripts/run-deploy.sh b/deploy/k8s/scripts/run-deploy.sh index d9c136d..f30ae75 100755 --- a/deploy/k8s/scripts/run-deploy.sh +++ b/deploy/k8s/scripts/run-deploy.sh @@ -15,8 +15,9 @@ set -euo pipefail MASTER_HOST="${MASTER_HOST:-host_172.16.16.16}" # Intranet IPs that the MASTER uses to reach workers (no alias on the CVMs). WORKER_INTRANET_IPS=( - "172.16.16.17" - "172.16.16.8" + "10.1.0.6" + "172.16.32.10" + "172.16.32.16" ) NAMESPACE="tankwar" @@ -141,12 +142,10 @@ step_verify() { ------------------------------------------------------------ Public endpoints (after DNS on www.igeek.site takes effect): - wss://www.igeek.site:30081/ (via NodePort on any of the 3 CVMs) + wss://www.igeek.site:30081/ (via NodePort) Direct CVM access for smoke test: wscat -c ws://43.139.80.61:30081/ - wscat -c ws://43.138.255.42:30081/ - wscat -c ws://159.75.104.221:30081/ Remember to allow TCP/30081 in the CVM security group. ------------------------------------------------------------ diff --git a/js/base/GameGlobal.js b/js/base/GameGlobal.js index c4aab8e..e714fd3 100644 --- a/js/base/GameGlobal.js +++ b/js/base/GameGlobal.js @@ -272,6 +272,8 @@ const NET_MSG = { PLAYER_RESPAWN: 'player_respawn', TEAM_GAME_START: 'team_game_start', TEAM_GAME_OVER: 'team_game_over', + TERRAIN_CHANGE: 'terrain_change', + BOT_STATE: 'bot_state', RECONNECT: 'reconnect', RECONNECT_OK: 'reconnect_ok', PLAYER_DISCONNECT: 'player_disconnect', diff --git a/js/entities/Bullet.js b/js/entities/Bullet.js index a0e9270..859b89a 100644 --- a/js/entities/Bullet.js +++ b/js/entities/Bullet.js @@ -77,12 +77,24 @@ class Bullet { /** * Render the bullet. + * In team battle mode, bullet color is determined by the _isAlly flag + * set by the scene: ally = bright yellow, enemy = red. + * In single-player / PVE mode, owner-based colors are used. * @param {CanvasRenderingContext2D} ctx */ render(ctx) { if (!this.alive) return; - ctx.fillStyle = this.owner === 'player' ? '#FFFF00' : '#FF6600'; + let fillColor; + if (this._isAlly !== undefined) { + // Team mode: use team-aware coloring + fillColor = this._isAlly ? '#FFFF00' : '#FF4444'; + } else { + // Single-player / PVE fallback + fillColor = this.owner === 'player' ? '#FFFF00' : '#FF6600'; + } + + ctx.fillStyle = fillColor; ctx.fillRect( this.x - this.halfSize, this.y - this.halfSize, diff --git a/js/entities/PlayerTank.js b/js/entities/PlayerTank.js index 33d5efe..a12ed29 100644 --- a/js/entities/PlayerTank.js +++ b/js/entities/PlayerTank.js @@ -45,7 +45,7 @@ class PlayerTank extends Tank { // Skin colors (reserved for future use) this._skinColors = null; - this._skinId = 'default'; + this._skinId = null; // Fire level system this.fireLevel = FIRE_LEVEL.LV1; diff --git a/js/entities/Tank.js b/js/entities/Tank.js index 17efe8c..88775e8 100644 --- a/js/entities/Tank.js +++ b/js/entities/Tank.js @@ -307,6 +307,14 @@ class Tank { ctx.scale(k, k); drawTankSkin(ctx, this._skinId, this._skinColors, t); ctx.restore(); + // Gold border for local player identification + if (this._isLocal) { + ctx.strokeStyle = '#FFD700'; + ctx.lineWidth = 2; + ctx.strokeRect(-this.halfSize, -this.halfSize, this.size, this.size); + // Also outline the barrel area + ctx.strokeRect(-this.size * 0.15 / 2, -this.halfSize - barrelExtra, this.size * 0.15, barrelExtra); + } ctx.restore(); return; } @@ -344,6 +352,15 @@ class Tank { ctx.fillRect(-hs, -hs, trackW, this.size); ctx.fillRect(hs - trackW, -hs, trackW, this.size); + // Gold border for local player identification + if (this._isLocal) { + ctx.strokeStyle = '#FFD700'; + ctx.lineWidth = 2; + ctx.strokeRect(-hs, -hs, this.size, this.size); + // Barrel outline + ctx.strokeRect(-barrelW / 2, -hs - barrelH, barrelW, barrelH); + } + ctx.restore(); } diff --git a/js/managers/NetworkManager.js b/js/managers/NetworkManager.js index 7d06a70..4ad50fd 100644 --- a/js/managers/NetworkManager.js +++ b/js/managers/NetworkManager.js @@ -202,6 +202,7 @@ class NetworkManager { const profile = (typeof GameGlobal !== 'undefined') ? GameGlobal.playerProfile : null; const nickname = (profile && profile.nickname) ? profile.nickname : ''; const avatarUrl = (profile && profile.avatarUrl) ? profile.avatarUrl : ''; + const skinId = (GameGlobal && GameGlobal.skinManager) ? (GameGlobal.skinManager.getEquippedSkinId() || '') : ''; const message = JSON.stringify({ type, @@ -209,6 +210,7 @@ class NetworkManager { playerId: this._playerId, nickname, avatarUrl, + skinId, roomId: this._roomId, timestamp: Date.now(), }); diff --git a/js/managers/ShareManager.js b/js/managers/ShareManager.js index a914ea6..a3f1666 100644 --- a/js/managers/ShareManager.js +++ b/js/managers/ShareManager.js @@ -20,7 +20,7 @@ class ShareManager { if (wx.showShareMenu) { wx.showShareMenu({ withShareTicket: true, - menus: ['shareAppMessage'], + menus: ['shareAppMessage', 'shareTimeline'], }); } if (wx.onShareAppMessage) { diff --git a/js/scenes/GameScene.js b/js/scenes/GameScene.js index d0752d4..7f2b5e9 100644 --- a/js/scenes/GameScene.js +++ b/js/scenes/GameScene.js @@ -140,10 +140,13 @@ const GameScene = { }); this._playerTank.activateShield(3000); // spawn protection - // Apply equipped skin colors to player tank + // Apply equipped skin — only non-default skins override tank color if (GameGlobal.skinManager) { - this._playerTank._skinColors = GameGlobal.skinManager.getCurrentSkinColors(); - this._playerTank._skinId = GameGlobal.skinManager.getEquippedSkinId(); + const skinId = GameGlobal.skinManager.getEquippedSkinId(); + if (skinId && skinId !== 'default') { + this._playerTank._skinColors = GameGlobal.skinManager.getCurrentSkinColors(); + this._playerTank._skinId = skinId; + } } // Safety: ensure player spawn area is clear of blocking terrain diff --git a/js/scenes/TeamGameScene.js b/js/scenes/TeamGameScene.js index 3bee356..4422683 100644 --- a/js/scenes/TeamGameScene.js +++ b/js/scenes/TeamGameScene.js @@ -158,6 +158,10 @@ const TeamGameScene = { const teamAMembers = (params && params.teamA) || []; const teamBMembers = (params && params.teamB) || []; + console.log(`[TeamGameScene] teamA: ${JSON.stringify(teamAMembers.map(m => ({ playerId: m.playerId, isBot: m.isBot })))}`); + console.log(`[TeamGameScene] teamB: ${JSON.stringify(teamBMembers.map(m => ({ playerId: m.playerId, isBot: m.isBot })))}`); + console.log(`[TeamGameScene] myPlayerId: ${this._myPlayerId}`); + this._myTeam = teamAMembers.find(m => m.playerId === this._myPlayerId) ? 'A' : 'B'; // Create all player tanks @@ -165,9 +169,25 @@ const TeamGameScene = { this._createTeamPlayers(teamAMembers, 'A', this._mapData.teamASpawns); this._createTeamPlayers(teamBMembers, 'B', this._mapData.teamBSpawns); + // Log _players for duplicate check + const playerIds = this._players.map(p => p.playerId); + const duplicates = playerIds.filter((id, idx) => playerIds.indexOf(id) !== idx); + if (duplicates.length > 0) { + console.error(`[TeamGameScene] DUPLICATE playerIds: ${JSON.stringify(duplicates)}`); + } + console.log(`[TeamGameScene] All players: ${JSON.stringify(this._players.map(p => ({ playerId: p.playerId, team: p.team, isLocal: p.isLocal, isBot: p.isBot })))}`); + // Find local player this._localPlayer = this._players.find(p => p.isLocal); + // Check if enemy team has no human players (all bots) — + // if so, this client must run enemy bot AI locally since no remote + // client exists to act as authority + const enemyTeam = this._myTeam === 'A' ? 'B' : 'A'; + this._enemyTeamAllBots = !this._players.some( + p => p.team === enemyTeam && !p.isBot && !p.isLocal + ); + // Initialize stats for (const p of this._players) { this._stats[p.playerId] = { kills: 0, deaths: 0, assists: 0, baseDamage: 0 }; @@ -203,14 +223,9 @@ const TeamGameScene = { tankColor = team === 'A' ? PLAYER1_COLOR : PLAYER2_COLOR; } } else { - // 3v3: local=gold, ally=blue, enemy=red - if (isLocal) { - tankColor = LOCAL_PLAYER_COLOR; - } else if (isMyTeam) { - tankColor = TEAM_A_COLOR; - } else { - tankColor = TEAM_B_COLOR; - } + // 3v3: Team A = blue, Team B = red + // Local player uses team color too (gold border drawn separately for identification) + tankColor = team === 'A' ? TEAM_A_COLOR : TEAM_B_COLOR; } let tank; @@ -240,15 +255,28 @@ const TeamGameScene = { tank.color = tankColor; // Unlimited lives for 3v3 tank.lives = 999; - // Apply equipped skin (only for the LOCAL player — other players keep team color) - if (GameGlobal.skinManager && isLocal) { - tank._skinColors = GameGlobal.skinManager.getCurrentSkinColors(); - tank._skinId = GameGlobal.skinManager.getEquippedSkinId(); + // Apply equipped skin — only non-default skins override team color + if (GameGlobal.skinManager) { + const skinId = isLocal + ? GameGlobal.skinManager.getEquippedSkinId() + : (member.skinId || ''); + if (skinId && skinId !== 'default') { + const skinDef = GameGlobal.skinManager.getSkin(skinId); + if (skinDef && skinDef.colors) { + tank._skinColors = skinDef.colors; + tank._skinId = skinId; + } + } } } tank.activateShield(3000); + // Mark local player's tank for gold-border rendering + if (isLocal) { + tank._isLocal = true; + } + // Set initial direction based on team if (team === 'A') { tank.direction = DIRECTION.RIGHT; @@ -321,9 +349,13 @@ const TeamGameScene = { // Receive bullet fire from other players unsubs.push(nm.on(NET_MSG.BULLET_FIRE, (data) => { - if (data.playerId && data.playerId !== this._myPlayerId) { - this._spawnRemoteBullet(data); - } + if (!data.playerId) return; + // Ignore our own bullets (local player or our team's bots) — we already + // created them locally. Only spawn remote bullets for enemy players/bots. + const shooter = this._players.find(p => p.playerId === data.playerId); + if (shooter && shooter.team === this._myTeam) return; + if (data.playerId === this._myPlayerId) return; + this._spawnRemoteBullet(data); })); // Receive player killed notification @@ -470,6 +502,25 @@ const TeamGameScene = { } })); + // Receive terrain changes from remote client (brick/steel/base_wall destruction) + unsubs.push(nm.on(NET_MSG.TERRAIN_CHANGE, (data) => { + if (data.row !== undefined && data.col !== undefined && data.terrain !== undefined) { + const currentTerrain = this._mapManager.getTerrain(data.row, data.col); + // Only apply if the terrain still matches the original type (avoid double-apply) + // Accept EMPTY→EMPTY as no-op, but apply any real change + if (currentTerrain !== data.terrain) { + this._mapManager.setTerrain(data.row, data.col, data.terrain); + } + } + })); + + // Receive bot state from remote client (enemy team bots) + unsubs.push(nm.on(NET_MSG.BOT_STATE, (data) => { + if (data.playerId) { + this._updateRemotePlayerState(data); + } + })); + this._unsubscribers = unsubs; }, @@ -558,9 +609,16 @@ const TeamGameScene = { } else if (!player.isBot) { // Remote player interpolation this._interpolateRemoteTank(player, dt); - } else { - // Bot AI using BotTank.updateAI + } else if (player.team === this._myTeam) { + // Our team's bot — we are the authority, run AI locally this._updateBotAI(player, dt); + } else if (this._enemyTeamAllBots) { + // Enemy team's bot but enemy has no human players — + // run AI locally since no remote client exists to drive them + this._updateBotAI(player, dt); + } else { + // Enemy team's bot — interpolated from remote state (authority is on their side) + this._interpolateRemoteTank(player, dt); } player.tank.update(dt); @@ -673,6 +731,9 @@ const TeamGameScene = { hp: tank.hp, alive: tank.alive, }); + + // Also sync our team's bot states + this._sendBotStates(); }, _sendInputIfChanged() { @@ -696,6 +757,32 @@ const TeamGameScene = { } }, + _sendTerrainChange(row, col, newTerrain) { + if (!this._networkManager) return; + this._networkManager.send(NET_MSG.TERRAIN_CHANGE, { + row, + col, + terrain: newTerrain, + }); + }, + + _sendBotStates() { + if (!this._networkManager) return; + // Only sync bots on OUR team (we are the authority for our team's bots) + const myBots = this._players.filter(p => p.isBot && p.team === this._myTeam); + for (const bot of myBots) { + const tank = bot.tank; + this._networkManager.send(NET_MSG.BOT_STATE, { + playerId: bot.playerId, + col: (tank.x - MAP_OFFSET_X) / TILE_SIZE, + row: (tank.y - MAP_OFFSET_Y) / TILE_SIZE, + direction: tank.direction, + alive: tank.alive, + hp: tank.hp, + }); + } + }, + // ============================================================ // Collision Detection // ============================================================ @@ -738,15 +825,21 @@ const TeamGameScene = { } const terrain = this._mapManager.getTerrain(row, col); + const bulletOwner = this._players.find(p => p.playerId === bullet.ownerPlayerId); + // Only our team's bullets can modify terrain locally; enemy bullets are + // visual-only and their terrain changes come via TERRAIN_CHANGE messages. + const isAuthority = bulletOwner && bulletOwner.team === this._myTeam; if (terrain === TERRAIN.BRICK) { - this._mapManager.setTerrain(row, col, TERRAIN.EMPTY); + if (isAuthority) { + this._mapManager.setTerrain(row, col, TERRAIN.EMPTY); + this._sendTerrainChange(row, col, TERRAIN.EMPTY); + } bullet.destroy(); this._spawnExplosion(bullet.x, bullet.y, false); } else if (terrain === TERRAIN.BASE_WALL) { // Determine which team this base wall belongs to const wallTeam = this._getBaseWallTeam(row, col); - const bulletOwner = this._players.find(p => p.playerId === bullet.ownerPlayerId); // Friendly-fire immunity: own team's bullets don't damage own base walls if (bulletOwner && wallTeam && bulletOwner.team === wallTeam) { @@ -754,13 +847,21 @@ const TeamGameScene = { return; } - // Base wall has HP — use bulletHitTerrain for proper HP tracking - this._mapManager.bulletHitTerrain(row, col, bullet.canBreakSteel); + if (isAuthority) { + // Base wall has HP — use bulletHitTerrain for proper HP tracking + const prevTerrain = this._mapManager.getTerrain(row, col); + this._mapManager.bulletHitTerrain(row, col, bullet.canBreakSteel); + const newTerrain = this._mapManager.getTerrain(row, col); + if (prevTerrain !== newTerrain) { + this._sendTerrainChange(row, col, newTerrain); + } + } bullet.destroy(); this._spawnExplosion(bullet.x, bullet.y, false); } else if (terrain === TERRAIN.STEEL) { - if (bullet.canBreakSteel) { + if (bullet.canBreakSteel && isAuthority) { this._mapManager.setTerrain(row, col, TERRAIN.EMPTY); + this._sendTerrainChange(row, col, TERRAIN.EMPTY); } bullet.destroy(); this._spawnExplosion(bullet.x, bullet.y, false); @@ -836,8 +937,11 @@ const TeamGameScene = { return; // ignore friendly base hit } - // Local player or local bot reports base hits to server - if ((bulletOwner.isLocal || bulletOwner.isBot) && this._networkManager) { + // Local player or our team's bot reports base hits to server. + // Also report when enemy team is all bots (we are the authority for them). + const isLocalAuthority = bulletOwner.isLocal || (bulletOwner.isBot && bulletOwner.team === this._myTeam); + const isEnemyBotAuthority = this._enemyTeamAllBots && bulletOwner.isBot && bulletOwner.team !== this._myTeam; + if ((isLocalAuthority || isEnemyBotAuthority) && this._networkManager) { this._networkManager.send(NET_MSG.BASE_HIT, { targetTeam, damage: 1, @@ -856,6 +960,13 @@ const TeamGameScene = { const bulletOwner = this._players.find(p => p.playerId === bullet.ownerPlayerId); if (!bulletOwner) return; + // Only perform tank hit detection for bullets from our team. + // Enemy bullets are visual-only on our side; the enemy client is the + // authority for those hits and will send PLAYER_KILLED. + // Exception: when the enemy team has no human players (all bots), + // we run enemy bot AI locally and must also resolve their bullet hits. + if (bulletOwner.team !== this._myTeam && !this._enemyTeamAllBots) return; + for (const player of this._players) { if (!player.tank.alive || player.isRespawning) continue; @@ -972,6 +1083,7 @@ const TeamGameScene = { ownerTank: tank, }); bullet.ownerPlayerId = this._myPlayerId; + bullet._isAlly = true; // local player's bullets are always ally tank.activeBullets++; this._bullets.push(bullet); GameGlobal.audioManager.playSFX('shoot'); @@ -1003,8 +1115,20 @@ const TeamGameScene = { ownerTank: tank, }); bullet.ownerPlayerId = player.playerId; + bullet._isAlly = player.team === this._myTeam; // bot on my team = ally tank.activeBullets++; this._bullets.push(bullet); + + // Sync our team's bot bullets to the remote client + if (player.team === this._myTeam && this._networkManager) { + this._networkManager.send(NET_MSG.BULLET_FIRE, { + playerId: player.playerId, + col: (bullet.x - MAP_OFFSET_X) / TILE_SIZE, + row: (bullet.y - MAP_OFFSET_Y) / TILE_SIZE, + direction: bullet.direction, + canBreakSteel: false, + }); + } }, _spawnRemoteBullet(data) { @@ -1031,6 +1155,7 @@ const TeamGameScene = { ownerTank: player.tank, }); bullet.ownerPlayerId = data.playerId; + bullet._isAlly = player.team === this._myTeam; // remote on my team = ally player.tank.activeBullets++; this._bullets.push(bullet); }, @@ -1070,8 +1195,11 @@ const TeamGameScene = { // Start respawn timer this._startRespawn(victim); - // If local player or local bot killed someone, notify server - if ((killer.isLocal || killer.isBot) && this._networkManager) { + // If local player or our team's bot killed someone, notify server. + // Also notify when enemy team is all bots (we are the authority for them). + const isLocalAuthority = killer.isLocal || (killer.isBot && killer.team === this._myTeam); + const isEnemyBotAuthority = this._enemyTeamAllBots && killer.isBot && killer.team !== this._myTeam; + if ((isLocalAuthority || isEnemyBotAuthority) && this._networkManager) { this._networkManager.send(NET_MSG.PLAYER_KILLED, { killerId: killer.playerId, victimId: victim.playerId, @@ -1191,12 +1319,11 @@ const TeamGameScene = { // Per-tank team color: // - local player → gold - // - ally (not me) → blue - // - enemy → red + // - Team A (ally or enemy) → blue + // - Team B (ally or enemy) → red let labelColor; if (player.isLocal) labelColor = LOCAL_PLAYER_COLOR; - else if (player.team === this._myTeam) labelColor = TEAM_A_COLOR; - else labelColor = TEAM_B_COLOR; + else labelColor = player.team === 'A' ? TEAM_A_COLOR : TEAM_B_COLOR; ctx.fillStyle = labelColor; ctx.textAlign = 'center'; @@ -1289,15 +1416,21 @@ const TeamGameScene = { if (profile && profile.nickname) raw = profile.nickname; else raw = player.nickname || ''; } else { + // For remote players, use the server-provided nickname. + // Do NOT fall back to profile.getDisplayName() because that returns + // the LOCAL player's nickname when set, which would show the wrong + // name for every remote player. raw = player.nickname || ''; } if (!raw) { if (player.isBot) { raw = ''; // bot — we already draw the 🤖 marker, skip name - } else if (profile && typeof profile.getDisplayName === 'function') { - raw = profile.getDisplayName(player.playerId); + } else if (player.playerId && typeof player.playerId === 'string') { + // Derive a stable anonymous tag from the remote player's own ID. + const tail = player.playerId.slice(-4).toUpperCase(); + raw = `Tanker_${tail}`; } else { - raw = player.playerId || ''; + raw = ''; } } if (!raw) return ''; diff --git a/js/scenes/TeamRoomScene.js b/js/scenes/TeamRoomScene.js index 9c23fc2..167e7a8 100644 --- a/js/scenes/TeamRoomScene.js +++ b/js/scenes/TeamRoomScene.js @@ -360,6 +360,8 @@ const TeamRoomScene = { teamB: data.teamB, teamABaseHp: data.teamABaseHp, teamBBaseHp: data.teamBBaseHp, + battleMode: data.battleMode || '3v3', + roomId: data.roomId || '', myPlayerId: this._myPlayerId, }); }, diff --git a/server/.dockerignore b/server/.dockerignore index 09d6184..afcb0bd 100644 --- a/server/.dockerignore +++ b/server/.dockerignore @@ -1,4 +1,3 @@ -node_modules npm-debug.log .DS_Store .git diff --git a/server/DEPLOYMENT_GUIDE.md b/server/DEPLOYMENT_GUIDE.md index 32c28fa..4b5d673 100644 --- a/server/DEPLOYMENT_GUIDE.md +++ b/server/DEPLOYMENT_GUIDE.md @@ -6,10 +6,11 @@ ## 集群信息 -目标K8s集群由以下3台CVM组成: -- 43.139.80.61 (host_172.16.16.16) -- 43.138.255.42 (host_172.16.16.17) -- 159.75.104.221 (host_172.16.16.8) +目标K8s集群由以下4台CVM组成: +- 43.139.80.61 (host_172.16.16.16) — Master +- 10.1.0.6 (vm-0-6-opencloudos) — Worker +- 172.16.32.10 (vm-32-10-tencentos) — Worker +- 172.16.32.16 (vm-32-16-tencentos) — Worker SSH连接:`ssh root@host_172.16.16.16` diff --git a/server/Dockerfile b/server/Dockerfile index ebf3715..721c25c 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -5,12 +5,8 @@ LABEL maintainer="tankwar" \ WORKDIR /app -# Install dependencies first (leverage Docker layer cache) -COPY package.json package-lock.json* ./ -RUN npm install --omit=dev --no-audit --no-fund \ - && npm cache clean --force - -# Copy the rest of the source +# Copy all source including node_modules (pre-installed locally) +# This avoids npm install issues due to network restrictions on build nodes COPY . . ENV NODE_ENV=production \ @@ -19,7 +15,5 @@ ENV NODE_ENV=production \ EXPOSE 3000 -# Graceful shutdown & init for PID 1 -RUN apk add --no-cache tini -ENTRYPOINT ["/sbin/tini", "--"] +# Use node directly (tini unavailable due to network restrictions on nodes) CMD ["node", "index.js"] \ No newline at end of file diff --git a/server/index.js b/server/index.js index 8219f51..4d29621 100644 --- a/server/index.js +++ b/server/index.js @@ -146,6 +146,8 @@ const NET_MSG = { PLAYER_RESPAWN: 'player_respawn', TEAM_GAME_START: 'team_game_start', TEAM_GAME_OVER: 'team_game_over', + TERRAIN_CHANGE: 'terrain_change', + BOT_STATE: 'bot_state', RECONNECT: 'reconnect', RECONNECT_OK: 'reconnect_ok', PLAYER_DISCONNECT: 'player_disconnect', @@ -230,6 +232,7 @@ class PlayerInfo { this.playerId = playerId; this.nickname = ''; this.avatarUrl = ''; + this.skinId = ''; // equipped tank skin id this.roomId = null; this.teamId = null; this.isAlive = true; @@ -249,7 +252,7 @@ class TeamRoom { * @param {string} [battleMode='3v3'] - Battle mode ('1v1' or '3v3') * @param {string} [leaderNickname=''] - Display nickname of the leader */ - constructor(id, leaderWs, leaderId, battleMode = '3v3', leaderNickname = '', leaderAvatarUrl = '') { + constructor(id, leaderWs, leaderId, battleMode = '3v3', leaderNickname = '', leaderAvatarUrl = '', leaderSkinId = '') { this.id = id; this.state = 'forming'; // forming | matching | playing | finished this.createdAt = Date.now(); @@ -260,8 +263,8 @@ class TeamRoom { this.teamSize = config.teamSize; this.fillWithBotsEnabled = config.fillWithBots; - // Team A members: { ws, playerId, nickname, avatarUrl, ready, isBot, disconnectedAt } - this.teamA = [{ ws: leaderWs, playerId: leaderId, nickname: leaderNickname || '', avatarUrl: leaderAvatarUrl || '', ready: true, isBot: false, disconnectedAt: null }]; + // Team A members: { ws, playerId, nickname, avatarUrl, skinId, ready, isBot, disconnectedAt } + this.teamA = [{ ws: leaderWs, playerId: leaderId, nickname: leaderNickname || '', avatarUrl: leaderAvatarUrl || '', skinId: leaderSkinId || '', ready: true, isBot: false, disconnectedAt: null }]; // Team B members this.teamB = []; this.leaderId = leaderId; @@ -329,15 +332,19 @@ class TeamRoom { } /** Add a player to team A */ - addToTeamA(ws, playerId, nickname = '', avatarUrl = '') { + addToTeamA(ws, playerId, nickname = '', avatarUrl = '', skinId = '') { if (this.teamA.length >= this.teamSize) return false; - this.teamA.push({ ws, playerId, nickname, avatarUrl, ready: false, isBot: false, disconnectedAt: null }); + // Prevent duplicate playerId across both teams + if (this.teamA.some(m => m.playerId === playerId) || this.teamB.some(m => m.playerId === playerId)) return false; + this.teamA.push({ ws, playerId, nickname, avatarUrl, skinId, ready: false, isBot: false, disconnectedAt: null }); return true; } - addToTeamB(ws, playerId, nickname = '', avatarUrl = '') { + addToTeamB(ws, playerId, nickname = '', avatarUrl = '', skinId = '') { if (this.teamB.length >= this.teamSize) return false; - this.teamB.push({ ws, playerId, nickname, avatarUrl, ready: false, isBot: false, disconnectedAt: null }); + // Prevent duplicate playerId across both teams + if (this.teamA.some(m => m.playerId === playerId) || this.teamB.some(m => m.playerId === playerId)) return false; + this.teamB.push({ ws, playerId, nickname, avatarUrl, skinId, ready: false, isBot: false, disconnectedAt: null }); return true; } /** Remove a player from the team room */ @@ -435,6 +442,7 @@ class TeamRoom { playerId: m.playerId, nickname: m.nickname || '', avatarUrl: m.avatarUrl || '', + skinId: m.skinId || '', ready: m.ready, isBot: m.isBot, isLeader: m.playerId === this.leaderId, @@ -444,6 +452,7 @@ class TeamRoom { playerId: m.playerId, nickname: m.nickname || '', avatarUrl: m.avatarUrl || '', + skinId: m.skinId || '', ready: m.ready, isBot: m.isBot, connected: m.isBot || (m.ws && m.ws.readyState === 1), @@ -551,7 +560,7 @@ function handleCreateRoom(ws, data) { const roomCode = generateRoomCode(); // Create a TeamRoom in 1v1 mode instead of a legacy Room -const teamRoom = new TeamRoom(roomCode, ws, playerInfo.playerId, '1v1', playerInfo.nickname || '', playerInfo.avatarUrl || ''); +const teamRoom = new TeamRoom(roomCode, ws, playerInfo.playerId, '1v1', playerInfo.nickname || '', playerInfo.avatarUrl || '', playerInfo.skinId || ''); teamRooms.set(roomCode, teamRoom); playerInfo.teamId = roomCode; @@ -600,7 +609,7 @@ function handleJoinRoom(ws, data) { } // Join as team B - teamRoom.addToTeamB(ws, playerInfo.playerId, playerInfo.nickname || '', playerInfo.avatarUrl || ''); + teamRoom.addToTeamB(ws, playerInfo.playerId, playerInfo.nickname || '', playerInfo.avatarUrl || '', playerInfo.skinId || ''); playerInfo.teamId = roomId; console.log(`[Server] Player ${playerInfo.playerId} joined 1v1 room ${roomId} (TeamRoom)`); @@ -670,7 +679,7 @@ function handleCreateTeam(ws, data) { } const teamId = generateTeamId(); - const teamRoom = new TeamRoom(teamId, ws, playerInfo.playerId, '3v3', playerInfo.nickname || '', playerInfo.avatarUrl || ''); + const teamRoom = new TeamRoom(teamId, ws, playerInfo.playerId, '3v3', playerInfo.nickname || '', playerInfo.avatarUrl || '', playerInfo.skinId || ''); teamRooms.set(teamId, teamRoom); playerInfo.teamId = teamId; @@ -694,7 +703,7 @@ function handleJoinTeam(ws, data) { // Team was cleaned up (e.g. leader disconnected during dev-tool reload). // Auto-create a new room with the same ID so the invite link still works. console.log(`[Server] Team ${teamId} not found, auto-creating for ${playerInfo.playerId}`); - teamRoom = new TeamRoom(teamId, ws, playerInfo.playerId, '3v3', playerInfo.nickname || '', playerInfo.avatarUrl || ''); + teamRoom = new TeamRoom(teamId, ws, playerInfo.playerId, '3v3', playerInfo.nickname || '', playerInfo.avatarUrl || '', playerInfo.skinId || ''); teamRooms.set(teamId, teamRoom); playerInfo.teamId = teamId; sendMessage(ws, NET_MSG.TEAM_STATE, teamRoom.getTeamState()); @@ -716,7 +725,7 @@ function handleJoinTeam(ws, data) { handleLeaveTeam(ws, {}); } - teamRoom.addToTeamA(ws, playerInfo.playerId, playerInfo.nickname || '', playerInfo.avatarUrl || ''); + teamRoom.addToTeamA(ws, playerInfo.playerId, playerInfo.nickname || '', playerInfo.avatarUrl || '', playerInfo.skinId || ''); playerInfo.teamId = teamId; console.log(`[Server] Player ${playerInfo.playerId} joined team ${teamId}`); @@ -874,8 +883,10 @@ function handleMatchStart(ws, data) { teamRoom.state = 'matching'; teamRoom.matchStartTime = Date.now(); - // Add to match pool - teamMatchPool.push(teamRoom); + // Add to match pool (dedup guard) + if (!teamMatchPool.includes(teamRoom)) { + teamMatchPool.push(teamRoom); + } console.log(`[Server] Team ${teamRoom.id} entered matching pool`); @@ -917,14 +928,16 @@ function handleSoloMatch(ws, data) { // Create a solo team room for this player const teamId = generateTeamId(); - const teamRoom = new TeamRoom(teamId, ws, playerInfo.playerId, '3v3', playerInfo.nickname || '', playerInfo.avatarUrl || ''); + const teamRoom = new TeamRoom(teamId, ws, playerInfo.playerId, '3v3', playerInfo.nickname || '', playerInfo.avatarUrl || '', playerInfo.skinId || ''); teamRoom.state = 'matching'; teamRoom.matchStartTime = Date.now(); teamRooms.set(teamId, teamRoom); playerInfo.teamId = teamId; - // Add to solo match pool - soloMatchPool.push(ws); + // Add to solo match pool (dedup guard) + if (!soloMatchPool.includes(ws)) { + soloMatchPool.push(ws); + } console.log(`[Server] Player ${playerInfo.playerId} entered solo match pool (team ${teamId})`); @@ -988,9 +1001,11 @@ function tryMatchTeams() { const teamA_room = teamMatchPool.shift(); const teamB_room = teamMatchPool.shift(); - // Merge team B members into team A room as opponents - for (const member of teamB_room.teamA) { - teamA_room.addToTeamB(member.ws, member.playerId, member.nickname || '', member.avatarUrl || ''); + // Merge team B room members into team A room as opponents + // Both teamA and teamB of teamB_room should be moved + const allBMembers = [...teamB_room.teamA, ...teamB_room.teamB]; + for (const member of allBMembers) { + teamA_room.addToTeamB(member.ws, member.playerId, member.nickname || '', member.avatarUrl || '', member.skinId || ''); if (member.ws) { const info = players.get(member.ws); if (info) info.teamId = teamA_room.id; @@ -1019,8 +1034,15 @@ function tryMatchTeams() { }); if (availableSolos.length >= 2) { - // Take up to 10 solo players and form a game - const gamePlayers = availableSolos.splice(0, Math.min(10, availableSolos.length)); + // Deduplicate by playerId — same player should not appear twice + const seenIds = new Set(); + const gamePlayersRaw = availableSolos.splice(0, Math.min(10, availableSolos.length)); + const gamePlayers = gamePlayersRaw.filter(ws => { + const info = players.get(ws); + if (!info || seenIds.has(info.playerId)) return false; + seenIds.add(info.playerId); + return true; + }); // Remove from solo pool for (const ws of gamePlayers) { @@ -1053,11 +1075,17 @@ function tryMatchTeams() { info.teamId = gameRoom.id; - // Alternate: odd index -> team A, even index -> team B - if (i % 2 === 1 && !gameRoom.isTeamAFull()) { - gameRoom.addToTeamA(ws, info.playerId, info.nickname || '', info.avatarUrl || ''); + // Alternate teams: first remaining player → teamB, next → teamA, etc. + // (player at index 0 is already in teamA as the room creator) + const isTeamBSlot = (i % 2 === 1); + if (isTeamBSlot && !gameRoom.isTeamBFull()) { + gameRoom.addToTeamB(ws, info.playerId, info.nickname || '', info.avatarUrl || '', info.skinId || ''); + } else if (!isTeamBSlot && !gameRoom.isTeamAFull()) { + gameRoom.addToTeamA(ws, info.playerId, info.nickname || '', info.avatarUrl || '', info.skinId || ''); + } else if (!gameRoom.isTeamBFull()) { + gameRoom.addToTeamB(ws, info.playerId, info.nickname || '', info.avatarUrl || '', info.skinId || ''); } else { - gameRoom.addToTeamB(ws, info.playerId, info.nickname || '', info.avatarUrl || ''); + gameRoom.addToTeamA(ws, info.playerId, info.nickname || '', info.avatarUrl || '', info.skinId || ''); } } @@ -1088,8 +1116,8 @@ function startTeamGame(teamRoom) { const gameData = { mapId: teamRoom.mapId, - teamA: teamRoom.teamA.map(m => ({ playerId: m.playerId, nickname: m.nickname || '', isBot: m.isBot })), - teamB: teamRoom.teamB.map(m => ({ playerId: m.playerId, nickname: m.nickname || '', isBot: m.isBot })), + teamA: teamRoom.teamA.map(m => ({ playerId: m.playerId, nickname: m.nickname || '', isBot: m.isBot, skinId: m.skinId || '' })), + teamB: teamRoom.teamB.map(m => ({ playerId: m.playerId, nickname: m.nickname || '', isBot: m.isBot, skinId: m.skinId || '' })), teamABaseHp: teamRoom.teamABaseHp, teamBBaseHp: teamRoom.teamBBaseHp, battleMode: teamRoom.battleMode, @@ -1097,6 +1125,8 @@ function startTeamGame(teamRoom) { }; console.log(`[Server] ${teamRoom.battleMode} game starting in room ${teamRoom.id}`); + console.log(`[Server] teamA: ${JSON.stringify(gameData.teamA.map(m => ({ playerId: m.playerId, isBot: m.isBot })))}`); + console.log(`[Server] teamB: ${JSON.stringify(gameData.teamB.map(m => ({ playerId: m.playerId, isBot: m.isBot })))}`); // For 1v1, use GAME_START message (client RoomScene listens for it) // For 3v3, use TEAM_GAME_START message (client TeamRoomScene listens for it) @@ -1408,7 +1438,7 @@ function handleMessage(ws, rawData) { return; } - const { type, data, playerId, nickname, avatarUrl } = msg; + const { type, data, playerId, nickname, avatarUrl, skinId } = msg; // Update player info const playerInfo = players.get(ws); @@ -1451,6 +1481,20 @@ function handleMessage(ws, rawData) { } } } + // Refresh skinId on every message (equipped skin may change mid-session). + if (typeof skinId === 'string' && skinId && playerInfo.skinId !== skinId) { + playerInfo.skinId = skinId; + if (playerInfo.teamId) { + const tr = teamRooms.get(playerInfo.teamId); + if (tr) { + const member = tr.getMemberByWs(ws); + if (member && member.skinId !== skinId) { + member.skinId = skinId; + tr.broadcast(NET_MSG.TEAM_STATE, tr.getTeamState()); + } + } + } + } } switch (type) { @@ -1469,15 +1513,27 @@ function handleMessage(ws, rawData) { // Relay gameplay messages case NET_MSG.PLAYER_INPUT: + // Messages where playerId is the sender themselves — override to prevent spoofing + case NET_MSG.PLAYER_INPUT: + if (playerInfo && playerInfo.teamId) { + relayToTeamRoom(ws, type, { ...data, playerId: playerInfo.playerId }); + } else if (playerInfo && playerInfo.roomId) { + relayToOpponent(ws, type, data || {}); + } + break; + + // Messages where playerId/victimId/killerId refer to specific entities (bots, etc.) + // — must NOT be overwritten with the sender's playerId case NET_MSG.PLAYER_STATE: case NET_MSG.BULLET_FIRE: case NET_MSG.BULLET_HIT: case NET_MSG.PLAYER_HIT: case NET_MSG.PLAYER_KILLED: case NET_MSG.GAME_OVER: - // All modes now use teamRoom relay + case NET_MSG.TERRAIN_CHANGE: + case NET_MSG.BOT_STATE: if (playerInfo && playerInfo.teamId) { - relayToTeamRoom(ws, type, { ...data, playerId: playerInfo.playerId }); + relayToTeamRoom(ws, type, data || {}); } else if (playerInfo && playerInfo.roomId) { relayToOpponent(ws, type, data || {}); } diff --git a/server/k8s-deployment.yaml b/server/k8s-deployment.yaml index 6767ad3..540bcf9 100644 --- a/server/k8s-deployment.yaml +++ b/server/k8s-deployment.yaml @@ -14,7 +14,7 @@ metadata: labels: app: tankwar-server spec: - replicas: 3 + replicas: 1 selector: matchLabels: app: tankwar-server @@ -78,7 +78,7 @@ metadata: labels: app: tankwar-server spec: - replicas: 3 + replicas: 1 selector: matchLabels: app: tankwar-server diff --git a/server/node_modules/.package-lock.json b/server/node_modules/.package-lock.json index d94e53e..ac2d52e 100644 --- a/server/node_modules/.package-lock.json +++ b/server/node_modules/.package-lock.json @@ -6,8 +6,6 @@ "packages": { "node_modules/accepts": { "version": "2.0.0", - "resolved": "https://mirrors.tencent.com/npm/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", "dependencies": { "mime-types": "^3.0.0", @@ -19,14 +17,10 @@ }, "node_modules/append-field": { "version": "1.0.0", - "resolved": "https://mirrors.tencent.com/npm/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", "license": "MIT" }, "node_modules/body-parser": { "version": "2.2.2", - "resolved": "https://mirrors.tencent.com/npm/body-parser/-/body-parser-2.2.2.tgz", - "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "license": "MIT", "dependencies": { "bytes": "^3.1.2", @@ -49,14 +43,10 @@ }, "node_modules/buffer-from": { "version": "1.1.2", - "resolved": "https://mirrors.tencent.com/npm/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "license": "MIT" }, "node_modules/busboy": { "version": "1.6.0", - "resolved": "https://mirrors.tencent.com/npm/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", "dependencies": { "streamsearch": "^1.1.0" }, @@ -66,8 +56,6 @@ }, "node_modules/bytes": { "version": "3.1.2", - "resolved": "https://mirrors.tencent.com/npm/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -75,8 +63,7 @@ }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", - "resolved": "https://mirrors.tencent.com/npm/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" @@ -87,8 +74,6 @@ }, "node_modules/call-bound": { "version": "1.0.4", - "resolved": "https://mirrors.tencent.com/npm/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -103,11 +88,10 @@ }, "node_modules/concat-stream": { "version": "2.0.0", - "resolved": "https://mirrors.tencent.com/npm/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", "engines": [ "node >= 6.0" ], + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -117,8 +101,6 @@ }, "node_modules/content-disposition": { "version": "1.1.0", - "resolved": "https://mirrors.tencent.com/npm/content-disposition/-/content-disposition-1.1.0.tgz", - "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", "license": "MIT", "engines": { "node": ">=18" @@ -130,16 +112,13 @@ }, "node_modules/content-type": { "version": "1.0.5", - "resolved": "https://mirrors.tencent.com/npm/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie": { "version": "0.7.2", - "resolved": "https://mirrors.tencent.com/npm/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -147,8 +126,6 @@ }, "node_modules/cookie-signature": { "version": "1.2.2", - "resolved": "https://mirrors.tencent.com/npm/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "license": "MIT", "engines": { "node": ">=6.6.0" @@ -156,8 +133,6 @@ }, "node_modules/debug": { "version": "4.4.3", - "resolved": "https://mirrors.tencent.com/npm/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -173,8 +148,6 @@ }, "node_modules/depd": { "version": "2.0.0", - "resolved": "https://mirrors.tencent.com/npm/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -182,8 +155,6 @@ }, "node_modules/dunder-proto": { "version": "1.0.1", - "resolved": "https://mirrors.tencent.com/npm/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -196,13 +167,10 @@ }, "node_modules/ee-first": { "version": "1.1.1", - "resolved": "https://mirrors.tencent.com/npm/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + "license": "MIT" }, "node_modules/encodeurl": { "version": "2.0.0", - "resolved": "https://mirrors.tencent.com/npm/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -210,8 +178,6 @@ }, "node_modules/es-define-property": { "version": "1.0.1", - "resolved": "https://mirrors.tencent.com/npm/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -219,16 +185,14 @@ }, "node_modules/es-errors": { "version": "1.3.0", - "resolved": "https://mirrors.tencent.com/npm/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-object-atoms": { "version": "1.1.1", - "resolved": "https://mirrors.tencent.com/npm/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0" }, @@ -238,13 +202,10 @@ }, "node_modules/escape-html": { "version": "1.0.3", - "resolved": "https://mirrors.tencent.com/npm/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "license": "MIT" }, "node_modules/etag": { "version": "1.8.1", - "resolved": "https://mirrors.tencent.com/npm/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -252,8 +213,6 @@ }, "node_modules/express": { "version": "5.2.1", - "resolved": "https://mirrors.tencent.com/npm/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", "dependencies": { "accepts": "^2.0.0", @@ -295,8 +254,6 @@ }, "node_modules/finalhandler": { "version": "2.1.1", - "resolved": "https://mirrors.tencent.com/npm/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -316,8 +273,6 @@ }, "node_modules/forwarded": { "version": "0.2.0", - "resolved": "https://mirrors.tencent.com/npm/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -325,16 +280,13 @@ }, "node_modules/fresh": { "version": "2.0.0", - "resolved": "https://mirrors.tencent.com/npm/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/function-bind": { "version": "1.1.2", - "resolved": "https://mirrors.tencent.com/npm/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -342,8 +294,7 @@ }, "node_modules/get-intrinsic": { "version": "1.3.0", - "resolved": "https://mirrors.tencent.com/npm/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", @@ -365,8 +316,6 @@ }, "node_modules/get-proto": { "version": "1.0.1", - "resolved": "https://mirrors.tencent.com/npm/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -378,8 +327,7 @@ }, "node_modules/gopd": { "version": "1.2.0", - "resolved": "https://mirrors.tencent.com/npm/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -389,8 +337,7 @@ }, "node_modules/has-symbols": { "version": "1.1.0", - "resolved": "https://mirrors.tencent.com/npm/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -400,8 +347,7 @@ }, "node_modules/hasown": { "version": "2.0.3", - "resolved": "https://mirrors.tencent.com/npm/hasown/-/hasown-2.0.3.tgz", - "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -411,8 +357,7 @@ }, "node_modules/http-errors": { "version": "2.0.1", - "resolved": "https://mirrors.tencent.com/npm/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", @@ -430,8 +375,6 @@ }, "node_modules/iconv-lite": { "version": "0.7.2", - "resolved": "https://mirrors.tencent.com/npm/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -446,14 +389,10 @@ }, "node_modules/inherits": { "version": "2.0.4", - "resolved": "https://mirrors.tencent.com/npm/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, "node_modules/ipaddr.js": { "version": "1.9.1", - "resolved": "https://mirrors.tencent.com/npm/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "license": "MIT", "engines": { "node": ">= 0.10" @@ -461,14 +400,10 @@ }, "node_modules/is-promise": { "version": "4.0.0", - "resolved": "https://mirrors.tencent.com/npm/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "license": "MIT" }, "node_modules/math-intrinsics": { "version": "1.1.0", - "resolved": "https://mirrors.tencent.com/npm/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -476,8 +411,6 @@ }, "node_modules/media-typer": { "version": "1.1.0", - "resolved": "https://mirrors.tencent.com/npm/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -485,8 +418,6 @@ }, "node_modules/merge-descriptors": { "version": "2.0.0", - "resolved": "https://mirrors.tencent.com/npm/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "license": "MIT", "engines": { "node": ">=18" @@ -497,8 +428,6 @@ }, "node_modules/mime-db": { "version": "1.54.0", - "resolved": "https://mirrors.tencent.com/npm/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -506,8 +435,7 @@ }, "node_modules/mime-types": { "version": "3.0.2", - "resolved": "https://mirrors.tencent.com/npm/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", "dependencies": { "mime-db": "^1.54.0" }, @@ -521,13 +449,10 @@ }, "node_modules/ms": { "version": "2.1.3", - "resolved": "https://mirrors.tencent.com/npm/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "license": "MIT" }, "node_modules/multer": { "version": "2.1.1", - "resolved": "https://mirrors.tencent.com/npm/multer/-/multer-2.1.1.tgz", - "integrity": "sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==", "license": "MIT", "dependencies": { "append-field": "^1.0.0", @@ -545,8 +470,6 @@ }, "node_modules/multer/node_modules/media-typer": { "version": "0.3.0", - "resolved": "https://mirrors.tencent.com/npm/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -554,8 +477,6 @@ }, "node_modules/multer/node_modules/mime-db": { "version": "1.52.0", - "resolved": "https://mirrors.tencent.com/npm/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -563,8 +484,7 @@ }, "node_modules/multer/node_modules/mime-types": { "version": "2.1.35", - "resolved": "https://mirrors.tencent.com/npm/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -574,8 +494,7 @@ }, "node_modules/multer/node_modules/type-is": { "version": "1.6.18", - "resolved": "https://mirrors.tencent.com/npm/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -586,8 +505,6 @@ }, "node_modules/negotiator": { "version": "1.0.0", - "resolved": "https://mirrors.tencent.com/npm/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -595,8 +512,6 @@ }, "node_modules/object-inspect": { "version": "1.13.4", - "resolved": "https://mirrors.tencent.com/npm/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -607,8 +522,7 @@ }, "node_modules/on-finished": { "version": "2.4.1", - "resolved": "https://mirrors.tencent.com/npm/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -618,24 +532,21 @@ }, "node_modules/once": { "version": "1.4.0", - "resolved": "https://mirrors.tencent.com/npm/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", "dependencies": { "wrappy": "1" } }, "node_modules/parseurl": { "version": "1.3.3", - "resolved": "https://mirrors.tencent.com/npm/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/path-to-regexp": { "version": "8.4.2", - "resolved": "https://mirrors.tencent.com/npm/path-to-regexp/-/path-to-regexp-8.4.2.tgz", - "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/express" @@ -643,8 +554,6 @@ }, "node_modules/proxy-addr": { "version": "2.0.7", - "resolved": "https://mirrors.tencent.com/npm/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "license": "MIT", "dependencies": { "forwarded": "0.2.0", @@ -656,8 +565,6 @@ }, "node_modules/qs": { "version": "6.15.1", - "resolved": "https://mirrors.tencent.com/npm/qs/-/qs-6.15.1.tgz", - "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -671,8 +578,6 @@ }, "node_modules/range-parser": { "version": "1.2.1", - "resolved": "https://mirrors.tencent.com/npm/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -680,8 +585,7 @@ }, "node_modules/raw-body": { "version": "3.0.2", - "resolved": "https://mirrors.tencent.com/npm/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", @@ -694,8 +598,7 @@ }, "node_modules/readable-stream": { "version": "3.6.2", - "resolved": "https://mirrors.tencent.com/npm/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -707,8 +610,6 @@ }, "node_modules/router": { "version": "2.2.0", - "resolved": "https://mirrors.tencent.com/npm/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -723,8 +624,6 @@ }, "node_modules/safe-buffer": { "version": "5.2.1", - "resolved": "https://mirrors.tencent.com/npm/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -738,17 +637,16 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safer-buffer": { "version": "2.1.2", - "resolved": "https://mirrors.tencent.com/npm/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "license": "MIT" }, "node_modules/send": { "version": "1.2.1", - "resolved": "https://mirrors.tencent.com/npm/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", @@ -772,8 +670,6 @@ }, "node_modules/serve-static": { "version": "2.2.1", - "resolved": "https://mirrors.tencent.com/npm/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "license": "MIT", "dependencies": { "encodeurl": "^2.0.0", @@ -791,13 +687,11 @@ }, "node_modules/setprototypeof": { "version": "1.2.0", - "resolved": "https://mirrors.tencent.com/npm/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "license": "ISC" }, "node_modules/side-channel": { "version": "1.1.0", - "resolved": "https://mirrors.tencent.com/npm/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", @@ -814,8 +708,6 @@ }, "node_modules/side-channel-list": { "version": "1.0.1", - "resolved": "https://mirrors.tencent.com/npm/side-channel-list/-/side-channel-list-1.0.1.tgz", - "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -830,8 +722,6 @@ }, "node_modules/side-channel-map": { "version": "1.0.1", - "resolved": "https://mirrors.tencent.com/npm/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -848,8 +738,6 @@ }, "node_modules/side-channel-weakmap": { "version": "1.0.2", - "resolved": "https://mirrors.tencent.com/npm/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -867,8 +755,6 @@ }, "node_modules/statuses": { "version": "2.0.2", - "resolved": "https://mirrors.tencent.com/npm/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -876,24 +762,19 @@ }, "node_modules/streamsearch": { "version": "1.1.0", - "resolved": "https://mirrors.tencent.com/npm/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", "engines": { "node": ">=10.0.0" } }, "node_modules/string_decoder": { "version": "1.3.0", - "resolved": "https://mirrors.tencent.com/npm/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } }, "node_modules/toidentifier": { "version": "1.0.1", - "resolved": "https://mirrors.tencent.com/npm/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "license": "MIT", "engines": { "node": ">=0.6" @@ -901,8 +782,7 @@ }, "node_modules/type-is": { "version": "2.0.1", - "resolved": "https://mirrors.tencent.com/npm/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", @@ -914,13 +794,10 @@ }, "node_modules/typedarray": { "version": "0.0.6", - "resolved": "https://mirrors.tencent.com/npm/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + "license": "MIT" }, "node_modules/unpipe": { "version": "1.0.0", - "resolved": "https://mirrors.tencent.com/npm/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -928,29 +805,23 @@ }, "node_modules/util-deprecate": { "version": "1.0.2", - "resolved": "https://mirrors.tencent.com/npm/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, "node_modules/vary": { "version": "1.1.2", - "resolved": "https://mirrors.tencent.com/npm/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/wrappy": { "version": "1.0.2", - "resolved": "https://mirrors.tencent.com/npm/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, "node_modules/ws": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", - "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", - "license": "MIT", + "version": "8.18.0", + "resolved": "https://mirrors.tencent.com/npm/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "engines": { "node": ">=10.0.0" }, diff --git a/server/node_modules/ws/index.js b/server/node_modules/ws/index.js index 3fdb7b2..41edb3b 100644 --- a/server/node_modules/ws/index.js +++ b/server/node_modules/ws/index.js @@ -1,22 +1,13 @@ 'use strict'; -const createWebSocketStream = require('./lib/stream'); -const extension = require('./lib/extension'); -const PerMessageDeflate = require('./lib/permessage-deflate'); -const Receiver = require('./lib/receiver'); -const Sender = require('./lib/sender'); -const subprotocol = require('./lib/subprotocol'); const WebSocket = require('./lib/websocket'); -const WebSocketServer = require('./lib/websocket-server'); -WebSocket.createWebSocketStream = createWebSocketStream; -WebSocket.extension = extension; -WebSocket.PerMessageDeflate = PerMessageDeflate; -WebSocket.Receiver = Receiver; -WebSocket.Sender = Sender; -WebSocket.Server = WebSocketServer; -WebSocket.subprotocol = subprotocol; +WebSocket.createWebSocketStream = require('./lib/stream'); +WebSocket.Server = require('./lib/websocket-server'); +WebSocket.Receiver = require('./lib/receiver'); +WebSocket.Sender = require('./lib/sender'); + WebSocket.WebSocket = WebSocket; -WebSocket.WebSocketServer = WebSocketServer; +WebSocket.WebSocketServer = WebSocket.Server; module.exports = WebSocket; diff --git a/server/node_modules/ws/lib/constants.js b/server/node_modules/ws/lib/constants.js index 69b2fe3..74214d4 100644 --- a/server/node_modules/ws/lib/constants.js +++ b/server/node_modules/ws/lib/constants.js @@ -7,7 +7,6 @@ if (hasBlob) BINARY_TYPES.push('blob'); module.exports = { BINARY_TYPES, - CLOSE_TIMEOUT: 30000, EMPTY_BUFFER: Buffer.alloc(0), GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', hasBlob, diff --git a/server/node_modules/ws/lib/permessage-deflate.js b/server/node_modules/ws/lib/permessage-deflate.js index aa5db76..77d918b 100644 --- a/server/node_modules/ws/lib/permessage-deflate.js +++ b/server/node_modules/ws/lib/permessage-deflate.js @@ -37,9 +37,6 @@ class PerMessageDeflate { * acknowledge disabling of client context takeover * @param {Number} [options.concurrencyLimit=10] The number of concurrent * calls to zlib - * @param {Boolean} [options.isServer=false] Create the instance in either - * server or client mode - * @param {Number} [options.maxPayload=0] The maximum allowed message length * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the * use of a custom server window size * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept @@ -50,13 +47,16 @@ class PerMessageDeflate { * deflate * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on * inflate + * @param {Boolean} [isServer=false] Create the instance in either server or + * client mode + * @param {Number} [maxPayload=0] The maximum allowed message length */ - constructor(options) { + constructor(options, isServer, maxPayload) { + this._maxPayload = maxPayload | 0; this._options = options || {}; this._threshold = this._options.threshold !== undefined ? this._options.threshold : 1024; - this._maxPayload = this._options.maxPayload | 0; - this._isServer = !!this._options.isServer; + this._isServer = !!isServer; this._deflate = null; this._inflate = null; @@ -494,14 +494,6 @@ function inflateOnData(chunk) { this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'; this[kError][kStatusCode] = 1009; this.removeListener('data', inflateOnData); - - // - // The choice to employ `zlib.reset()` over `zlib.close()` is dictated by the - // fact that in Node.js versions prior to 13.10.0, the callback for - // `zlib.flush()` is not called if `zlib.close()` is used. Utilizing - // `zlib.reset()` ensures that either the callback is invoked or an error is - // emitted. - // this.reset(); } @@ -517,12 +509,6 @@ function inflateOnError(err) { // closed when an error is emitted. // this[kPerMessageDeflate]._inflate = null; - - if (this[kError]) { - this[kCallback](this[kError]); - return; - } - err[kStatusCode] = 1007; this[kCallback](err); } diff --git a/server/node_modules/ws/lib/sender.js b/server/node_modules/ws/lib/sender.js index a8b1da3..ee16cea 100644 --- a/server/node_modules/ws/lib/sender.js +++ b/server/node_modules/ws/lib/sender.js @@ -551,7 +551,7 @@ class Sender { /** * Sends a frame. * - * @param {(Buffer | String)[]} list The frame to send + * @param {Buffer[]} list The frame to send * @param {Function} [cb] Callback * @private */ diff --git a/server/node_modules/ws/lib/stream.js b/server/node_modules/ws/lib/stream.js index 4c58c91..230734b 100644 --- a/server/node_modules/ws/lib/stream.js +++ b/server/node_modules/ws/lib/stream.js @@ -1,7 +1,5 @@ -/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^WebSocket$" }] */ 'use strict'; -const WebSocket = require('./websocket'); const { Duplex } = require('stream'); /** diff --git a/server/node_modules/ws/lib/websocket-server.js b/server/node_modules/ws/lib/websocket-server.js index 68aa789..67b52ff 100644 --- a/server/node_modules/ws/lib/websocket-server.js +++ b/server/node_modules/ws/lib/websocket-server.js @@ -11,7 +11,7 @@ const extension = require('./extension'); const PerMessageDeflate = require('./permessage-deflate'); const subprotocol = require('./subprotocol'); const WebSocket = require('./websocket'); -const { CLOSE_TIMEOUT, GUID, kWebSocket } = require('./constants'); +const { GUID, kWebSocket } = require('./constants'); const keyRegex = /^[+/0-9A-Za-z]{22}==$/; @@ -38,9 +38,6 @@ class WebSocketServer extends EventEmitter { * pending connections * @param {Boolean} [options.clientTracking=true] Specifies whether or not to * track clients - * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to - * wait for the closing handshake to finish after `websocket.close()` is - * called * @param {Function} [options.handleProtocols] A hook to handle protocols * @param {String} [options.host] The hostname where to bind the server * @param {Number} [options.maxPayload=104857600] The maximum allowed message @@ -70,7 +67,6 @@ class WebSocketServer extends EventEmitter { perMessageDeflate: false, handleProtocols: null, clientTracking: true, - closeTimeout: CLOSE_TIMEOUT, verifyClient: null, noServer: false, backlog: null, // use default (511 as implemented in net.js) @@ -260,11 +256,9 @@ class WebSocketServer extends EventEmitter { return; } - if (version !== 13 && version !== 8) { + if (version !== 8 && version !== 13) { const message = 'Missing or invalid Sec-WebSocket-Version header'; - abortHandshakeOrEmitwsClientError(this, req, socket, 400, message, { - 'Sec-WebSocket-Version': '13, 8' - }); + abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); return; } @@ -293,11 +287,11 @@ class WebSocketServer extends EventEmitter { this.options.perMessageDeflate && secWebSocketExtensions !== undefined ) { - const perMessageDeflate = new PerMessageDeflate({ - ...this.options.perMessageDeflate, - isServer: true, - maxPayload: this.options.maxPayload - }); + const perMessageDeflate = new PerMessageDeflate( + this.options.perMessageDeflate, + true, + this.options.maxPayload + ); try { const offers = extension.parse(secWebSocketExtensions); @@ -532,23 +526,15 @@ function abortHandshake(socket, code, message, headers) { * @param {Duplex} socket The socket of the upgrade request * @param {Number} code The HTTP response status code * @param {String} message The HTTP response body - * @param {Object} [headers] The HTTP response headers * @private */ -function abortHandshakeOrEmitwsClientError( - server, - req, - socket, - code, - message, - headers -) { +function abortHandshakeOrEmitwsClientError(server, req, socket, code, message) { if (server.listenerCount('wsClientError')) { const err = new Error(message); Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError); server.emit('wsClientError', err, socket, req); } else { - abortHandshake(socket, code, message, headers); + abortHandshake(socket, code, message); } } diff --git a/server/node_modules/ws/lib/websocket.js b/server/node_modules/ws/lib/websocket.js index 75d5bb2..7fb4029 100644 --- a/server/node_modules/ws/lib/websocket.js +++ b/server/node_modules/ws/lib/websocket.js @@ -18,7 +18,6 @@ const { isBlob } = require('./validation'); const { BINARY_TYPES, - CLOSE_TIMEOUT, EMPTY_BUFFER, GUID, kForOnEventAttribute, @@ -33,6 +32,7 @@ const { const { format, parse } = require('./extension'); const { toBuffer } = require('./buffer-util'); +const closeTimeout = 30 * 1000; const kAborted = Symbol('kAborted'); const protocolVersions = [8, 13]; const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED']; @@ -88,7 +88,6 @@ class WebSocket extends EventEmitter { initAsClient(this, address, protocols, options); } else { this._autoPong = options.autoPong; - this._closeTimeout = options.closeTimeout; this._isServer = true; } } @@ -630,8 +629,6 @@ module.exports = WebSocket; * times in the same tick * @param {Boolean} [options.autoPong=true] Specifies whether or not to * automatically send a pong in response to a ping - * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to wait - * for the closing handshake to finish after `websocket.close()` is called * @param {Function} [options.finishRequest] A function which can be used to * customize the headers of each http request before it is sent * @param {Boolean} [options.followRedirects=false] Whether or not to follow @@ -658,7 +655,6 @@ function initAsClient(websocket, address, protocols, options) { const opts = { allowSynchronousEvents: true, autoPong: true, - closeTimeout: CLOSE_TIMEOUT, protocolVersion: protocolVersions[1], maxPayload: 100 * 1024 * 1024, skipUTF8Validation: false, @@ -677,7 +673,6 @@ function initAsClient(websocket, address, protocols, options) { }; websocket._autoPong = opts.autoPong; - websocket._closeTimeout = opts.closeTimeout; if (!protocolVersions.includes(opts.protocolVersion)) { throw new RangeError( @@ -693,7 +688,7 @@ function initAsClient(websocket, address, protocols, options) { } else { try { parsedUrl = new URL(address); - } catch { + } catch (e) { throw new SyntaxError(`Invalid URL: ${address}`); } } @@ -713,7 +708,7 @@ function initAsClient(websocket, address, protocols, options) { if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) { invalidUrlMessage = 'The URL\'s protocol must be one of "ws:", "wss:", ' + - '"http:", "https:", or "ws+unix:"'; + '"http:", "https", or "ws+unix:"'; } else if (isIpcUrl && !parsedUrl.pathname) { invalidUrlMessage = "The URL's pathname is empty"; } else if (parsedUrl.hash) { @@ -755,11 +750,11 @@ function initAsClient(websocket, address, protocols, options) { opts.timeout = opts.handshakeTimeout; if (opts.perMessageDeflate) { - perMessageDeflate = new PerMessageDeflate({ - ...opts.perMessageDeflate, - isServer: false, - maxPayload: opts.maxPayload - }); + perMessageDeflate = new PerMessageDeflate( + opts.perMessageDeflate !== true ? opts.perMessageDeflate : {}, + false, + opts.maxPayload + ); opts.headers['Sec-WebSocket-Extensions'] = format({ [PerMessageDeflate.extensionName]: perMessageDeflate.offer() }); @@ -1295,7 +1290,7 @@ function senderOnError(err) { function setCloseTimer(websocket) { websocket._closeTimer = setTimeout( websocket._socket.destroy.bind(websocket._socket), - websocket._closeTimeout + closeTimeout ); } @@ -1313,23 +1308,23 @@ function socketOnClose() { websocket._readyState = WebSocket.CLOSING; + let chunk; + // // The close frame might not have been received or the `'end'` event emitted, // for example, if the socket was destroyed due to an error. Ensure that the // `receiver` stream is closed after writing any remaining buffered data to // it. If the readable side of the socket is in flowing mode then there is no - // buffered data as everything has been already written. If instead, the - // socket is paused, any possible buffered data will be read as a single - // chunk. + // buffered data as everything has been already written and `readable.read()` + // will return `null`. If instead, the socket is paused, any possible buffered + // data will be read as a single chunk. // if ( !this._readableState.endEmitted && !websocket._closeFrameReceived && !websocket._receiver._writableState.errorEmitted && - this._readableState.length !== 0 + (chunk = websocket._socket.read()) !== null ) { - const chunk = this.read(this._readableState.length); - websocket._receiver.write(chunk); } diff --git a/server/node_modules/ws/package.json b/server/node_modules/ws/package.json index 3618050..4f7155d 100644 --- a/server/node_modules/ws/package.json +++ b/server/node_modules/ws/package.json @@ -1,6 +1,6 @@ { "name": "ws", - "version": "8.20.0", + "version": "8.18.0", "description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js", "keywords": [ "HyBi", @@ -55,13 +55,12 @@ } }, "devDependencies": { - "@eslint/js": "^10.0.1", "benchmark": "^2.1.4", "bufferutil": "^4.0.1", - "eslint": "^10.0.1", - "eslint-config-prettier": "^10.0.1", + "eslint": "^9.0.0", + "eslint-config-prettier": "^9.0.0", "eslint-plugin-prettier": "^5.0.0", - "globals": "^17.0.0", + "globals": "^15.0.0", "mocha": "^8.4.0", "nyc": "^15.0.0", "prettier": "^3.0.0", diff --git a/server/node_modules/ws/wrapper.mjs b/server/node_modules/ws/wrapper.mjs index a8ffabb..7245ad1 100644 --- a/server/node_modules/ws/wrapper.mjs +++ b/server/node_modules/ws/wrapper.mjs @@ -1,21 +1,8 @@ import createWebSocketStream from './lib/stream.js'; -import extension from './lib/extension.js'; -import PerMessageDeflate from './lib/permessage-deflate.js'; import Receiver from './lib/receiver.js'; import Sender from './lib/sender.js'; -import subprotocol from './lib/subprotocol.js'; import WebSocket from './lib/websocket.js'; import WebSocketServer from './lib/websocket-server.js'; -export { - createWebSocketStream, - extension, - PerMessageDeflate, - Receiver, - Sender, - subprotocol, - WebSocket, - WebSocketServer -}; - +export { createWebSocketStream, Receiver, Sender, WebSocket, WebSocketServer }; export default WebSocket; diff --git a/server/package-lock.json b/server/package-lock.json index f176520..ec0dad8 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -10,13 +10,11 @@ "dependencies": { "express": "^5.2.1", "multer": "^2.1.1", - "ws": "^8.16.0" + "ws": "8.18.0" } }, "node_modules/accepts": { "version": "2.0.0", - "resolved": "https://mirrors.tencent.com/npm/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", "dependencies": { "mime-types": "^3.0.0", @@ -28,14 +26,10 @@ }, "node_modules/append-field": { "version": "1.0.0", - "resolved": "https://mirrors.tencent.com/npm/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", "license": "MIT" }, "node_modules/body-parser": { "version": "2.2.2", - "resolved": "https://mirrors.tencent.com/npm/body-parser/-/body-parser-2.2.2.tgz", - "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "license": "MIT", "dependencies": { "bytes": "^3.1.2", @@ -58,14 +52,10 @@ }, "node_modules/buffer-from": { "version": "1.1.2", - "resolved": "https://mirrors.tencent.com/npm/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "license": "MIT" }, "node_modules/busboy": { "version": "1.6.0", - "resolved": "https://mirrors.tencent.com/npm/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", "dependencies": { "streamsearch": "^1.1.0" }, @@ -75,8 +65,6 @@ }, "node_modules/bytes": { "version": "3.1.2", - "resolved": "https://mirrors.tencent.com/npm/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -84,8 +72,7 @@ }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", - "resolved": "https://mirrors.tencent.com/npm/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" @@ -96,8 +83,6 @@ }, "node_modules/call-bound": { "version": "1.0.4", - "resolved": "https://mirrors.tencent.com/npm/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -112,11 +97,10 @@ }, "node_modules/concat-stream": { "version": "2.0.0", - "resolved": "https://mirrors.tencent.com/npm/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", "engines": [ "node >= 6.0" ], + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -126,8 +110,6 @@ }, "node_modules/content-disposition": { "version": "1.1.0", - "resolved": "https://mirrors.tencent.com/npm/content-disposition/-/content-disposition-1.1.0.tgz", - "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", "license": "MIT", "engines": { "node": ">=18" @@ -139,16 +121,13 @@ }, "node_modules/content-type": { "version": "1.0.5", - "resolved": "https://mirrors.tencent.com/npm/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie": { "version": "0.7.2", - "resolved": "https://mirrors.tencent.com/npm/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -156,8 +135,6 @@ }, "node_modules/cookie-signature": { "version": "1.2.2", - "resolved": "https://mirrors.tencent.com/npm/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "license": "MIT", "engines": { "node": ">=6.6.0" @@ -165,8 +142,6 @@ }, "node_modules/debug": { "version": "4.4.3", - "resolved": "https://mirrors.tencent.com/npm/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -182,8 +157,6 @@ }, "node_modules/depd": { "version": "2.0.0", - "resolved": "https://mirrors.tencent.com/npm/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -191,8 +164,6 @@ }, "node_modules/dunder-proto": { "version": "1.0.1", - "resolved": "https://mirrors.tencent.com/npm/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -205,13 +176,10 @@ }, "node_modules/ee-first": { "version": "1.1.1", - "resolved": "https://mirrors.tencent.com/npm/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + "license": "MIT" }, "node_modules/encodeurl": { "version": "2.0.0", - "resolved": "https://mirrors.tencent.com/npm/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -219,8 +187,6 @@ }, "node_modules/es-define-property": { "version": "1.0.1", - "resolved": "https://mirrors.tencent.com/npm/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -228,16 +194,14 @@ }, "node_modules/es-errors": { "version": "1.3.0", - "resolved": "https://mirrors.tencent.com/npm/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-object-atoms": { "version": "1.1.1", - "resolved": "https://mirrors.tencent.com/npm/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0" }, @@ -247,13 +211,10 @@ }, "node_modules/escape-html": { "version": "1.0.3", - "resolved": "https://mirrors.tencent.com/npm/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "license": "MIT" }, "node_modules/etag": { "version": "1.8.1", - "resolved": "https://mirrors.tencent.com/npm/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -261,8 +222,6 @@ }, "node_modules/express": { "version": "5.2.1", - "resolved": "https://mirrors.tencent.com/npm/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", "dependencies": { "accepts": "^2.0.0", @@ -304,8 +263,6 @@ }, "node_modules/finalhandler": { "version": "2.1.1", - "resolved": "https://mirrors.tencent.com/npm/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -325,8 +282,6 @@ }, "node_modules/forwarded": { "version": "0.2.0", - "resolved": "https://mirrors.tencent.com/npm/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -334,16 +289,13 @@ }, "node_modules/fresh": { "version": "2.0.0", - "resolved": "https://mirrors.tencent.com/npm/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/function-bind": { "version": "1.1.2", - "resolved": "https://mirrors.tencent.com/npm/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -351,8 +303,7 @@ }, "node_modules/get-intrinsic": { "version": "1.3.0", - "resolved": "https://mirrors.tencent.com/npm/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", @@ -374,8 +325,6 @@ }, "node_modules/get-proto": { "version": "1.0.1", - "resolved": "https://mirrors.tencent.com/npm/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -387,8 +336,7 @@ }, "node_modules/gopd": { "version": "1.2.0", - "resolved": "https://mirrors.tencent.com/npm/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -398,8 +346,7 @@ }, "node_modules/has-symbols": { "version": "1.1.0", - "resolved": "https://mirrors.tencent.com/npm/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -409,8 +356,7 @@ }, "node_modules/hasown": { "version": "2.0.3", - "resolved": "https://mirrors.tencent.com/npm/hasown/-/hasown-2.0.3.tgz", - "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -420,8 +366,7 @@ }, "node_modules/http-errors": { "version": "2.0.1", - "resolved": "https://mirrors.tencent.com/npm/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", @@ -439,8 +384,6 @@ }, "node_modules/iconv-lite": { "version": "0.7.2", - "resolved": "https://mirrors.tencent.com/npm/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -455,14 +398,10 @@ }, "node_modules/inherits": { "version": "2.0.4", - "resolved": "https://mirrors.tencent.com/npm/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, "node_modules/ipaddr.js": { "version": "1.9.1", - "resolved": "https://mirrors.tencent.com/npm/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "license": "MIT", "engines": { "node": ">= 0.10" @@ -470,14 +409,10 @@ }, "node_modules/is-promise": { "version": "4.0.0", - "resolved": "https://mirrors.tencent.com/npm/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "license": "MIT" }, "node_modules/math-intrinsics": { "version": "1.1.0", - "resolved": "https://mirrors.tencent.com/npm/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -485,8 +420,6 @@ }, "node_modules/media-typer": { "version": "1.1.0", - "resolved": "https://mirrors.tencent.com/npm/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -494,8 +427,6 @@ }, "node_modules/merge-descriptors": { "version": "2.0.0", - "resolved": "https://mirrors.tencent.com/npm/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "license": "MIT", "engines": { "node": ">=18" @@ -506,8 +437,6 @@ }, "node_modules/mime-db": { "version": "1.54.0", - "resolved": "https://mirrors.tencent.com/npm/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -515,8 +444,7 @@ }, "node_modules/mime-types": { "version": "3.0.2", - "resolved": "https://mirrors.tencent.com/npm/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", "dependencies": { "mime-db": "^1.54.0" }, @@ -530,13 +458,10 @@ }, "node_modules/ms": { "version": "2.1.3", - "resolved": "https://mirrors.tencent.com/npm/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "license": "MIT" }, "node_modules/multer": { "version": "2.1.1", - "resolved": "https://mirrors.tencent.com/npm/multer/-/multer-2.1.1.tgz", - "integrity": "sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==", "license": "MIT", "dependencies": { "append-field": "^1.0.0", @@ -554,8 +479,6 @@ }, "node_modules/multer/node_modules/media-typer": { "version": "0.3.0", - "resolved": "https://mirrors.tencent.com/npm/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -563,8 +486,6 @@ }, "node_modules/multer/node_modules/mime-db": { "version": "1.52.0", - "resolved": "https://mirrors.tencent.com/npm/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -572,8 +493,7 @@ }, "node_modules/multer/node_modules/mime-types": { "version": "2.1.35", - "resolved": "https://mirrors.tencent.com/npm/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -583,8 +503,7 @@ }, "node_modules/multer/node_modules/type-is": { "version": "1.6.18", - "resolved": "https://mirrors.tencent.com/npm/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -595,8 +514,6 @@ }, "node_modules/negotiator": { "version": "1.0.0", - "resolved": "https://mirrors.tencent.com/npm/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -604,8 +521,6 @@ }, "node_modules/object-inspect": { "version": "1.13.4", - "resolved": "https://mirrors.tencent.com/npm/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -616,8 +531,7 @@ }, "node_modules/on-finished": { "version": "2.4.1", - "resolved": "https://mirrors.tencent.com/npm/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -627,24 +541,21 @@ }, "node_modules/once": { "version": "1.4.0", - "resolved": "https://mirrors.tencent.com/npm/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", "dependencies": { "wrappy": "1" } }, "node_modules/parseurl": { "version": "1.3.3", - "resolved": "https://mirrors.tencent.com/npm/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/path-to-regexp": { "version": "8.4.2", - "resolved": "https://mirrors.tencent.com/npm/path-to-regexp/-/path-to-regexp-8.4.2.tgz", - "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/express" @@ -652,8 +563,6 @@ }, "node_modules/proxy-addr": { "version": "2.0.7", - "resolved": "https://mirrors.tencent.com/npm/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "license": "MIT", "dependencies": { "forwarded": "0.2.0", @@ -665,8 +574,6 @@ }, "node_modules/qs": { "version": "6.15.1", - "resolved": "https://mirrors.tencent.com/npm/qs/-/qs-6.15.1.tgz", - "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -680,8 +587,6 @@ }, "node_modules/range-parser": { "version": "1.2.1", - "resolved": "https://mirrors.tencent.com/npm/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -689,8 +594,7 @@ }, "node_modules/raw-body": { "version": "3.0.2", - "resolved": "https://mirrors.tencent.com/npm/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", @@ -703,8 +607,7 @@ }, "node_modules/readable-stream": { "version": "3.6.2", - "resolved": "https://mirrors.tencent.com/npm/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -716,8 +619,6 @@ }, "node_modules/router": { "version": "2.2.0", - "resolved": "https://mirrors.tencent.com/npm/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -732,8 +633,6 @@ }, "node_modules/safe-buffer": { "version": "5.2.1", - "resolved": "https://mirrors.tencent.com/npm/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -747,17 +646,16 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safer-buffer": { "version": "2.1.2", - "resolved": "https://mirrors.tencent.com/npm/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "license": "MIT" }, "node_modules/send": { "version": "1.2.1", - "resolved": "https://mirrors.tencent.com/npm/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", @@ -781,8 +679,6 @@ }, "node_modules/serve-static": { "version": "2.2.1", - "resolved": "https://mirrors.tencent.com/npm/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "license": "MIT", "dependencies": { "encodeurl": "^2.0.0", @@ -800,13 +696,11 @@ }, "node_modules/setprototypeof": { "version": "1.2.0", - "resolved": "https://mirrors.tencent.com/npm/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "license": "ISC" }, "node_modules/side-channel": { "version": "1.1.0", - "resolved": "https://mirrors.tencent.com/npm/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", @@ -823,8 +717,6 @@ }, "node_modules/side-channel-list": { "version": "1.0.1", - "resolved": "https://mirrors.tencent.com/npm/side-channel-list/-/side-channel-list-1.0.1.tgz", - "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -839,8 +731,6 @@ }, "node_modules/side-channel-map": { "version": "1.0.1", - "resolved": "https://mirrors.tencent.com/npm/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -857,8 +747,6 @@ }, "node_modules/side-channel-weakmap": { "version": "1.0.2", - "resolved": "https://mirrors.tencent.com/npm/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -876,8 +764,6 @@ }, "node_modules/statuses": { "version": "2.0.2", - "resolved": "https://mirrors.tencent.com/npm/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -885,24 +771,19 @@ }, "node_modules/streamsearch": { "version": "1.1.0", - "resolved": "https://mirrors.tencent.com/npm/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", "engines": { "node": ">=10.0.0" } }, "node_modules/string_decoder": { "version": "1.3.0", - "resolved": "https://mirrors.tencent.com/npm/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } }, "node_modules/toidentifier": { "version": "1.0.1", - "resolved": "https://mirrors.tencent.com/npm/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "license": "MIT", "engines": { "node": ">=0.6" @@ -910,8 +791,7 @@ }, "node_modules/type-is": { "version": "2.0.1", - "resolved": "https://mirrors.tencent.com/npm/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", @@ -923,13 +803,10 @@ }, "node_modules/typedarray": { "version": "0.0.6", - "resolved": "https://mirrors.tencent.com/npm/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + "license": "MIT" }, "node_modules/unpipe": { "version": "1.0.0", - "resolved": "https://mirrors.tencent.com/npm/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -937,29 +814,23 @@ }, "node_modules/util-deprecate": { "version": "1.0.2", - "resolved": "https://mirrors.tencent.com/npm/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, "node_modules/vary": { "version": "1.1.2", - "resolved": "https://mirrors.tencent.com/npm/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/wrappy": { "version": "1.0.2", - "resolved": "https://mirrors.tencent.com/npm/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, "node_modules/ws": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", - "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", - "license": "MIT", + "version": "8.18.0", + "resolved": "https://mirrors.tencent.com/npm/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "engines": { "node": ">=10.0.0" }, diff --git a/server/package.json b/server/package.json index 83b478b..8d2c0ae 100644 --- a/server/package.json +++ b/server/package.json @@ -11,6 +11,6 @@ "dependencies": { "express": "^5.2.1", "multer": "^2.1.1", - "ws": "^8.16.0" + "ws": "8.18.0" } } diff --git a/server/run-deploy.sh b/server/run-deploy.sh index 9e47e11..ed7165d 100755 --- a/server/run-deploy.sh +++ b/server/run-deploy.sh @@ -13,7 +13,7 @@ exec > >(tee -a "$LOG") 2>&1 SERVER_DIR="/Users/hanchengxi/workspace/tankwar_proj/server" MASTER="root@host_172.16.16.16" -WORKERS_IP=("172.16.16.17" "172.16.16.8") +WORKERS_IP=("10.1.0.6" "172.16.32.10" "172.16.32.16") REMOTE_BUILD_DIR="/tmp/tankwar-build" IMAGE_NAME="tankwar/tankwar-server:latest" @@ -24,7 +24,7 @@ ts() { echo "[$(date '+%H:%M:%S')]"; } # ------------------------------------------------------------ echo "$(ts) ===== Syncing tankwar server source to master node =====" ssh -o StrictHostKeyChecking=no "$MASTER" "mkdir -p $REMOTE_BUILD_DIR" -rsync -az --delete --exclude='.git' --exclude='node_modules' \ +rsync -az --delete --exclude='.git' \ -e "ssh -o StrictHostKeyChecking=no" \ "$SERVER_DIR/" "${MASTER}:${REMOTE_BUILD_DIR}/server/" echo "$(ts) ✓ Source synced"